Load palette from console

Post tutorials on how to do certain tasks within game or engine code here.
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Load palette from console

Post by qbism »

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.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Load palette from console

Post by leileilol »

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
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

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

This is a pretty good Tutorial!
Sajt
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Post by Sajt »

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.
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

Oh well. Good tutorial nonetheless
andrewj
Posts: 133
Joined: Mon Aug 30, 2010 3:29 pm
Location: Australia

Re: Load palette from console

Post by andrewj »

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?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

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.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

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
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Post by qbism »

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.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

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 ..
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Post by qbism »

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
Sajt
Posts: 1215
Joined: Sat Oct 16, 2004 3:39 am

Post by Sajt »

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.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

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 ..
Ranger366
Posts: 203
Joined: Thu Mar 18, 2010 5:51 pm

Post by Ranger366 »

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.
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Post by qbism »

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.
Post Reply