X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_brush.c;h=5788727d4c6f4da4f6f6731a26163b92736bda02;hb=579d8a7ad10a567c0ade9a198e9a690440b58b1a;hp=088671193e612439db269020e0823808c857afc1;hpb=fb50b725b05ef354988b9725eb6369bbe5af29aa;p=xonotic%2Fdarkplaces.git diff --git a/model_brush.c b/model_brush.c index 08867119..5788727d 100644 --- a/model_brush.c +++ b/model_brush.c @@ -48,6 +48,7 @@ cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "select cvar_t mod_q3bsp_lightmapmergepower = {CVAR_SAVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."}; cvar_t mod_q3bsp_nolightmaps = {CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"}; cvar_t mod_q3bsp_tracelineofsight_brushes = {0, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"}; +cvar_t mod_q3bsp_sRGBlightmaps = {0, "mod_q3bsp_sRGBlightmaps", "0", "treat lightmaps from Q3 maps as sRGB when vid_sRGB is active"}; cvar_t mod_q3shader_default_offsetmapping = {CVAR_SAVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are using q3 shader files"}; cvar_t mod_q3shader_default_offsetmapping_scale = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_scale", "1", "default scale used for offsetmapping"}; cvar_t mod_q3shader_default_offsetmapping_bias = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_bias", "0", "default bias used for offsetmapping"}; @@ -57,7 +58,6 @@ cvar_t mod_q3shader_force_addalpha = {0, "mod_q3shader_force_addalpha", "0", "tr cvar_t mod_q1bsp_polygoncollisions = {0, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"}; cvar_t mod_collision_bih = {0, "mod_collision_bih", "1", "enables use of generated Bounding Interval Hierarchy tree instead of compiled bsp tree in collision code"}; cvar_t mod_recalculatenodeboxes = {0, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"}; -extern cvar_t vid_sRGB; static texture_t mod_q1bsp_texture_solid; static texture_t mod_q1bsp_texture_sky; @@ -88,6 +88,7 @@ void Mod_BrushInit(void) Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush); Cvar_RegisterVariable(&mod_q3bsp_lightmapmergepower); Cvar_RegisterVariable(&mod_q3bsp_nolightmaps); + Cvar_RegisterVariable(&mod_q3bsp_sRGBlightmaps); Cvar_RegisterVariable(&mod_q3bsp_tracelineofsight_brushes); Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping); Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping_scale); @@ -1293,7 +1294,7 @@ loc0: } } -void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal) +static void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal) { // pretend lighting is coming down from above (due to lack of a lightgrid to know primary lighting direction) VectorSet(diffusenormal, 0, 0, 1); @@ -1531,7 +1532,7 @@ R_Q1BSP_LoadSplitSky A sky texture is 256*128, with the right side being a masked overlay ============== */ -void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesperpixel) +static void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesperpixel) { int x, y; int w = width/2; @@ -1609,6 +1610,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) const char *s; char mapname[MAX_QPATH], name[MAX_QPATH]; unsigned char zeroopaque[4], zerotrans[4]; + char vabuf[1024]; Vector4Set(zeroopaque, 0, 0, 0, 255); Vector4Set(zerotrans, 0, 0, 0, 128); @@ -1772,6 +1774,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) { tx->supercontents = mod_q1bsp_texture_sky.supercontents; tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags; + tx->supercontents |= SUPERCONTENTS_SOLID; // for the surface traceline we need to hit this surface as a solid... } else { @@ -1784,9 +1787,9 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) // LordHavoc: HL sky textures are entirely different than quake if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == mtheight * 2) { - data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), false, false, false, NULL); + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), false, false, false, NULL); if (!data) - data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), false, false, false, NULL); + data = loadimagepixelsbgra(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), false, false, false, NULL); if (data && image_width == image_height * 2) { R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); @@ -1797,9 +1800,9 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) } else { - skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s/%s", mapname, tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); if (!skinframe) - skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); + skinframe = R_SkinFrame_LoadExternal(gamemode == GAME_TENEBRAE ? tx->name : va(vabuf, sizeof(vabuf), "textures/%s", tx->name), TEXF_ALPHA | TEXF_MIPMAP | TEXF_ISWORLD | TEXF_PICMIP | TEXF_COMPRESS, false); if (skinframe) tx->offsetmapping = OFFSETMAPPING_DEFAULT; // allow offsetmapping on external textures without a q3 shader if (!skinframe) @@ -2074,13 +2077,13 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) int i, j, k; if (!data) return; - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] != '{') return; // error while (1) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] == '}') break; // end of worldspawn @@ -2090,7 +2093,7 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) strlcpy(key, com_token, sizeof(key)); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error dpsnprintf(value, sizeof(value), "%s", com_token); if (!strcmp("wad", key)) // for HalfLife maps @@ -2163,7 +2166,7 @@ static void Mod_Q1BSP_LoadVertexes(lump_t *l) // The following two functions should be removed and MSG_* or SZ_* function sets adjusted so they // can be used for this // REMOVEME -int SB_ReadInt (unsigned char **buffer) +static int SB_ReadInt (unsigned char **buffer) { int i; i = ((*buffer)[0]) + 256*((*buffer)[1]) + 65536*((*buffer)[2]) + 16777216*((*buffer)[3]); @@ -2172,7 +2175,7 @@ int SB_ReadInt (unsigned char **buffer) } // REMOVEME -float SB_ReadFloat (unsigned char **buffer) +static float SB_ReadFloat (unsigned char **buffer) { union { @@ -2459,6 +2462,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber, lightmapsize, totallightmapsamples; float texmins[2], texmaxs[2], val; rtexture_t *lightmaptexture, *deluxemaptexture; + char vabuf[1024]; in = (dface_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -2667,9 +2671,9 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) loadmodel->brushq3.num_mergedlightmaps = lightmapnumber + 1; loadmodel->brushq3.data_lightmaps = (rtexture_t **)Mem_Realloc(loadmodel->mempool, loadmodel->brushq3.data_lightmaps, loadmodel->brushq3.num_mergedlightmaps * sizeof(loadmodel->brushq3.data_lightmaps[0])); loadmodel->brushq3.data_deluxemaps = (rtexture_t **)Mem_Realloc(loadmodel->mempool, loadmodel->brushq3.data_deluxemaps, loadmodel->brushq3.num_mergedlightmaps * sizeof(loadmodel->brushq3.data_deluxemaps[0])); - loadmodel->brushq3.data_lightmaps[lightmapnumber] = lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); + loadmodel->brushq3.data_lightmaps[lightmapnumber] = lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); if (loadmodel->brushq1.nmaplightdata) - loadmodel->brushq3.data_deluxemaps[lightmapnumber] = deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); + loadmodel->brushq3.data_deluxemaps[lightmapnumber] = deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%i", lightmapnumber), lightmapsize, lightmapsize, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_ALLOWUPDATES, -1, NULL); lightmapnumber++; Mod_AllocLightmap_Reset(&allocState); Mod_AllocLightmap_Block(&allocState, ssize, tsize, &lightmapx, &lightmapy); @@ -2889,7 +2893,7 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) } } -qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void) +static qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void) { int i, j; mleaf_t *leaf; @@ -3059,12 +3063,12 @@ static void Mod_Q1BSP_LoadMapBrushes(void) if (!maptext) return; text = maptext; - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error submodel = 0; for (;;) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) break; if (com_token[0] != '{') return; // error @@ -3075,7 +3079,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void) brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t)); for (;;) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] == '}') break; // end of entity @@ -3099,7 +3103,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void) } for (;;) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) return; // error if (com_token[0] == '}') break; // end of brush @@ -3108,25 +3112,25 @@ static void Mod_Q1BSP_LoadMapBrushes(void) // FIXME: support hl .map format for (pointnum = 0;pointnum < 3;pointnum++) { - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); for (componentnum = 0;componentnum < 3;componentnum++) { - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); point[pointnum][componentnum] = atof(com_token); } - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); } - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); strlcpy(facetexture, com_token, sizeof(facetexture)); - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); //scroll_s = atof(com_token); - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); //scroll_t = atof(com_token); - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); //rotate = atof(com_token); - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); //scale_s = atof(com_token); - COM_ParseToken_Simple(&data, false, false); + COM_ParseToken_Simple(&data, false, false, true); //scale_t = atof(com_token); TriangleNormal(point[0], point[1], point[2], planenormal); VectorNormalizeDouble(planenormal); @@ -4373,7 +4377,7 @@ static void Mod_Q2BSP_LoadModels(lump_t *l) */ } -void static Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +static void Mod_Q2BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) { int i; q2dheader_t *header; @@ -4449,11 +4453,11 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l) // some Q3 maps override the lightgrid_cellsize with a worldspawn key // VorteX: q3map2 FS-R generates tangentspace deluxemaps for q3bsp and sets 'deluxeMaps' key loadmodel->brushq3.deluxemapping = false; - if (data && COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{') + if (data && COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{') { while (1) { - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) break; // error if (com_token[0] == '}') break; // end of worldspawn @@ -4463,7 +4467,7 @@ static void Mod_Q3BSP_LoadEntities(lump_t *l) strlcpy(key, com_token, sizeof(key)); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; - if (!COM_ParseToken_Simple(&data, false, false)) + if (!COM_ParseToken_Simple(&data, false, false, true)) break; // error strlcpy(value, com_token, sizeof(value)); if (!strcasecmp("gridsize", key)) // this one is case insensitive to 100% match q3map2 @@ -4724,9 +4728,40 @@ static void Mod_Q3BSP_LoadVertices(lump_t *l) loadmodel->brushq3.data_texcoordlightmap2f[i * 2 + 0] = LittleFloat(in->lightmap2f[0]); loadmodel->brushq3.data_texcoordlightmap2f[i * 2 + 1] = LittleFloat(in->lightmap2f[1]); // svector/tvector are calculated later in face loading - loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); - loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); - loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + if(mod_q3bsp_sRGBlightmaps.integer) + { + // if lightmaps are sRGB, vertex colors are sRGB too, so we need to linearize them + // note: when this is in use, lightmap color 128 is no longer neutral, but "sRGB half power" is + // working like this may be odd, but matches q3map2 -gamma 2.2 + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + // we fix the brightness consistently via lightmapscale + } + else + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = Image_LinearFloatFromsRGB(in->color4ub[0]); + loadmodel->brushq3.data_color4f[i * 4 + 1] = Image_LinearFloatFromsRGB(in->color4ub[1]); + loadmodel->brushq3.data_color4f[i * 4 + 2] = Image_LinearFloatFromsRGB(in->color4ub[2]); + } + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[0]); + loadmodel->brushq3.data_color4f[i * 4 + 1] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[1]); + loadmodel->brushq3.data_color4f[i * 4 + 2] = Image_sRGBFloatFromLinear_Lightmap(in->color4ub[2]); + } + else + { + loadmodel->brushq3.data_color4f[i * 4 + 0] = in->color4ub[0] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 1] = in->color4ub[1] * (1.0f / 255.0f); + loadmodel->brushq3.data_color4f[i * 4 + 2] = in->color4ub[2] * (1.0f / 255.0f); + } + } loadmodel->brushq3.data_color4f[i * 4 + 3] = in->color4ub[3] * (1.0f / 255.0f); if(in->color4ub[0] != 255 || in->color4ub[1] != 255 || in->color4ub[2] != 255) loadmodel->lit = true; @@ -4798,6 +4833,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) char mapname[MAX_QPATH]; qboolean external; unsigned char *inpixels[10000]; // max count q3map2 can output (it uses 4 digits) + char vabuf[1024]; // defaults for q3bsp size = 128; @@ -4834,7 +4870,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) if (developer_loading.integer) Con_Printf("Using external lightmaps\n"); FS_StripExtension(loadmodel->name, mapname, sizeof(mapname)); - inpixels[0] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, 0), false, false, false, NULL); + inpixels[0] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, 0), false, false, false, NULL); if(!inpixels[0]) return; @@ -4854,7 +4890,7 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) for(count = 1; ; ++count) { - inpixels[count] = loadimagepixelsbgra(va("%s/lm_%04d", mapname, count), false, false, false, NULL); + inpixels[count] = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s/lm_%04d", mapname, count), false, false, false, NULL); if(!inpixels[count]) break; // we got all of them if(image_width != size || image_height != size) @@ -5008,12 +5044,27 @@ static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump) if (((realindex + 1) & (mergedrowsxcolumns - 1)) == 0 || (realindex + 1) == realcount) { if (loadmodel->brushq3.deluxemapping && (i & 1)) - loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), mergedwidth, mergedheight, mergeddeluxepixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%04i", lightmapindex), mergedwidth, mergedheight, mergeddeluxepixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bspdeluxemaps.integer ? TEXF_COMPRESS : 0), -1, NULL); else { - if(vid_sRGB.integer && !vid.sRGBcapable3D) - Image_MakesRGBColorsFromLinear(mergedpixels, mergedpixels, mergedwidth * mergedheight); - loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + if(mod_q3bsp_sRGBlightmaps.integer) + { + textype_t t; + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + t = TEXTYPE_BGRA; // in stupid fallback mode, we upload lightmaps in sRGB form and just fix their brightness + // we fix the brightness consistently via lightmapscale + } + else + t = TEXTYPE_SRGB_BGRA; // normally, we upload lightmaps in sRGB form (possibly downconverted to linear) + loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, t, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + Image_MakesRGBColorsFromLinear_Lightmap(mergedpixels, mergedpixels, mergedwidth * mergedheight); + loadmodel->brushq3.data_lightmaps [lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va(vabuf, sizeof(vabuf), "lightmap%04i", lightmapindex), mergedwidth, mergedheight, mergedpixels, TEXTYPE_BGRA, TEXF_FORCELINEAR | (gl_texturecompression_q3bsplightmaps.integer ? TEXF_COMPRESS : 0), -1, NULL); + } } } } @@ -5764,6 +5815,7 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) q3dlightgrid_t *in; q3dlightgrid_t *out; int count; + int i; in = (q3dlightgrid_t *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -5799,6 +5851,45 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) loadmodel->brushq3.num_lightgrid = count; // no swapping or validation necessary memcpy(out, in, count * (int)sizeof(*out)); + + if(mod_q3bsp_sRGBlightmaps.integer) + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + // we fix the brightness consistently via lightmapscale + } + else + { + for(i = 0; i < count; ++i) + { + out[i].ambientrgb[0] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[0]) * 255.0f + 0.5f); + out[i].ambientrgb[1] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[1]) * 255.0f + 0.5f); + out[i].ambientrgb[2] = floor(Image_LinearFloatFromsRGB(out[i].ambientrgb[2]) * 255.0f + 0.5f); + out[i].diffusergb[0] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[0]) * 255.0f + 0.5f); + out[i].diffusergb[1] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[1]) * 255.0f + 0.5f); + out[i].diffusergb[2] = floor(Image_LinearFloatFromsRGB(out[i].diffusergb[2]) * 255.0f + 0.5f); + } + } + } + else + { + if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + for(i = 0; i < count; ++i) + { + out[i].ambientrgb[0] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[0]) * 255.0f + 0.5f); + out[i].ambientrgb[1] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[1]) * 255.0f + 0.5f); + out[i].ambientrgb[2] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].ambientrgb[2]) * 255.0f + 0.5f); + out[i].diffusergb[0] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[0]) * 255.0f + 0.5f); + out[i].diffusergb[1] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[1]) * 255.0f + 0.5f); + out[i].diffusergb[2] = floor(Image_sRGBFloatFromLinear_Lightmap(out[i].diffusergb[2]) * 255.0f + 0.5f); + } + } + else + { + // all is good + } + } } } @@ -6064,7 +6155,7 @@ void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameble } } -void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, const bih_t *bih) +static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, const bih_t *bih) { const bih_leaf_t *leaf; const bih_node_t *node; @@ -6338,7 +6429,7 @@ void Mod_CollisionBIH_TraceBox(dp_model_t *model, const frameblend_t *frameblend } -int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point) +static int Mod_CollisionBIH_PointSuperContents(struct model_s *model, int frame, const vec3_t point) { trace_t trace; Mod_CollisionBIH_TracePoint(model, NULL, NULL, &trace, point, 0); @@ -6660,7 +6751,7 @@ static void Mod_Q3BSP_TraceLine(dp_model_t *model, const frameblend_t *frameblen Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs); } -void Mod_Q3BSP_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *start, colbrushf_t *end, int hitsupercontentsmask) +static void Mod_Q3BSP_TraceBrush(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, colbrushf_t *start, colbrushf_t *end, int hitsupercontentsmask) { float segmentmins[3], segmentmaxs[3]; int i; @@ -6725,9 +6816,7 @@ static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const q3mbrush_t *brush; if (mod_collision_bih.integer) { - trace_t trace; - Mod_Q3BSP_TracePoint(model, NULL, NULL, &trace, point, 0); - supercontents = trace.startsupercontents; + supercontents = Mod_CollisionBIH_PointSuperContents(model, frame, point); } // test if the point is inside each brush else if (model->brush.submodel) @@ -6957,7 +7046,7 @@ static int Mod_Q3BSP_NativeContentsFromSuperContents(dp_model_t *model, int supe return nativecontents; } -void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node) +static void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node) { int numleafs; while (node->plane) @@ -6970,7 +7059,7 @@ void Mod_Q3BSP_RecursiveFindNumLeafs(mnode_t *node) loadmodel->brush.num_leafs = numleafs; } -void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) +static void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) { int i, j, lumps; q3dheader_t *header; @@ -7205,6 +7294,30 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) Mod_BuildVBOs(); } + if (mod_q3bsp_sRGBlightmaps.integer) + { + if (vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D) + { + // actually we do in sRGB fallback with sRGB lightmaps: Image_sRGBFloatFromLinear_Lightmap(Image_LinearFloatFromsRGBFloat(x)) + // neutral point is at Image_sRGBFloatFromLinearFloat(0.5) + // so we need to map Image_sRGBFloatFromLinearFloat(0.5) to 0.5 + // factor is 0.5 / Image_sRGBFloatFromLinearFloat(0.5) + //loadmodel->lightmapscale *= 0.679942f; // fixes neutral level + } + else // if this is NOT set, regular rendering looks right by this requirement anyway + { + /* + // we want color 1 to do the same as without sRGB + // so, we want to map 1 to Image_LinearFloatFromsRGBFloat(2) instead of to 2 + loadmodel->lightmapscale *= 2.476923f; // fixes max level + */ + + // neutral level 0.5 gets uploaded as sRGB and becomes Image_LinearFloatFromsRGBFloat(0.5) + // we need to undo that + loadmodel->lightmapscale *= 2.336f; // fixes neutral level + } + } + Con_DPrintf("Stats for q3bsp model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); } @@ -7814,40 +7927,3 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) Con_DPrintf("Stats for obj model \"%s\": %i faces, %i nodes, %i leafs, %i clusters, %i clusterportals, mesh: %i vertices, %i triangles, %i surfaces\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->num_surfaces); } - -qboolean Mod_CanSeeBox_Trace(int numsamples, float t, dp_model_t *model, vec3_t eye, vec3_t minsX, vec3_t maxsX) -{ - // we already have done PVS culling at this point... - // so we don't need to do it again. - - int i; - vec3_t testorigin, mins, maxs; - - testorigin[0] = (minsX[0] + maxsX[0]) * 0.5; - testorigin[1] = (minsX[1] + maxsX[1]) * 0.5; - testorigin[2] = (minsX[2] + maxsX[2]) * 0.5; - - if(model->brush.TraceLineOfSight(model, eye, testorigin)) - return 1; - - // expand the box a little - mins[0] = (t+1) * minsX[0] - t * maxsX[0]; - maxs[0] = (t+1) * maxsX[0] - t * minsX[0]; - mins[1] = (t+1) * minsX[1] - t * maxsX[1]; - maxs[1] = (t+1) * maxsX[1] - t * minsX[1]; - mins[2] = (t+1) * minsX[2] - t * maxsX[2]; - maxs[2] = (t+1) * maxsX[2] - t * minsX[2]; - - for(i = 0; i != numsamples; ++i) - { - testorigin[0] = lhrandom(mins[0], maxs[0]); - testorigin[1] = lhrandom(mins[1], maxs[1]); - testorigin[2] = lhrandom(mins[2], maxs[2]); - - if(model->brush.TraceLineOfSight(model, eye, testorigin)) - return 1; - } - - return 0; -} -