+skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height, int bitsperpixel, const unsigned int *palette, const unsigned int *alphapalette)
+{
+ int i;
+ unsigned char *temp1, *temp2;
+ skinframe_t *skinframe;
+
+ if (cls.state == ca_dedicated)
+ return NULL;
+
+ // if already loaded just return it, otherwise make a new skinframe
+ skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
+ if (skinframe && skinframe->base)
+ return skinframe;
+
+ skinframe->stain = NULL;
+ skinframe->merged = NULL;
+ skinframe->base = r_texture_notexture;
+ skinframe->pants = NULL;
+ skinframe->shirt = NULL;
+ skinframe->nmap = r_texture_blanknormalmap;
+ skinframe->gloss = NULL;
+ skinframe->glow = NULL;
+ skinframe->fog = NULL;
+
+ // if no data was provided, then clearly the caller wanted to get a blank skinframe
+ if (!skindata)
+ return NULL;
+
+ if (bitsperpixel == 32)
+ {
+ if (r_shadow_bumpscale_basetexture.value > 0)
+ {
+ temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+ temp2 = temp1 + width * height * 4;
+ Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
+ skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
+ Mem_Free(temp1);
+ }
+ skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+ if (textureflags & TEXF_ALPHA)
+ {
+ for (i = 3;i < width * height * 4;i += 4)
+ if (skindata[i] < 255)
+ break;
+ if (i < width * height * 4)
+ {
+ unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
+ memcpy(fogpixels, skindata, width * height * 4);
+ for (i = 0;i < width * height * 4;i += 4)
+ fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
+ skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
+ Mem_Free(fogpixels);
+ }
+ }
+ }
+ else if (bitsperpixel == 8)
+ {
+ if (r_shadow_bumpscale_basetexture.value > 0)
+ {
+ temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
+ temp2 = temp1 + width * height * 4;
+ if (bitsperpixel == 32)
+ Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
+ else
+ {
+ // use either a custom palette or the quake palette
+ Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
+ Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
+ }
+ skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
+ Mem_Free(temp1);
+ }
+ // use either a custom palette, or the quake palette
+ skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette ? palette : (loadglowtexture ? palette_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_transparent : palette_complete)), skinframe->textureflags, true); // all
+ if (!palette && loadglowtexture)
+ skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
+ if (!palette && loadpantsandshirt)
+ {
+ skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
+ skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
+ }
+ if (skinframe->pants || skinframe->shirt)
+ skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
+ if (textureflags & TEXF_ALPHA)
+ {
+ // if not using a custom alphapalette, use the quake one
+ if (!alphapalette)
+ alphapalette = palette_alpha;
+ for (i = 0;i < width * height;i++)
+ if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
+ break;
+ if (i < width * height)
+ skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
+ }
+ }
+
+ return skinframe;
+}
+
+skinframe_t *R_SkinFrame_LoadMissing(void)
+{
+ skinframe_t *skinframe;
+
+ if (cls.state == ca_dedicated)
+ return NULL;
+
+ skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
+ skinframe->stain = NULL;
+ skinframe->merged = NULL;
+ skinframe->base = r_texture_notexture;
+ skinframe->pants = NULL;
+ skinframe->shirt = NULL;
+ skinframe->nmap = r_texture_blanknormalmap;
+ skinframe->gloss = NULL;
+ skinframe->glow = NULL;
+ skinframe->fog = NULL;
+
+ return skinframe;
+}
+
+void gl_main_start(void)
+{
+ int x;
+ double r, alpha;
+
+ r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
+ for (x = 0;x < FOGMASKTABLEWIDTH;x++)
+ {
+ alpha = 1 - exp(r / ((double)x*(double)x));
+ if (x == FOGMASKTABLEWIDTH - 1)
+ alpha = 0;
+ r_refdef.fogmasktable[x] = bound(0, alpha, 1);
+ }
+
+ memset(r_qwskincache, 0, sizeof(r_qwskincache));
+ memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
+
+ // set up r_skinframe loading system for textures
+ memset(&r_skinframe, 0, sizeof(r_skinframe));
+ r_skinframe.loadsequence = 1;
+ Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
+
+ r_main_texturepool = R_AllocTexturePool();
+ R_BuildBlankTextures();
+ R_BuildNoTexture();
+ if (gl_texturecubemap)
+ {
+ R_BuildWhiteCube();
+ R_BuildNormalizationCube();
+ }
+ R_BuildFogTexture();
+ memset(&r_bloomstate, 0, sizeof(r_bloomstate));
+ memset(&r_waterstate, 0, sizeof(r_waterstate));
+ memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
+ memset(&r_svbsp, 0, sizeof (r_svbsp));
+}
+
+void gl_main_shutdown(void)
+{
+ memset(r_qwskincache, 0, sizeof(r_qwskincache));
+ memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
+
+ // clear out the r_skinframe state
+ Mem_ExpandableArray_FreeArray(&r_skinframe.array);
+ memset(&r_skinframe, 0, sizeof(r_skinframe));
+
+ if (r_svbsp.nodes)
+ Mem_Free(r_svbsp.nodes);
+ memset(&r_svbsp, 0, sizeof (r_svbsp));
+ R_FreeTexturePool(&r_main_texturepool);
+ r_texture_blanknormalmap = NULL;
+ r_texture_white = NULL;
+ r_texture_grey128 = NULL;
+ r_texture_black = NULL;
+ r_texture_whitecube = NULL;
+ r_texture_normalizationcube = NULL;
+ memset(&r_bloomstate, 0, sizeof(r_bloomstate));
+ memset(&r_waterstate, 0, sizeof(r_waterstate));
+ R_GLSL_Restart_f();
+}
+
+extern void CL_ParseEntityLump(char *entitystring);
+void gl_main_newmap(void)
+{
+ // FIXME: move this code to client
+ int l;
+ char *entities, entname[MAX_QPATH];
+ if (cl.worldmodel)
+ {
+ strlcpy(entname, cl.worldmodel->name, sizeof(entname));
+ l = (int)strlen(entname) - 4;
+ if (l >= 0 && !strcmp(entname + l, ".bsp"))
+ {
+ memcpy(entname + l, ".ent", 5);
+ if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
+ {
+ CL_ParseEntityLump(entities);
+ Mem_Free(entities);
+ return;
+ }
+ }
+ if (cl.worldmodel->brush.entities)
+ CL_ParseEntityLump(cl.worldmodel->brush.entities);
+ }
+}
+
+void GL_Main_Init(void)
+{
+ r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
+
+ Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
+ Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
+ // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
+ if (gamemode == GAME_NEHAHRA)
+ {
+ Cvar_RegisterVariable (&gl_fogenable);
+ Cvar_RegisterVariable (&gl_fogdensity);
+ Cvar_RegisterVariable (&gl_fogred);
+ Cvar_RegisterVariable (&gl_foggreen);
+ Cvar_RegisterVariable (&gl_fogblue);
+ Cvar_RegisterVariable (&gl_fogstart);
+ Cvar_RegisterVariable (&gl_fogend);
+ }
+ Cvar_RegisterVariable(&r_depthfirst);