Forum

Load palette from console

Post tutorials on how to do certain tasks within game or engine code here.

Moderator: InsideQC Admins

Load palette from console

Postby qbism » Thu Jan 13, 2011 3:36 am

Lately I've been using GIMP and fimg to tweak the palette just to see what happens. The idea is to change the ambiance. For example, rebalance dark colors toward blue and light colors toward yellow, like sunlight and shadow. Another example- make the palette mostly desaturated for a '300' or 'Sin City' look.

This tutorial allows different palette lmp files to be loaded in the console, "loadpalette mypal" will load mypal.lmp. It's simple but will need adjustment for your particular engine.

What I'm not sure of... should there be a way to load a colormap lmp?

EDIT: Removed ifdef around Q_snprintfz per discussion below.

In r_main.c:
Code: Select all
extern   byte      *host_basepal;

/*
===============
R_LoadPalette
===============
*/

void R_LoadPalette (char *name) //qbism - load a palette lmp
{
    loadedfile_t   *fileinfo;
    char   pathname[MAX_QPATH];

    Q_snprintfz (pathname, sizeof(pathname), "gfx/%s.lmp", name);

    fileinfo = COM_LoadHunkFile (pathname);
    if (!fileinfo)
    {
        Con_Printf("Palette not found.\n");
        return;
    }
    Q_memcpy (host_basepal, fileinfo->data, 768);
    VID_SetPalette (host_basepal);
}

/*
===============
R_LoadPalette_f
===============
*/
void R_LoadPalette_f (void) //qbism - load an alternate palette
{
    if (Cmd_Argc() != 2)
    {
        Con_Printf ("loadpalette <name> : load a color palette\n");
        return;
    }
    R_LoadPalette(Cmd_Argv(1));
}



EDIT: Add regenerate colormap. This will greatly improve lighting quality for your new palette. Add the following code above loadpalette, it is indeed adapted from qlumpy.

Code: Select all
/*
=============================================================================

COLORMAP GRABBING

=============================================================================
*/

/*
===============
BestColor - qbism- from qlumpy
===============
*/
byte BestColor (int r, int g, int b, int start, int stop)
{
   int   i;
   int   dr, dg, db;
   int   bestdistortion, distortion;
   int   bestcolor;
   byte   *pal;

//
// let any color go to 0 as a last resort
//
   bestdistortion = ( (int)r*r + (int)g*g + (int)b*b )*2;
   bestcolor = 0;

   pal = host_basepal + start*3;
   for (i=start ; i<= stop ; i++)
   {
      dr = r - (int)pal[0];
      dg = g - (int)pal[1];
      db = b - (int)pal[2];
      pal += 3;
      distortion = dr*dr + dg*dg + db*db;
      if (distortion < bestdistortion)
      {
         if (!distortion)
            return i;      // perfect match

         bestdistortion = distortion;
         bestcolor = i;
      }
   }

   return bestcolor;
}


/*
==============
GrabColormap - qbism- from qlumpy

filename COLORMAP levels fullbrights
the first map is an identiy 0-255
the final map is all black except for the fullbrights
the remaining maps are evenly spread
fullbright colors start at the top of the palette.
==============
*/
void GrabColormap (void)
{
   int      levels, brights;
   int      l, c;
   float   frac, red, green, blue;
   byte *colmap;

   colmap = host_colormap;

   levels = 32;
   brights = 256;

// identity lump
   for (l=0 ; l<256 ; l++)
      *colmap++ = l;

// shaded levels
   for (l=1;l<levels;l++)
   {
      frac = 1.0 - (float)l/(levels-1);
      for (c=0 ; c<256-brights ; c++)
      {
         red = host_basepal[c*3];
         green = host_basepal[c*3+1];
         blue = host_basepal[c*3+2];

         red = (int)(red*frac+0.5);
         green = (int)(green*frac+0.5);
         blue = (int)(blue*frac+0.5);

//
// note: 254 instead of 255 because 255 is the transparent color, and we
// don't want anything remapping to that
//
         *colmap++ = BestColor(red,green,blue, 0, 254);
      }
      for ( ; c<256 ; c++)
         *colmap++ = c;
   }

   *colmap++ = brights;
}



In R_LoadPalette, Add this above Vid_SetPalette
Code: Select all
GrabColormap();




If you want to add a palette field to the worldspawn, add a check for it in CL_ParseEntityLump.

A further step might be remipping textures using the new palette. So far I haven't noticed anything horrible enough to warrant this intensive step.
Last edited by qbism on Wed Apr 06, 2011 4:59 pm, edited 3 times in total.
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Re: Load palette from console

Postby leileilol » Thu Jan 13, 2011 4:10 am

qbism wrote:should there be a way to load a colormap lmp?


Sure, but with today's awesome CPUs above 300mhz you can just generate it on the fly - no excuse for that now.

Check the qlumpy source in qtools_gpl.tar.gz for that, and have fun adapting it and throwing cvars in there for it.

The biggest problem are mipmaps - either regenerate those as well or deal with pixely artifacts from anti-aliased pixels meant for the former palette.
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Postby Mexicouger » Thu Jan 13, 2011 4:26 am

