{
}
-void R_Model_Alias_GetMesh_Vertex3f(const entity_render_t *ent, const aliasmesh_t *mesh, float *out3f)
-{
- if (mesh->num_vertexboneweights)
- {
- int i, k, blends;
- aliasvertexboneweight_t *v;
- float *out, *matrix, m[12], bonepose[256][12];
- // vertex weighted skeletal
- // interpolate matrices and concatenate them to their parents
- for (i = 0;i < ent->model->alias.aliasnum_bones;i++)
- {
- for (k = 0;k < 12;k++)
- m[k] = 0;
- for (blends = 0;blends < 4 && ent->frameblend[blends].lerp > 0;blends++)
- {
- matrix = ent->model->alias.aliasdata_poses + (ent->frameblend[blends].frame * ent->model->alias.aliasnum_bones + i) * 12;
- for (k = 0;k < 12;k++)
- m[k] += matrix[k] * ent->frameblend[blends].lerp;
- }
- if (ent->model->alias.aliasdata_bones[i].parent >= 0)
- R_ConcatTransforms(bonepose[ent->model->alias.aliasdata_bones[i].parent], m, bonepose[i]);
- else
- for (k = 0;k < 12;k++)
- bonepose[i][k] = m[k];
- }
- // blend the vertex bone weights
- memset(out3f, 0, mesh->num_vertices * sizeof(float[3]));
- v = mesh->data_vertexboneweights;
- for (i = 0;i < mesh->num_vertexboneweights;i++, v++)
- {
- out = out3f + v->vertexindex * 3;
- matrix = bonepose[v->boneindex];
- // FIXME: this can very easily be optimized with SSE or 3DNow
- out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3];
- out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7];
- out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11];
- }
- }
- else
- {
- int i, vertcount;
- float lerp1, lerp2, lerp3, lerp4;
- const float *vertsbase, *verts1, *verts2, *verts3, *verts4;
- // vertex morph
- vertsbase = mesh->data_morphvertex3f;
- vertcount = mesh->num_vertices;
- verts1 = vertsbase + ent->frameblend[0].frame * vertcount * 3;
- lerp1 = ent->frameblend[0].lerp;
- if (ent->frameblend[1].lerp)
- {
- verts2 = vertsbase + ent->frameblend[1].frame * vertcount * 3;
- lerp2 = ent->frameblend[1].lerp;
- if (ent->frameblend[2].lerp)
- {
- verts3 = vertsbase + ent->frameblend[2].frame * vertcount * 3;
- lerp3 = ent->frameblend[2].lerp;
- if (ent->frameblend[3].lerp)
- {
- verts4 = vertsbase + ent->frameblend[3].frame * vertcount * 3;
- lerp4 = ent->frameblend[3].lerp;
- for (i = 0;i < vertcount * 3;i++)
- VectorMAMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, lerp4, verts4 + i, out3f + i);
- }
- else
- for (i = 0;i < vertcount * 3;i++)
- VectorMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, out3f + i);
- }
- else
- for (i = 0;i < vertcount * 3;i++)
- VectorMAM(lerp1, verts1 + i, lerp2, verts2 + i, out3f + i);
- }
- else
- memcpy(out3f, verts1, vertcount * sizeof(float[3]));
- }
-}
-
aliaslayer_t r_aliasnoskinlayers[2] = {{ALIASLAYER_DIFFUSE, NULL, NULL}, {ALIASLAYER_FOG | ALIASLAYER_FORCEDRAW_IF_FIRSTPASS, NULL, NULL}};
aliasskin_t r_aliasnoskin = {0, 2, r_aliasnoskinlayers};
aliasskin_t *R_FetchAliasSkin(const entity_render_t *ent, const aliasmesh_t *mesh)
{
int c, fullbright, layernum, firstpass, generatenormals = true;
float tint[3], fog, ifog, colorscale, ambientcolor4f[4], diffusecolor[3], diffusenormal[3];
+ float *vertex3f, *normal3f;
vec3_t diff;
qbyte *bcolor;
rmeshstate_t m;
firstpass = true;
skin = R_FetchAliasSkin(ent, mesh);
- R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f);
+
+ if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
+ {
+ vertex3f = mesh->data_basevertex3f;
+ normal3f = mesh->data_basenormal3f;
+ }
+ else
+ {
+ vertex3f = varray_vertex3f;
+ Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
+ normal3f = NULL;
+ }
for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++)
{
if (!(layer->flags & ALIASLAYER_FORCEDRAW_IF_FIRSTPASS) || !firstpass)
m.texrgbscale[0] = 4;
}
}
- m.pointer_vertex = varray_vertex3f;
+ m.pointer_vertex = vertex3f;
c_alias_polys += mesh->num_triangles;
if (layer->flags & ALIASLAYER_FOG)
if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha, false))
{
m.pointer_color = varray_color4f;
- if (generatenormals)
+ if (normal3f == NULL)
{
- generatenormals = false;
- Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_texcoord2f, mesh->data_element3i, NULL, NULL, varray_normal3f);
+ normal3f = varray_normal3f;
+ Mod_BuildNormals(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, normal3f);
}
- R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, varray_vertex3f, varray_normal3f, varray_color4f);
+ R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, vertex3f, normal3f, varray_color4f);
}
else
GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
int meshnum;
aliasmesh_t *mesh;
aliasskin_t *skin;
- float projectdistance;
+ float projectdistance, *vertex3f;
if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
return;
projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin));
skin = R_FetchAliasSkin(ent, mesh);
if (skin->flags & ALIASSKIN_TRANSPARENT)
continue;
- R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f);
- R_Shadow_VolumeFromSphere(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, lightradius);
+ if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
+ vertex3f = mesh->data_basevertex3f;
+ else
+ {
+ vertex3f = varray_vertex3f;
+ Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
+ }
+ R_Shadow_VolumeFromSphere(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, lightradius);
}
}
}
{
int c, meshnum, layernum;
float fog, ifog, lightcolor2[3];
+ float *vertex3f, *svector3f, *tvector3f, *normal3f;
vec3_t diff;
qbyte *bcolor;
aliasmesh_t *mesh;
skin = R_FetchAliasSkin(ent, mesh);
if (skin->flags & ALIASSKIN_TRANSPARENT)
continue;
- R_Model_Alias_GetMesh_Vertex3f(ent, mesh, varray_vertex3f);
- Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, varray_vertex3f, mesh->data_texcoord2f, mesh->data_element3i, varray_svector3f, varray_tvector3f, varray_normal3f);
+ if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
+ {
+ vertex3f = mesh->data_basevertex3f;
+ svector3f = mesh->data_basesvector3f;
+ tvector3f = mesh->data_basetvector3f;
+ normal3f = mesh->data_basenormal3f;
+ }
+ else
+ {
+ vertex3f = varray_vertex3f;
+ svector3f = varray_svector3f;
+ tvector3f = varray_tvector3f;
+ normal3f = varray_normal3f;
+ Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
+ Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_texcoord2f, mesh->data_element3i, svector3f, tvector3f, normal3f);
+ }
for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++)
{
if (!(layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR))
if (layer->flags & ALIASLAYER_SPECULAR)
{
c_alias_polys += mesh->num_triangles;
- R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, varray_svector3f, varray_tvector3f, varray_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_SPECULAR);
+ R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_SPECULAR);
}
else if (layer->flags & ALIASLAYER_DIFFUSE)
{
lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f);
}
c_alias_polys += mesh->num_triangles;
- R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, varray_vertex3f, varray_svector3f, varray_tvector3f, varray_normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_DIFFUSE);
+ R_Shadow_RenderLighting(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, relativelightorigin, relativeeyeorigin, lightcolor2, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, layer->texture, layer->nmap, layer->texture, lightcubemap, LIGHTING_DIFFUSE);
}
}
}
{
}
+void Mod_Alias_GetMesh_Vertex3f(const model_t *model, const frameblend_t *frameblend, const aliasmesh_t *mesh, float *out3f)
+{
+ if (mesh->num_vertexboneweights)
+ {
+ int i, k, blends;
+ aliasvertexboneweight_t *v;
+ float *out, *matrix, m[12], bonepose[256][12];
+ // vertex weighted skeletal
+ // interpolate matrices and concatenate them to their parents
+ for (i = 0;i < model->alias.aliasnum_bones;i++)
+ {
+ for (k = 0;k < 12;k++)
+ m[k] = 0;
+ for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
+ {
+ matrix = model->alias.aliasdata_poses + (frameblend[blends].frame * model->alias.aliasnum_bones + i) * 12;
+ for (k = 0;k < 12;k++)
+ m[k] += matrix[k] * frameblend[blends].lerp;
+ }
+ if (model->alias.aliasdata_bones[i].parent >= 0)
+ R_ConcatTransforms(bonepose[model->alias.aliasdata_bones[i].parent], m, bonepose[i]);
+ else
+ for (k = 0;k < 12;k++)
+ bonepose[i][k] = m[k];
+ }
+ // blend the vertex bone weights
+ memset(out3f, 0, mesh->num_vertices * sizeof(float[3]));
+ v = mesh->data_vertexboneweights;
+ for (i = 0;i < mesh->num_vertexboneweights;i++, v++)
+ {
+ out = out3f + v->vertexindex * 3;
+ matrix = bonepose[v->boneindex];
+ // FIXME: this can very easily be optimized with SSE or 3DNow
+ out[0] += v->origin[0] * matrix[0] + v->origin[1] * matrix[1] + v->origin[2] * matrix[ 2] + v->origin[3] * matrix[ 3];
+ out[1] += v->origin[0] * matrix[4] + v->origin[1] * matrix[5] + v->origin[2] * matrix[ 6] + v->origin[3] * matrix[ 7];
+ out[2] += v->origin[0] * matrix[8] + v->origin[1] * matrix[9] + v->origin[2] * matrix[10] + v->origin[3] * matrix[11];
+ }
+ }
+ else
+ {
+ int i, vertcount;
+ float lerp1, lerp2, lerp3, lerp4;
+ const float *vertsbase, *verts1, *verts2, *verts3, *verts4;
+ // vertex morph
+ vertsbase = mesh->data_morphvertex3f;
+ vertcount = mesh->num_vertices;
+ verts1 = vertsbase + frameblend[0].frame * vertcount * 3;
+ lerp1 = frameblend[0].lerp;
+ if (frameblend[1].lerp)
+ {
+ verts2 = vertsbase + frameblend[1].frame * vertcount * 3;
+ lerp2 = frameblend[1].lerp;
+ if (frameblend[2].lerp)
+ {
+ verts3 = vertsbase + frameblend[2].frame * vertcount * 3;
+ lerp3 = frameblend[2].lerp;
+ if (frameblend[3].lerp)
+ {
+ verts4 = vertsbase + frameblend[3].frame * vertcount * 3;
+ lerp4 = frameblend[3].lerp;
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, lerp4, verts4 + i, out3f + i);
+ }
+ else
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAMAM(lerp1, verts1 + i, lerp2, verts2 + i, lerp3, verts3 + i, out3f + i);
+ }
+ else
+ for (i = 0;i < vertcount * 3;i++)
+ VectorMAM(lerp1, verts1 + i, lerp2, verts2 + i, out3f + i);
+ }
+ else
+ memcpy(out3f, verts1, vertcount * sizeof(float[3]));
+ }
+}
+
+static void Mod_Alias_Mesh_CompileFrameZero(aliasmesh_t *mesh)
+{
+ frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
+ mesh->data_basevertex3f = Mem_Alloc(loadmodel->mempool, mesh->num_vertices * sizeof(float[3][4]));
+ mesh->data_basesvector3f = mesh->data_basevertex3f + mesh->num_vertices * 3;
+ mesh->data_basetvector3f = mesh->data_basevertex3f + mesh->num_vertices * 6;
+ mesh->data_basenormal3f = mesh->data_basevertex3f + mesh->num_vertices * 9;
+ Mod_Alias_GetMesh_Vertex3f(loadmodel, frameblend, mesh, mesh->data_basevertex3f);
+ Mod_BuildTextureVectorsAndNormals(mesh->num_vertices, mesh->num_triangles, mesh->data_basevertex3f, mesh->data_texcoord2f, mesh->data_element3i, mesh->data_basesvector3f, mesh->data_basetvector3f, mesh->data_basenormal3f);
+}
+
static void Mod_MDLMD2MD3_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
{
int i, framenum;
Mod_MDL_LoadFrames (startframes, numverts, scale, translate, vertremap);
Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
Mod_CalcAliasModelBBoxes();
+ Mod_Alias_Mesh_CompileFrameZero(loadmodel->alias.aliasdata_meshes);
Mem_Free(vertst);
Mem_Free(vertremap);
loadmodel->alias.aliasdata_meshes->data_neighbor3i = Mem_Alloc(loadmodel->mempool, loadmodel->alias.aliasdata_meshes->num_triangles * sizeof(int[3]));
Mod_BuildTriangleNeighbors(loadmodel->alias.aliasdata_meshes->data_neighbor3i, loadmodel->alias.aliasdata_meshes->data_element3i, loadmodel->alias.aliasdata_meshes->num_triangles);
Mod_CalcAliasModelBBoxes();
+ Mod_Alias_Mesh_CompileFrameZero(loadmodel->alias.aliasdata_meshes);
}
void Mod_IDP3_Load(model_t *mod, void *buffer)
Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
+ Mod_Alias_Mesh_CompileFrameZero(mesh);
if (LittleLong(pinmesh->num_shaders) >= 1)
Mod_BuildAliasSkinsFromSkinFiles(mesh->data_skins, skinfiles, pinmesh->name, ((md3shader_t *)((qbyte *) pinmesh + pinmesh->lump_shaders))->name);
Mod_ValidateElements(mesh->data_element3i, mesh->num_triangles, mesh->num_vertices, __FILE__, __LINE__);
Mod_BuildTriangleNeighbors(mesh->data_neighbor3i, mesh->data_element3i, mesh->num_triangles);
+ Mod_Alias_Mesh_CompileFrameZero(mesh);
// since zym models do not have named sections, reuse their shader
// name as the section name
int num_morphframes;
float *data_morphvertex3f;
+ // base frame (frame zero typically)
+ // since most models do not animate, caching the base frame helps
+ float *data_basevertex3f;
+ float *data_basesvector3f;
+ float *data_basetvector3f;
+ float *data_basenormal3f;
+
// skeletal blending, these are zero if model is morph
int num_vertexboneweights;
aliasvertexboneweight_t *data_vertexboneweights;
}
aliasbone_t;
+struct frameblend_s;
+void Mod_Alias_GetMesh_Vertex3f(const struct model_s *model, const struct frameblend_s *frameblend, const struct aliasmesh_s *mesh, float *out3f);
+
#endif
Con_Printf("Mod_ValidateElements: out of bounds element detected at %s:%d\n", filename, fileline);
}
+// warning: this is an expensive function!
+void Mod_BuildNormals(int numverts, int numtriangles, const float *vertex3f, const int *elements, float *normal3f)
+{
+ int i, tnum;
+ float normal[3], *v;
+ const int *e;
+ // clear the vectors
+ memset(normal3f, 0, numverts * sizeof(float[3]));
+ // process each vertex of each triangle and accumulate the results
+ for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
+ {
+ TriangleNormal(vertex3f + e[0] * 3, vertex3f + e[1] * 3, vertex3f + e[2] * 3, normal);
+ VectorNormalize(normal);
+ v = normal3f + e[0] * 3;
+ v[0] += normal[0];
+ v[1] += normal[1];
+ v[2] += normal[2];
+ v = normal3f + e[1] * 3;
+ v[0] += normal[0];
+ v[1] += normal[1];
+ v[2] += normal[2];
+ v = normal3f + e[2] * 3;
+ v[0] += normal[0];
+ v[1] += normal[1];
+ v[2] += normal[2];
+ }
+ // now we could divide the vectors by the number of averaged values on
+ // each vertex... but instead normalize them
+ for (i = 0, v = normal3f;i < numverts;i++, v += 3)
+ VectorNormalize(v);
+}
+
void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f)
{
float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
// 103 add/sub/negate/multiply (1 cycle), 3 divide (20 cycle), 3 sqrt (22 cycle), 4 compare (3 cycle?), total cycles not counting load/store/exchange roughly 241 cycles
// 12 add, 28 subtract, 57 multiply, 3 divide, 3 sqrt, 4 compare, 50% chance of 6 negates
- // 18 multiply, 19 subtract
+ // 6 multiply, 9 subtract
VectorSubtract(v1, v0, v10);
VectorSubtract(v2, v0, v20);
normal3f[0] = v10[1] * v20[2] - v10[2] * v20[1];
normal3f[1] = v10[2] * v20[0] - v10[0] * v20[2];
normal3f[2] = v10[0] * v20[1] - v10[1] * v20[0];
+ // 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare
+ VectorNormalize(normal3f);
+ // 12 multiply, 10 subtract
tc10[1] = tc1[1] - tc0[1];
tc20[1] = tc2[1] - tc0[1];
svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
- // 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare
- VectorNormalize(normal3f);
// 12 multiply, 4 add, 6 subtract
f = DotProduct(svector3f, normal3f);
svector3f[0] -= f * normal3f[0];
}
}
-// warning: this is an expensive function!
+// warning: this is a very expensive function!
void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex3f, const float *texcoord2f, const int *elements, float *svector3f, float *tvector3f, float *normal3f)
{
int i, tnum;
int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices);
void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles);
void Mod_ValidateElements(const int *elements, int numtriangles, int numverts, const char *filename, int fileline);
+void Mod_BuildNormals(int numverts, int numtriangles, const float *vertex3f, const int *elements, float *normal3f);
void Mod_BuildTextureVectorsAndNormals(int numverts, int numtriangles, const float *vertex, const float *texcoord, const int *elements, float *svectors, float *tvectors, float *normals);
shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable);