/* gl_md3.c * Based on code from the Aftershock 3D rendering engine * Copyright (C) 1999 Stephen C. Taylor * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //gl_md3.c "dont mess" lethal!!! #include "quakedef.h" qboolean r_md3fullbright_draw; // precalculated dot products for quantized angles float r_avertexnormal_dots_md3[16][256] = #include "anorm_dots.h" ; float *shadedots_md3 = r_avertexnormal_dots_md3[0]; float *shadedots2_md3 = r_avertexnormal_dots_md3[0]; // make these seperate "works" // only lightcolor is shared but thats k float shadelightmd3, ambientlightmd3; float apitchmd3, ayawmd3; float lightlerpoffsetmd3; /* ============= GL_CalcQ3LightLerp Calculates lightning between two angles ============= */ float GL_CalcQ3LightLerp (float l1, float l2) { float l, diff; if (l1 != l2) { if (l1 > l2) { diff = (l1 - l2) * -1; } else { diff = l2 - l1; } diff *= lightlerpoffsetmd3; l = l1 + diff; } else { l = l1; } // add contrast - this is a nasty hack from Pox's tut which simulates specular lighting // mainly introduced cos at the time he didn't know the norms. however, my engine does // calculate the norms at model load time (although it doesn't really use them) so i // should be able to do proper specular lighting... if only i knew how :-( l *= l; return l; } /* ================= GL_DrawQ3AliasFrame Please fix this ANYONE!!! ================= */ void GL_DrawQ3AliasFrame (md3header_mem_t *header, int lastpose, int pose, float blend, qboolean mtex) { int i, j, k; int frame; int lastframe; int vertframeoffset; int lastvertframeoffset; vec3_t l_v; float alpha, iblend; float d1, d2, l, l1, l2; md3frame_mem_t *light, *lastlight; md3surface_mem_t *surf; md3st_mem_t *tc; md3tri_mem_t *tris; md3vert_mem_t *verts, *vertslast; md3trivertx_t *lightverts, *lastlightverts; alpha = (currententity == &cl.viewent && gl_mtexable) ? ((cl.items & IT_INVISIBILITY) ? gl_ringalpha.value : bound(0, r_drawviewmodel.value, 1)) : model_alpha; iblend = 1.0 - blend; surf = (md3surface_mem_t *)((byte *)header + header->offs_surfaces); if (alpha < 1.0) { glEnable (GL_BLEND); } for (i = 0; i < header->num_surfaces; i++) { if (*(long *)surf->id != MD3IDHEADER) { Con_Printf("MD3 bad surface for: %s\n", header->filename); } if (surf->num_surf_frames == 0){ surf = (md3surface_mem_t *)((byte *)surf + surf->offs_end); continue; //shouldn't ever do this, each surface should have at least one frame } frame = pose%surf->num_surf_frames; //cap the frame inside the list of frames in the model vertframeoffset = frame*surf->num_surf_verts * sizeof(md3vert_mem_t); lastframe = lastpose%surf->num_surf_frames; lastvertframeoffset = lastframe*surf->num_surf_verts * sizeof(md3vert_mem_t); tc = (md3st_mem_t *)((byte *)surf + surf->offs_tc); tris = (md3tri_mem_t *)((byte *)surf + surf->offs_tris); verts = (md3vert_mem_t *)((byte *)surf + surf->offs_verts + vertframeoffset); vertslast = (md3vert_mem_t *)((byte *)surf + surf->offs_verts + lastvertframeoffset); // now this gets hackish light = (md3frame_mem_t *)((int) header + header->offs_frames + (header->num_frames * lastpose)); lastlight = (md3frame_mem_t *)((int) header + header->offs_frames + (header->num_frames * pose)); // damn this was a bitch to get going !! lightverts = &light->verts[0]; lastlightverts = &lastlight->verts[0]; // normals and vertexes come from the frame list // blend the light intensity from the two frames together if (gl_vertexlights.value && !r_md3fullbright_draw) { l = R_LerpVertexLight (lightverts->lightnormalindex, lastlightverts->lightnormalindex, blend, apitchmd3, ayawmd3); l = min(l, 1); } else { d1 = (shadedots_md3[lastlightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3) - (shadedots2_md3[lightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3); d2 = (shadedots_md3[lastlightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3) - (shadedots2_md3[lightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3); l1 = min(1, (shadedots_md3[lightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3) + (blend * d1) / 256); l2 = min(1, (shadedots_md3[lightverts->lightnormalindex] * shadelightmd3 + ambientlightmd3) + (blend * d2) / 256); l = GL_CalcQ3LightLerp (l1, l2); } if (!r_md3fullbright_draw) { for (i=0 ; i<3 ; i++) { l_v[i] = lightcolor[i] / 256 + l; } glColor4f (l_v[0], l_v[1], l_v[2], alpha); } else { glColor4f (l, l, l, alpha); } if (blend >=1) { glNormalPointer(GL_FLOAT, 6 * sizeof(float), (float *)verts->normal); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (float *)verts->vec); glEnableClientState(GL_VERTEX_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, (float *)tc); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawElements(GL_TRIANGLES, surf->num_surf_tris*3, GL_UNSIGNED_INT, (int *)tris); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } else { glBegin(GL_TRIANGLES); //for each triangle for (j = 0; j < surf->num_surf_tris; j++) { //draw the poly for (k=0; k < 3; k++) { //interpolated if(mtex) { qglMultiTexCoord2f (GL_TEXTURE0_ARB,tc[tris[j].tri[k]].s, tc[tris[j].tri[k]].t); qglMultiTexCoord2f (GL_TEXTURE1_ARB,tc[tris[j].tri[k]].s, tc[tris[j].tri[k]].t); } else { glTexCoord2f (tc[tris[j].tri[k]].s, tc[tris[j].tri[k]].t); } // Faster than the former struct glVertex3f(verts[tris[j].tri[k]].vec[0] * blend + vertslast[tris[j].tri[k]].vec[0] * iblend, verts[tris[j].tri[k]].vec[1] * blend + vertslast[tris[j].tri[k]].vec[1] * iblend, verts[tris[j].tri[k]].vec[2] * blend + vertslast[tris[j].tri[k]].vec[2] * iblend); // Faster than the former struct glNormal3f(verts[tris[j].tri[k]].normal[0] * blend + vertslast[tris[j].tri[k]].normal[0] * iblend, verts[tris[j].tri[k]].normal[1] * blend + vertslast[tris[j].tri[k]].normal[1] * iblend, verts[tris[j].tri[k]].normal[2] * blend + vertslast[tris[j].tri[k]].normal[2] * iblend); } } } glEnd(); // crap i mounted this in the wrong spot before causing all sorts off strange behaviour } surf = (md3surface_mem_t *)((byte *)surf + surf->offs_end); if (alpha < 1.0) { glDisable (GL_BLEND); } glColor3f (1, 1, 1); } /* ================= R_SetupQ3AliasFrame From TQ148 thx Tomaz ================= */ void R_SetupQ3AliasFrame (int frame, md3header_mem_t *header, entity_t *e, qboolean mtex) { float blend; // im getting confirms on non existing frames here // but dunno if its a bug with the md3 models, so far // it only seems to adhere to the rocketlauncher ? if ((frame >= header->num_frames) || (frame < 0)) { Con_DPrintf ("R_SetupQ3AliasFrame: no such frame %d\n", frame); frame = 0; } //md3 interpolation if (e->draw_lastmodel == e->model) { if (frame != e->draw_pose) { e->draw_lastpose = e->draw_pose; e->draw_pose = frame; e->draw_lerpstart = cl.time; blend = 0; } else { blend = (cl.time - e->draw_lerpstart) * 10.0; } } else { // uninitialized e->draw_lastmodel = e->model; e->draw_lastpose = e->draw_pose = frame; e->draw_lerpstart = cl.time; blend = 0; } if (blend > 1) { blend = 1; } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawQ3AliasFrame(header, e->draw_lastpose, frame, blend, mtex); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } /* ================= R_DrawQ3Model Modified Dr Labmans md3 code splitting it up to make it easier to add dynamic lighting code ================= */ void R_DrawQ3Model(entity_t *e) { md3header_mem_t *header; md3shader_mem_t *shader; md3surface_mem_t *surf; model_t *clmodel; vec3_t dist, ang, dlight_color; vec3_t vertexlightmd3; float add, ang_ceil, ang_floor, radiusmax = 0.0; int shaders, i, lnum; if (!gl_notrans.value) { // allways true if not -nehahra model_alpha = currententity->transparency; if (model_alpha == 0) { model_alpha = 1.0; } } else { model_alpha = 1.0; } clmodel = e->model; // get lighting information // make thunderbolt and torches full light if (clmodel->mflags & MOD_BOLT) { ambientlightmd3 = 210; shadelightmd3 = 0; r_md3fullbright_draw = true; } else if (clmodel->mflags & MOD_FLAME) { ambientlightmd3 = 255; shadelightmd3 = 0; r_md3fullbright_draw = true; } else { // normal lighting r_md3fullbright_draw = false; ambientlightmd3 = shadelightmd3 = R_LightPoint (e->origin); for (lnum = 0 ; lnum < MAX_DLIGHTS ; lnum++) { if (cl_dlights[lnum].die < cl.time || !cl_dlights[lnum].radius) continue; VectorSubtract (e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - VectorLength (dist); if (add > 0) { if (gl_vertexlights.value) { if (!radiusmax || cl_dlights[lnum].radius > radiusmax) { radiusmax = cl_dlights[lnum].radius; VectorCopy(cl_dlights[lnum].origin, vertexlightmd3); } } VectorCopy(bubblecolor[cl_dlights[lnum].type], dlight_color); for (i=0 ; i<3 ; i++) { lightcolor[i] = lightcolor[i] + (dlight_color[i] * add) * 2; if (lightcolor[i] > 256) { switch (i) { case 0: lightcolor[1] = lightcolor[1] - (1 * lightcolor[1]/3); lightcolor[2] = lightcolor[2] - (1 * lightcolor[2]/3); break; case 1: lightcolor[0] = lightcolor[0] - (1 * lightcolor[0]/3); lightcolor[2] = lightcolor[2] - (1 * lightcolor[2]/3); break; case 2: lightcolor[1] = lightcolor[1] - (1 * lightcolor[1]/3); lightcolor[0] = lightcolor[0] - (1 * lightcolor[0]/3); break; } } } } } // calculate pitch and yaw for vertex lighting if (gl_vertexlights.value) { apitchmd3 = e->angles[0]; ayawmd3 = e->angles[1]; if (!radiusmax) { vlight_pitch = 45; vlight_yaw = 45; } else { VectorSubtract(vertexlightmd3, e->origin, dist); vectoangles(dist, ang); vlight_pitch = ang[0]; vlight_yaw = ang[1]; } } // clamp lighting so it doesn't overbright as much ambientlightmd3 = min(128, ambientlightmd3); if (ambientlightmd3 + shadelightmd3 > 192) { shadelightmd3 = 192 - ambientlightmd3; } // always give the gun some light if (e == &cl.viewent && ambientlightmd3 < 24) { ambientlightmd3 = shadelightmd3 = 24; } // never allow players to go totally black if (clmodel->mflags & MOD_PLAYER) { if (ambientlightmd3 < 8) { ambientlightmd3 = shadelightmd3 = 8; r_md3fullbright_draw = false; } } } if (r_fullbrightskins.value && (clmodel->mflags & MOD_PLAYER)) { ambientlightmd3 = shadelightmd3 = 128; r_md3fullbright_draw = true; } if (gl_vertexlights.value) { // YUCK YUCK YUCK shadedots_md3= r_avertexnormal_dots_md3[((int)(e->angles[1])) & (16 - 1)]; } else { // add pitch angle so lighting changes when looking up/down (mainly for viewmodel) lightlerpoffsetmd3 = e->angles[1] * (16 / 360.0); ang_ceil = ceil(lightlerpoffsetmd3); ang_floor = floor(lightlerpoffsetmd3); lightlerpoffsetmd3 = ang_ceil - lightlerpoffsetmd3; // it gives me the crepaas !! shadedots_md3 = r_avertexnormal_dots_md3[(int)ang_ceil & (16 - 1)]; shadedots2_md3 = r_avertexnormal_dots_md3[(int)ang_floor & (16 - 1)]; if (e->lastShadeLight) { shadelightmd3 = (shadelightmd3 + e->lastShadeLight) / 2; } if (shadelightmd3) { e->lastShadeLight = shadelightmd3; } else { e->lastShadeLight = 1; } } // Allocate the header header = (md3header_mem_t *)Mod_Extradata (e->model); // locate the proper data "huh surface related"! surf = (md3surface_mem_t *)((byte *)header + header->offs_surfaces); c_alias_polys += surf->num_surf_tris; //get pointer to shaders shader = (md3shader_mem_t *)((byte *)surf + surf->offs_shaders); shaders = shader[(currententity->skinnum%surf->num_surf_shaders)].texnum; if (shaders!=0) { GL_Bind(shaders); } else { GL_Bind(0); } if (*(long *)header->id != MD3IDHEADER){ Con_Printf("MD3 bad model for: %s\n", header->filename); return; } glPushMatrix(); //interpolate unless its the viewmodel if (gl_interpolate_animation.value && e != &cl.viewent) { R_BlendedRotateForEntity (e, 0); } else { R_RotateForEntity (e); } if (gl_smoothmodels.value) { glShadeModel (GL_SMOOTH); } if (gl_affinemodels.value) { glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); } if (gl_mtexable) { R_SetupQ3AliasFrame (e->frame, header, e, true); } else { R_SetupQ3AliasFrame (e->frame, header, e, false); } glShadeModel (GL_FLAT); if (gl_affinemodels.value) { glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); } glPopMatrix(); } int md3bboxmins[3], md3bboxmaxs[3]; /* ================= Mod_LoadQ3Model ================= */ void Mod_LoadQ3Model(model_t *mod, void *buffer) { md3header_t *header; md3header_mem_t *mem_head; md3surface_t *surf; md3surface_mem_t *currentsurf; md3shader_mem_t *shader; md3frame_t *framein; md3frame_mem_t *frameout; int i, j, picmip_flag; int posn; int surfstartposn; char name[128]; //we want to work out the size of the model in memory int surf_size = 0; int mem_size = 0; picmip_flag = gl_picmip_all.value ? TEX_MIPMAP : 0; //pointer to header header = (md3header_t *)buffer; //pointer to the surface list surf = (md3surface_t *)((byte *)buffer + header->surface_offs); for (i = 0; i < header->num_surfaces; i++) { surf_size += sizeof(md3surface_mem_t); surf_size += surf->num_surf_shaders * sizeof(md3shader_mem_t); surf_size += surf->num_surf_tris * sizeof(md3tri_mem_t); surf_size += surf->num_surf_verts * sizeof(md3st_mem_t); surf_size += surf->num_surf_verts * surf->num_surf_frames * sizeof(md3vert_mem_t); //goto next surf surf = (md3surface_t *)((byte *)surf + surf->end_offs); } //total size = header size + num_frames * frame size + num_tags * tag size + //size of surfaces mem_size = sizeof(md3header_mem_t); mem_size += header->num_frames * sizeof(md3frame_mem_t); mem_size += header->num_tags * sizeof(md3tag_mem_t); mem_size += surf_size; Con_DPrintf("Loading md3 model...%s (%s)\n", header->filename, mod->name); // cannot allocate on hunk WTF !!! mem_head = (md3header_mem_t *)Cache_Alloc (&mod->cache, mem_size, mod->name); // ignore cache just check if the header contains data // dont try any funny moves here it wont work :( if (!mem_head) { return; //cache alloc failed } //setup more mem stuff mod->type = mod_md3; mod->aliastype = MD3IDHEADER; mod->synctype = ST_RAND; //copy stuff across from disk buffer to memory posn = 0; //posn in new buffer //copy header Q_memcpy(mem_head, header, sizeof(md3header_t)); posn += sizeof(md3header_mem_t); //posn of frames mem_head->offs_frames = posn; //copy frames Q_memcpy((byte *)mem_head + mem_head->offs_frames, (byte *)header + header->frame_offs, sizeof(md3frame_t)*header->num_frames); posn += sizeof(md3frame_mem_t)*header->num_frames; //posn of tags mem_head->offs_tags = posn; //copy tags Q_memcpy((byte *)mem_head + mem_head->offs_tags, (byte *)header + header->tag_offs, sizeof(md3tag_t)*header->num_tags); posn += sizeof(md3tag_mem_t)*header->num_tags; //posn of surfaces mem_head->offs_surfaces = posn; //get pointer to surface in file surf = (md3surface_t *)((byte *)header + header->surface_offs); //get pointer to surface in memory currentsurf = (md3surface_mem_t *)((byte *)mem_head + posn); surfstartposn = posn; for (i=0; i < header->num_surfaces; i++) { //copy size of surface Q_memcpy((byte *)mem_head + posn, (byte *)header + header->surface_offs, sizeof(md3surface_t)); posn += sizeof(md3surface_mem_t); //posn of shaders for this surface currentsurf->offs_shaders = posn - surfstartposn; for (j=0; j < surf->num_surf_shaders; j++){ //copy jth shader accross Q_memcpy((byte *)mem_head + posn, (byte *)surf + surf->shader_offs + j * sizeof(md3shader_t), sizeof(md3shader_t)); posn += sizeof(md3shader_mem_t); //copyed non-mem into mem one } //posn of tris for this surface currentsurf->offs_tris = posn - surfstartposn; //copy tri Q_memcpy((byte *)mem_head + posn, (byte *)surf + surf->tris_offs, sizeof(md3tri_t) * surf->num_surf_tris); posn += sizeof(md3tri_mem_t) * surf->num_surf_tris; //posn of tex coords in this surface currentsurf->offs_tc = posn - surfstartposn; //copy st Q_memcpy((byte *)mem_head + posn, (byte *)surf + surf->tc_offs, sizeof(md3st_t) * surf->num_surf_verts); posn += sizeof(md3st_t) * surf->num_surf_verts; //posn points to surface->verts currentsurf->offs_verts = posn - surfstartposn; //next to have to be redone for (j=0; j < surf->num_surf_verts * surf->num_surf_frames; j++){ float lat; float lng; //convert verts from shorts to floats md3vert_mem_t *mem_vert = (md3vert_mem_t *)((byte *)mem_head + posn); md3vert_t *disk_vert = (md3vert_t *)((byte *)surf + surf->vert_offs + j * sizeof(md3vert_t)); mem_vert->vec[0] = (float)disk_vert->vec[0] * MD3_XYZ_SCALE; mem_vert->vec[1] = (float)disk_vert->vec[1] * MD3_XYZ_SCALE; mem_vert->vec[2] = (float)disk_vert->vec[2] * MD3_XYZ_SCALE; //work out normals lat = (disk_vert->normal + 255) * (2 * M_PI) / 255; lng = ((disk_vert->normal >> 8) & 255) * (2 * M_PI) / 255; mem_vert->normal[0] = cos (lat) * sin (lng); mem_vert->normal[1] = sin (lat) * sin (lng); mem_vert->normal[2] = cos (lng); posn += sizeof(md3vert_mem_t); //copyed non-mem into mem one } //point to next surf (or eof) surf = (md3surface_t*)((byte *)surf + surf->end_offs); //posn points to the end of this surface currentsurf->offs_end = posn; //next start of surf (if there is one) surfstartposn = posn; } //posn should now equal mem_size if (posn != mem_size){ Con_Printf("Copied different ammount to what was worked out, copied: %i worked out: %i\n",posn, mem_size); } // load frames // Needed for lights "took me ages to complete this mess" :/ // nasty hack but OMG ! it works :D Reckless: // from the looks off it this should also mean you can do Q1 style shadows // from this struct. but its not working with glcmdlists "sigh" framein = (void *)((int) header + LittleLong(header->frame_offs)); frameout = (void *)((int) mem_head + LittleLong(mem_head->offs_frames)); for (i=0 ; inum_frames ; i++) { for (j=0 ; j<3 ; j++) { frameout->mins[j] = LittleFloat (framein->mins[j]); frameout->maxs[j] = LittleFloat (framein->maxs[j]); frameout->pos[j] = LittleFloat (framein->pos[j]); } frameout->radius = LittleFloat (framein->radius); mod->radius = max(mod->radius, frameout->radius); strcpy (frameout->name, framein->name); // whats the freakin size here ??? "i need an index pointer goddammit!" for (j=0 ; jnum_surfaces-1 ; j++) { vec3_t bbox; VectorCopy (framein->verts[j].v, frameout->verts[j].v); frameout->verts[j].lightnormalindex = framein->verts[j].lightnormalindex; bbox[0] = frameout->verts[j].v[0] * frameout->mins[0] + frameout->maxs[0]; bbox[1] = frameout->verts[j].v[1] * frameout->mins[1] + frameout->maxs[1]; bbox[2] = frameout->verts[j].v[2] * frameout->mins[2] + frameout->maxs[2]; // update bounding box if (bbox[0] < md3bboxmins[0]) md3bboxmins[0] = bbox[0]; if (bbox[1] < md3bboxmins[1]) md3bboxmins[1] = bbox[1]; if (bbox[2] < md3bboxmins[2]) md3bboxmins[2] = bbox[2]; if (bbox[0] > md3bboxmaxs[0]) md3bboxmaxs[0] = bbox[0]; if (bbox[1] > md3bboxmaxs[1]) md3bboxmaxs[1] = bbox[1]; if (bbox[2] > md3bboxmaxs[2]) md3bboxmaxs[2] = bbox[2]; } framein = (void *) &framein->verts[j].v[0]; frameout = (void *) &frameout->verts[j].v[0]; } VectorCopy (md3bboxmins, mod->mins); VectorCopy (md3bboxmaxs, mod->maxs); // TODO: Make a gl_command list for shadows :/ // HACK: we dont have flags in md3 so give them some to enable effects ;) if (!strcmp (mod->name, "progs/g_shot.mdl") || !strcmp (mod->name, "progs/g_nail.mdl") || !strcmp (mod->name, "progs/g_nail2.mdl") || !strcmp (mod->name, "progs/g_rock.mdl") || !strcmp (mod->name, "progs/g_rock2.mdl") || !strcmp (mod->name, "progs/g_light.mdl") || !strcmp (mod->name, "progs/armor.mdl") || !strcmp (mod->name, "progs/backpack.mdl") || !strcmp (mod->name, "progs/w_g_key.mdl") || !strcmp (mod->name, "progs/w_s_key.mdl") || !strcmp (mod->name, "progs/m_g_key.mdl") || !strcmp (mod->name, "progs/m_s_key.mdl") || !strcmp (mod->name, "progs/b_g_key.mdl") || !strcmp (mod->name, "progs/b_s_key.mdl") || !strcmp (mod->name, "progs/quaddama.mdl") || !strcmp (mod->name, "progs/invisibl.mdl") || !strcmp (mod->name, "progs/invulner.mdl") || !strcmp (mod->name, "progs/jetpack.mdl") || !strcmp (mod->name, "progs/cube.mdl") || !strcmp (mod->name, "progs/suit.mdl") || !strcmp (mod->name, "progs/boots.mdl") || !strcmp (mod->name, "progs/end1.mdl") || !strcmp (mod->name, "progs/end2.mdl") || !strcmp (mod->name, "progs/end3.mdl") || !strcmp (mod->name, "progs/end4.mdl")) { mem_head->flags |= EF_ROTATE; } else if (!strcmp (mod->name, "progs/missile.mdl")) { mem_head->flags |= EF_ROCKET; } else if (!strcmp (mod->name, "progs/gib1.mdl") || //EF_GIB !strcmp (mod->name, "progs/gib2.mdl") || !strcmp (mod->name, "progs/gib3.mdl") || !strcmp (mod->name, "progs/h_player.mdl") || !strcmp (mod->name, "progs/h_dog.mdl") || !strcmp (mod->name, "progs/h_mega.mdl") || !strcmp (mod->name, "progs/h_guard.mdl") || !strcmp (mod->name, "progs/h_wizard.mdl") || !strcmp (mod->name, "progs/h_knight.mdl") || !strcmp (mod->name, "progs/h_hellkn.mdl") || !strcmp (mod->name, "progs/h_zombie.mdl") || !strcmp (mod->name, "progs/h_shams.mdl") || !strcmp (mod->name, "progs/h_shal.mdl") || !strcmp (mod->name, "progs/h_ogre.mdl") || !strcmp (mod->name, "progs/armor.mdl") || !strcmp (mod->name, "progs/h_demon.mdl")) { mem_head->flags |= EF_GIB; } else if (!strcmp (mod->name, "progs/grenade.mdl")) { mem_head->flags |= EF_GRENADE; } else if (!strcmp (mod->name, "progs/w_spike.mdl")) { mem_head->flags |= EF_TRACER; } else if (!strcmp (mod->name, "progs/k_spike.mdl")) { mem_head->flags |= EF_TRACER2; } else if (!strcmp (mod->name, "progs/v_spike.mdl")) { mem_head->flags |= EF_TRACER3; } else if (!strcmp (mod->name, "progs/zom_gib.mdl")) { mem_head->flags |= EF_ZOMGIB; } mod->flags = LittleLong (mem_head->flags); mod->numframes = LittleLong (mem_head->num_frames); //get pointer to first surface currentsurf = (md3surface_mem_t *)((byte *)mem_head + mem_head->offs_surfaces); for (i=0; inum_surfaces; i++) { if (*(long *)currentsurf->id != MD3IDHEADER){ Con_Printf("MD3 bad surface for: %s\n", mem_head->filename); } else { shader = (md3shader_mem_t *)((byte *)currentsurf + currentsurf->offs_shaders); for (j=0; jnum_surf_shaders; j++){ sprintf (&name[0], "textures/md3skins/%s", shader[j].name); shader[j].texnum = GL_LoadTextureImage (&name[0], NULL, 0, 0, picmip_flag | TEX_BLEND); if (!shader[j].texnum) { sprintf (&name[0], "textures/md3boxes/%s", shader[j].name); shader[j].texnum = GL_LoadTextureImage (&name[0], NULL, 0, 0, picmip_flag | TEX_BLEND); } if (!shader[j].texnum) { Con_Printf("Model: %s Texture missing: %s\n", mod->name, shader[j].name); } } } currentsurf = (md3surface_mem_t *)((byte *)currentsurf + currentsurf->offs_end); } }