cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4"};
-cvar_t r_subdivisions_minlevel = {0, "r_subdivisions_minlevel", "0"};
-cvar_t r_subdivisions_maxlevel = {0, "r_subdivisions_maxlevel", "10"};
+cvar_t r_subdivisions_mintess = {0, "r_subdivisions_mintess", "1"};
+cvar_t r_subdivisions_maxtess = {0, "r_subdivisions_maxtess", "1024"};
cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536"};
cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15"};
-cvar_t r_subdivisions_collision_minlevel = {0, "r_subdivisions_collision_minlevel", "0"};
-cvar_t r_subdivisions_collision_maxlevel = {0, "r_subdivisions_collision_maxlevel", "10"};
+cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "1"};
+cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024"};
cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225"};
cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"};
cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"};
Cvar_RegisterVariable(&r_lightmaprgba);
Cvar_RegisterVariable(&r_nosurftextures);
Cvar_RegisterVariable(&r_subdivisions_tolerance);
- Cvar_RegisterVariable(&r_subdivisions_minlevel);
- Cvar_RegisterVariable(&r_subdivisions_maxlevel);
+ Cvar_RegisterVariable(&r_subdivisions_mintess);
+ Cvar_RegisterVariable(&r_subdivisions_maxtess);
Cvar_RegisterVariable(&r_subdivisions_maxvertices);
Cvar_RegisterVariable(&r_subdivisions_collision_tolerance);
- Cvar_RegisterVariable(&r_subdivisions_collision_minlevel);
- Cvar_RegisterVariable(&r_subdivisions_collision_maxlevel);
+ Cvar_RegisterVariable(&r_subdivisions_collision_mintess);
+ Cvar_RegisterVariable(&r_subdivisions_collision_maxtess);
Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices);
Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
}
}
+/*
+=============
+R_Q1BSP_LoadSplitSky
+
+A sky texture is 256*128, with the right side being a masked overlay
+==============
+*/
+void R_Q1BSP_LoadSplitSky (qbyte *src, int bytesperpixel)
+{
+ int i, j;
+ unsigned solidpixels[128*128], alphapixels[128*128];
+
+ if (bytesperpixel == 4)
+ {
+ for (i = 0;i < 128;i++)
+ {
+ for (j = 0;j < 128;j++)
+ {
+ solidpixels[(i*128) + j] = ((unsigned *)src)[i*256+j+128];
+ alphapixels[(i*128) + j] = ((unsigned *)src)[i*256+j];
+ }
+ }
+ }
+ else
+ {
+ // make an average value for the back to avoid
+ // a fringe on the top level
+ int p, r, g, b;
+ union
+ {
+ unsigned int i;
+ unsigned char b[4];
+ }
+ rgba;
+ r = g = b = 0;
+ for (i = 0;i < 128;i++)
+ {
+ for (j = 0;j < 128;j++)
+ {
+ rgba.i = palette_complete[src[i*256 + j + 128]];
+ r += rgba.b[0];
+ g += rgba.b[1];
+ b += rgba.b[2];
+ }
+ }
+ rgba.b[0] = r/(128*128);
+ rgba.b[1] = g/(128*128);
+ rgba.b[2] = b/(128*128);
+ rgba.b[3] = 0;
+ for (i = 0;i < 128;i++)
+ {
+ for (j = 0;j < 128;j++)
+ {
+ solidpixels[(i*128) + j] = palette_complete[src[i*256 + j + 128]];
+ alphapixels[(i*128) + j] = (p = src[i*256 + j]) ? palette_complete[p] : rgba.i;
+ }
+ }
+ }
+
+ loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", 128, 128, (qbyte *) solidpixels, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ loadmodel->brush.alphaskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_alphatexture", 128, 128, (qbyte *) alphapixels, TEXTYPE_RGBA, TEXF_ALPHA | TEXF_PRECACHE, NULL);
+}
+
static void Mod_Q1BSP_LoadTextures(lump_t *l)
{
int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
{
if (image_width == 256 && image_height == 128)
{
- R_InitSky(data, 4);
+ R_Q1BSP_LoadSplitSky(data, 4);
Mem_Free(data);
}
else
Mem_Free(data);
Con_Printf("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
if (mtdata != NULL)
- R_InitSky(mtdata, 1);
+ R_Q1BSP_LoadSplitSky(mtdata, 1);
}
}
else if (mtdata != NULL)
- R_InitSky(mtdata, 1);
+ R_Q1BSP_LoadSplitSky(mtdata, 1);
}
}
else
mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains;
if (loadmodel->isworldmodel)
- {
Cvar_SetValue("halflifebsp", mod->brush.ishlbsp);
- // until we get a texture for it...
- R_ResetQuakeSky();
- }
// swap all the lumps
mod_base = (qbyte *)header;
Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION);
mod->brush.ishlbsp = false;
if (loadmodel->isworldmodel)
- {
Cvar_SetValue("halflifebsp", mod->brush.ishlbsp);
- // until we get a texture for it...
- R_ResetQuakeSky();
- }
mod_base = (qbyte *)header;
{
if (!strcasecmp(parameter[0], "blendfunc"))
{
- Con_Printf("!\n");
if (numparameters == 2 && !strcasecmp(parameter[1], "add"))
flags2 |= Q3TEXTUREFLAG_ADDITIVE;
else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_one") && !strcasecmp(parameter[2], "gl_one"))
{
q3dface_t *in;
q3msurface_t *out;
- int i, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xlevel, ylevel, row0, row1, x, y, *e, finalvertices, finaltriangles, firstvertex, firstelement, type;
+ int i, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2;
//int *originalelement3i;
//int *originalneighbor3i;
float *originalvertex3f;
n = LittleLong(in->effectindex);
if (n < -1 || n >= loadmodel->brushq3.num_effects)
{
- Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
+ if (developer.integer >= 2)
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
n = -1;
}
if (n == -1)
case Q3FACETYPE_PATCH:
patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
- if (patchsize[0] < 1 || patchsize[1] < 1)
+ if (patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer))
{
Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
out->num_vertices = 0;
//originalneighbor3i = out->data_neighbor3i;
*/
// convert patch to Q3FACETYPE_MESH
- xlevel = QuadraticBSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10);
- ylevel = QuadraticBSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value, 10);
+ xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+ ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
// bound to user settings
- xlevel = bound(r_subdivisions_minlevel.integer, xlevel, r_subdivisions_maxlevel.integer);
- ylevel = bound(r_subdivisions_minlevel.integer, ylevel, r_subdivisions_maxlevel.integer);
+ xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
+ ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
// bound to sanity settings
- xlevel = bound(0, xlevel, 10);
- ylevel = bound(0, ylevel, 10);
+ xtess = bound(1, xtess, 1024);
+ ytess = bound(1, ytess, 1024);
// bound to user limit on vertices
- while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
+ while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
{
- if (xlevel > ylevel)
- xlevel--;
+ if (xtess > ytess)
+ xtess--;
else
- ylevel--;
+ ytess--;
}
- finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
- finalheight = ((patchsize[1] - 1) << ylevel) + 1;
+ finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+ finalheight = ((patchsize[1] - 1) * ytess) + 1;
finalvertices = finalwidth * finalheight;
finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
out->data_vertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[20]) * finalvertices);
out->num_triangles = finaltriangles;
// generate geometry
// (note: normals are skipped because they get recalculated)
- QuadraticBSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 3, originalvertex3f, out->data_vertex3f);
- QuadraticBSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 2, originaltexcoordtexture2f, out->data_texcoordtexture2f);
- QuadraticBSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 2, originaltexcoordlightmap2f, out->data_texcoordlightmap2f);
- QuadraticBSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 4, originalcolor4f, out->data_color4f);
- // generate elements
- e = out->data_element3i;
- for (y = 0;y < finalheight - 1;y++)
- {
- row0 = (y + 0) * finalwidth;
- row1 = (y + 1) * finalwidth;
- for (x = 0;x < finalwidth - 1;x++)
- {
- *e++ = row0;
- *e++ = row1;
- *e++ = row0 + 1;
- *e++ = row1;
- *e++ = row1 + 1;
- *e++ = row0 + 1;
- row0++;
- row1++;
- }
- }
- out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, out->data_element3i, out->data_element3i, out->data_vertex3f);
- if (developer.integer)
+ Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_vertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+ Q3PatchTesselateFloat(2, sizeof(float[2]), out->data_texcoordtexture2f, patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess);
+ Q3PatchTesselateFloat(2, sizeof(float[2]), out->data_texcoordlightmap2f, patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess);
+ Q3PatchTesselateFloat(4, sizeof(float[4]), out->data_color4f, patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
+ Q3PatchTriangleElements(out->data_element3i, finalwidth, finalheight);
+ if (developer.integer >= 2)
{
if (out->num_triangles < finaltriangles)
Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
}
// q3map does not put in collision brushes for curves... ugh
// build the lower quality collision geometry
- xlevel = QuadraticBSplinePatchSubdivisionLevelOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10);
- ylevel = QuadraticBSplinePatchSubdivisionLevelOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value, 10);
+ xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
+ ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
// bound to user settings
- xlevel = bound(r_subdivisions_collision_minlevel.integer, xlevel, r_subdivisions_collision_maxlevel.integer);
- ylevel = bound(r_subdivisions_collision_minlevel.integer, ylevel, r_subdivisions_collision_maxlevel.integer);
+ xtess = bound(r_subdivisions_collision_mintess.integer, xtess, r_subdivisions_collision_maxtess.integer);
+ ytess = bound(r_subdivisions_collision_mintess.integer, ytess, r_subdivisions_collision_maxtess.integer);
// bound to sanity settings
- xlevel = bound(0, xlevel, 10);
- ylevel = bound(0, ylevel, 10);
+ xtess = bound(1, xtess, 1024);
+ ytess = bound(1, ytess, 1024);
// bound to user limit on vertices
- while ((xlevel > 0 || ylevel > 0) && (((patchsize[0] - 1) << xlevel) + 1) * (((patchsize[1] - 1) << ylevel) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
+ while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
{
- if (xlevel > ylevel)
- xlevel--;
+ if (xtess > ytess)
+ xtess--;
else
- ylevel--;
+ ytess--;
}
- finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
- finalheight = ((patchsize[1] - 1) << ylevel) + 1;
+ finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+ finalheight = ((patchsize[1] - 1) * ytess) + 1;
finalvertices = finalwidth * finalheight;
finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+
out->data_collisionvertex3f = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
out->data_collisionelement3i = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
out->num_collisionvertices = finalvertices;
out->num_collisiontriangles = finaltriangles;
- QuadraticBSplinePatchSubdivideFloatBuffer(patchsize[0], patchsize[1], xlevel, ylevel, 3, originalvertex3f, out->data_collisionvertex3f);
- // generate elements
- e = out->data_collisionelement3i;
- for (y = 0;y < finalheight - 1;y++)
- {
- row0 = (y + 0) * finalwidth;
- row1 = (y + 1) * finalwidth;
- for (x = 0;x < finalwidth - 1;x++)
- {
- *e++ = row0;
- *e++ = row1;
- *e++ = row0 + 1;
- *e++ = row1;
- *e++ = row1 + 1;
- *e++ = row0 + 1;
- row0++;
- row1++;
- }
- }
+ Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+ Q3PatchTriangleElements(out->data_collisionelement3i, finalwidth, finalheight);
+
+ Mod_SnapVertices(3, out->num_vertices, out->data_vertex3f, 0.25);
+ Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
+
+ oldnumtriangles = out->num_triangles;
+ oldnumtriangles2 = out->num_collisiontriangles;
+ out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, out->data_element3i, out->data_element3i, out->data_vertex3f);
out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
if (developer.integer)
- {
- if (out->num_collisiontriangles < finaltriangles)
- Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_collisionvertices, finaltriangles, finaltriangles - out->num_collisiontriangles, out->num_collisiontriangles);
- else
- Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided for collisions to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_collisionvertices, out->num_collisiontriangles);
- }
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
break;
case Q3FACETYPE_FLARE:
- Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
+ if (developer.integer >= 2)
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
// don't render it
out->num_vertices = 0;
out->num_triangles = 0;
if (i != Q3BSPVERSION)
Host_Error("Mod_Q3BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q3BSPVERSION);
if (mod->isworldmodel)
- {
Cvar_SetValue("halflifebsp", false);
- // until we get a texture for it...
- R_ResetQuakeSky();
- }
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q3BSP_TraceBox;