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);
fssearch_t *search;
char *f;
const char *text;
- int flags;
+ int flags, flags2, numparameters, passnumber;
char shadername[Q3PATHLENGTH];
char sky[Q3PATHLENGTH];
+ char firstpasstexturename[Q3PATHLENGTH];
+ char parameter[4][Q3PATHLENGTH];
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
out->surfaceflags = LittleLong(in->surfaceflags);
out->nativecontents = LittleLong(in->contents);
out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, out->nativecontents);
- Mod_LoadSkinFrame(&out->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true, true);
out->surfaceparms = -1;
}
{
strlcpy (shadername, com_token, sizeof (shadername));
flags = 0;
+ flags2 = 0;
sky[0] = 0;
+ passnumber = 0;
+ firstpasstexturename[0] = 0;
if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{"))
{
while (COM_ParseToken(&text, false))
{
if (!strcasecmp(com_token, "}"))
break;
+ if (!strcasecmp(com_token, "\n"))
+ continue;
+ numparameters = 0;
+ for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
+ {
+ if (j < 4)
+ {
+ strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+ numparameters = j + 1;
+ }
+ if (!COM_ParseToken(&text, true))
+ break;
+ }
+ if (developer.integer >= 2)
+ {
+ Con_Printf("%s %i: ", shadername, passnumber);
+ for (j = 0;j < numparameters;j++)
+ Con_Printf(" %s", parameter[j]);
+ Con_Print("\n");
+ }
+ if (passnumber == 0 && numparameters >= 1)
+ {
+ if (!strcasecmp(parameter[0], "blendfunc"))
+ {
+ if (numparameters == 2 && !strcasecmp(parameter[1], "add"))
+ flags2 |= Q3TEXTUREFLAG_ADDITIVE;
+ else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_one") && !strcasecmp(parameter[2], "gl_one"))
+ flags2 |= Q3TEXTUREFLAG_ADDITIVE;
+ else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_src_alpha") && !strcasecmp(parameter[2], "gl_one"))
+ flags2 |= Q3TEXTUREFLAG_ADDITIVE;
+ }
+ else if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
+ strlcpy(firstpasstexturename, parameter[1], sizeof(firstpasstexturename));
+ else if (numparameters >= 3 && !strcasecmp(parameter[0], "animmap"))
+ strlcpy(firstpasstexturename, parameter[2], sizeof(firstpasstexturename));
+ }
+ // break out a level if it was }
+ if (!strcasecmp(com_token, "}"))
+ break;
}
+ passnumber++;
+ continue;
}
- else if (!strcasecmp(com_token, "surfaceparm"))
+ numparameters = 0;
+ for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
{
- if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
+ if (j < 4)
{
- if (!strcasecmp(com_token, "alphashadow"))
- flags |= Q3SURFACEPARM_ALPHASHADOW;
- else if (!strcasecmp(com_token, "areaportal"))
- flags |= Q3SURFACEPARM_AREAPORTAL;
- else if (!strcasecmp(com_token, "clusterportal"))
- flags |= Q3SURFACEPARM_CLUSTERPORTAL;
- else if (!strcasecmp(com_token, "detail"))
- flags |= Q3SURFACEPARM_DETAIL;
- else if (!strcasecmp(com_token, "donotenter"))
- flags |= Q3SURFACEPARM_DONOTENTER;
- else if (!strcasecmp(com_token, "fog"))
- flags |= Q3SURFACEPARM_FOG;
- else if (!strcasecmp(com_token, "lava"))
- flags |= Q3SURFACEPARM_LAVA;
- else if (!strcasecmp(com_token, "lightfilter"))
- flags |= Q3SURFACEPARM_LIGHTFILTER;
- else if (!strcasecmp(com_token, "metalsteps"))
- flags |= Q3SURFACEPARM_METALSTEPS;
- else if (!strcasecmp(com_token, "nodamage"))
- flags |= Q3SURFACEPARM_NODAMAGE;
- else if (!strcasecmp(com_token, "nodlight"))
- flags |= Q3SURFACEPARM_NODLIGHT;
- else if (!strcasecmp(com_token, "nodraw"))
- flags |= Q3SURFACEPARM_NODRAW;
- else if (!strcasecmp(com_token, "nodrop"))
- flags |= Q3SURFACEPARM_NODROP;
- else if (!strcasecmp(com_token, "noimpact"))
- flags |= Q3SURFACEPARM_NOIMPACT;
- else if (!strcasecmp(com_token, "nolightmap"))
- flags |= Q3SURFACEPARM_NOLIGHTMAP;
- else if (!strcasecmp(com_token, "nomarks"))
- flags |= Q3SURFACEPARM_NOMARKS;
- else if (!strcasecmp(com_token, "nomipmaps"))
- flags |= Q3SURFACEPARM_NOMIPMAPS;
- else if (!strcasecmp(com_token, "nonsolid"))
- flags |= Q3SURFACEPARM_NONSOLID;
- else if (!strcasecmp(com_token, "origin"))
- flags |= Q3SURFACEPARM_ORIGIN;
- else if (!strcasecmp(com_token, "playerclip"))
- flags |= Q3SURFACEPARM_PLAYERCLIP;
- else if (!strcasecmp(com_token, "sky"))
- flags |= Q3SURFACEPARM_SKY;
- else if (!strcasecmp(com_token, "slick"))
- flags |= Q3SURFACEPARM_SLICK;
- else if (!strcasecmp(com_token, "slime"))
- flags |= Q3SURFACEPARM_SLIME;
- else if (!strcasecmp(com_token, "structural"))
- flags |= Q3SURFACEPARM_STRUCTURAL;
- else if (!strcasecmp(com_token, "trans"))
- flags |= Q3SURFACEPARM_TRANS;
- else if (!strcasecmp(com_token, "water"))
- flags |= Q3SURFACEPARM_WATER;
- else
- Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], com_token);
- if (!COM_ParseToken(&text, true) || strcasecmp(com_token, "\n"))
- {
- Con_Printf("%s parsing error: surfaceparm only takes one parameter.\n", search->filenames[i]);
- goto parseerror;
- }
+ strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+ numparameters = j + 1;
}
+ if (!COM_ParseToken(&text, true))
+ break;
+ }
+ if (i == 0 && !strcasecmp(com_token, "}"))
+ break;
+ if (developer.integer >= 2)
+ {
+ Con_Printf("%s: ", shadername);
+ for (j = 0;j < numparameters;j++)
+ Con_Printf(" %s", parameter[j]);
+ Con_Print("\n");
+ }
+ if (numparameters < 1)
+ continue;
+ if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
+ {
+ if (!strcasecmp(parameter[1], "alphashadow"))
+ flags |= Q3SURFACEPARM_ALPHASHADOW;
+ else if (!strcasecmp(parameter[1], "areaportal"))
+ flags |= Q3SURFACEPARM_AREAPORTAL;
+ else if (!strcasecmp(parameter[1], "clusterportal"))
+ flags |= Q3SURFACEPARM_CLUSTERPORTAL;
+ else if (!strcasecmp(parameter[1], "detail"))
+ flags |= Q3SURFACEPARM_DETAIL;
+ else if (!strcasecmp(parameter[1], "donotenter"))
+ flags |= Q3SURFACEPARM_DONOTENTER;
+ else if (!strcasecmp(parameter[1], "fog"))
+ flags |= Q3SURFACEPARM_FOG;
+ else if (!strcasecmp(parameter[1], "lava"))
+ flags |= Q3SURFACEPARM_LAVA;
+ else if (!strcasecmp(parameter[1], "lightfilter"))
+ flags |= Q3SURFACEPARM_LIGHTFILTER;
+ else if (!strcasecmp(parameter[1], "metalsteps"))
+ flags |= Q3SURFACEPARM_METALSTEPS;
+ else if (!strcasecmp(parameter[1], "nodamage"))
+ flags |= Q3SURFACEPARM_NODAMAGE;
+ else if (!strcasecmp(parameter[1], "nodlight"))
+ flags |= Q3SURFACEPARM_NODLIGHT;
+ else if (!strcasecmp(parameter[1], "nodraw"))
+ flags |= Q3SURFACEPARM_NODRAW;
+ else if (!strcasecmp(parameter[1], "nodrop"))
+ flags |= Q3SURFACEPARM_NODROP;
+ else if (!strcasecmp(parameter[1], "noimpact"))
+ flags |= Q3SURFACEPARM_NOIMPACT;
+ else if (!strcasecmp(parameter[1], "nolightmap"))
+ flags |= Q3SURFACEPARM_NOLIGHTMAP;
+ else if (!strcasecmp(parameter[1], "nomarks"))
+ flags |= Q3SURFACEPARM_NOMARKS;
+ else if (!strcasecmp(parameter[1], "nomipmaps"))
+ flags |= Q3SURFACEPARM_NOMIPMAPS;
+ else if (!strcasecmp(parameter[1], "nonsolid"))
+ flags |= Q3SURFACEPARM_NONSOLID;
+ else if (!strcasecmp(parameter[1], "origin"))
+ flags |= Q3SURFACEPARM_ORIGIN;
+ else if (!strcasecmp(parameter[1], "playerclip"))
+ flags |= Q3SURFACEPARM_PLAYERCLIP;
+ else if (!strcasecmp(parameter[1], "sky"))
+ flags |= Q3SURFACEPARM_SKY;
+ else if (!strcasecmp(parameter[1], "slick"))
+ flags |= Q3SURFACEPARM_SLICK;
+ else if (!strcasecmp(parameter[1], "slime"))
+ flags |= Q3SURFACEPARM_SLIME;
+ else if (!strcasecmp(parameter[1], "structural"))
+ flags |= Q3SURFACEPARM_STRUCTURAL;
+ else if (!strcasecmp(parameter[1], "trans"))
+ flags |= Q3SURFACEPARM_TRANS;
+ else if (!strcasecmp(parameter[1], "water"))
+ flags |= Q3SURFACEPARM_WATER;
else
- {
- Con_Printf("%s parsing error: surfaceparm expects a parameter.\n", search->filenames[i]);
- goto parseerror;
- }
+ Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], parameter[1]);
}
- else if (!strcasecmp(com_token, "sky"))
+ else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
+ strlcpy(sky, parameter[1], sizeof(sky));
+ else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
{
- if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
- if (strlen(com_token) < sizeof(sky))
- strcpy(sky, com_token);
+ if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
+ strlcpy(sky, parameter[1], sizeof(sky));
}
- else if (!strcasecmp(com_token, "skyparms"))
+ else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
{
- if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
- {
- if (strlen(com_token) < sizeof(sky) && !atoi(com_token) && strcasecmp(com_token, "-"))
- strcpy(sky, com_token);
- if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
- COM_ParseToken(&text, true);
- }
+ if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
+ flags2 |= Q3TEXTUREFLAG_TWOSIDED;
}
- else
+ else if (!strcasecmp(parameter[0], "nomipmaps"))
+ flags2 |= Q3TEXTUREFLAG_NOMIPMAPS;
+ else if (!strcasecmp(parameter[0], "nopicmip"))
+ flags2 |= Q3TEXTUREFLAG_NOPICMIP;
+ else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
{
- // look for linebreak or }
- while(COM_ParseToken(&text, true) && strcasecmp(com_token, "\n") && strcasecmp(com_token, "}"));
- // break out to top level if it was }
- if (!strcasecmp(com_token, "}"))
- break;
+ if (!strcasecmp(parameter[1], "autosprite") && numparameters == 2)
+ flags2 |= Q3TEXTUREFLAG_AUTOSPRITE;
+ if (!strcasecmp(parameter[1], "autosprite2") && numparameters == 2)
+ flags2 |= Q3TEXTUREFLAG_AUTOSPRITE2;
}
}
+ // force transparent render path for a number of odd
+ // shader effects to avoid bogging down the normal
+ // render path unnecessarily
+ if (flags2 & (Q3TEXTUREFLAG_ADDITIVE | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
+ flags |= Q3SURFACEPARM_TRANS;
// add shader to list (shadername and flags)
// actually here we just poke into the texture settings
for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++)
if (!strcasecmp(out->name, shadername))
{
out->surfaceparms = flags;
+ out->textureflags = flags2;
+ strlcpy(out->firstpasstexturename, firstpasstexturename, sizeof(out->firstpasstexturename));
if ((flags & Q3SURFACEPARM_SKY) && sky[0])
{
// quake3 seems to append a _ to the skybox name, so this must do so as well
Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
out->surfaceparms = 0;
// these are defaults
- if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk")
- || !strcmp(out->name, "nodraw") || !strcmp(out->name, "common/nodraw") || !strcmp(out->name, "textures/common/nodraw"))
- out->surfaceparms |= Q3SURFACEPARM_NODRAW;
if (!strncmp(out->name, "textures/skies/", 15))
out->surfaceparms |= Q3SURFACEPARM_SKY;
- if (R_TextureHasAlpha(out->skin.base))
- out->surfaceparms |= Q3SURFACEPARM_TRANS;
+ //if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk")
+ // || !strcmp(out->name, "nodraw") || !strcmp(out->name, "common/nodraw") || !strcmp(out->name, "textures/common/nodraw"))
+ // out->surfaceparms |= Q3SURFACEPARM_NODRAW;
+ //if (R_TextureHasAlpha(out->skin.base))
+ // out->surfaceparms |= Q3SURFACEPARM_TRANS;
}
+ if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true))
+ Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true, true);
}
Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
}
{
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;
+ 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;
for (i = 0;i < count;i++, in++, out++)
{
// check face type first
- out->type = LittleLong(in->type);
- if (out->type != Q3FACETYPE_POLYGON
- && out->type != Q3FACETYPE_PATCH
- && out->type != Q3FACETYPE_MESH
- && out->type != Q3FACETYPE_FLARE)
+ type = LittleLong(in->type);
+ if (type != Q3FACETYPE_POLYGON
+ && type != Q3FACETYPE_PATCH
+ && type != Q3FACETYPE_MESH
+ && type != Q3FACETYPE_FLARE)
{
- Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, out->type);
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type);
out->num_vertices = 0;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
}
Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures);
out->num_vertices = 0;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
n = 0;
}
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)
else
out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
- out->firstvertex = LittleLong(in->firstvertex);
+ firstvertex = LittleLong(in->firstvertex);
out->num_vertices = LittleLong(in->numvertices);
- out->firstelement = LittleLong(in->firstelement);
+ firstelement = LittleLong(in->firstelement);
out->num_triangles = LittleLong(in->numelements) / 3;
if (out->num_triangles * 3 != LittleLong(in->numelements))
{
Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements));
out->num_vertices = 0;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
}
- if (out->firstvertex < 0 || out->firstvertex + out->num_vertices > loadmodel->brushq3.num_vertices)
+ if (firstvertex < 0 || firstvertex + out->num_vertices > loadmodel->brushq3.num_vertices)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, out->firstvertex, out->firstvertex + out->num_vertices, loadmodel->brushq3.num_vertices);
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + out->num_vertices, loadmodel->brushq3.num_vertices);
out->num_vertices = 0;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
}
- if (out->firstelement < 0 || out->firstelement + out->num_triangles * 3 > loadmodel->brushq3.num_triangles * 3)
+ if (firstelement < 0 || firstelement + out->num_triangles * 3 > loadmodel->brushq3.num_triangles * 3)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, out->firstelement, out->firstelement + out->num_triangles * 3, loadmodel->brushq3.num_triangles * 3);
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + out->num_triangles * 3, loadmodel->brushq3.num_triangles * 3);
out->num_vertices = 0;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
}
- switch(out->type)
+ switch(type)
{
case Q3FACETYPE_POLYGON:
case Q3FACETYPE_MESH:
// no processing necessary
- out->data_vertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
- out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2;
- out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2;
- out->data_svector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
- out->data_tvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
- out->data_normal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3;
- out->data_color4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4;
- out->data_element3i = loadmodel->brushq3.data_element3i + out->firstelement;
- out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement;
+ out->data_vertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+ out->data_texcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
+ out->data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
+ out->data_svector3f = loadmodel->brushq3.data_svector3f + firstvertex * 3;
+ out->data_tvector3f = loadmodel->brushq3.data_tvector3f + firstvertex * 3;
+ out->data_normal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3;
+ out->data_color4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
+ out->data_element3i = loadmodel->brushq3.data_element3i + firstelement;
+ out->data_neighbor3i = loadmodel->brushq3.data_neighbor3i + firstelement;
break;
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;
out->num_triangles = 0;
- out->type = 0; // error
+ type = 0; // error
continue;
}
- originalvertex3f = loadmodel->brushq3.data_vertex3f + out->firstvertex * 3;
- //originalsvector3f = loadmodel->brushq3.data_svector3f + out->firstvertex * 3;
- //originaltvector3f = loadmodel->brushq3.data_tvector3f + out->firstvertex * 3;
- //originalnormal3f = loadmodel->brushq3.data_normal3f + out->firstvertex * 3;
- originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + out->firstvertex * 2;
- originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + out->firstvertex * 2;
- originalcolor4f = loadmodel->brushq3.data_color4f + out->firstvertex * 4;
- //originalelement3i = loadmodel->brushq3.data_element3i + out->firstelement;
- //originalneighbor3i = loadmodel->brushq3.data_neighbor3i + out->firstelement;
+ originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+ //originalsvector3f = loadmodel->brushq3.data_svector3f + firstvertex * 3;
+ //originaltvector3f = loadmodel->brushq3.data_tvector3f + firstvertex * 3;
+ //originalnormal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3;
+ originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
+ originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
+ originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
+ //originalelement3i = loadmodel->brushq3.data_element3i + firstelement;
+ //originalneighbor3i = loadmodel->brushq3.data_neighbor3i + firstelement;
/*
originalvertex3f = out->data_vertex3f;
//originalsvector3f = out->data_svector3f;
//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->data_texcoordlightmap2f = out->data_texcoordtexture2f + finalvertices * 2;
out->data_element3i = Mem_Alloc(loadmodel->mempool, sizeof(int[6]) * finaltriangles);
out->data_neighbor3i = out->data_element3i + finaltriangles * 3;
- out->type = Q3FACETYPE_MESH;
- out->firstvertex = -1;
+ type = Q3FACETYPE_MESH;
+ firstvertex = -1;
out->num_vertices = finalvertices;
- out->firstelement = -1;
+ firstelement = -1;
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
- out->collisions = true;
- 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);
+
+ 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;
- out->type = 0;
+ type = 0;
break;
}
for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++)
invalidelements++;
if (invalidelements)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->nativecontents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, out->type, out->texture->name, out->texture->surfaceflags, out->texture->nativecontents, out->firstvertex, out->num_vertices, out->firstelement, out->num_triangles * 3);
+ Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, texture->nativecontents = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, out->texture->nativecontents, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3);
for (j = 0;j < out->num_triangles * 3;j++)
{
Con_Printf(" %i", out->data_element3i[j]);
loadmodel->brushq3.data_leaffaces = out;
loadmodel->brushq3.num_leaffaces = count;
+ loadmodel->brushq3.data_leaffacenums = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
+
for (i = 0;i < count;i++, in++, out++)
{
n = LittleLong(*in);
if (n < 0 || n >= loadmodel->brushq3.num_faces)
Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, loadmodel->brushq3.num_faces);
*out = loadmodel->brushq3.data_faces + n;
+ loadmodel->brushq3.data_leaffacenums[i] = n;
}
}
if (n < 0 || n + c > loadmodel->brushq3.num_leaffaces)
Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafface range %i : %i (%i leaffaces)\n", n, n + c, loadmodel->brushq3.num_leaffaces);
out->firstleafface = loadmodel->brushq3.data_leaffaces + n;
+ out->firstleaffacenum = loadmodel->brushq3.data_leaffacenums + n;
out->numleaffaces = c;
n = LittleLong(in->firstleafbrush);
c = LittleLong(in->numleafbrushes);
for (i = 0;i < leaf->numleaffaces;i++)
{
face = leaf->firstleafface[i];
- if (face->collisions && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
+ if (face->num_collisiontriangles && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
face->collisionmarkframe = markframe;
Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
for (i = 0;i < leaf->numleaffaces;i++)
{
face = leaf->firstleafface[i];
- if (face->collisions && face->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
+ if (face->num_collisiontriangles && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
- face->markframe = markframe;
+ face->collisionmarkframe = markframe;
Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++)
{
face = model->brushq3.data_thismodel->firstface + i;
- if (face->collisions)
+ if (face->num_collisiontriangles)
Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++)
{
face = model->brushq3.data_thismodel->firstface + i;
- if (face->collisions)
+ if (face->num_collisiontriangles)
Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_collisiontriangles, face->data_collisionelement3i, face->data_collisionvertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
}
*/
+void Mod_Q3BSP_BuildTextureFaceLists(void)
+{
+ int i, j;
+ loadmodel->brushq3.data_texturefaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummodelsurfaces * sizeof(q3msurface_t *));
+ loadmodel->brushq3.data_texturefacenums = Mem_Alloc(loadmodel->mempool, loadmodel->nummodelsurfaces * sizeof(int));
+ for (i = 0;i < loadmodel->brushq3.num_textures;i++)
+ loadmodel->brushq3.data_textures[i].numfaces = 0;
+ for (i = 0;i < loadmodel->nummodelsurfaces;i++)
+ loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces++;
+ j = 0;
+ for (i = 0;i < loadmodel->brushq3.num_textures;i++)
+ {
+ loadmodel->brushq3.data_textures[i].facelist = loadmodel->brushq3.data_texturefaces + j;
+ loadmodel->brushq3.data_textures[i].facenumlist = loadmodel->brushq3.data_texturefacenums + j;
+ j += loadmodel->brushq3.data_textures[i].numfaces;
+ loadmodel->brushq3.data_textures[i].numfaces = 0;
+ }
+ for (i = 0;i < loadmodel->nummodelsurfaces;i++)
+ {
+ loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->facenumlist[loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces] = loadmodel->surfacelist[i];
+ loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->facelist[loadmodel->brushq3.data_faces[loadmodel->surfacelist[i]].texture->numfaces++] = loadmodel->brushq3.data_faces + loadmodel->surfacelist[i];
+ }
+}
+
void Mod_Q3BSP_RecursiveFindNumLeafs(q3mnode_t *node)
{
int numleafs;
if (j < mod->brushq3.data_thismodel->numfaces)
mod->DrawSky = R_Q3BSP_DrawSky;
}
+
+ Mod_Q3BSP_BuildTextureFaceLists();
}
void Mod_IBSP_Load(model_t *mod, void *buffer)