void R_Mesh_Draw(const rmeshinfo_t *m)
{
// these are static because gcc runs out of virtual registers otherwise
- static int i, j, overbright;
+ static int i, j, overbright, *index;
static float *in, scaler;
static float cr, cg, cb, ca;
static buf_mesh_t *mesh;
mesh = &buf_transmesh[currenttransmesh++];
mesh->firsttriangle = currenttranstriangle;
mesh->firstvert = currenttransvertex;
- memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
+ index = &buf_transtri[currenttranstriangle].index[0];
currenttranstriangle += m->numtriangles;
currenttransvertex += m->numverts;
mesh = &buf_mesh[currentmesh++];
mesh->firsttriangle = currenttriangle;
mesh->firstvert = currentvertex;
- memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
+ index = &buf_tri[currenttriangle].index[0];
+
currenttriangle += m->numtriangles;
currentvertex += m->numverts;
}
// code shared for transparent and opaque meshs
+ memcpy(index, m->index, sizeof(int[3]) * m->numtriangles);
mesh->blendfunc1 = m->blendfunc1;
mesh->blendfunc2 = m->blendfunc2;
mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m)
{
// these are static because gcc runs out of virtual registers otherwise
- static int i, j, overbright;
+ static int i, j, overbright, *index;
static float *in, scaler;
static buf_mesh_t *mesh;
static buf_vertex_t *vert;
mesh = &buf_transmesh[currenttransmesh++];
mesh->firsttriangle = currenttranstriangle;
mesh->firstvert = currenttransvertex;
- memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
+ index = &buf_transtri[currenttranstriangle].index[0];
currenttranstriangle += m->numtriangles;
currenttransvertex += m->numverts;
}
mesh = &buf_mesh[currentmesh++];
mesh->firsttriangle = currenttriangle;
mesh->firstvert = currentvertex;
- memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
+ index = &buf_tri[currenttriangle].index[0];
currenttriangle += m->numtriangles;
currentvertex += m->numverts;
}
// code shared for transparent and opaque meshs
+ memcpy(index, m->index, sizeof(int[3]) * m->numtriangles);
mesh->blendfunc1 = m->blendfunc1;
mesh->blendfunc2 = m->blendfunc2;
mesh->depthmask = (m->blendfunc2 == GL_ZERO || m->depthwrite);
}
}
-/*
-void R_Mesh_Draw_GetBuffer(volatile rmeshinfo_t *m)
+// allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
+// (this is used for very high speed rendering, no copying)
+int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m)
{
// these are static because gcc runs out of virtual registers otherwise
- static int i, j, *index, overbright;
- static float *in, scaler;
+ int i, j, overbright;
+ float scaler;
+ buf_mesh_t *mesh;
if (!backendactive)
Sys_Error("R_Mesh_Draw: called when backend is not active\n");
|| !m->numverts)
Host_Error("R_Mesh_Draw: no triangles or verts\n");
- scaler = 1;
- if (m->blendfunc2 == GL_SRC_COLOR)
- {
- if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
- scaler *= 0.5f;
- }
- else
- {
- if (m->tex[0])
- {
- overbright = gl_combine.integer;
- if (overbright)
- scaler *= 0.25f;
- }
- scaler *= overbrightscale;
- }
-
if (m->transparent)
{
if (currenttransmesh >= max_meshs || (currenttranstriangle + m->numtriangles) > max_meshs || (currenttransvertex + m->numverts) > max_verts)
Con_Printf("R_Mesh_Draw: ran out of room for transparent meshs\n");
transranout = true;
}
- return;
+ return false;
}
c_transmeshs++;
c_transtris += m->numtriangles;
+ m->index = &buf_transtri[currenttranstriangle].index[0];
m->vertex = &buf_transvertex[currenttransvertex].v[0];
m->color = &buf_transfcolor[currenttransvertex].c[0];
for (i = 0;i < backendunits;i++)
- m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].tc[0];
+ m->texcoords[i] = &buf_transtexcoord[i][currenttransvertex].t[0];
// transmesh is only for storage of transparent meshs until they
// are inserted into the main mesh array
mesh = &buf_transmesh[currenttransmesh++];
mesh->firsttriangle = currenttranstriangle;
mesh->firstvert = currenttransvertex;
- memcpy(&buf_transtri[currenttranstriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
currenttranstriangle += m->numtriangles;
currenttransvertex += m->numverts;
}
{
if (m->numtriangles > max_meshs || m->numverts > max_verts)
{
- Con_Printf("R_Mesh_Draw_NativeOnly: mesh too big for buffers\n");
- return;
+ Con_Printf("R_Mesh_Draw_GetBuffer: mesh too big for buffers\n");
+ return false;
}
if (currentmesh >= max_meshs || (currenttriangle + m->numtriangles) > max_batch || (currentvertex + m->numverts) > max_verts)
c_meshs++;
c_meshtris += m->numtriangles;
- vert = &buf_vertex[currentvertex];
- fcolor = &buf_fcolor[currentvertex];
+ m->index = &buf_tri[currenttriangle].index[0];
+ m->vertex = &buf_vertex[currentvertex].v[0];
+ m->color = &buf_fcolor[currentvertex].c[0];
for (i = 0;i < backendunits;i++)
- texcoord[i] = &buf_texcoord[i][currentvertex];
+ m->texcoords[i] = &buf_texcoord[i][currentvertex].t[0];
// opaque meshs are rendered directly
mesh = &buf_mesh[currentmesh++];
mesh->firsttriangle = currenttriangle;
mesh->firstvert = currentvertex;
- memcpy(&buf_tri[currenttriangle].index[0], m->index, sizeof(int[3]) * m->numtriangles);
currenttriangle += m->numtriangles;
currentvertex += m->numverts;
}
mesh->depthtest = !m->depthdisable;
mesh->triangles = m->numtriangles;
mesh->verts = m->numverts;
+
+ overbright = false;
+ scaler = 1;
+ if (m->blendfunc2 == GL_SRC_COLOR)
+ {
+ if (m->blendfunc1 == GL_DST_COLOR) // 2x modulate with framebuffer
+ scaler *= 0.5f;
+ }
+ else
+ {
+ if (m->tex[0])
+ {
+ overbright = gl_combine.integer;
+ if (overbright)
+ scaler *= 0.25f;
+ }
+ scaler *= overbrightscale;
+ }
+ m->colorscale = scaler;
+
j = -1;
- for (i = 0;i < backendunits;i++)
+ for (i = 0;i < MAX_TEXTUREUNITS;i++)
{
if ((mesh->textures[i] = m->tex[i]))
+ {
j = i;
+ if (i >= backendunits)
+ Sys_Error("R_Mesh_Draw_GetBuffer: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
+ }
mesh->texturergbscale[i] = m->texrgbscale[i];
if (mesh->texturergbscale[i] != 1 && mesh->texturergbscale[i] != 2 && mesh->texturergbscale[i] != 4)
mesh->texturergbscale[i] = 1;
if (overbright && j >= 0)
mesh->texturergbscale[j] = 4;
- if (m->vertexstep != sizeof(buf_vertex_t))
- Host_Error("R_Mesh_Draw_NativeOnly: unsupported vertexstep\n");
- if (m->colorstep != sizeof(buf_fcolor_t))
- Host_Error("R_Mesh_Draw_NativeOnly: unsupported colorstep\n");
- if (m->color == NULL)
- Host_Error("R_Mesh_Draw_NativeOnly: must provide color array\n");
- for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
- {
- if (j >= backendunits)
- Sys_Error("R_Mesh_Draw_NativeOnly: texture %i supplied when there are only %i texture units\n", j + 1, backendunits);
- if (m->texcoordstep[j] != sizeof(buf_texcoord_t))
- Host_Error("R_Mesh_Draw_NativeOnly: unsupported texcoordstep\n");
- }
-
- memcpy(vert, m->vertex, m->numverts * sizeof(buf_vertex_t));
- for (j = 0;j < MAX_TEXTUREUNITS && m->tex[j];j++)
- memcpy(&texcoord[j][0].t[0], m->texcoords[j], m->numverts * sizeof(buf_texcoord_t));
- #if 0
- for (;j < backendunits;j++)
- memset(&texcoord[j][0].t[0], 0, m->numverts * sizeof(buf_texcoord_t));
- #endif
-
- memcpy(fcolor, m->color, m->numverts * sizeof(buf_fcolor_t));
-
- // do this as a second step because memcpy preloaded the cache, which we can't easily do
- if (scaler != 1)
- {
- for (i = 0;i < m->numverts;i++)
- {
- fcolor[i].c[0] *= scaler;
- fcolor[i].c[1] *= scaler;
- fcolor[i].c[2] *= scaler;
- }
- }
+ return true;
}
-*/
void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts)
{
int vertexstep;
float *color;
int colorstep;
- // if color is NULL, these are used for all vertices
- float cr, cg, cb, ca;
+ float cr, cg, cb, ca; // if color is NULL, these are used for all vertices
int tex[MAX_TEXTUREUNITS];
float *texcoords[MAX_TEXTUREUNITS];
int texcoordstep[MAX_TEXTUREUNITS];
}
rmeshinfo_t;
+typedef struct
+{
+ //input to R_Mesh_Draw_GetBuffer
+ int transparent;
+ int depthwrite; // force depth writing enabled even if polygon is not opaque
+ int depthdisable; // disable depth read/write entirely
+ int blendfunc1;
+ int blendfunc2;
+ int numtriangles;
+ int numverts;
+ int tex[MAX_TEXTUREUNITS];
+ float texrgbscale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
+
+ // output
+ int *index;
+ float *vertex;
+ float *color;
+ float colorscale;
+ float *texcoords[MAX_TEXTUREUNITS];
+}
+rmeshbufferinfo_t;
+
// adds console variables and registers the render module (only call from GL_Init)
void gl_backend_init(void);
// sets up mesh renderer for the frame
void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts);
// same as normal, except for harsh format restrictions (vertex must be 4 float, color must be 4 float, texcoord must be 2 float, flat color not supported)
void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m);
+// allocates space in geometry buffers, and fills in pointers to the buffers in passsed struct
+// (this is used for very high speed rendering, no copying)
+int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m);
{
// allocate vertex processing arrays
gl_models_mempool = Mem_AllocPool("GL_Models");
- aliasvert = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][3]));
+ aliasvert = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
aliasvertnorm = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][3]));
aliasvertcolor = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
aliasvertcolor2 = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
avn = aliasvertnorm;
while (vertcount >= 4)
{
- VectorCopy(av, point);softwaretransform(point, av);av += 3;
- VectorCopy(av, point);softwaretransform(point, av);av += 3;
- VectorCopy(av, point);softwaretransform(point, av);av += 3;
- VectorCopy(av, point);softwaretransform(point, av);av += 3;
+ VectorCopy(av, point);softwaretransform(point, av);av += 4;
+ VectorCopy(av, point);softwaretransform(point, av);av += 4;
+ VectorCopy(av, point);softwaretransform(point, av);av += 4;
+ VectorCopy(av, point);softwaretransform(point, av);av += 4;
VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
}
while(vertcount > 0)
{
- VectorCopy(av, point);softwaretransform(point, av);av += 3;
+ VectorCopy(av, point);softwaretransform(point, av);av += 4;
VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
vertcount--;
}
avn[0] = n1[0] * lerp1 + n2[0] * lerp2 + n3[0] * lerp3 + n4[0] * lerp4;
avn[1] = n1[1] * lerp1 + n2[1] * lerp2 + n3[1] * lerp3 + n4[1] * lerp4;
avn[2] = n1[2] * lerp1 + n2[2] * lerp2 + n3[2] * lerp3 + n4[2] * lerp4;
- av += 3;
+ av += 4;
avn += 3;
verts1++;verts2++;verts3++;verts4++;
}
avn[0] = n1[0] * lerp1 + n2[0] * lerp2 + n3[0] * lerp3;
avn[1] = n1[1] * lerp1 + n2[1] * lerp2 + n3[1] * lerp3;
avn[2] = n1[2] * lerp1 + n2[2] * lerp2 + n3[2] * lerp3;
- av += 3;
+ av += 4;
avn += 3;
verts1++;verts2++;verts3++;
}
avn[0] = n1[0] * lerp1 + n2[0] * lerp2;
avn[1] = n1[1] * lerp1 + n2[1] * lerp2;
avn[2] = n1[2] * lerp1 + n2[2] * lerp2;
- av += 3;
+ av += 4;
avn += 3;
verts1++;verts2++;
}
avn[0] = n1[0] * lerp1;
avn[1] = n1[1] * lerp1;
avn[2] = n1[2] * lerp1;
- av += 3;
+ av += 4;
avn += 3;
verts1++;
}
av[1] = verts1->v[1] * scale1[1] + translate[1];
av[2] = verts1->v[2] * scale1[2] + translate[2];
VectorCopy(m_bytenormals[verts1->lightnormalindex], avn);
- av += 3;
+ av += 4;
avn += 3;
verts1++;
}
R_LightModel(model->numverts);
}
-void R_DrawQ1AliasModel (void)
+void R_DrawQ1Q2AliasModel (void)
{
float fog;
vec3_t diff;
memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
aliasmeshinfo.vertex = aliasvert;
- aliasmeshinfo.vertexstep = sizeof(float[3]);
+ aliasmeshinfo.vertexstep = sizeof(float[4]);
aliasmeshinfo.numverts = model->numverts;
aliasmeshinfo.numtriangles = model->numtris;
- aliasmeshinfo.index = model->mdldata_indices;
+ aliasmeshinfo.index = model->mdlmd2data_indices;
aliasmeshinfo.colorstep = sizeof(float[4]);
- aliasmeshinfo.texcoords[0] = model->mdldata_texcoords;
+ aliasmeshinfo.texcoords[0] = model->mdlmd2data_texcoords;
aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
fog = 0;
else
R_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
- if (fog)
+ if (fog && aliasmeshinfo.blendfunc2 != GL_ONE)
{
aliasmeshinfo.tex[0] = R_GetTexture(skinframe->fog);
aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
}
}
-void R_DrawQ2AliasModel (void)
-{
- int *order, count;
- vec3_t diff;
- skinframe_t *skinframe;
- model_t *model;
-
- model = currentrenderentity->model;
-
- R_SetupMDLMD2Frames(&skinframe);
-
- if (!r_render.integer)
- return;
-
- // FIXME FIXME FIXME rewrite loader to convert to triangle mesh
- glBindTexture(GL_TEXTURE_2D, R_GetTexture(skinframe->base));
-
- if (currentrenderentity->effects & EF_ADDITIVE)
- {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
- glEnable(GL_BLEND);
- glDepthMask(0);
- }
- else if (currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(skinframe->base))
- {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
- glDepthMask(0);
- }
- else
- {
- glDisable(GL_BLEND);
- glDepthMask(1);
- }
-
- // LordHavoc: big mess...
- // using vertex arrays only slightly, although it is enough to prevent duplicates
- // (saving half the transforms)
- glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
- glColorPointer(4, GL_FLOAT, sizeof(float[4]), aliasvertcolor);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- GL_LockArray(0, model->numverts);
-
- order = model->md2data_glcmds;
- while(1)
- {
- if (!(count = *order++))
- break;
- if (count > 0)
- glBegin(GL_TRIANGLE_STRIP);
- else
- {
- glBegin(GL_TRIANGLE_FAN);
- count = -count;
- }
- do
- {
- glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
- glArrayElement(order[2]);
- order += 3;
- }
- while (count--);
- }
-
- GL_UnlockArray();
-
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
-
- if (fogenabled)
- {
- glDisable (GL_TEXTURE_2D);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable (GL_BLEND);
- glDepthMask(0); // disable zbuffer updates
-
- VectorSubtract(currentrenderentity->origin, r_origin, diff);
- glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], currentrenderentity->alpha * exp(fogdensity/DotProduct(diff,diff)));
-
- // LordHavoc: big mess...
- // using vertex arrays only slightly, although it is enough to prevent duplicates
- // (saving half the transforms)
- glVertexPointer(3, GL_FLOAT, sizeof(float[3]), aliasvert);
- glEnableClientState(GL_VERTEX_ARRAY);
-
- GL_LockArray(0, model->numverts);
-
- order = model->md2data_glcmds;
- while(1)
- {
- if (!(count = *order++))
- break;
- if (count > 0)
- glBegin(GL_TRIANGLE_STRIP);
- else
- {
- glBegin(GL_TRIANGLE_FAN);
- count = -count;
- }
- do
- {
- glArrayElement(order[2]);
- order += 3;
- }
- while (count--);
- }
-
- GL_UnlockArray();
-
- glDisableClientState(GL_VERTEX_ARRAY);
-
- glEnable (GL_TEXTURE_2D);
- glColor3f (1,1,1);
- }
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable (GL_BLEND);
- glDepthMask(1);
-}
-
int ZymoticLerpBones(int count, zymbonematrix *bonebase, frameblend_t *blend, zymbone_t *bone)
{
int i;
vert++;
}
}
- out += 3;
+ out += 4;
}
}
d = *renderlist++;
while (d--)
{
- a = renderlist[0]*3;
- b = renderlist[1]*3;
- c = renderlist[2]*3;
+ a = renderlist[0]*4;
+ b = renderlist[1]*4;
+ c = renderlist[2]*4;
v1[0] = aliasvert[a+0] - aliasvert[b+0];
v1[1] = aliasvert[a+1] - aliasvert[b+1];
v1[2] = aliasvert[a+2] - aliasvert[b+2];
CrossProduct(v1, v2, normal);
VectorNormalizeFast(normal);
// add surface normal to vertices
+ a = renderlist[0] * 3;
aliasvertnorm[a+0] += normal[0];
aliasvertnorm[a+1] += normal[1];
aliasvertnorm[a+2] += normal[2];
aliasvertusage[renderlist[0]]++;
- aliasvertnorm[b+0] += normal[0];
- aliasvertnorm[b+1] += normal[1];
- aliasvertnorm[b+2] += normal[2];
+ a = renderlist[1] * 3;
+ aliasvertnorm[a+0] += normal[0];
+ aliasvertnorm[a+1] += normal[1];
+ aliasvertnorm[a+2] += normal[2];
aliasvertusage[renderlist[1]]++;
- aliasvertnorm[c+0] += normal[0];
- aliasvertnorm[c+1] += normal[1];
- aliasvertnorm[c+2] += normal[2];
+ a = renderlist[2] * 3;
+ aliasvertnorm[a+0] += normal[0];
+ aliasvertnorm[a+1] += normal[1];
+ aliasvertnorm[a+2] += normal[2];
aliasvertusage[renderlist[2]]++;
renderlist += 3;
}
}
+ // FIXME: precalc this
// average surface normals
out = aliasvertnorm;
u = aliasvertusage;
texture = (rtexture_t **)(m->lump_shaders.start + (int) m);
aliasmeshinfo.vertex = aliasvert;
- aliasmeshinfo.vertexstep = sizeof(float[3]);
+ aliasmeshinfo.vertexstep = sizeof(float[4]);
aliasmeshinfo.color = aliasvertcolor;
aliasmeshinfo.colorstep = sizeof(float[4]);
aliasmeshinfo.texcoords[0] = (float *)(m->lump_texcoords.start + (int) m);
if (currentrenderentity->model->aliastype == ALIASTYPE_ZYM)
R_DrawZymoticModel();
- else if (currentrenderentity->model->aliastype == ALIASTYPE_MD2)
- R_DrawQ2AliasModel();
else
- R_DrawQ1AliasModel();
+ R_DrawQ1Q2AliasModel();
}
static int RSurfShader_Wall_Fullbright(int stage, msurface_t *s)
{
+ if (stage == 0)
+ c_brush_polys++;
switch(stage)
{
case 0:
static int RSurfShader_Wall_Vertex(int stage, msurface_t *s)
{
+ if (stage == 0)
+ c_brush_polys++;
switch(stage)
{
case 0:
static int RSurfShader_Wall_Lightmap(int stage, msurface_t *s)
{
+ if (stage == 0)
+ c_brush_polys++;
if (r_vertexsurfaces.integer)
{
switch(stage)
loadmodel->name, version, ALIAS_VERSION);
loadmodel->type = mod_alias;
- loadmodel->aliastype = ALIASTYPE_MDL;
+ loadmodel->aliastype = ALIASTYPE_MDLMD2;
loadmodel->numskins = LittleLong(pinmodel->numskins);
BOUNDI(loadmodel->numskins,0,256);
}
// load triangle data
- loadmodel->mdldata_indices = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->numtris);
+ loadmodel->mdlmd2data_indices = Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->numtris);
// count the vertices used
for (i = 0;i < numverts*2;i++)
// remap the triangle references
for (i = 0;i < loadmodel->numtris;i++)
{
- loadmodel->mdldata_indices[i*3+0] = vertremap[temptris[i][0]];
- loadmodel->mdldata_indices[i*3+1] = vertremap[temptris[i][1]];
- loadmodel->mdldata_indices[i*3+2] = vertremap[temptris[i][2]];
+ loadmodel->mdlmd2data_indices[i*3+0] = vertremap[temptris[i][0]];
+ loadmodel->mdlmd2data_indices[i*3+1] = vertremap[temptris[i][1]];
+ loadmodel->mdlmd2data_indices[i*3+2] = vertremap[temptris[i][2]];
}
// store the texture coordinates
- loadmodel->mdldata_texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * totalverts);
+ loadmodel->mdlmd2data_texcoords = Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * totalverts);
for (i = 0;i < totalverts;i++)
{
- loadmodel->mdldata_texcoords[i*2+0] = vertst[i][0];
- loadmodel->mdldata_texcoords[i*2+1] = vertst[i][1];
+ loadmodel->mdlmd2data_texcoords[i*2+0] = vertst[i][0];
+ loadmodel->mdlmd2data_texcoords[i*2+1] = vertst[i][1];
}
// load the frames
loadmodel->DrawShadow = NULL;
}
-static void Mod_MD2_ConvertVerts (int numverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out)
+static void Mod_MD2_ConvertVerts (vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out, int *vertremap)
{
int i, invalidnormals = 0;
float dist;
+ trivertx_t *in;
vec3_t temp;
- for (i = 0;i < numverts;i++)
+ for (i = 0;i < loadmodel->numverts;i++)
{
- VectorCopy(v[i].v, out[i].v);
- temp[0] = v[i].v[0] * scale[0] + translate[0];
- temp[1] = v[i].v[1] * scale[1] + translate[1];
- temp[2] = v[i].v[2] * scale[2] + translate[2];
+ in = v + vertremap[i];
+ VectorCopy(in->v, out[i].v);
+ temp[0] = in->v[0] * scale[0] + translate[0];
+ temp[1] = in->v[1] * scale[1] + translate[1];
+ temp[2] = in->v[2] * scale[2] + translate[2];
// update bounding box
if (temp[0] < aliasbboxmin[0]) aliasbboxmin[0] = temp[0];
if (temp[1] < aliasbboxmin[1]) aliasbboxmin[1] = temp[1];
dist += temp[2]*temp[2];
if (modelradius < dist)
modelradius = dist;
- out[i].lightnormalindex = v[i].lightnormalindex;
+ out[i].lightnormalindex = in->lightnormalindex;
if (out[i].lightnormalindex >= NUMVERTEXNORMALS)
{
invalidnormals++;
Con_Printf("Mod_MD2_ConvertVerts: \"%s\", %i invalid normal indices found\n", loadmodel->name, invalidnormals);
}
-void Mod_MD2_ReadHeader(md2_t *in, int *numglcmds)
+void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
{
+ int *vertremap;
+ md2_t *pinmodel;
+ long base;
int version, end;
+ int i, j, k, hashindex, num, numxyz, numst, xyz, st;
+ float *stverts, s, t;
+ struct md2verthash_s
+ {
+ struct md2verthash_s *next;
+ int xyz;
+ float st[2];
+ }
+ *hash, **md2verthash, *md2verthashdata;
+ long datapointer;
+ md2frame_t *pinframe;
+ char *inskin;
+ md2triangle_t *intri;
+ unsigned short *inst;
+ int skinwidth, skinheight;
+
+ pinmodel = buffer;
+ base = (long) buffer;
- version = LittleLong (in->version);
+ version = LittleLong (pinmodel->version);
if (version != MD2ALIAS_VERSION)
Host_Error ("%s has wrong version number (%i should be %i)",
loadmodel->name, version, MD2ALIAS_VERSION);
loadmodel->type = mod_alias;
- loadmodel->aliastype = ALIASTYPE_MD2;
+ loadmodel->aliastype = ALIASTYPE_MDLMD2;
loadmodel->SERAddEntity = Mod_Alias_SERAddEntity;
loadmodel->Draw = R_DrawAliasModel;
loadmodel->DrawSky = NULL;
loadmodel->DrawShadow = NULL;
- if (LittleLong(in->num_tris < 1) || LittleLong(in->num_tris) > MD2MAX_TRIANGLES)
- Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(in->num_tris));
- if (LittleLong(in->num_xyz < 1) || LittleLong(in->num_xyz) > MD2MAX_VERTS)
- Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(in->num_xyz));
- if (LittleLong(in->num_frames < 1) || LittleLong(in->num_frames) > MD2MAX_FRAMES)
- Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(in->num_frames));
- if (LittleLong(in->num_skins < 0) || LittleLong(in->num_skins) > MAX_SKINS)
- Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(in->num_skins));
-
- end = LittleLong(in->ofs_end);
- if (LittleLong(in->num_skins) >= 1 && (LittleLong(in->ofs_skins <= 0) || LittleLong(in->ofs_skins) >= end))
+ if (LittleLong(pinmodel->num_tris < 1) || LittleLong(pinmodel->num_tris) > MD2MAX_TRIANGLES)
+ Host_Error ("%s has invalid number of triangles: %i", loadmodel->name, LittleLong(pinmodel->num_tris));
+ if (LittleLong(pinmodel->num_xyz < 1) || LittleLong(pinmodel->num_xyz) > MD2MAX_VERTS)
+ Host_Error ("%s has invalid number of vertices: %i", loadmodel->name, LittleLong(pinmodel->num_xyz));
+ if (LittleLong(pinmodel->num_frames < 1) || LittleLong(pinmodel->num_frames) > MD2MAX_FRAMES)
+ Host_Error ("%s has invalid number of frames: %i", loadmodel->name, LittleLong(pinmodel->num_frames));
+ if (LittleLong(pinmodel->num_skins < 0) || LittleLong(pinmodel->num_skins) > MAX_SKINS)
+ Host_Error ("%s has invalid number of skins: %i", loadmodel->name, LittleLong(pinmodel->num_skins));
+
+ end = LittleLong(pinmodel->ofs_end);
+ if (LittleLong(pinmodel->num_skins) >= 1 && (LittleLong(pinmodel->ofs_skins <= 0) || LittleLong(pinmodel->ofs_skins) >= end))
Host_Error ("%s is not a valid model", loadmodel->name);
- if (LittleLong(in->ofs_st <= 0) || LittleLong(in->ofs_st) >= end)
+ if (LittleLong(pinmodel->ofs_st <= 0) || LittleLong(pinmodel->ofs_st) >= end)
Host_Error ("%s is not a valid model", loadmodel->name);
- if (LittleLong(in->ofs_tris <= 0) || LittleLong(in->ofs_tris) >= end)
+ if (LittleLong(pinmodel->ofs_tris <= 0) || LittleLong(pinmodel->ofs_tris) >= end)
Host_Error ("%s is not a valid model", loadmodel->name);
- if (LittleLong(in->ofs_frames <= 0) || LittleLong(in->ofs_frames) >= end)
+ if (LittleLong(pinmodel->ofs_frames <= 0) || LittleLong(pinmodel->ofs_frames) >= end)
Host_Error ("%s is not a valid model", loadmodel->name);
- if (LittleLong(in->ofs_glcmds <= 0) || LittleLong(in->ofs_glcmds) >= end)
+ if (LittleLong(pinmodel->ofs_glcmds <= 0) || LittleLong(pinmodel->ofs_glcmds) >= end)
Host_Error ("%s is not a valid model", loadmodel->name);
- loadmodel->numskins = LittleLong(in->num_skins);
- loadmodel->numverts = LittleLong(in->num_xyz);
-// loadmodel->md2num_st = LittleLong(in->num_st);
- loadmodel->numtris = LittleLong(in->num_tris);
- loadmodel->numframes = LittleLong(in->num_frames);
- *numglcmds = LittleLong(in->num_glcmds);
+ loadmodel->numskins = LittleLong(pinmodel->num_skins);
+ numxyz = LittleLong(pinmodel->num_xyz);
+ numst = LittleLong(pinmodel->num_st);
+ loadmodel->numtris = LittleLong(pinmodel->num_tris);
+ loadmodel->numframes = LittleLong(pinmodel->num_frames);
loadmodel->flags = 0; // there are no MD2 flags
loadmodel->synctype = ST_RAND;
-}
-void Mod_MD2_LoadSkins(char *in)
-{
- int i;
-// load the skins
+ // load the skins
+ inskin = (void*)(base + LittleLong(pinmodel->ofs_skins));
if (loadmodel->numskins)
{
loadmodel->skinscenes = Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numskins);
loadmodel->skinscenes[i].framecount = 1;
loadmodel->skinscenes[i].loop = true;
loadmodel->skinscenes[i].framerate = 10;
- loadmodel->skinframes[i].base = loadtextureimagewithmask (loadmodel->texturepool, in, 0, 0, true, r_mipskins.integer, true);
+ loadmodel->skinframes[i].base = loadtextureimagewithmask (loadmodel->texturepool, inskin, 0, 0, true, r_mipskins.integer, true);
loadmodel->skinframes[i].fog = image_masktex;
loadmodel->skinframes[i].pants = NULL;
loadmodel->skinframes[i].shirt = NULL;
loadmodel->skinframes[i].glow = NULL;
loadmodel->skinframes[i].merged = NULL;
- in += MD2MAX_SKINNAME;
+ inskin += MD2MAX_SKINNAME;
}
}
-}
-/*
-void Mod_MD2_LoadTriangles(md2triangle_t *in)
-{
- int i, j;
- loadmodel->md2data_tris = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(md2triangle_t));
+ // load the triangles and stvert data
+ inst = (void*)(base + LittleLong(pinmodel->ofs_st));
+ intri = (void*)(base + LittleLong(pinmodel->ofs_tris));
+ skinwidth = LittleLong(pinmodel->skinwidth);
+ skinheight = LittleLong(pinmodel->skinheight);
+
+ stverts = Mem_Alloc(tempmempool, numst * sizeof(float[2]));
+ s = 1.0f / skinwidth;
+ t = 1.0f / skinheight;
+ for (i = 0;i < numst;i++)
+ {
+ j = (unsigned short) LittleShort(inst[i*2+0]);
+ k = (unsigned short) LittleShort(inst[i*2+1]);
+ if (j >= skinwidth || k >= skinheight)
+ {
+ Mem_Free(stverts);
+ Host_Error("Mod_MD2_LoadGeometry: invalid skin coordinate (%i %i) on vert %i of model %s\n", j, k, i, loadmodel->name);
+ }
+ stverts[i*2+0] = j * s;
+ stverts[i*2+1] = k * t;
+ }
+
+ md2verthash = Mem_Alloc(tempmempool, 256 * sizeof(hash));
+ md2verthashdata = Mem_Alloc(tempmempool, loadmodel->numtris * 3 * sizeof(*hash));
// swap the triangle list
+ num = 0;
+ loadmodel->mdlmd2data_indices = Mem_Alloc(loadmodel->mempool, loadmodel->numtris * sizeof(int[3]));
for (i = 0;i < loadmodel->numtris;i++)
{
for (j = 0;j < 3;j++)
{
- loadmodel->md2data_tris[i].index_xyz[j] = LittleShort (in[i].index_xyz[j]);
- loadmodel->md2data_tris[i].index_st[j] = LittleShort (in[i].index_st[j]);
- if (loadmodel->md2data_tris[i].index_xyz[j] >= loadmodel->md2num_xyz)
- Host_Error ("%s has invalid vertex indices", loadmodel->name);
- if (loadmodel->md2data_tris[i].index_st[j] >= loadmodel->md2num_st)
- Host_Error ("%s has invalid vertex indices", loadmodel->name);
+ xyz = (unsigned short) LittleShort (intri[i].index_xyz[j]);
+ st = (unsigned short) LittleShort (intri[i].index_st[j]);
+ if (xyz >= numxyz || st >= numst)
+ {
+ Mem_Free(md2verthash);
+ Mem_Free(md2verthashdata);
+ Mem_Free(stverts);
+ if (xyz >= numxyz)
+ Host_Error("Mod_MD2_LoadGeometry: invalid xyz index (%i) on triangle %i of model %s\n", xyz, i, loadmodel->name);
+ if (st >= numst)
+ Host_Error("Mod_MD2_LoadGeometry: invalid st index (%i) on triangle %i of model %s\n", st, i, loadmodel->name);
+ }
+ s = stverts[st*2+0];
+ t = stverts[st*2+1];
+ hashindex = (xyz * 17 + st) & 255;
+ for (hash = md2verthash[hashindex];hash;hash = hash->next)
+ if (hash->xyz == xyz && hash->st[0] == s && hash->st[1] == t)
+ break;
+ if (hash == NULL)
+ {
+ hash = md2verthashdata + num++;
+ hash->xyz = xyz;
+ hash->st[0] = s;
+ hash->st[1] = t;
+ hash->next = md2verthash[hashindex];
+ md2verthash[hashindex] = hash;
+ }
+ loadmodel->mdlmd2data_indices[i*3+j] = (hash - md2verthashdata);
}
}
-}
-*/
-void Mod_MD2_LoadFrames(void *start)
-{
- int i, j;
- long datapointer;
- md2frame_t *pinframe;
+ Mem_Free(stverts);
+
+ loadmodel->numverts = num;
+ vertremap = Mem_Alloc(loadmodel->mempool, num * sizeof(int));
+ loadmodel->mdlmd2data_texcoords = Mem_Alloc(loadmodel->mempool, num * sizeof(float[2]));
+ for (i = 0;i < num;i++)
+ {
+ hash = md2verthashdata + i;
+ vertremap[i] = hash->xyz;
+ loadmodel->mdlmd2data_texcoords[i*2+0] = hash->st[0];
+ loadmodel->mdlmd2data_texcoords[i*2+1] = hash->st[1];
+ }
+
+ Mem_Free(md2verthash);
+ Mem_Free(md2verthashdata);
+
+ // load frames
// LordHavoc: doing proper bbox for model
aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000000000;
aliasbboxmax[0] = aliasbboxmax[1] = aliasbboxmax[2] = -1000000000;
modelyawradius = 0;
modelradius = 0;
- datapointer = (long) start;
-// load the frames
+ datapointer = (base + LittleLong(pinmodel->ofs_frames));
+ // load the frames
loadmodel->animscenes = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(animscene_t));
loadmodel->mdlmd2data_frames = Mem_Alloc(loadmodel->mempool, loadmodel->numframes * sizeof(md2frame_t));
loadmodel->mdlmd2data_pose = Mem_Alloc(loadmodel->mempool, loadmodel->numverts * loadmodel->numframes * sizeof(trivertx_t));
loadmodel->mdlmd2data_frames[i].scale[j] = LittleFloat(pinframe->scale[j]);
loadmodel->mdlmd2data_frames[i].translate[j] = LittleFloat(pinframe->translate[j]);
}
- Mod_MD2_ConvertVerts (loadmodel->numverts, loadmodel->mdlmd2data_frames[i].scale, loadmodel->mdlmd2data_frames[i].translate, (void *)datapointer, &loadmodel->mdlmd2data_pose[i * loadmodel->numverts]);
- datapointer += loadmodel->numverts * sizeof(trivertx_t);
+ Mod_MD2_ConvertVerts (loadmodel->mdlmd2data_frames[i].scale, loadmodel->mdlmd2data_frames[i].translate, (void *)datapointer, &loadmodel->mdlmd2data_pose[i * loadmodel->numverts], vertremap);
+ datapointer += numxyz * sizeof(trivertx_t);
strcpy(loadmodel->animscenes[i].name, loadmodel->mdlmd2data_frames[i].name);
loadmodel->animscenes[i].firstframe = i;
loadmodel->animscenes[i].loop = true;
}
+ Mem_Free(vertremap);
+
// LordHavoc: model bbox
modelyawradius = sqrt(modelyawradius);
modelradius = sqrt(modelradius);
loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
}
-void Mod_MD2_LoadGLCmds(int *in, int numglcmds)
-{
- int i;
- // load the draw list
- loadmodel->md2data_glcmds = Mem_Alloc(loadmodel->mempool, numglcmds * sizeof(int));
- for (i = 0;i < numglcmds;i++)
- loadmodel->md2data_glcmds[i] = LittleLong(in[i]);
-}
-
-void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
-{
- md2_t *pinmodel;
- int numglcmds;
- long base;
- pinmodel = buffer;
- base = (long) buffer;
- Mod_MD2_ReadHeader(pinmodel, &numglcmds);
- Mod_MD2_LoadSkins((void*)(base + LittleLong(pinmodel->ofs_skins)));
-// Mod_MD2_LoadTriangles((void*)(base + LittleLong(pinmodel->ofs_tris)));
- Mod_MD2_LoadFrames((void*)(base + LittleLong(pinmodel->ofs_frames)));
- Mod_MD2_LoadGLCmds((void*)(base + LittleLong(pinmodel->ofs_glcmds)), numglcmds);
-}
-
static void zymswapintblock(int *m, int size)
{
size /= 4;
int ofs_end; // end of file
} md2_t;
-#define ALIASTYPE_MDL 1
-#define ALIASTYPE_MD2 2
-#define ALIASTYPE_ZYM 3
+// LordHavoc: Q1 and Q2 models are converted to the same internal format
+#define ALIASTYPE_MDLMD2 1
+#define ALIASTYPE_ZYM 2
extern void Mod_LoadAliasModel (struct model_s *mod, void *buffer);
extern void Mod_LoadQ2AliasModel (struct model_s *mod, void *buffer);
animscene_t *animscenes; // [numframes]
- // Q2 model information
-// md2triangle_t *md2data_tris;
- // FIXME: redesign to use triangle mesh
- int *md2data_glcmds;
-
- float *mdldata_texcoords;
- int *mdldata_indices;
-
+ // Q1 and Q2 models are the same after loading
+ int *mdlmd2data_indices;
+ float *mdlmd2data_texcoords;
md2frame_t *mdlmd2data_frames;
trivertx_t *mdlmd2data_pose;
VectorCopy(color, avc);
avc[3] = a;
avc += 4;
- av += 3;
+ av += 4;
avn += 3;
}
}