cvar_t mcbsp = {0, "mcbsp", "0", "indicates the current map is mcbsp format (useful to know because of different bounding box sizes)"};
cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1", "whether to use RGBA (32bit) or RGB (24bit) lightmaps"};
-cvar_t r_picmipworld = {0, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too"};
+cvar_t r_picmipworld = {CVAR_SAVE, "r_picmipworld", "1", "whether gl_picmip shall apply to world textures too"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
cvar_t r_subdivisions_mintess = {0, "r_subdivisions_mintess", "1", "minimum number of subdivisions (values above 1 will smooth curves that don't need it)"};
int i, j, k;
if (!data)
return;
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
if (com_token[0] != '{')
return; // error
while (1)
{
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
dpsnprintf(value, sizeof(value), "%s", com_token);
if (!strcmp("wad", key)) // for HalfLife maps
if (!maptext)
return;
text = maptext;
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
submodel = 0;
for (;;)
{
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
break;
if (com_token[0] != '{')
return; // error
brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t));
for (;;)
{
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
if (com_token[0] == '}')
break; // end of entity
}
for (;;)
{
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
return; // error
if (com_token[0] == '}')
break; // end of brush
// FIXME: support hl .map format
for (pointnum = 0;pointnum < 3;pointnum++)
{
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
for (componentnum = 0;componentnum < 3;componentnum++)
{
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
point[pointnum][componentnum] = atof(com_token);
}
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
}
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
strlcpy(facetexture, com_token, sizeof(facetexture));
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
//scroll_s = atof(com_token);
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
//scroll_t = atof(com_token);
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
//rotate = atof(com_token);
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
//scale_s = atof(com_token);
- COM_ParseTokenConsole(&data);
+ COM_ParseToken_Simple(&data, false);
//scale_t = atof(com_token);
TriangleNormal(point[0], point[1], point[2], planenormal);
VectorNormalizeDouble(planenormal);
// this gets altered below if sky is used
mod->DrawSky = NULL;
mod->Draw = R_Q1BSP_Draw;
+ mod->DrawDepth = R_Q1BSP_DrawDepth;
mod->GetLightInfo = R_Q1BSP_GetLightInfo;
mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
data = loadmodel->brush.entities;
// some Q3 maps override the lightgrid_cellsize with a worldspawn key
- if (data && COM_ParseTokenConsole(&data) && com_token[0] == '{')
+ if (data && COM_ParseToken_Simple(&data, false) && com_token[0] == '{')
{
while (1)
{
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
break; // error
if (com_token[0] == '}')
break; // end of worldspawn
strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseTokenConsole(&data))
+ if (!COM_ParseToken_Simple(&data, false))
break; // error
strlcpy(value, com_token, sizeof(value));
if (!strcmp("gridsize", key))
text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
if (!f)
continue;
- while (COM_ParseToken(&text, false))
+ while (COM_ParseToken_QuakeC(&text, false))
{
if (q3shaders_numshaders >= Q3SHADER_MAXSHADERS)
{
shader = q3shaders_shaders + q3shaders_numshaders++;
memset(shader, 0, sizeof(*shader));
strlcpy(shader->name, com_token, sizeof(shader->name));
- if (!COM_ParseToken(&text, false) || strcasecmp(com_token, "{"))
+ if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
{
Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
break;
}
- while (COM_ParseToken(&text, false))
+ while (COM_ParseToken_QuakeC(&text, false))
{
if (!strcasecmp(com_token, "}"))
break;
}
else
layer = NULL;
- while (COM_ParseToken(&text, false))
+ while (COM_ParseToken_QuakeC(&text, false))
{
if (!strcasecmp(com_token, "}"))
break;
strlcpy(parameter[j], com_token, sizeof(parameter[j]));
numparameters = j + 1;
}
- if (!COM_ParseToken(&text, true))
+ if (!COM_ParseToken_QuakeC(&text, true))
break;
}
if (developer.integer >= 100)
strlcpy(parameter[j], com_token, sizeof(parameter[j]));
numparameters = j + 1;
}
- if (!COM_ParseToken(&text, true))
+ if (!COM_ParseToken_QuakeC(&text, true))
break;
}
if (fileindex == 0 && !strcasecmp(com_token, "}"))
out->skinframerate = shader->primarylayer->framerate;
for (j = 0;j < shader->primarylayer->numframes;j++)
if (!(out->skinframes[j] = R_SkinFrame_LoadExternal(shader->primarylayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | ((!r_picmipworld.integer || (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP)) ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0), false)))
+ {
Con_DPrintf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
+ out->skinframes[j] = R_SkinFrame_LoadMissing();
+ }
}
if (shader->backgroundlayer)
{
static void Mod_Q3BSP_LoadLightmaps(lump_t *l, lump_t *faceslump)
{
q3dlightmap_t *in;
- int i, j, count, power, power2, mask, endlightmap;
+ int i, j, count, power, power2, mask, endlightmap, mergewidth, mergeheight;
unsigned char *c;
if (!l->filelen)
// figure out what the most reasonable merge power is within limits
loadmodel->brushq3.num_lightmapmergepower = 0;
- for (power = 1;power <= mod_q3bsp_lightmapmergepower.integer && (1 << power) <= gl_max_texture_size && (1 << (power * 2)) < 4 * (count >> loadmodel->brushq3.deluxemapping);power++)
+ for (power = 1;power <= mod_q3bsp_lightmapmergepower.integer && (128 << power) <= gl_max_texture_size && (1 << (power * 2)) < 4 * (count >> loadmodel->brushq3.deluxemapping);power++)
loadmodel->brushq3.num_lightmapmergepower = power;
loadmodel->brushq3.num_lightmapmerge = 1 << loadmodel->brushq3.num_lightmapmergepower;
if (loadmodel->texturepool == NULL && cls.state != ca_dedicated)
loadmodel->texturepool = R_AllocTexturePool();
- j = 128 << loadmodel->brushq3.num_lightmapmergepower;
- if (loadmodel->brushq3.data_lightmaps)
- for (i = 0;i < loadmodel->brushq3.num_mergedlightmaps;i++)
- loadmodel->brushq3.data_lightmaps[i] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), j, j, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-
- if (loadmodel->brushq3.data_deluxemaps)
- for (i = 0;i < loadmodel->brushq3.num_mergedlightmaps;i++)
- loadmodel->brushq3.data_deluxemaps[i] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", i), j, j, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
-
- power = loadmodel->brushq3.num_lightmapmergepower;
- power2 = power * 2;
- mask = (1 << power) - 1;
- for (i = 0;i < count;i++)
+ if (loadmodel->brushq3.num_lightmapmergepower > 0)
{
- j = i >> loadmodel->brushq3.deluxemapping;
- if (loadmodel->brushq3.deluxemapping && (i & 1))
- R_UpdateTexture(loadmodel->brushq3.data_deluxemaps[j >> power2], in[i].rgb, (j & mask) * 128, ((j >> power) & mask) * 128, 128, 128);
- else
- R_UpdateTexture(loadmodel->brushq3.data_lightmaps [j >> power2], in[i].rgb, (j & mask) * 128, ((j >> power) & mask) * 128, 128, 128);
+ power = loadmodel->brushq3.num_lightmapmergepower;
+ power2 = power * 2;
+ mask = (1 << power) - 1;
+ for (i = 0;i < count;i++)
+ {
+ // figure out which merged lightmap texture this fits into
+ int lightmapindex = i >> (loadmodel->brushq3.deluxemapping + power2);
+ // if the lightmap has not been allocated yet, create it
+ if (!loadmodel->brushq3.data_lightmaps[lightmapindex])
+ {
+ // create a lightmap only as large as necessary to hold the
+ // remaining 128x128 blocks
+ // if there are multiple merged lightmap textures then they will
+ // all be full size except the last one which may be smaller
+ // because it only needs to the remaining blocks, and it will often
+ // be odd sizes like 2048x512 due to only being 25% full or so.
+ j = (count >> loadmodel->brushq3.deluxemapping) - (lightmapindex << power2);
+ for (mergewidth = 1;mergewidth < j && mergewidth < (1 << power);mergewidth *= 2)
+ ;
+ for (mergeheight = 1;mergewidth*mergeheight < j && mergeheight < (1 << power);mergeheight *= 2)
+ ;
+ Con_DPrintf("lightmap merge texture #%i is %ix%i (%i of %i used)\n", lightmapindex, mergewidth*128, mergeheight*128, min(j, mergewidth*mergeheight), mergewidth*mergeheight);
+ loadmodel->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), mergewidth * 128, mergeheight * 128, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ if (loadmodel->brushq3.data_deluxemaps)
+ loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), mergewidth * 128, mergeheight * 128, NULL, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ }
+ mergewidth = R_TextureWidth(loadmodel->brushq3.data_lightmaps[lightmapindex]) / 128;
+ mergeheight = R_TextureHeight(loadmodel->brushq3.data_lightmaps[lightmapindex]) / 128;
+ j = (i >> loadmodel->brushq3.deluxemapping) & ((1 << power2) - 1);
+ if (loadmodel->brushq3.deluxemapping && (i & 1))
+ R_UpdateTexture(loadmodel->brushq3.data_deluxemaps[lightmapindex], in[i].rgb, (j % mergewidth) * 128, (j / mergewidth) * 128, 128, 128);
+ else
+ R_UpdateTexture(loadmodel->brushq3.data_lightmaps [lightmapindex], in[i].rgb, (j % mergewidth) * 128, (j / mergewidth) * 128, 128, 128);
+ }
+ }
+ else
+ {
+ for (i = 0;i < count;i++)
+ {
+ // figure out which merged lightmap texture this fits into
+ int lightmapindex = i >> loadmodel->brushq3.deluxemapping;
+ if (loadmodel->brushq3.deluxemapping && (i & 1))
+ loadmodel->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%04i", lightmapindex), 128, 128, in[i].rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ else
+ loadmodel->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", lightmapindex), 128, 128, in[i].rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ }
}
}
q3dface_t *in, *oldin;
msurface_t *out, *oldout;
int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshvertices, meshtriangles, numvertices, numtriangles;
- float lightmaptcbase[2], lightmaptcscale;
+ float lightmaptcbase[2], lightmaptcscale[2];
//int *originalelement3i;
//int *originalneighbor3i;
float *originalvertex3f;
VectorClear(out->maxs);
if (out->num_vertices)
{
- int lightmapindex = LittleLong(in->lightmapindex);
- if (lightmapindex >= 0 && cls.state != ca_dedicated)
+ if (cls.state != ca_dedicated && out->lightmaptexture)
{
- lightmapindex >>= loadmodel->brushq3.deluxemapping;
- lightmaptcscale = 1.0f / loadmodel->brushq3.num_lightmapmerge;
- lightmaptcbase[0] = ((lightmapindex ) & (loadmodel->brushq3.num_lightmapmerge - 1)) * lightmaptcscale;
- lightmaptcbase[1] = ((lightmapindex >> loadmodel->brushq3.num_lightmapmergepower) & (loadmodel->brushq3.num_lightmapmerge - 1)) * lightmaptcscale;
+ // figure out which part of the merged lightmap this fits into
+ int lightmapindex = LittleLong(in->lightmapindex) >> loadmodel->brushq3.deluxemapping;
+ int mergewidth = R_TextureWidth(out->lightmaptexture) / 128;
+ int mergeheight = R_TextureHeight(out->lightmaptexture) / 128;
+ lightmapindex &= mergewidth * mergeheight - 1;
+ lightmaptcscale[0] = 1.0f / mergewidth;
+ lightmaptcscale[1] = 1.0f / mergeheight;
+ lightmaptcbase[0] = (lightmapindex % mergewidth) * lightmaptcscale[0];
+ lightmaptcbase[1] = (lightmapindex / mergewidth) * lightmaptcscale[1];
// modify the lightmap texcoords to match this region of the merged lightmap
for (j = 0, v = loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex;j < out->num_vertices;j++, v += 2)
{
- v[0] = v[0] * lightmaptcscale + lightmaptcbase[0];
- v[1] = v[1] * lightmaptcscale + lightmaptcbase[1];
+ v[0] = v[0] * lightmaptcscale[0] + lightmaptcbase[0];
+ v[1] = v[1] * lightmaptcscale[1] + lightmaptcbase[1];
}
}
VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->mins);
static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
{
int i, j, k, index[3];
- float transformed[3], blend1, blend2, blend, yaw, pitch, sinpitch, stylescale;
+ float transformed[3], blend1, blend2, blend, stylescale;
q3dlightgrid_t *a, *s;
// scale lighting by lightstyle[0] so that darkmode in dpmod works properly
s = a + (k * model->brushq3.num_lightgrid_isize[1] + j) * model->brushq3.num_lightgrid_isize[0] + i;
VectorMA(ambientcolor, blend * (1.0f / 128.0f), s->ambientrgb, ambientcolor);
VectorMA(diffusecolor, blend * (1.0f / 128.0f), s->diffusergb, diffusecolor);
- pitch = s->diffusepitch * M_PI / 128;
- yaw = s->diffuseyaw * M_PI / 128;
- sinpitch = sin(pitch);
- diffusenormal[0] += blend * (cos(yaw) * sinpitch);
- diffusenormal[1] += blend * (sin(yaw) * sinpitch);
- diffusenormal[2] += blend * (cos(pitch));
+ // this uses the mod_md3_sin table because the values are
+ // already in the 0-255 range, the 64+ bias fetches a cosine
+ // instead of a sine value
+ diffusenormal[0] += blend * (mod_md3_sin[64 + s->diffuseyaw] * mod_md3_sin[s->diffusepitch]);
+ diffusenormal[1] += blend * (mod_md3_sin[ s->diffuseyaw] * mod_md3_sin[s->diffusepitch]);
+ diffusenormal[2] += blend * (mod_md3_sin[64 + s->diffusepitch]);
//Con_Printf("blend %f: ambient %i %i %i, diffuse %i %i %i, diffusepitch %i diffuseyaw %i (%f %f, normal %f %f %f)\n", blend, s->ambientrgb[0], s->ambientrgb[1], s->ambientrgb[2], s->diffusergb[0], s->diffusergb[1], s->diffusergb[2], s->diffusepitch, s->diffuseyaw, pitch, yaw, (cos(yaw) * cospitch), (sin(yaw) * cospitch), (-sin(pitch)));
}
}
mod->brush.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
mod->brush.PointInLeaf = Mod_Q1BSP_PointInLeaf;
mod->Draw = R_Q1BSP_Draw;
+ mod->DrawDepth = R_Q1BSP_DrawDepth;
mod->GetLightInfo = R_Q1BSP_GetLightInfo;
mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;