This could be used to attach to models too correct? Like load a palette for a certain model?

This is a pretty good Tutorial!
User avatar
Mexicouger
 
Posts: 514
Joined: Sat May 01, 2010 10:12 pm

Postby Sajt » Thu Jan 13, 2011 4:28 am

Mexicouger wrote:This could be used to attach to models too correct? Like load a palette for a certain model?


Nope, it replaces the global palette.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Sajt
 
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Postby Mexicouger » Thu Jan 13, 2011 5:38 am

Oh well. Good tutorial nonetheless
User avatar
Mexicouger
 
Posts: 514
Joined: Sat May 01, 2010 10:12 pm

Re: Load palette from console

Postby andrewj » Thu Jan 13, 2011 6:31 am

qbism wrote:#ifdef __linux__
sprintf (pathname, sizeof(pathname), "gfx/%s.lmp\0", name);
#else
Q_snprintfz (pathname, sizeof(pathname), "gfx/%s.lmp\0", name);
#endif

I'm curious, why does Linux need special treatment there?
andrewj
 
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Postby Spike » Thu Jan 13, 2011 9:54 am

because someone forgot to #define Q_snprintfz snprintf for linux.
of course, if you try compiling the code, the linux version will crash due to seeing an int where it expected a string, because its got sprintf instead of snprintf. so mneh.
note that windows' _snprintf function is not compatible with linux/bsd's snprintf as it doesn't guarentee null termination. I think the return values are different too, but those are rarely used.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby mh » Thu Jan 13, 2011 11:29 am

Spike wrote:because someone forgot to #define Q_snprintfz snprintf for linux.
of course, if you try compiling the code, the linux version will crash due to seeing an int where it expected a string, because its got sprintf instead of snprintf. so mneh.
note that windows' _snprintf function is not compatible with linux/bsd's snprintf as it doesn't guarentee null termination. I think the return values are different too, but those are rarely used.

Which is probably why Q_snprintfz is used for non-Linux in this code (which won't compile either as Q_snprintfz doesn't exist in stock ID Quake, but that's beside the point). Maybe the question should be "why does non-Linux need special treatment there?" instead?
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Postby qbism » Thu Jan 13, 2011 6:04 pm

Regarding Q_snprintfz, I should have mentioned that, but good explanation above. MicroSoft's _snprintf does not guarantee null termintation as gcc's snprintf does.

I haven't tried to compile this in Linux, the #ifdef is patterned after similar (ancient) parts of the source. But it would probably be better to deal with that in the definition of Q_snprintfz instead of every single time it's called. If that's even possible. Currently I've been using mingw which includes gcc . I don't know if gcc in Linux would have the same behavior. If it did, that #ifdef could be removed.

leileilol wrote:The biggest problem are mipmaps - either regenerate those as well or deal with pixely artifacts from anti-aliased pixels meant for the former palette.
Hadn't thought of that, but noticed it when the colors stray too far from original.
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Postby Baker » Thu Jan 13, 2011 9:19 pm

Very interesting tutorial. :D

#ifdef __linux__
sprintf (pathname, sizeof(pathname), "gfx/%s.lmp\0", name);
#else
Q_snprintfz (pathname, sizeof(pathname), "gfx/%s.lmp\0", name);

#endif


Should be ...

Q_snprintfz (pathname, sizeof(pathname), "gfx/%s.lmp", name);


You can kill the #ifdef and kill the "\0" ... Q_snprintfz is platform neutral and null terminates so the Linux #ifdef is unnecessary and Q_snprintfz null terminates so adding a "\0" to the string is not only redundant, but is actually entirely unhelpful because if the resulting string length > sizeof(pathname) it would be truncated from the result anyway (!!).
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby qbism » Fri Jan 14, 2011 12:40 am

Baker wrote:kill the #ifdef and kill the "\0" ... Q_snprintfz is platform neutral

Excellent, corrected above! I don't know why I never removed the \0 before. :D
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Postby Sajt » Fri Jan 14, 2011 3:12 am

Baker wrote:You can kill the #ifdef and kill the "\0" ... Q_snprintfz is platform neutral and null terminates so the Linux #ifdef is unnecessary and Q_snprintfz null terminates so adding a "\0" to the string is not only redundant, but is actually entirely unhelpful because if the resulting string length > sizeof(pathname) it would be truncated from the result anyway (!!).


Actually, the \0 doesn't make a difference. It's baffling that someone would put it in there.
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Sajt
 
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Postby Baker » Fri Jan 14, 2011 3:56 am

Okay\0
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Postby Ranger366 » Fri Jan 14, 2011 5:38 pm

I already wanted to implent something similar to my engine, that a map has the ability to have an own palette file. But i stopped it.
User avatar
Ranger366
 
Posts: 203
Joined: Thu Mar 18, 2010 5:51 pm

Postby qbism » Sat Jan 15, 2011 3:24 am

Ranger366 wrote:I already wanted to implent something similar to my engine, that a map has the ability to have an own palette file.
Look at how skyboxes are implemented.
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Next

Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest