/* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2007 Peter Mackay and Chris Swindle. Copyright (C) 2008-2009 Crow_bar. 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. */ // models.c -- model loading and caching // models are the only shared resource between a client and server running // on the same machine. extern "C" { #include "../quakedef.h" } #include #include #include "video_hardware_fullbright.h" #include "video_hardware_hlmdl.h" #include "video_hardware_images.h" int LIGHTMAP_BYTES; model_t *loadmodel; char loadname[32]; // for hunk tags //void UnloadWads (void); //wad unload by Crow_bar void VID_InitPaleteH2(unsigned char* palette); void Mod_LoadSpriteModel (model_t *mod, void *buffer); void Mod_LoadBrushModel (model_t *mod, void *buffer); void Mod_LoadAliasModel (model_t *mod, void *buffer); void Mod_LoadH2AliasModel (model_t *mod, void *buffer); void Mod_LoadQ2AliasModel (model_t *mod, void *buffer); qboolean Mod_LoadQ2SpriteModel (model_t *mod, void *buffer); //void Mod_LoadQ2BrushModel (model_t *mod, void *buffer); void Mod_LoadQ3AliasModel (model_t *mod, void *buffer); model_t *Mod_LoadModel (model_t *mod, qboolean crash); byte mod_novis[MAX_MAP_LEAFS/8]; #define MAX_MOD_KNOWN 512 model_t mod_known[MAX_MOD_KNOWN]; int mod_numknown; //model_t mod_inline[MAX_MOD_KNOWN]; cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", qtrue}; extern int solidskytexture; extern int alphaskytexture; /* =============== Mod_Init =============== */ void Mod_Init (void) { Cvar_RegisterVariable (&gl_subdivide_size); memset (mod_novis, 0xff, sizeof(mod_novis)); } /* =============== Mod_Init Caches the data if needed =============== */ void *Mod_Extradata (model_t *mod) { void *r; r = Cache_Check (&mod->cache); if (r) return r; Mod_LoadModel (mod, qtrue); if (!mod->cache.data) Sys_Error ("Mod_Extradata: caching failed"); return mod->cache.data; } /* =============== Mod_PointInLeaf =============== */ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) { mnode_t *node; float d; mplane_t *plane; if (!model || !model->nodes) Sys_Error ("Mod_PointInLeaf: bad model"); node = model->nodes; while (1) { if (node->contents < 0) return (mleaf_t *)node; plane = node->plane; d = DotProduct (p,plane->normal) - plane->dist; if (d > 0) node = node->children[0]; else node = node->children[1]; } return NULL; // never reached } /* =================== Mod_DecompressVis =================== */ byte *Mod_DecompressVis (byte *in, model_t *model) { static byte decompressed[MAX_MAP_LEAFS/8]; int c; byte *out; int row; row = (model->numleafs+7)>>3; out = decompressed; #if 0 memcpy (out, in, row); #else if (!in) { // no vis info, so make all visible while (row) { *out++ = 0xff; row--; } return decompressed; } do { if (*in) { *out++ = *in++; continue; } c = in[1]; in += 2; while (c) { *out++ = 0; c--; } } while (out - decompressed < row); #endif return decompressed; } byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model) { if (leaf == model->leafs) return mod_novis; return Mod_DecompressVis (leaf->compressed_vis, model); } /* =================== Mod_ClearAll =================== */ static byte *ent_file = NULL; void Mod_ClearAll (void) { int i,texture_index; model_t *mod; for (i=0 , mod=mod_known ; itype != mod_alias && mod->type != mod_md3 && mod->type != mod_halflife) { mod->needload = qtrue; } //Models & Sprite Unloading code By Crow_bar if (mod->type == mod_alias || mod->type == mod_md3 || mod->type == mod_halflife) { if (Cache_Check (&mod->cache)) Cache_Free (&mod->cache); } else if (mod->type == mod_sprite) { mod->cache.data = NULL; } } UnloadWads(); //Crow_bar ent_file = NULL; //~~~~ GL_UnloadAllTextures(); solidskytexture = -1; alphaskytexture = -1; //purge old sky textures for (i=0; i<6; i++) skyimage[i] = NULL; //purge old lightmaps for (i=0; iname, name) ) break; return mod; } */ // // search the currently loaded models // for (i=0 , mod=mod_known ; iname, name) ) break; if (i == mod_numknown) { if (mod_numknown == MAX_MOD_KNOWN) Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); strcpy (mod->name, name); mod->needload = qtrue; mod_numknown++; } return mod; } /* ================== Mod_TouchModel ================== */ void Mod_TouchModel (char *name) { model_t *mod; mod = Mod_FindName (name); if (!mod->needload && (mod->type == mod_alias || mod->type == mod_md3 || mod->type == mod_halflife)) Cache_Check (&mod->cache); } /* ================== Mod_LoadModel Loads a model into the cache ================== */ model_t *Mod_LoadModel (model_t *mod, qboolean crash) { void *d; unsigned *buf; byte stackbuf[1024]; // avoid dirtying the cache heap char strip[128]; char md3name[128]; if (!mod->needload) { if (mod->type == mod_alias || mod->type == mod_md3 || mod->type == mod_halflife) { d = Cache_Check (&mod->cache); if (d) return mod; } else return mod; // not cached at all } // // because the world is so huge, load it one piece at a time // if (!crash) { } // // load the file // if (r_loadq3models.value) { COM_StripExtension(mod->name, &strip[0]); sprintf (&md3name[0], "%s.md3", &strip[0]); buf = (unsigned *)COM_LoadStackFile (md3name, stackbuf, sizeof(stackbuf)); if (!buf) { buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); if (!buf) { if (crash) Sys_Error ("Mod_NumForName: %s not found", mod->name); return NULL; } } } else { buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); if (!buf && crash) { // Reload with another .mdl buf = (unsigned *)COM_LoadStackFile("progs/missing_model.mdl", stackbuf, sizeof(stackbuf)); if (buf) { Con_Printf ("Missing model %s substituted\n", mod->name); } } if (!buf) { if (crash) Sys_Error ("Mod_NumForName: %s not found", mod->name); return NULL; } } // // allocate a new model // COM_FileBase (mod->name, loadname); loadmodel = mod; // // fill it in // // call the apropriate loader mod->needload = qfalse; switch (LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: //Quake .mdl support Mod_LoadAliasModel (mod, buf); break; case RAPOLYHEADER: //Hexen II .mdl support Mod_LoadH2AliasModel (mod, buf); break; case MD2IDALIASHEADER: //Quake II .md2 support Mod_LoadQ2AliasModel (mod, buf); break; case MD3IDHEADER: //Quake III .md3 support Mod_LoadQ3AliasModel (mod, buf); break; case HLPOLYHEADER: //Half-Life .mdl support Mod_LoadHLModel (mod, buf); break; case IDSPRITEHEADER: //Quake .spr .spr32 and HL sprite support Mod_LoadSpriteModel (mod, buf); break; case IDSPRITE2HEADER: //Quake II .sp2 support Mod_LoadQ2SpriteModel (mod, buf); break; /* case IDBSPHEADER: //q2 bsp support Mod_LoadQ2BrushModel (mod, buf); break; */ default: //.bsp ver 29,30 support Mod_LoadBrushModel (mod, buf); break; } return mod; } /* ================== Mod_ForName Loads in a model for the given name ================== */ model_t *Mod_ForName (char *name, qboolean crash) { model_t *mod; mod = Mod_FindName (name); return Mod_LoadModel (mod, crash); } /* =============================================================================== BRUSHMODEL LOADING =============================================================================== */ byte *mod_base; int GL_LoadTexturePixels (byte *data, char *identifier, int width, int height, int mode); #define ISSKYTEX(name) ((name)[0] == 's' && (name)[1] == 'k' && (name)[2] == 'y') #define ISTURBTEX(name) ((loadmodel->bspversion == BSPVERSION && (name)[0] == '*') || \ (loadmodel->bspversion == HL_BSPVERSION && (name)[0] == '!') || \ (loadmodel->bspversion == NZP_BSPVERSION && (name)[0] == '!')) extern int nonetexture; /* ================= Mod_LoadTextures ================= */ void Mod_LoadTextures (lump_t *l) { int i, j, pixels, num, max, altmax; miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10]; texture_t *altanims[10]; dmiptexlump_t *m; char texname[64]; loadmodel->textures = NULL; char fbr_mask_name[64]; if (!l->filelen) { return; } m = (dmiptexlump_t *)(mod_base + l->fileofs); m->nummiptex = LittleLong (m->nummiptex); loadmodel->numtextures = m->nummiptex; loadmodel->textures = static_cast(Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname)); loading_num_step = loading_num_step + m->nummiptex; for (i=0 ; inummiptex ; i++) { m->dataofs[i] = LittleLong(m->dataofs[i]); if (m->dataofs[i] == -1) continue; mt = (miptex_t *)((byte *)m + m->dataofs[i]); mt->width = LittleLong (mt->width); mt->height = LittleLong (mt->height); for (j=0 ; joffsets[j] = LittleLong (mt->offsets[j]); if ( (mt->width & 15) || (mt->height & 15) ) Sys_Error ("Texture %s is not 16 aligned", mt->name); pixels = mt->width*mt->height/64*85; tx = static_cast(Hunk_AllocName (sizeof(texture_t) , loadname )); const std::size_t buffer_size = pixels; byte* tx_pixels = static_cast(memalign(16, buffer_size)); if (!tx_pixels) { Sys_Error("BrushTex: Out of RAM for loading textures\n"); } loadmodel->textures[i] = tx; memcpy_vfpu(tx->name, mt->name, sizeof(tx->name)); tx->width = mt->width; tx->height = mt->height; for (j=0 ; joffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); // the pixels immediately follow the structures memcpy_vfpu( tx_pixels, mt+1, pixels); int level = 0; if (r_mipmaps.value > 0) level = 3; //if (loadmodel->isworldmodel && loadmodel->bspversion != HL_BSPVERSION && ISSKYTEX(tx->name)) if (loadmodel->bspversion != HL_BSPVERSION && loadmodel->bspversion != NZP_BSPVERSION && ISSKYTEX(tx->name)) { R_InitSky (tx_pixels); } else { if (loadmodel->bspversion == HL_BSPVERSION || loadmodel->bspversion == NZP_BSPVERSION) { char filename[64]; // Filename to check r4w file byte *f; sprintf(filename, "textures/maps/%s/%s.r4w", sv.name, mt->name); // search in textures/maps/MAPNAME/TEXNAME f = static_cast(COM_LoadHunkFile(filename)); if (!f) { sprintf(filename, "textures/%s.r4w", mt->name); // search in textures/TEXNAME f = static_cast(COM_LoadHunkFile(filename)); } if (!f) { Con_Printf("Loading texture %s as WAD3, %dx%d\n", mt->name, mt->width, mt->height); // didn't find the texture in the folder // naievil -- try to push wad3 loading int index = WAD3_LoadTexture(mt); if(index) { com_netpath[0] = 0; tx->gl_texturenum = index; tx->fullbright = -1; tx->dt_texturenum = 0; // if(tx_pixels = WAD3_LoadTexture(mt)) // { // com_netpath[0] = 0; // tx->gl_texturenum = GL_LoadPalletedTexture (tx_pixels, tx->name, tx->width, tx->height, 0); // tx->fullbright = -1; // mapTextureNameList.push_back(tx->gl_texturenum); // tx->dt_texturenum = 0; } else { Con_Printf("Texture %s not found\n", mt->name); // didn't find the texture in the folder com_netpath[0] = 0; tx->gl_texturenum = nonetexture; } } else { int w, h; unsigned int magic = *((unsigned int*)(f)); if (magic == 0x65663463) // what the fuck? { w = *((int*)(f + 4)); h = *((int*)(f + 8)); tx->gl_texturenum = GL_LoadTexture4(mt->name, w, h, (byte*)(f + 16), GU_LINEAR, qfalse); } } } else { sprintf (texname, "textures/%s", mt->name); tx->gl_texturenum = loadtextureimage (texname, 0, 0, qfalse, GU_LINEAR); if(tx->gl_texturenum == 0) { tx->gl_texturenum = GL_LoadTexture (mt->name, tx->width, tx->height, (byte *)(tx_pixels), qtrue, GU_LINEAR, level); } /* //Crow_bar mult detail textures sprintf (detname, "gfx/detail/%s", mt->name); tx->dt_texturenum = loadtextureimage (detname, 0, 0, qfalse, GU_LINEAR); mapTextureNameList.push_back(tx->dt_texturenum); */ tx->dt_texturenum = 0; // check for fullbright pixels in the texture - only if it ain't liquid, etc also if ((tx->name[0] != '*') && (FindFullbrightTexture ((byte *)(tx_pixels), pixels))) { // convert any non fullbright pixel to fully transparent ConvertPixels ((byte *)(tx_pixels), pixels); // get a new name for the fullbright mask to avoid cache mismatches sprintf (fbr_mask_name, "fullbright_mask_%s", mt->name); // load the fullbright pixels version of the texture tx->fullbright = GL_LoadTexture (fbr_mask_name, tx->width, tx->height, (byte *)(tx_pixels), qtrue, GU_LINEAR, level); } else tx->fullbright = -1; // because 0 is a potentially valid texture number } } strcpy(loading_name, mt->name); free (tx_pixels); loading_cur_step++; SCR_UpdateScreen(); } // // sequence the animations // for (i=0 ; inummiptex ; i++) { tx = loadmodel->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) continue; // allready sequenced // find the number of frames in the animation memset (anims, 0, sizeof(anims)); memset (altanims, 0, sizeof(altanims)); max = tx->name[1]; altmax = 0; if (max >= 'a' && max <= 'z') max -= 'a' - 'A'; if (max >= '0' && max <= '9') { max -= '0'; altmax = 0; anims[max] = tx; max++; } else if (max >= 'A' && max <= 'J') { altmax = max - 'A'; max = 0; altanims[altmax] = tx; altmax++; } else Sys_Error ("Bad animating texture %s", tx->name); for (j=i+1 ; jnummiptex ; j++) { tx2 = loadmodel->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name+2, tx->name+2)) continue; num = tx2->name[1]; if (num >= 'a' && num <= 'z') num -= 'a' - 'A'; if (num >= '0' && num <= '9') { num -= '0'; anims[num] = tx2; if (num+1 > max) max = num + 1; } else if (num >= 'A' && num <= 'J') { num = num - 'A'; altanims[num] = tx2; if (num+1 > altmax) altmax = num+1; } else Sys_Error ("Bad animating texture %s", tx->name); } #define ANIM_CYCLE 2 // link them all together for (j=0 ; jname); tx2->anim_total = max * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = anims[ (j+1)%max ]; if (altmax) tx2->alternate_anims = altanims[0]; } for (j=0 ; jname); tx2->anim_total = altmax * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = altanims[ (j+1)%altmax ]; if (max) tx2->alternate_anims = anims[0]; } } } /* ================= Mod_LoadLighting ================= */ void Mod_LoadLighting (lump_t *l) { if (COM_CheckParm ("-lm_1")) LIGHTMAP_BYTES = 1; else if (COM_CheckParm ("-lm_2")) LIGHTMAP_BYTES = 2; else if (COM_CheckParm ("-lm_3")) LIGHTMAP_BYTES = 3; else LIGHTMAP_BYTES = 4; loadmodel->lightdata = NULL; if (loadmodel->bspversion == HL_BSPVERSION || loadmodel->bspversion == NZP_BSPVERSION) { if (!l->filelen) { return; } loadmodel->lightdata = static_cast(Hunk_AllocName ( l->filelen, loadname)); memcpy_vfpu(loadmodel->lightdata, mod_base + l->fileofs, l->filelen); return; } int i; byte *in, *out, *data; byte d; char litfilename[1024]; // LordHavoc: check for a .lit file strcpy(litfilename, loadmodel->name); COM_StripExtension(litfilename, litfilename); strcat(litfilename, ".lit"); data = (byte*) COM_LoadHunkFile (litfilename); if (data) { if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) { Con_DPrintf("%s loaded", litfilename); loadmodel->lightdata = data + 8; return; } else Con_Printf("Unknown .lit file version (%d)\n", i); } else Con_Printf("Corrupt .lit file (old version?), ignoring\n"); } // LordHavoc: no .lit found, expand the white lighting data to color if (!l->filelen) { return; } loadmodel->lightdata = static_cast(Hunk_AllocName ( l->filelen*3, litfilename)); in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write out = loadmodel->lightdata; memcpy_vfpu(in, mod_base + l->fileofs, l->filelen); for (i = 0;i < l->filelen;i++) { d = *in++; *out++ = d; *out++ = d; *out++ = d; } // LordHavoc: .lit support end } // added by dr_mabuse1981 /* ================= Mod_HL_LoadLighting ================= */ void Mod_HL_LoadLighting (lump_t *l) { if (COM_CheckParm ("-lm_1")) LIGHTMAP_BYTES = 1; else if (COM_CheckParm ("-lm_2")) LIGHTMAP_BYTES = 2; else if (COM_CheckParm ("-lm_3")) LIGHTMAP_BYTES = 3; else LIGHTMAP_BYTES = 4; if (!l->filelen) { loadmodel->lightdata = NULL; return; } loadmodel->lightdata = static_cast(Hunk_AllocName ( l->filelen, loadname)); memcpy_vfpu(loadmodel->lightdata, mod_base + l->fileofs, l->filelen); } /* ================= Mod_LoadVisibility ================= */ void Mod_LoadVisibility (lump_t *l) { loadmodel->visdata = NULL; if (!l->filelen) { return; } loadmodel->visdata = static_cast(Hunk_AllocName ( l->filelen, loadname)); memcpy_vfpu(loadmodel->visdata, mod_base + l->fileofs, l->filelen); } /* ================= Mod_ParseWadsFromEntityLump For Half-life maps ================= */ static void Mod_ParseWadsFromEntityLump(char *data) { char *s, key[1024], value[1024]; int i, j, k; if (!data || !(data = COM_Parse(data))) return; if (com_token[0] != '{') return; // error while (1) { if (!(data = COM_Parse(data))) return; // error if (com_token[0] == '}') break; // end of worldspawn Q_strncpyz(key, (com_token[0] == '_') ? com_token + 1 : com_token, sizeof(key)); for (s = key + strlen(key) - 1; s >= key && *s == ' '; s--) // remove trailing spaces *s = 0; if (!(data = COM_Parse(data))) return; // error Q_strncpyz(value, com_token, sizeof(value)); if (!strcmp("MaxRange", key)) Cvar_Set("r_maxrange", value); if (!strcmp("wad", key)) { j = 0; for (i = 0; i < strlen(value); i++) { if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':') break; } if (!value[i]) continue; for ( ; i < sizeof(value); i++) { // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'... if (value[i] == '\\' || value[i] == '/' || value[i] == ':') { j = i + 1; } else if (value[i] == ';' || value[i] == 0) { k = value[i]; value[i] = 0; if (value[j]) WAD3_LoadTextureWadFile (value + j); j = i + 1; if (!k) break; } } } } } /* ================= Mod_LoadEntities .ent file support by Crow_bar ================= */ void Mod_LoadEntities (lump_t *l) { char entfilename[128]; loadmodel->entities = NULL; strcpy(entfilename, loadmodel->name); COM_StripExtension(entfilename, entfilename); strcat(entfilename, ".ent"); ent_file = (byte*) COM_LoadHunkFile (entfilename); if (ent_file) { if (ent_file[0] == '{') { Con_DPrintf("%s loaded", entfilename); loadmodel->entities = (char*)ent_file; return; } else Con_Printf("Corrupt .ent file, ignoring\n"); } if (!l->filelen) { //loadmodel->entities = NULL; return; } loadmodel->entities = static_cast(Hunk_AllocName ( l->filelen, entfilename)); memcpy_vfpu(loadmodel->entities, mod_base + l->fileofs, l->filelen); if (loadmodel->bspversion == HL_BSPVERSION || loadmodel->bspversion == NZP_BSPVERSION) Mod_ParseWadsFromEntityLump(loadmodel->entities); } /* ================= Mod_LoadVertexes ================= */ void Mod_LoadVertexes (lump_t *l) { dvertex_t *in; mvertex_t *out; int i, count; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->vertexes = out; loadmodel->numvertexes = count; for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); out->position[1] = LittleFloat (in->point[1]); out->position[2] = LittleFloat (in->point[2]); } } /* ================= Mod_LoadSubmodels ================= */ void Mod_LoadSubmodels (lump_t *l) { dmodel_t *in; dmodel_t *out; int i, j, count; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->submodels = out; loadmodel->numsubmodels = count; for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; out->maxs[j] = LittleFloat (in->maxs[j]) + 1; out->origin[j] = LittleFloat (in->origin[j]); } for (j=0 ; jheadnode[j] = LittleLong (in->headnode[j]); out->visleafs = LittleLong (in->visleafs); out->firstface = LittleLong (in->firstface); out->numfaces = LittleLong (in->numfaces); } } /* ================= Mod_LoadEdges ================= */ void Mod_LoadEdges (lump_t *l) { dedge_t *in; medge_t *out; int i, count; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( (count + 1) * sizeof(*out), loadname)); loadmodel->edges = out; loadmodel->numedges = count; for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); out->v[1] = (unsigned short)LittleShort(in->v[1]); } } /* ================= Mod_LoadTexinfo ================= */ void Mod_LoadTexinfo (lump_t *l) { texinfo_t *in; mtexinfo_t *out; int i, j, count; int miptex; float len1, len2; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->texinfo = out; loadmodel->numtexinfo = count; for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); len1 = Length (out->vecs[0]); len2 = Length (out->vecs[1]); len1 = (len1 + len2)/2; if (len1 < 0.32) out->mipadjust = 4; else if (len1 < 0.49) out->mipadjust = 3; else if (len1 < 0.99) out->mipadjust = 2; else out->mipadjust = 1; #if 0 if (len1 + len2 < 0.001) out->mipadjust = 1; // don't crash else out->mipadjust = 1 / floorf( (len1+len2)/2 + 0.1 ); #endif miptex = LittleLong (in->miptex); out->flags = LittleLong (in->flags); if (!loadmodel->textures) { out->texture = r_notexture_mip; // checkerboard texture out->flags = 0; } else { if (miptex >= loadmodel->numtextures) Sys_Error ("miptex >= loadmodel->numtextures"); out->texture = loadmodel->textures[miptex]; if (!out->texture) { out->texture = r_notexture_mip; // texture not found out->flags = 0; } } } } /* ================ CalcSurfaceExtents Fills in s->texturemins[] and s->extents[] ================ */ void CalcSurfaceExtents (msurface_t *s) { float mins[2], maxs[2], val; int i,j, e; mvertex_t *v; mtexinfo_t *tex; int bmins[2], bmaxs[2]; mins[0] = mins[1] = 999999; maxs[0] = maxs[1] = -99999; tex = s->texinfo; for (i=0 ; inumedges ; i++) { e = loadmodel->surfedges[s->firstedge+i]; if (e >= 0) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; for (j=0 ; j<2 ; j++) { val = v->position[0] * tex->vecs[j][0] + v->position[1] * tex->vecs[j][1] + v->position[2] * tex->vecs[j][2] + tex->vecs[j][3]; if (val < mins[j]) mins[j] = val; if (val > maxs[j]) maxs[j] = val; } } for (i=0 ; i<2 ; i++) { bmins[i] = (int)floorf(mins[i]/16); bmaxs[i] = (int)ceilf(maxs[i]/16); s->texturemins[i] = bmins[i] * 16; s->extents[i] = (bmaxs[i] - bmins[i]) * 16; if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512 /* 256 */ ) Sys_Error ("Bad surface extents"); } } /* ================= Mod_LoadFaces ================= */ void Mod_LoadFaces (lump_t *l) { dface_t *in; msurface_t *out; int i, count, surfnum; int planenum, side; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->surfaces = out; loadmodel->numsurfaces = count; for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); out->flags = 0; planenum = LittleShort(in->planenum); side = LittleShort(in->side); if (side) out->flags |= SURF_PLANEBACK; out->plane = loadmodel->planes + planenum; out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo); CalcSurfaceExtents (out); // lighting info for (i=0 ; istyles[i] = in->styles[i]; if (loadmodel->bspversion == HL_BSPVERSION || loadmodel->bspversion == NZP_BSPVERSION) i = LittleLong(in->lightofs); else i = LittleLong(in->lightofs * 3); if (i == -1) out->samples = NULL; else out->samples = loadmodel->lightdata + (i); // cypress -- moved from video_hardware_surface // modified to use new TEXFLAG hacky fields and have // surfs use the same shabang. const char* tex_name = out->texinfo->texture->name; // Sky textures. if (tex_name[0] == 's' && tex_name[1] == 'k' && tex_name[2] == 'y') { out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); GL_Surface(out); // Don't cut up polygon for warps continue; } // Turbulent. else if (tex_name[0] == '*') { out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); for (i=0 ; i<2 ; i++) { out->extents[i] = 16384; out->texturemins[i] = -8192; } GL_Surface (out); // Don't cut up polygon for warps continue; } // Don't draw texture and lightmaps. else if (tex_name[0] == 'n' && tex_name[1] == 'o' && tex_name[2] == 'd' && tex_name[3] == 'r' && tex_name[4] == 'a' && tex_name[5] == 'w') { out->flags |= TEXFLAG_NODRAW; continue; } // Surface uvmaps warp, like metal or glass effects. else if ((tex_name[0] == 'e' && tex_name[1] == 'n' && tex_name[2] == 'v') || (tex_name[0] == 'g' && tex_name[1] == 'l' && tex_name[2] == 'a' && tex_name[3] == 's' && tex_name[4] == 's')) { out->flags |= TEXFLAG_REFLECT; continue; } else { out->flags |= TEXFLAG_NORMAL; continue; } // cypress -- end modification } } /* ================= Mod_SetParent ================= */ void Mod_SetParent (mnode_t *node, mnode_t *parent) { node->parent = parent; if (node->contents < 0) return; Mod_SetParent (node->children[0], node); Mod_SetParent (node->children[1], node); } /* ================= Mod_LoadNodes ================= */ void Mod_LoadNodes (lump_t *l) { int i, j, count, p; dnode_t *in; mnode_t *out; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->nodes = out; loadmodel->numnodes = count; for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->planenum); out->plane = loadmodel->planes + p; out->firstsurface = LittleShort (in->firstface); out->numsurfaces = LittleShort (in->numfaces); for (j=0 ; j<2 ; j++) { p = LittleShort (in->children[j]); if (p >= 0) out->children[j] = loadmodel->nodes + p; else out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); } } Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs } /* ================= Mod_LoadLeafs ================= */ void Mod_LoadLeafs (lump_t *l) { dleaf_t *in; mleaf_t *out; int i, j, count, p; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->leafs = out; loadmodel->numleafs = count; for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); out->minmaxs[3+j] = LittleShort (in->maxs[j]); } p = LittleLong(in->contents); out->contents = p; out->firstmarksurface = loadmodel->marksurfaces + LittleShort(in->firstmarksurface); out->nummarksurfaces = LittleShort(in->nummarksurfaces); p = LittleLong(in->visofs); if (p == -1) out->compressed_vis = NULL; else out->compressed_vis = loadmodel->visdata + p; out->efrags = NULL; for (j=0 ; j<4 ; j++) out->ambient_sound_level[j] = in->ambient_level[j]; // gl underwater warp if (out->contents != CONTENTS_EMPTY) { for (j=0 ; jnummarksurfaces ; j++) out->firstmarksurface[j]->flags |= SURF_UNDERWATER; } } } /* ================= Mod_LoadClipnodes ================= */ void Mod_LoadClipnodes (lump_t *l) { dclipnode_t *in, *out; int i, count; hull_t *hull; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->clipnodes = out; loadmodel->numclipnodes = count; if (loadmodel->bspversion == HL_BSPVERSION || loadmodel->bspversion == NZP_BSPVERSION) { hull = &loadmodel->hulls[1]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -36; hull->clip_maxs[0] = 16; hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 36; hull = &loadmodel->hulls[2]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -32; hull->clip_maxs[0] = 32; hull->clip_maxs[1] = 32; hull->clip_maxs[2] = 32; hull = &loadmodel->hulls[3]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -18; hull->clip_maxs[0] = 16; hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 18; } else { hull = &loadmodel->hulls[1]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -24; hull->clip_maxs[0] = 16; hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 32; hull = &loadmodel->hulls[2]; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -24; hull->clip_maxs[0] = 32; hull->clip_maxs[1] = 32; hull->clip_maxs[2] = 64; } for (i=0 ; iplanenum = LittleLong(in->planenum); out->children[0] = LittleShort(in->children[0]); out->children[1] = LittleShort(in->children[1]); } } /* ================= Mod_MakeHull0 Deplicate the drawing hull structure as a clipping hull ================= */ void Mod_MakeHull0 (void) { mnode_t *in, *child; dclipnode_t *out; int i, j, count; hull_t *hull; hull = &loadmodel->hulls[0]; in = loadmodel->nodes; count = loadmodel->numnodes; out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count-1; hull->planes = loadmodel->planes; for (i=0 ; iplanenum = in->plane - loadmodel->planes; for (j=0 ; j<2 ; j++) { child = in->children[j]; if (child->contents < 0) out->children[j] = child->contents; else out->children[j] = child - loadmodel->nodes; } } } /* ================= Mod_LoadMarksurfaces ================= */ void Mod_LoadMarksurfaces (lump_t *l) { int i, j, count; short *in; msurface_t **out; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->marksurfaces = out; loadmodel->nummarksurfaces = count; for ( i=0 ; i= loadmodel->numsurfaces) Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); out[i] = loadmodel->surfaces + j; } } /* ================= Mod_LoadSurfedges ================= */ void Mod_LoadSurfedges (lump_t *l) { int i, count; int *in, *out; in = reinterpret_cast(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*sizeof(*out), loadname)); loadmodel->surfedges = out; loadmodel->numsurfedges = count; for ( i=0 ; i(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Con_Printf("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); out = static_cast(Hunk_AllocName ( count*2*sizeof(*out), loadname)); loadmodel->planes = out; loadmodel->numplanes = count; for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); if (out->normal[j] < 0) bits |= 1<dist = LittleFloat (in->dist); out->type = LittleLong (in->type); out->signbits = bits; } } /* ================= RadiusFromBounds ================= */ float RadiusFromBounds (vec3_t mins, vec3_t maxs) { int i; vec3_t corner; for (i=0 ; i<3 ; i++) { corner[i] = fabsf(mins[i]) > fabsf(maxs[i]) ? fabsf(mins[i]) : fabsf(maxs[i]); } return Length (corner); } /* ================= Mod_LoadBrushModel ================= */ void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; dheader_t *header; dmodel_t *bm; loadmodel->type = mod_brush; header = (dheader_t *)buffer; i = LittleLong (header->version); mod->bspversion = LittleLong (header->version); if (mod->bspversion != BSPVERSION && mod->bspversion != HL_BSPVERSION && mod->bspversion != NZP_BSPVERSION) Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or %i (HalfLife))", mod->name, mod->bspversion, BSPVERSION, HL_BSPVERSION); //loadmodel->isworldmodel = !strcmp(loadmodel->name, va("maps/%s.bsp", mapname.string)); if (mod->bspversion == BSPVERSION && r_hlbsponly.value && !developer.value) Host_Error ("Mod_LoadBrushModel: Normal quake maps are disabled. Please use half life bsp. "); // swap all the lumps mod_base = (byte *)header; for (i=0 ; ilumps[LUMP_VERTEXES]); loading_cur_step++; strcpy(loading_name, "Edges"); SCR_UpdateScreen (); Mod_LoadEdges (&header->lumps[LUMP_EDGES]); loading_cur_step++; strcpy(loading_name, "Surfedges"); SCR_UpdateScreen (); Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); loading_cur_step++; strcpy(loading_name, "Entities"); SCR_UpdateScreen (); Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); loading_cur_step++; strcpy(loading_name, "Textures"); SCR_UpdateScreen (); Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); if(mod->bspversion == HL_BSPVERSION || mod->bspversion == NZP_BSPVERSION) // dr_mabuse1981 { Mod_HL_LoadLighting (&header->lumps[LUMP_LIGHTING]); } else { Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); } loading_cur_step++; SCR_UpdateScreen (); Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); loading_cur_step++; strcpy(loading_name, "Texinfo"); SCR_UpdateScreen (); Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); loading_cur_step++; strcpy(loading_name, "Faces"); SCR_UpdateScreen (); Mod_LoadFaces (&header->lumps[LUMP_FACES]); loading_cur_step++; strcpy(loading_name, "Marksurfaces"); SCR_UpdateScreen (); Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]); loading_cur_step++; strcpy(loading_name, "Visibility"); SCR_UpdateScreen (); Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); loading_cur_step++; strcpy(loading_name, "Leafs"); SCR_UpdateScreen (); Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); loading_cur_step++; strcpy(loading_name, "Nodes"); SCR_UpdateScreen (); Mod_LoadNodes (&header->lumps[LUMP_NODES]); loading_cur_step++; strcpy(loading_name, "Clipnodes"); SCR_UpdateScreen (); Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]); loading_cur_step++; strcpy(loading_name, "Submodels"); SCR_UpdateScreen (); Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); loading_cur_step++; strcpy(loading_name, "Hull"); SCR_UpdateScreen (); Mod_MakeHull0 (); loading_cur_step++; loading_step = 3; strcpy(loading_name, "Screen"); loading_cur_step++; SCR_UpdateScreen (); mod->numframes = 2; // regular and alternate animation // // set up the submodels (FIXME: this is confusing) // for (i=0 ; inumsubmodels ; i++) { bm = &mod->submodels[i]; mod->hulls[0].firstclipnode = bm->headnode[0]; for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; mod->hulls[j].lastclipnode = mod->numclipnodes-1; } mod->firstmodelsurface = bm->firstface; mod->nummodelsurfaces = bm->numfaces; VectorCopy (bm->maxs, mod->maxs); VectorCopy (bm->mins, mod->mins); mod->radius = RadiusFromBounds (mod->mins, mod->maxs); mod->numleafs = bm->visleafs; if (i < mod->numsubmodels-1) { // duplicate the basic information char name[10]; sprintf (name, "*%i", i+1); loadmodel = Mod_FindName (name); *loadmodel = *mod; strcpy (loadmodel->name, name); mod = loadmodel; } } } /* ============================================================================== ALIAS MODELS ============================================================================== */ aliashdr_t *pheader; stvert_t stverts[MAXALIASVERTS]; mtriangle_t triangles[MAXALIASTRIS]; mh2triangle_t h2triangles[MAXALIASTRIS]; // a pose is a single set of vertexes. a frame may be // an animating sequence of poses trivertx_t *poseverts[MAXALIASFRAMES]; int posenum; byte **player_8bit_texels_tbl; byte *player_8bit_texels; /* ================= Mod_LoadAliasFrame ================= */ void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame) { //trivertx_t *pframe; trivertx_t *pinframe; int i; //int j; daliasframe_t *pdaliasframe; pdaliasframe = (daliasframe_t *)pin; strcpy (frame->name, pdaliasframe->name); frame->firstpose = posenum; frame->numposes = 1; for (i=0 ; i<3 ; i++) { // these are byte values, so we don't have to worry about // endianness frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i] - 128; frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i] - 128; } pinframe = (trivertx_t *)(pdaliasframe + 1); poseverts[posenum] = pinframe; for (i = 0; i < pheader->numverts; i++) { utrivertx_t * unsigned_vert = (utrivertx_t*)&(poseverts[posenum][i]); poseverts[posenum][i].v[0] = unsigned_vert->v[0] - 128; poseverts[posenum][i].v[1] = unsigned_vert->v[1] - 128; poseverts[posenum][i].v[2] = unsigned_vert->v[2] - 128; } posenum++; pinframe += pheader->numverts; return (void *)pinframe; } /* ================= Mod_LoadAliasGroup ================= */ void *Mod_LoadAliasGroup (void * pin, maliasframedesc_t *frame) { daliasgroup_t *pingroup; int i, numframes; daliasinterval_t *pin_intervals; void *ptemp; pingroup = (daliasgroup_t *)pin; numframes = LittleLong (pingroup->numframes); frame->firstpose = posenum; frame->numposes = numframes; for (i=0 ; i<3 ; i++) { // these are byte values, so we don't have to worry about endianness frame->bboxmin.v[i] = pingroup->bboxmin.v[i] - 128; frame->bboxmax.v[i] = pingroup->bboxmax.v[i] - 128; } pin_intervals = (daliasinterval_t *)(pingroup + 1); frame->interval = LittleFloat (pin_intervals->interval); pin_intervals += numframes; ptemp = (void *)pin_intervals; for (i=0 ; inumverts; j++) { utrivertx_t * unsigned_vert = (utrivertx_t*)&(poseverts[posenum][j]); poseverts[posenum][j].v[0] = unsigned_vert->v[0] - 128; poseverts[posenum][j].v[1] = unsigned_vert->v[1] - 128; poseverts[posenum][j].v[2] = unsigned_vert->v[2] - 128; } posenum++; ptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts; } return ptemp; } //========================================================= /* ================= Mod_FloodFillSkin Fill background pixels so mipmapping doesn't have haloes - Ed ================= */ typedef struct { short x, y; } floodfill_t; /* extern unsigned d_8to24table[]; */ // must be a power of 2 #define FLOODFILL_FIFO_SIZE 0x1000 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) #define FLOODFILL_STEP( off, dx, dy ) \ { \ if (pos[off] == fillcolor) \ { \ pos[off] = 255; \ fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ } \ else if (pos[off] != 255) fdc = pos[off]; \ } void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) { byte fillcolor = *skin; // assume this is the pixel to fill floodfill_t fifo[FLOODFILL_FIFO_SIZE]; int inpt = 0, outpt = 0; int filledcolor = -1; int i; if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) { if (d_8to24table[i] == (255 << 0)) // alpha 1.0 { filledcolor = i; break; } } } // can't fill to filled color or to transparent color (used as visited marker) if ((fillcolor == filledcolor) || (fillcolor == 255)) { //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); return; } fifo[inpt].x = 0, fifo[inpt].y = 0; inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x, y = fifo[outpt].y; int fdc = filledcolor; byte *pos = &skin[x + skinwidth * y]; outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); skin[x + skinwidth * y] = fdc; } } qboolean model_is_gun(char name[MAX_QPATH]) { char wep_path[15]; for (int i = 0; i < 15; i++) { wep_path[i] = name[i]; } wep_path[14] = '\0'; if (strcmp(wep_path, "models/weapons") == 0) { return qtrue; } return qfalse; } qboolean model_is_zombie(char name[MAX_QPATH]) { if (strcmp(name, "models/ai/zb%.mdl") == 0 || strcmp(name, "models/ai/zbc%.mdl") == 0 || strcmp(name, "models/ai/zcfull.mdl") == 0 || strcmp(name, "models/ai/zhc^.mdl") == 0 || strcmp(name, "models/ai/zalc(.mdl") == 0 || strcmp(name, "models/ai/zarc(.mdl") == 0 || strcmp(name, "models/ai/zfull.mdl") == 0 || strcmp(name, "models/ai/zh^.mdl") == 0 || strcmp(name, "models/ai/zal(.mdl") == 0 || strcmp(name, "models/ai/zar(.mdl") == 0) return qtrue; return qfalse; } /* =============== Mod_LoadAllSkins =============== */ static qboolean mod_h2; extern int has_pap; extern int has_perk_revive; extern int has_perk_juggernog; extern int has_perk_speedcola; extern int has_perk_doubletap; extern int has_perk_staminup; extern int has_perk_flopper; extern int has_perk_deadshot; extern int has_perk_mulekick; void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) { int i, j, k; char name[64], model[64], model2[64]; int s; //byte *copy; byte *skin; //byte *texels; daliasskingroup_t *pinskingroup; int groupskins; daliasskininterval_t *pinskinintervals; skin = (byte *)(pskintype + 1); if (numskins < 1 || numskins > MAX_SKINS) Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); s = pheader->skinwidth * pheader->skinheight; qboolean is_gun = model_is_gun(loadmodel->name); if (model_is_zombie(loadmodel->name) == qtrue) { Mod_FloodFillSkin(skin, pheader->skinwidth, pheader->skinheight); // force-fill 4 skin slots for (int i = 0; i < 4; i++) { switch(i) { case 0: pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; break; case 1: pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][1]; break; case 2: pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[1][0]; break; case 3: pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[1][1]; break; default: break; } } pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); return (void *)pskintype; } else { // // General texture override stuff. // // Mustang & Sally // v_biatch if (strcmp(loadmodel->name, "models/weapons/m1911/v_biatch_left.mdl") == 0 || strcmp(loadmodel->name, "models/weapons/m1911/v_biatch_right.mdl") == 0) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/weapons/m1911/v_biatch.mdl_0", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); return (void *)pskintype; } // Perk Bottles // v_perk if (strcmp(loadmodel->name, "models/machines/v_perk.mdl") == 0) { for (int i = 0; i < 8; i++) { if (i == 0 && has_perk_revive) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_0", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_revive && i == 0) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 1 && has_perk_juggernog) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_1", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_juggernog && i == 1) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 2 && has_perk_speedcola) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_2", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_speedcola && i == 2) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 3 && has_perk_doubletap) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_3", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_doubletap && i == 3) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 4 && has_perk_staminup) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_4", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_staminup && i == 4) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 5 && has_perk_flopper) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_5", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_flopper && i == 5) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 6 && has_perk_deadshot) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_6", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_deadshot && i == 6) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } if (i == 7 && has_perk_mulekick) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/machines/v_perk.mdl_7", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else if (!has_perk_mulekick && i == 7) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = zombie_skins[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } } return (void *)pskintype; } } for (i=0 ; iname) && i >= 1) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = pheader->gl_texturenum[0][0]; pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); return (void *)pskintype; } #ifndef SLIM else if (has_pap && model_is_gun(loadmodel->name) && i >= 1) { pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage("models/weapons/v_papskin", 0, 0, qtrue, GU_LINEAR); pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); return (void *)pskintype; } #endif else if (pskintype->type == ALIAS_SKIN_SINGLE) { Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight ); COM_StripExtension(loadmodel->name, model); // HACK HACK HACK sprintf (model2, "%s.mdl_%i", model, i); //#ifdef SLIM pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadtextureimage (model2, 0, 0, qtrue, GU_LINEAR); if (pheader->gl_texturenum[i][0] == 0)// did not find a matching TGA... //#endif // SLIM { sprintf (name, "%s_%i", loadmodel->name, i); pheader->gl_texturenum[i][0] = pheader->gl_texturenum[i][1] = pheader->gl_texturenum[i][2] = pheader->gl_texturenum[i][3] = loadrgbafrompal(name, pheader->skinwidth, pheader->skinheight, (byte*)(pskintype+1)); } pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s); } else { // animating skin group. yuck. pskintype++; pinskingroup = (daliasskingroup_t *)pskintype; groupskins = LittleLong (pinskingroup->numskins); pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); pskintype = reinterpret_cast(pinskinintervals + groupskins); for (j=0 ; jskinwidth, pheader->skinheight ); COM_StripExtension(loadmodel->name, model); sprintf (model2, "%s_%i_%i", model, i, j); pheader->gl_texturenum[i][j&3] = loadtextureimage (model2, 0, 0, qfalse, GU_LINEAR); if (pheader->gl_texturenum[i][j&3] == 0)// did not find a matching TGA... { sprintf (name, "%s_%i_%i", loadmodel->name, i, j); if(mod_h2) { pheader->gl_texturenum[i][j&3] = GL_LoadPalTex (name, pheader->skinwidth,pheader->skinheight, (byte *)(pskintype), qtrue, GU_LINEAR, 0, NULL, PAL_H2); } else { pheader->gl_texturenum[i][j&3] = GL_LoadTexture (name, pheader->skinwidth,pheader->skinheight, (byte *)(pskintype), qtrue, GU_LINEAR, 0); } } pskintype = (daliasskintype_t *)((byte *)(pskintype) + s); } k = j; for (/* */; j < 4; j++) pheader->gl_texturenum[i][j&3] = pheader->gl_texturenum[i][j - k]; } } return (void *)pskintype; } //========================================================================= /* ================= Mod_LoadAliasModel ================= */ void Mod_LoadAliasModel (model_t *mod, void *buffer) { int i, j; mdl_t *pinmodel; stvert_t *pinstverts; dtriangle_t *pintriangles; int version, numframes; //numskins; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; int start, end, total; mod->modhint = MOD_NORMAL; start = Hunk_LowMark (); pinmodel = (mdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_VERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]); pheader = static_cast(Hunk_AllocName (size, loadname)); mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pheader->boundingradius = LittleFloat (pinmodel->boundingradius); pheader->numskins = LittleLong (pinmodel->numskins); pheader->skinwidth = LittleLong (pinmodel->skinwidth); pheader->skinheight = LittleLong (pinmodel->skinheight); if (pheader->skinheight > MAX_LBM_HEIGHT) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); pheader->numverts = LittleLong (pinmodel->numverts); if (pheader->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pheader->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pheader->numtris = LittleLong (pinmodel->numtris); if (pheader->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pheader->numframes = LittleLong (pinmodel->numframes); numframes = pheader->numframes; if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = static_cast(LittleLong (pinmodel->synctype)); mod->numframes = pheader->numframes; for (i=0 ; i<3 ; i++) { pheader->scale[i] = LittleFloat (pinmodel->scale[i]); pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]) + pheader->scale[i] * 128; pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]) + pheader->scale[i] * 128; } // // load the skins // pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = static_cast(Mod_LoadAllSkins (pheader->numskins, pskintype)); // // load base s and t vertices // pinstverts = (stvert_t *)pskintype; for (i=0 ; inumverts ; i++) { stverts[i].onseam = LittleLong (pinstverts[i].onseam); stverts[i].s = LittleLong (pinstverts[i].s); stverts[i].t = LittleLong (pinstverts[i].t); } // // load triangle lists // pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts]; for (i=0 ; inumtris ; i++) { triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { triangles[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // // load the frames // posenum = 0; pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; //maliasframedesc_t *frame0; for (i=0 ; i(LittleLong (pframetype->type)); /*if(i == 0)//see this right here? blubs can type, but something is a-miss with the precalculated mdl min and max values, so let's not use this. { frame0 = &pheader->frames[0]; mod->mins[0] = frame0->bboxmin.v[0]; mod->mins[1] = frame0->bboxmin.v[1]; mod->mins[2] = frame0->bboxmin.v[2]; mod->maxs[0] = frame0->bboxmax.v[0]; mod->maxs[1] = frame0->bboxmax.v[1]; mod->maxs[2] = frame0->bboxmax.v[2]; }*/ if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); } else { pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); } } pheader->numposes = posenum; mod->type = mod_alias; // FIXME: do this right mod->mins[0] = mod->mins[1] = mod->mins[2] = -32; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 32; // // build the draw lists // GL_MakeAliasModelDisplayLists (mod, pheader); // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; // cypress -- in rare instances the viewmodel is able to fuck this // up and try to allocate.. again.. let's tell it no and add this bound if (!mod->cache.data) Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy_vfpu(mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); } /* ================= Mod_LoadAliasH2Model reads extra field for num ST verts, and extra index list of them Hexen II model format ================= */ void GL_MakeAliasModelDisplayListsH2 (model_t *m, aliashdr_t *hdr); void Mod_LoadH2AliasModel (model_t *mod, void *buffer) { int i, j; newmdl_t *pinmodel; stvert_t *pinstverts; dnewtriangle_t *pintriangles; int version, numframes;//, numskins; int size; daliasframetype_t *pframetype; daliasskintype_t *pskintype; int start, end, total; start = Hunk_LowMark (); pinmodel = (newmdl_t *)buffer; version = LittleLong (pinmodel->version); if (version != ALIAS_NEWVERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_NEWVERSION); // // allocate space for a working header, plus all the data except the frames, // skin and group info // size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * sizeof (pheader->frames[0]); pheader = static_cast(Hunk_AllocName (size, loadname)); mod->flags = LittleLong (pinmodel->flags); // // endian-adjust and copy the data, starting with the alias model header // pheader->boundingradius = LittleFloat (pinmodel->boundingradius); pheader->numskins = LittleLong (pinmodel->numskins); pheader->skinwidth = LittleLong (pinmodel->skinwidth); pheader->skinheight = LittleLong (pinmodel->skinheight); //if (pheader->skinheight > MAX_LBM_HEIGHT) // Sys_Error ("model %s has a skin taller than %d", mod->name, // MAX_LBM_HEIGHT); pheader->numverts = LittleLong (pinmodel->numverts); pheader->version = LittleLong (pinmodel->num_st_verts); //hide num_st in version if (pheader->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); if (pheader->numverts > MAXALIASVERTS) Sys_Error ("model %s has too many vertices", mod->name); pheader->numtris = LittleLong (pinmodel->numtris); if (pheader->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); pheader->numframes = LittleLong (pinmodel->numframes); numframes = pheader->numframes; if (numframes < 1) Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; mod->synctype = static_cast(LittleLong (pinmodel->synctype)); mod->numframes = pheader->numframes; for (i=0 ; i<3 ; i++) { pheader->scale[i] = LittleFloat (pinmodel->scale[i]); pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); } /* // // load the skins // pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = static_cast(Mod_LoadAllSkins (pheader->numskins, pskintype, mod->flags)); */ mod_h2 = qtrue; pskintype = (daliasskintype_t *)&pinmodel[1]; pskintype = static_cast(Mod_LoadAllSkins (pheader->numskins, pskintype)); mod_h2 = qfalse; // // load base s and t vertices // pinstverts = (stvert_t *)pskintype; for (i=0 ; iversion ; i++) //version holds num_st_verts { stverts[i].onseam = LittleLong (pinstverts[i].onseam); stverts[i].s = LittleLong (pinstverts[i].s); stverts[i].t = LittleLong (pinstverts[i].t); } // // load triangle lists // pintriangles = (dnewtriangle_t *)&pinstverts[pheader->version]; for (i=0 ; inumtris ; i++) { triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j=0 ; j<3 ; j++) { h2triangles[i].vertindex[j] = LittleShort (pintriangles[i].vertindex[j]); h2triangles[i].stindex[j] = LittleShort (pintriangles[i].stindex[j]); } } // // load the frames // posenum = 0; pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; for (i=0 ; i(LittleLong (pframetype->type)); if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); } else { pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); } } pheader->numposes = posenum; mod->type = mod_alias; // FIXME: do this right mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; // // build the draw lists // GL_MakeAliasModelDisplayListsH2 (mod, pheader); // // move the complete, relocatable alias model to the cache // end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy_vfpu(mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); } /* ================= Mod_LoadQ2AliasModel ================= */ int loadtextureimage (char* filename, int matchwidth, int matchheight, qboolean complain, int filter); void Mod_LoadQ2AliasModel (model_t *mod, void *buffer) { //int numskins; int i, j, version, numframes, size, *pinglcmd, *poutglcmd, start, end, total; md2_t *pinmodel, *pheader; md2triangle_t *pintriangles, *pouttriangles; md2frame_t *pinframe, *poutframe; char *pinskins; //char skinname[256], *skinnamebase; start = Hunk_LowMark (); pinmodel = (md2_t *)buffer; version = LittleLong (pinmodel->version); if (version != MD2ALIAS_VERSION) Sys_Error ("%s has wrong version number (%i should be %i)", mod->name, version, MD2ALIAS_VERSION); mod->type = mod_alias; mod->aliastype = ALIASTYPE_MD2; // LordHavoc: see pheader ofs adjustment code below for why this is bigger size = LittleLong(pinmodel->ofs_end) + sizeof(md2_t); if (size <= 0 || size >= MD2MAX_SIZE) Sys_Error ("%s is not a valid model", mod->name); pheader = static_cast(Hunk_AllocName (size, loadname)); mod->flags = 0; // there are no MD2 flags // endian-adjust and copy the data, starting with the alias model header for (i = 0;i < 17;i++) // LordHavoc: err... FIXME or something... ((int*)pheader)[i] = LittleLong(((int *)pinmodel)[i]); mod->numframes = numframes = pheader->num_frames; mod->synctype = ST_RAND; if (pheader->ofs_skins <= 0 || pheader->ofs_skins >= pheader->ofs_end) Sys_Error ("%s is not a valid model", mod->name); if (pheader->ofs_st <= 0 || pheader->ofs_st >= pheader->ofs_end) Sys_Error ("%s is not a valid model", mod->name); if (pheader->ofs_tris <= 0 || pheader->ofs_tris >= pheader->ofs_end) Sys_Error ("%s is not a valid model", mod->name); if (pheader->ofs_frames <= 0 || pheader->ofs_frames >= pheader->ofs_end) Sys_Error ("%s is not a valid model", mod->name); if (pheader->ofs_glcmds <= 0 || pheader->ofs_glcmds >= pheader->ofs_end) Sys_Error ("%s is not a valid model", mod->name); if (pheader->num_tris < 1 || pheader->num_tris > MD2MAX_TRIANGLES) Sys_Error ("%s has invalid number of triangles: %i", mod->name, pheader->num_tris); if (pheader->num_xyz < 1 || pheader->num_xyz > MD2MAX_VERTS) Sys_Error ("%s has invalid number of vertices: %i", mod->name, pheader->num_xyz); if (pheader->num_frames < 1 || pheader->num_frames > 256) //MD2MAX_FRAMES) Sys_Error ("%s has invalid number of frames: %i", mod->name, pheader->num_frames); if (pheader->num_skins < 0 || pheader->num_skins > MD2MAX_SKINS) Sys_Error ("%s has invalid number of skins: %i", mod->name, pheader->num_skins); // LordHavoc: adjust offsets in new model to give us some room for the bigger header // cheap offsetting trick, just offset it all by the pheader size...mildly wasteful for (i = 0;i < 7;i++) ((int*)&pheader->ofs_skins)[i] += sizeof(pheader); // load the skins if (pheader->num_skins) { pinskins = static_cast((void*)((int) pinmodel + LittleLong(pinmodel->ofs_skins))); for (i = 0;i < pheader->num_skins;i++) { pheader->gl_texturenum[i] = loadtextureimage (pinskins, 0, 0, qtrue, GU_LINEAR); pinskins += MD2MAX_SKINNAME; } } // load triangles pintriangles = static_cast((void*)((int) pinmodel + LittleLong(pinmodel->ofs_tris))); pouttriangles = static_cast((void*)((int) pheader + pheader->ofs_tris)); // swap the triangle list for (i=0 ; i < pheader->num_tris ; i++) { for (j=0 ; j<3 ; j++) { pouttriangles->index_xyz[j] = LittleShort (pintriangles->index_xyz[j]); pouttriangles->index_st[j] = LittleShort (pintriangles->index_st[j]); if (pouttriangles->index_xyz[j] >= pheader->num_xyz) Sys_Error ("%s has invalid vertex indices", mod->name); if (pouttriangles->index_st[j] >= pheader->num_st) Sys_Error ("%s has invalid vertex indices", mod->name); } pintriangles++; pouttriangles++; } // // load the frames // pinframe = static_cast((void*) ((int) pinmodel + LittleLong(pinmodel->ofs_frames))); poutframe = static_cast((void*) ((int) pheader + pheader->ofs_frames)); for (i=0 ; i < numframes ; i++) { for (j = 0;j < 3;j++) { poutframe->scale[j] = LittleFloat(pinframe->scale[j]); poutframe->translate[j] = LittleFloat(pinframe->translate[j]); } for (j = 0;j < 16;j++) poutframe->name[j] = pinframe->name[j]; for (j = 0;j < pheader->num_xyz;j++) { poutframe->verts[j].v[0] = pinframe->verts[j].v[0]; poutframe->verts[j].v[1] = pinframe->verts[j].v[1]; poutframe->verts[j].v[2] = pinframe->verts[j].v[2]; poutframe->verts[j].lightnormalindex = pinframe->verts[j].lightnormalindex; } pinframe = static_cast((void*) &pinframe->verts[j].v[0]); poutframe = static_cast((void*) &poutframe->verts[j].v[0]); } // LordHavoc: I may fix this at some point mod->mins[0] = mod->mins[1] = mod->mins[2] = -64; mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 64; // load the draw list pinglcmd = static_cast((void*) ((int) pinmodel + LittleLong(pinmodel->ofs_glcmds))); poutglcmd = static_cast((void*) ((int) pheader + pheader->ofs_glcmds)); for (i = 0;i < pheader->num_glcmds;i++) *poutglcmd++ = LittleLong(*pinglcmd++); // move the complete, relocatable alias model to the cache end = Hunk_LowMark (); total = end - start; Cache_Alloc (&mod->cache, total, loadname); if (!mod->cache.data) return; memcpy_vfpu(mod->cache.data, pheader, total); Hunk_FreeToLowMark (start); } //============================================================================= //========================Q3 Models============================================ //============================================================================= //additional skin loading char **skinfilelist; int skinfilecount; static qboolean Mod_TryAddSkin(char *skinname, ...) { va_list argptr; char string[MAX_QPATH]; //make sure we don't add it twice int i; va_start (argptr, skinname); vsnprintf (string,sizeof(string)-1, skinname,argptr); va_end (argptr); string[MAX_QPATH-1] = '\0'; for (i = 0; i < skinfilecount; i++) { if (!strcmp(skinfilelist[i], string)) return qtrue; //already added } //if (!COM_FCheckExists(string)) // return false; if (!Sys_FileTime(string)) return qfalse; skinfilelist = static_cast(realloc(skinfilelist, sizeof(*skinfilelist)*(skinfilecount+1))); skinfilelist[skinfilecount] = static_cast(malloc(strlen(string)+1)); strcpy(skinfilelist[skinfilecount], string); skinfilecount++; return qtrue; } int Mod_BuildSkinFileList(char *modelname) { int i; char skinfilename[MAX_QPATH]; //flush the old list for (i = 0; i < skinfilecount; i++) { Z_Free(skinfilelist[i]); skinfilelist[i] = NULL; } skinfilecount=0; COM_StripExtension(modelname, skinfilename); //try and add numbered skins, and then try fixed names. for (i = 0; ; i++) { if (!Mod_TryAddSkin("%s_%i.skin", modelname, i)) { if (i == 0) { if (!Mod_TryAddSkin("%s_default.skin", skinfilename, i)) break; } else if (i == 1) { if (!Mod_TryAddSkin("%s_blue.skin", skinfilename, i)) break; } else if (i == 2) { if (!Mod_TryAddSkin("%s_red.skin", skinfilename, i)) break; } else if (i == 3) { if (!Mod_TryAddSkin("%s_green.skin", skinfilename, i)) break; } else if (i == 4) { if (!Mod_TryAddSkin("%s_yellow.skin", skinfilename, i)) break; } else break; } } return skinfilecount; } animdata_t anims[NUM_ANIMTYPES]; vec3_t md3bboxmins, md3bboxmaxs; void Mod_GetQ3AnimData (char *buf, char *animtype, animdata_t *adata) { int i, j, data[4]; char *token, num[4]; if ((token = strstr(buf, animtype))) { while (*token != '\n') token--; token++; // so we jump back to the first char for (i=0 ; i<4 ; i++) { memset (num, 0, sizeof(num)); for (j = 0 ; *token != '\t' ; j++) num[j] = *token++; data[i] = Q_atoi(num); token++; } adata->offset = data[0]; adata->num_frames = data[1]; adata->loop_frames = data[2]; adata->interval = 1.0 / (float)data[3]; } } void Mod_LoadQ3Animation (void) { int ofs_legs; char *animdata; animdata_t tmp1, tmp2; tmp1.offset = 0; tmp2.offset = 0; if (!(animdata = (char *)COM_LoadFile("progs/player/animation.cfg", 0))) { Con_Printf ("ERROR: Couldn't open animation file\n"); return; } memset (anims, 0, sizeof(anims)); Mod_GetQ3AnimData (animdata, "BOTH_DEATH1", &anims[both_death1]); Mod_GetQ3AnimData (animdata, "BOTH_DEATH2", &anims[both_death2]); Mod_GetQ3AnimData (animdata, "BOTH_DEATH3", &anims[both_death3]); Mod_GetQ3AnimData (animdata, "BOTH_DEAD1", &anims[both_dead1]); Mod_GetQ3AnimData (animdata, "BOTH_DEAD2", &anims[both_dead2]); Mod_GetQ3AnimData (animdata, "BOTH_DEAD3", &anims[both_dead3]); Mod_GetQ3AnimData (animdata, "TORSO_ATTACK", &anims[torso_attack]); Mod_GetQ3AnimData (animdata, "TORSO_ATTACK2", &anims[torso_attack2]); Mod_GetQ3AnimData (animdata, "TORSO_STAND", &anims[torso_stand]); Mod_GetQ3AnimData (animdata, "TORSO_STAND2", &anims[torso_stand2]); Mod_GetQ3AnimData (animdata, "TORSO_GESTURE", &tmp1); Mod_GetQ3AnimData (animdata, "LEGS_WALKCR", &tmp2); // we need to subtract the torso-only frames to get the correct indices ofs_legs = tmp2.offset - tmp1.offset; Mod_GetQ3AnimData (animdata, "LEGS_WALK", &anims[legs_walk]);//R00k Mod_GetQ3AnimData (animdata, "LEGS_RUN", &anims[legs_run]); Mod_GetQ3AnimData (animdata, "LEGS_IDLE", &anims[legs_idle]); anims[legs_walk].offset -= ofs_legs; anims[legs_run].offset -= ofs_legs; anims[legs_idle].offset -= ofs_legs; Z_Free (animdata); } /* ================= Mod_LoadQ3ModelTexture ================= */ void Mod_LoadQ3ModelTexture (char *identifier, int flags, int *gl_texnum) { char loadpath[64]; Q_snprintfz (loadpath, sizeof(loadpath), "textures/q3models/%s", identifier); *gl_texnum = loadtextureimage (loadpath, 0, 0, qtrue, GU_LINEAR); if (!*gl_texnum) { Q_snprintfz (loadpath, sizeof(loadpath), "textures/%s", identifier); *gl_texnum = loadtextureimage (loadpath, 0, 0, qtrue, GU_LINEAR); } if (!*gl_texnum) { Q_snprintfz (loadpath, sizeof(loadpath), "progs/%s", identifier); *gl_texnum = loadtextureimage (loadpath, 0, 0, qtrue, GU_LINEAR); } if (!*gl_texnum) { Q_snprintfz (loadpath, sizeof(loadpath), "maps/%s", identifier); *gl_texnum = loadtextureimage (loadpath, 0, 0, qtrue, GU_LINEAR); } } //============================================================================== #define CLASSIC_MAX_QPATH 64 typedef struct { char name[CLASSIC_MAX_QPATH]; int filepos, filelen; } packfile_t; typedef struct pack_s { char filename[MAX_OSPATH]; int handle; int numfiles; packfile_t *files; } pack_t; typedef struct searchpath_s { char filename[MAX_OSPATH]; pack_t *pack; // only one of filename / pack will be used struct searchpath_s *next; } searchpath_t; extern char loadname[32]; // for hunk tags typedef struct searchpath_s searchpath_t; extern searchpath_t* com_searchpaths; //============================================================================== /* ================= Mod_LoadAllQ3Skins supporting only the default skin yet ================= */ void Mod_LoadAllQ3Skins (char *modelname, md3header_t *header) { #if 0 int i, j, defaultskin, numskinsfound; char skinname[MAX_QPATH], **skinsfound; md3surface_t *surf; md3shader_t *shader; searchpath_t *search; i = strrchr (modelname, '/') - modelname; Q_strncpyz (skinname, modelname, i+1); /* //EraseDirEntries (); for (search = com_searchpaths ; search ; search = search->next) { if (!search->pack) { RDFlags |= RD_NOERASE; ReadDir (va("%s/%s", search->filename, skinname), va("%s*.skin", loadname)); } } numskinsfound = num_files; skinsfound = (char **)malloc (numskinsfound * sizeof(char *)); for (i=0 ; i(malloc (MAX_QPATH)); Q_snprintfz (skinsfound[i], MAX_QPATH, "%s/%s", skinname, i); } */ SceUID dir = sceIoDopen(va("%s/models/%s", com_gamedir, skinname)); if(dir < 0) { return; } SceIoDirent dirent; memset(&dirent, 0, sizeof(SceIoDirent)); while(sceIoDread(dir, &dirent) > 0) { if(dirent.d_name[0] == '.') { continue; } if(!strcmp(COM_FileExtension(dirent.d_name),".skin")|| !strcmp(COM_FileExtension(dirent.d_name),".SKIN")) { } } // It only works this lame way coz if I snprintf to skinname from skinname // then linux's vsnprintf clears out skinname first and it's gonna lost Q_strncpyz (skinname, va("%s/%s", skinname, loadname), MAX_QPATH); defaultskin = -1; for (i=0 ; iofssurfs); for (j = 0 ; j < header->numsurfs && strcmp(surf->name, token) ; j++) surf = (md3surface_t *)((byte *)surf + surf->ofsend); token = &skindata[pos]; while (skindata[pos] != '\n' && skindata[pos]) pos++; skindata[pos++-1] = '\0'; // becoz of \r\n if (token[0] && j < header->numsurfs) { shader = (md3shader_t *)((byte *)surf + surf->ofsshaders); for (j = 0 ; j < surf->numshaders ; j++, shader++) Q_strncpyz (shader->name, token, MAX_QPATH); } } Z_Free (skindata); } for (i=0 ; iname, &md3name[0]); if (!strcmp (md3name, "progs/g_shot") || !strcmp (md3name, "progs/g_nail") || !strcmp (md3name, "progs/g_nail2") || !strcmp (md3name, "progs/g_rock") || !strcmp (md3name, "progs/g_rock2") || !strcmp (md3name, "progs/g_light") || !strcmp (md3name, "progs/armor") || !strcmp (md3name, "progs/backpack") || !strcmp (md3name, "progs/w_g_key") || !strcmp (md3name, "progs/w_s_key") || !strcmp (md3name, "progs/m_g_key") || !strcmp (md3name, "progs/m_s_key") || !strcmp (md3name, "progs/b_g_key") || !strcmp (md3name, "progs/b_s_key") || !strcmp (md3name, "progs/quaddama") || !strcmp (md3name, "progs/invisibl") || !strcmp (md3name, "progs/invulner") || !strcmp (md3name, "progs/jetpack") || !strcmp (md3name, "progs/cube") || !strcmp (md3name, "progs/suit") || !strcmp (md3name, "progs/boots") || !strcmp (md3name, "progs/end1") || !strcmp (md3name, "progs/end2") || !strcmp (md3name, "progs/end3") || !strcmp (md3name, "progs/end4")) { mod->flags |= EF_ROTATE; } else if (!strcmp (md3name, "progs/missile")) { mod->flags |= EF_ROCKET; } else if (!strcmp (md3name, "progs/gib1") || //EF_GIB !strcmp (md3name, "progs/gib2") || !strcmp (md3name, "progs/gib3") || !strcmp (md3name, "progs/h_player") || !strcmp (md3name, "progs/h_dog") || !strcmp (md3name, "progs/h_mega") || !strcmp (md3name, "progs/h_guard") || !strcmp (md3name, "progs/h_wizard") || !strcmp (md3name, "progs/h_knight") || !strcmp (md3name, "progs/h_hellkn") || !strcmp (md3name, "progs/h_zombie") || !strcmp (md3name, "progs/h_shams") || !strcmp (md3name, "progs/h_shal") || !strcmp (md3name, "progs/h_ogre") || !strcmp (md3name, "progs/armor") || !strcmp (md3name, "progs/h_demon")) { mod->flags |= EF_GIB; } else if (!strcmp (md3name, "progs/grenade")) { mod->flags |= EF_GRENADE; } else if (!strcmp (md3name, "progs/w_spike")) { mod->flags |= EF_TRACER; } else if (!strcmp (md3name, "progs/k_spike")) { mod->flags |= EF_TRACER2; } else if (!strcmp (md3name, "progs/v_spike")) { mod->flags |= EF_TRACER3; } else if (!strcmp (md3name, "progs/zom_gib")) { mod->flags |= EF_ZOMGIB; } else if (!strcmp(md3name, "progs/VModel/v_colt") || !strcmp(md3name, "progs/VModel/v_kar") || !strcmp(md3name, "progs/VModel/v_thomp")) { mod->modhint = MOD_WEAPON; } else if (!strcmp (md3name, "progs/lavaball")) { mod->modhint = MOD_LAVABALL; } header = (md3header_t *)buffer; version = LittleLong (header->version); if (version != MD3_VERSION) Sys_Error ("Mod_LoadQ3Model: %s has wrong version number (%i should be %i)", md3name, version, MD3_VERSION); // endian-adjust all data header->numframes = LittleLong (header->numframes); if (header->numframes < 1) Sys_Error ("Mod_LoadQ3Model: model %s has no frames", md3name); else if (header->numframes > MAXMD3FRAMES) Sys_Error ("Mod_LoadQ3Model: model %s has too many frames", md3name); header->numtags = LittleLong (header->numtags); if (header->numtags > MAXMD3TAGS) Sys_Error ("Mod_LoadQ3Model: model %s has too many tags", md3name); header->numsurfs = LittleLong (header->numsurfs); if (header->numsurfs < 1) Sys_Error ("Mod_LoadQ3Model: model %s has no surfaces", md3name); else if (header->numsurfs > MAXMD3SURFS) Sys_Error ("Mod_LoadQ3Model: model %s has too many surfaces", md3name); header->numskins = LittleLong (header->numskins); header->ofsframes = LittleLong (header->ofsframes); header->ofstags = LittleLong (header->ofstags); header->ofssurfs = LittleLong (header->ofssurfs); header->ofsend = LittleLong (header->ofsend); // swap all the frames frame = (md3frame_t *)((byte *)header + header->ofsframes); for (i=0 ; inumframes ; i++) { frame[i].radius = LittleFloat (frame->radius); for (j=0 ; j<3 ; j++) { frame[i].mins[j] = LittleFloat (frame[i].mins[j]); frame[i].maxs[j] = LittleFloat (frame[i].maxs[j]); frame[i].pos[j] = LittleFloat (frame[i].pos[j]); } } // swap all the tags tag = (md3tag_t *)((byte *)header + header->ofstags); for (i=0 ; inumtags ; i++) { for (j=0 ; j<3 ; j++) { tag[i].pos[j] = LittleFloat (tag[i].pos[j]); tag[i].rot[0][j] = LittleFloat (tag[i].rot[0][j]); tag[i].rot[1][j] = LittleFloat (tag[i].rot[1][j]); tag[i].rot[2][j] = LittleFloat (tag[i].rot[2][j]); } } // swap all the surfaces surf = (md3surface_t *)((byte *)header + header->ofssurfs); for (i=0 ; inumsurfs ; i++) { surf->ident = LittleLong (surf->ident); surf->flags = LittleLong (surf->flags); surf->numframes = LittleLong (surf->numframes); if (surf->numframes != header->numframes) Sys_Error ("Mod_LoadQ3Model: number of frames don't match in %s", md3name); surf->numshaders = LittleLong (surf->numshaders); if (surf->numshaders <= 0) Sys_Error ("Mod_LoadQ3Model: model %s has no shaders", md3name); else if (surf->numshaders > MAXMD3SHADERS) Sys_Error ("Mod_LoadQ3Model: model %s has too many shaders", md3name); surf->numverts = LittleLong (surf->numverts); if (surf->numverts <= 0) Sys_Error ("Mod_LoadQ3Model: model %s has no vertices", md3name); else if (surf->numverts > MAXMD3VERTS) Sys_Error ("Mod_LoadQ3Model: model %s has too many vertices", md3name); surf->numtris = LittleLong (surf->numtris); if (surf->numtris <= 0) Sys_Error ("Mod_LoadQ3Model: model %s has no triangles", md3name); else if (surf->numtris > MAXMD3TRIS) Sys_Error ("Mod_LoadQ3Model: model %s has too many triangles", md3name); surf->ofstris = LittleLong (surf->ofstris); surf->ofsshaders = LittleLong (surf->ofsshaders); surf->ofstc = LittleLong (surf->ofstc); surf->ofsverts = LittleLong (surf->ofsverts); surf->ofsend = LittleLong (surf->ofsend); // swap all the shaders shader = (md3shader_t *)((byte *)surf + surf->ofsshaders); for (j=0 ; jnumshaders ; j++) shader[j].index = LittleLong (shader[j].index); // swap all the triangles tris = (md3triangle_t *)((byte *)surf + surf->ofstris); for (j=0 ; jnumtris ; j++) { tris[j].indexes[0] = LittleLong (tris[j].indexes[0]); tris[j].indexes[1] = LittleLong (tris[j].indexes[1]); tris[j].indexes[2] = LittleLong (tris[j].indexes[2]); } // swap all the texture coords tc = (md3tc_t *)((byte *)surf + surf->ofstc); for (j=0 ; jnumverts ; j++) { tc[j].s = LittleFloat (tc[j].s); tc[j].t = LittleFloat (tc[j].t); } // swap all the vertices vert = (md3vert_t *)((byte *)surf + surf->ofsverts); for (j=0 ; j < surf->numverts * surf->numframes ; j++) { vert[j].vec[0] = LittleShort (vert[j].vec[0]); vert[j].vec[1] = LittleShort (vert[j].vec[1]); vert[j].vec[2] = LittleShort (vert[j].vec[2]); vert[j].normal = LittleShort (vert[j].normal); } // find the next surface surf = (md3surface_t *)((byte *)surf + surf->ofsend); } // allocate extra size for structures different in memory surf = (md3surface_t *)((byte *)header + header->ofssurfs); for (size = 0, i = 0 ; i < header->numsurfs ; i++) { size += surf->numshaders * sizeof(md3shader_mem_t); // shader containing texnum size += surf->numverts * surf->numframes * sizeof(md3vert_mem_t); // floating point vertices surf = (md3surface_t *)((byte *)surf + surf->ofsend); } header = static_cast(Cache_Alloc (&mod->cache, com_filesize + size, loadname)); if (!mod->cache.data) return; memcpy_vfpu(header, buffer, com_filesize); base = com_filesize; mod->type = mod_md3; mod->numframes = header->numframes; md3bboxmins[0] = md3bboxmins[1] = md3bboxmins[2] = 99999; md3bboxmaxs[0] = md3bboxmaxs[1] = md3bboxmaxs[2] = -99999; radiusmax = 0; frame = (md3frame_t *)((byte *)header + header->ofsframes); for (i=0 ; inumframes ; i++) { for (j=0 ; j<3 ; j++) { md3bboxmins[j] = std::min(md3bboxmins[j], frame[i].mins[j]); md3bboxmaxs[j] = std::max(md3bboxmaxs[j], frame[i].maxs[j]); } radiusmax = std::max(radiusmax, frame[i].radius); } VectorCopy (md3bboxmins, mod->mins); VectorCopy (md3bboxmaxs, mod->maxs); mod->radius = radiusmax; // load the skins Mod_LoadAllQ3Skins (mod->name, header); // load the animation frames if loading the player model if (!strcmp(mod->name, "progs/player/lower.md3")) Mod_LoadQ3Animation (); surf = (md3surface_t *)((byte *)header + header->ofssurfs); for (i=0 ; inumsurfs; i++) { shader = (md3shader_t *)((byte *)surf + surf->ofsshaders); surf->ofsshaders = base; size = surf->numshaders; for (j=0 ; jofsshaders); Q_strncpyz (memshader[j].name, shader->name, sizeof(memshader[j].name)); memshader[j].index = shader->index; COM_StripExtension (COM_SkipPath(shader->name), basename); gl_texnum = 0; texture_flag = 0; Mod_LoadQ3ModelTexture (basename, texture_flag, &gl_texnum); memshader[j].gl_texnum = gl_texnum; shader++; } base += size * sizeof(md3shader_mem_t); vert = (md3vert_t *)((byte *)surf + surf->ofsverts); surf->ofsverts = base; size = surf->numverts * surf->numframes; for (j=0 ; jofsverts); vertexes[j].oldnormal = vert->normal; vertexes[j].vec[0] = (float)vert->vec[0] * MD3_XYZ_SCALE; vertexes[j].vec[1] = (float)vert->vec[1] * MD3_XYZ_SCALE; vertexes[j].vec[2] = (float)vert->vec[2] * MD3_XYZ_SCALE; lat = ((vert->normal >> 8) & 0xff) * M_PI / 128.0f; lng = (vert->normal & 0xff) * M_PI / 128.0f; #ifdef PSP_VFPU vertexes[j].normal[0] = vfpu_cosf(lat) * vfpu_sinf(lng); vertexes[j].normal[1] = vfpu_sinf(lat) * vfpu_sinf(lng); vertexes[j].normal[2] = vfpu_cosf(lng); #else vertexes[j].normal[0] = cos(lat) * sin(lng); vertexes[j].normal[1] = sin(lat) * sin(lng); vertexes[j].normal[2] = cos(lng); #endif vectoangles (vertexes[j].normal, ang); vertexes[j].anorm_pitch = ang[0] * 256 / 360; vertexes[j].anorm_yaw = ang[1] * 256 / 360; vert++; } base += size * sizeof(md3vert_mem_t); surf = (md3surface_t *)((byte *)surf + surf->ofsend); } } //============================================================================== /* ================= Mod_LoadSpriteFrame ================= */ void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum, int version, byte *palette) { dspriteframe_t *pinframe; mspriteframe_t *pspriteframe; int width, height, size, origin[2]; char name[64], sprite[64], sprite2[64]; pinframe = (dspriteframe_t *)pin; width = LittleLong (pinframe->width); height = LittleLong (pinframe->height); size = width * height; pspriteframe = static_cast(Hunk_AllocName (sizeof (mspriteframe_t),loadname)); Q_memset (pspriteframe, 0, sizeof (mspriteframe_t)); *ppframe = pspriteframe; pspriteframe->width = width; pspriteframe->height = height; origin[0] = LittleLong (pinframe->origin[0]); origin[1] = LittleLong (pinframe->origin[1]); pspriteframe->up = origin[1]; pspriteframe->down = origin[1] - height; pspriteframe->left = origin[0]; pspriteframe->right = width + origin[0]; // HACK HACK HACK sprintf (name, "%s.spr_%i", loadmodel->name, framenum); if (version == SPRITE_VERSION) { COM_StripExtension(loadmodel->name, sprite); sprintf (sprite2, "%s.spr_%i", sprite, framenum); pspriteframe->gl_texturenum = loadtextureimage (sprite2, 0, 0, qtrue, GU_LINEAR); if (pspriteframe->gl_texturenum == 0)// did not find a matching TGA... { pspriteframe->gl_texturenum = GL_LoadTexture (name, width, height, (byte *)(pinframe + 1), qtrue, GU_LINEAR, 0); } } else if (version == SPRITE32_VERSION) { size *= 4; pspriteframe->gl_texturenum = GL_LoadImages (name, width, height, (byte *)(pinframe + 1), qtrue, GU_LINEAR, 0, 4); } else if (version == SPRITEHL_VERSION) { pspriteframe->gl_texturenum = GL_LoadPalTex (name, width, height, (byte *)(pinframe + 1), qtrue, GU_LINEAR, 0, palette, PAL_RGBA); Con_Printf("HL Sprite TEX - OK\n"); } else { Sys_Error("Mod_LoadSpriteFrame: Non sprite type"); } return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size); } /* ================= Mod_LoadSpriteGroup ================= */ void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum, int version, byte *palette) { dspritegroup_t *pingroup; mspritegroup_t *pspritegroup; int i, numframes; dspriteinterval_t *pin_intervals; float *poutintervals; void *ptemp; pingroup = (dspritegroup_t *)pin; numframes = LittleLong (pingroup->numframes); pspritegroup = static_cast(Hunk_AllocName (sizeof (mspritegroup_t) + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname)); pspritegroup->numframes = numframes; *ppframe = (mspriteframe_t *)pspritegroup; pin_intervals = (dspriteinterval_t *)(pingroup + 1); poutintervals = static_cast(Hunk_AllocName (numframes * sizeof (float), loadname)); pspritegroup->intervals = poutintervals; for (i=0 ; iinterval); if (*poutintervals <= 0.0) { Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); } poutintervals++; pin_intervals++; } ptemp = (void *)pin_intervals; for (i=0 ; iframes[i], framenum * 100 + i, version, palette); } return ptemp; } /* ================= Mod_LoadSpriteModel ================= */ void Mod_LoadSpriteModel (model_t *mod, void *buffer) { int i; int version; //dsprite_t *pin; msprite_t *psprite; int numframes; int size; dspriteframetype_t *pframetype; byte palette[256*4]; int sptype; const unsigned char *datain; datain = (unsigned char *)buffer; version = LittleLong (((dsprite_t *)buffer)->version); switch (version) { case SPRITE_VERSION: case SPRITEHL_VERSION: case SPRITE32_VERSION: break; default: Sys_Error ("%s has wrong version number (%i should be %i(q1),%i(hl),%i(dp))", mod->name, version, SPRITE_VERSION, SPRITEHL_VERSION, SPRITE32_VERSION); } if (version == SPRITEHL_VERSION) //Not work { Con_Printf("Half_Life sprite begin loading\n"); int i, rendermode; const unsigned char *in; dspritehl_t *pinhlsprite; pinhlsprite = (dspritehl_t *)datain; datain += sizeof(dspritehl_t); numframes = LittleLong (pinhlsprite->numframes); size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); psprite = static_cast(Hunk_AllocName (size, loadname)); mod->cache.data = psprite; psprite->numframes = LittleLong (pinhlsprite->numframes); psprite->type = LittleLong (pinhlsprite->type); mod->synctype = (synctype_t)LittleLong (pinhlsprite->synctype); rendermode = LittleLong (pinhlsprite->texFormat); in = datain; datain += 2; i = in[0] + in[1] * 256; if (i != 256) Host_Error ("Mod_LoadSpriteModel: unexpected number of palette colors %i (should be 256)", i); in = datain; datain += 768; switch(rendermode) { case SPR_NORMAL: for (i = 0;i < 256;i++) { palette[i*4+2] = in[i*3+0]; palette[i*4+1] = in[i*3+1]; palette[i*4+0] = in[i*3+2]; palette[i*4+3] = 255; } break; case SPR_ADDITIVE: for (i = 0;i < 256;i++) { palette[i*4+2] = in[i*3+0]; palette[i*4+1] = in[i*3+1]; palette[i*4+0] = in[i*3+2]; palette[i*4+3] = 255; } // also passes additive == true to Mod_Sprite_SharedSetup break; case SPR_INDEXALPHA: for (i = 0;i < 256;i++) { palette[i*4+2] = in[765]; palette[i*4+1] = in[766]; palette[i*4+0] = in[767]; palette[i*4+3] = i; in += 3; } break; case SPR_ALPHATEST: for (i = 0;i < 256;i++) { palette[i*4+2] = in[i*3+0]; palette[i*4+1] = in[i*3+1]; palette[i*4+0] = in[i*3+2]; palette[i*4+3] = 255; } palette[255*4+0] = palette[255*4+1] = palette[255*4+2] = palette[255*4+3] = 0; // should this use alpha test or alpha blend? (currently blend) break; default: Host_Error("Mod_LoadSpriteModel: unknown texFormat (%i, should be 0, 1, 2, or 3)", i); return; } psprite->maxwidth = LittleLong (pinhlsprite->width); psprite->maxheight = LittleLong (pinhlsprite->height); psprite->beamlength = LittleFloat (pinhlsprite->beamlength); pframetype = (dspriteframetype_t *)(pinhlsprite + 1); Con_Printf("Half_Life sprite end loading\n"); } else { dsprite_t *pinqsprite; pinqsprite = (dsprite_t *)datain; datain += sizeof(dsprite_t); sptype = LittleLong (pinqsprite->type); numframes = LittleLong (pinqsprite->numframes); size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); psprite = static_cast(Hunk_AllocName (size, loadname)); mod->cache.data = psprite; psprite->type = sptype; mod->synctype = static_cast(LittleLong (pinqsprite->synctype)); psprite->numframes = numframes; psprite->maxwidth = LittleLong (pinqsprite->width); psprite->maxheight = LittleLong (pinqsprite->height); psprite->beamlength = LittleFloat (pinqsprite->beamlength); pframetype = (dspriteframetype_t *)(pinqsprite + 1); } mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; mod->mins[2] = -psprite->maxheight/2; mod->maxs[2] = psprite->maxheight/2; // // load the frames // if (numframes < 1) { Con_Printf ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); } mod->numframes = numframes; for (i=0 ; i(LittleFloat(pframetype->type)); psprite->frames[i].type = frametype; if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) Mod_LoadSpriteFrame (pframetype + 1, &psprite->frames[i].frameptr, i, version, palette); } else { pframetype = (dspriteframetype_t *) Mod_LoadSpriteGroup (pframetype + 1, &psprite->frames[i].frameptr, i, version, palette); } } mod->type = mod_sprite; } /* ================= Mod_LoadQ2SpriteModel By Crow_bar ================= */ qboolean Mod_LoadQ2SpriteModel (model_t *mod, void *buffer) { int i; int version; dmd2sprite_t *pin; msprite_t *psprite; int numframes; int size; dmd2sprframe_t *pframetype; mspriteframe_t *frame; float origin[2]; int hunkstart; hunkstart = Hunk_LowMark(); pin = (dmd2sprite_t *)buffer; version = LittleLong (pin->version); if (version != SPRITE2_VERSION) { Sys_Error ("%s has wrong version number " "(%i should be %i)", mod->name, version, SPRITE2_VERSION); return qfalse; } numframes = LittleLong (pin->numframes); size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); psprite = static_cast(Hunk_AllocName (size, loadname)); mod->cache.data = psprite; psprite->type = SPR_VP_PARALLEL; psprite->maxwidth = 1; psprite->maxheight = 1; psprite->beamlength = 1; mod->synctype = static_cast(1); psprite->numframes = numframes; mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; mod->mins[2] = -psprite->maxheight/2; mod->maxs[2] = psprite->maxheight/2; // // load the frames // if (numframes < 1) { Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); Hunk_FreeToLowMark(hunkstart); return qfalse; } mod->numframes = numframes; pframetype = pin->frames; for (i=0 ; iframes[i].type = frametype; frame = psprite->frames[i].frameptr = static_cast(Hunk_AllocName(sizeof(mspriteframe_t), loadname)); frame->gl_texturenum = loadtextureimage (pframetype->name, 0, 0, qtrue, GU_LINEAR); frame->width = LittleLong(pframetype->width); frame->height = LittleLong(pframetype->height); origin[0] = LittleLong (pframetype->origin_x); origin[1] = LittleLong (pframetype->origin_y); #if 0 //quake 2 negative translate frame->up = -origin[1]; frame->down = frame->height - origin[1]; frame->left = -origin[0]; frame->right = frame->width - origin[0]; #else frame->up = origin[1]; frame->down = origin[1] - frame->height; frame->left = -origin[0]; frame->right = -origin[0] + frame->width; #endif pframetype++; } mod->type = mod_sprite; return qtrue; } //============================================================================= /* ================ Mod_Print ================ */ extern "C" void Mod_Print (void) { int i; model_t *mod; Con_Printf ("Cached models:\n"); for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) { Con_Printf ("%8p : %s\n",mod->cache.data, mod->name); } }