// models.c -- model loading and caching // models are the only shared resource between a client and server running// on the same machine. #include <math.h>#include "quakedef.h"#include "r_shared.h"#include "r_local.h" model_t *loadmodel;char loadname[32]; // for hunk tags void Mod_LoadSpriteModel (model_t *mod, void *buffer);void Mod_LoadBrushModel (model_t *mod, void *buffer);void Mod_LoadAliasModel (model_t *mod, void *buffer);model_t *Mod_LoadModel (model_t *mod, bool crash); uint8_t mod_novis[MAX_MAP_LEAFS/8]; #define MAX_MOD_KNOWN 512model_t mod_known[MAX_MOD_KNOWN];int mod_numknown; // values for model_t's needload#define NL_PRESENT 0#define NL_NEEDS_LOADED 1#define NL_UNREFERENCED 2 /*===============Mod_Init===============*/void Mod_Init (void){ memset (mod_novis, 0xff, sizeof(mod_novis));} /*===============Mod_Extradata 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, true); 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===================*/uint8_t *Mod_DecompressVis (uint8_t *in, model_t *model){ static uint8_t decompressed[MAX_MAP_LEAFS/8]; int c; uint8_t *out; int row; row = (model->numleafs+7)>>3; out = decompressed; 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); return decompressed;} uint8_t *Mod_LeafPVS (mleaf_t *leaf, model_t *model){ if (leaf == model->leafs) return mod_novis; return Mod_DecompressVis (leaf->compressed_vis, model);} /*===================Mod_ClearAll===================*/void Mod_ClearAll (void){ int i; model_t *mod; for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) { mod->needload = NL_UNREFERENCED;//FIX FOR CACHE_ALLOC ERRORS: if (mod->type == mod_sprite) mod->cache.data = NULL; }} /*==================Mod_FindName ==================*/model_t *Mod_FindName (char *name){ int i; model_t *mod; model_t *avail = NULL; if (!name[0]) Sys_Error ("Mod_ForName: NULL name"); //// search the currently loaded models// for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) { if (!strcmp (mod->name, name) ) break; if (mod->needload == NL_UNREFERENCED) if (!avail || mod->type != mod_alias) avail = mod; } if (i == mod_numknown) { if (mod_numknown == MAX_MOD_KNOWN) { if (avail) { mod = avail; if (mod->type == mod_alias) if (Cache_Check (&mod->cache)) Cache_Free (&mod->cache); } else Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); } else mod_numknown++; strcpy (mod->name, name); mod->needload = NL_NEEDS_LOADED; } return mod;} /*==================Mod_TouchModel ==================*/void Mod_TouchModel (char *name){ model_t *mod; mod = Mod_FindName (name); if (mod->needload == NL_PRESENT) { if (mod->type == mod_alias) Cache_Check (&mod->cache); }} /*==================Mod_LoadModel Loads a model into the cache==================*/model_t *Mod_LoadModel (model_t *mod, bool crash){ unsigned *buf; uint8_t stackbuf[1024]; // avoid dirtying the cache heap if (mod->type == mod_alias) { if (Cache_Check (&mod->cache)) { mod->needload = NL_PRESENT; return mod; } } else { if (mod->needload == NL_PRESENT) return mod; } //// because the world is so huge, load it one piece at a time// //// load the file// buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); 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 = NL_PRESENT; switch (LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: Mod_LoadAliasModel (mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel (mod, buf); break; default: Mod_LoadBrushModel (mod, buf); break; } return mod;} /*==================Mod_ForName Loads in a model for the given name==================*/model_t *Mod_ForName (char *name, bool crash){ model_t *mod; mod = Mod_FindName (name); return Mod_LoadModel (mod, crash);} /*=============================================================================== BRUSHMODEL LOADING ===============================================================================*/ uint8_t *mod_base; /*=================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; if (!l->filelen) { loadmodel->textures = NULL; return; } m = (dmiptexlump_t *)(mod_base + l->fileofs); m->nummiptex = LittleLong (m->nummiptex); loadmodel->numtextures = m->nummiptex; loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname); for (i=0 ; i<m->nummiptex ; i++) { m->dataofs[i] = LittleLong(m->dataofs[i]); if (m->dataofs[i] == -1) continue; mt = (miptex_t *)((uint8_t *)m + m->dataofs[i]); mt->width = LittleLong (mt->width); mt->height = LittleLong (mt->height); for (j=0 ; j<MIPLEVELS ; j++) mt->offsets[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 = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); loadmodel->textures[i] = tx; memmove (tx->name, mt->name, sizeof(tx->name)); tx->width = mt->width; tx->height = mt->height; for (j=0 ; j<MIPLEVELS ; j++) tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); // the pixels immediately follow the structures memmove ( tx+1, mt+1, pixels); if (!strncmp(mt->name,"sky",3)) R_InitSky (tx); } //// sequence the animations// for (i=0 ; i<m->nummiptex ; 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 ; j<m->nummiptex ; 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 ; j<max ; j++) { tx2 = anims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); 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 ; j<altmax ; j++) { tx2 = altanims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); 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 (!l->filelen) { loadmodel->lightdata = NULL; return; } loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); memmove (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);} /*=================Mod_LoadVisibility=================*/void Mod_LoadVisibility (lump_t *l){Lines 1–500 of 1835. Load more
// models.c -- model loading and caching // models are the only shared resource between a client and server running // on the same machine. #include <math.h> #include "quakedef.h" #include "r_shared.h" #include "r_local.h" model_t *loadmodel; char loadname[32]; // for hunk tags void Mod_LoadSpriteModel (model_t *mod, void *buffer); void Mod_LoadBrushModel (model_t *mod, void *buffer); void Mod_LoadAliasModel (model_t *mod, void *buffer); model_t *Mod_LoadModel (model_t *mod, bool crash); uint8_t mod_novis[MAX_MAP_LEAFS/8]; #define MAX_MOD_KNOWN 512 model_t mod_known[MAX_MOD_KNOWN]; int mod_numknown; // values for model_t's needload #define NL_PRESENT 0 #define NL_NEEDS_LOADED 1 #define NL_UNREFERENCED 2 /* =============== Mod_Init =============== */ void Mod_Init (void) { memset (mod_novis, 0xff, sizeof(mod_novis)); } /* =============== Mod_Extradata 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, true); 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 =================== */ uint8_t *Mod_DecompressVis (uint8_t *in, model_t *model) { static uint8_t decompressed[MAX_MAP_LEAFS/8]; int c; uint8_t *out; int row; row = (model->numleafs+7)>>3; out = decompressed; 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); return decompressed; } uint8_t *Mod_LeafPVS (mleaf_t *leaf, model_t *model) { if (leaf == model->leafs) return mod_novis; return Mod_DecompressVis (leaf->compressed_vis, model); } /* =================== Mod_ClearAll =================== */ void Mod_ClearAll (void) { int i; model_t *mod; for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) { mod->needload = NL_UNREFERENCED; //FIX FOR CACHE_ALLOC ERRORS: if (mod->type == mod_sprite) mod->cache.data = NULL; } } /* ================== Mod_FindName ================== */ model_t *Mod_FindName (char *name) { int i; model_t *mod; model_t *avail = NULL; if (!name[0]) Sys_Error ("Mod_ForName: NULL name"); // // search the currently loaded models // for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) { if (!strcmp (mod->name, name) ) break; if (mod->needload == NL_UNREFERENCED) if (!avail || mod->type != mod_alias) avail = mod; } if (i == mod_numknown) { if (mod_numknown == MAX_MOD_KNOWN) { if (avail) { mod = avail; if (mod->type == mod_alias) if (Cache_Check (&mod->cache)) Cache_Free (&mod->cache); } else Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); } else mod_numknown++; strcpy (mod->name, name); mod->needload = NL_NEEDS_LOADED; } return mod; } /* ================== Mod_TouchModel ================== */ void Mod_TouchModel (char *name) { model_t *mod; mod = Mod_FindName (name); if (mod->needload == NL_PRESENT) { if (mod->type == mod_alias) Cache_Check (&mod->cache); } } /* ================== Mod_LoadModel Loads a model into the cache ================== */ model_t *Mod_LoadModel (model_t *mod, bool crash) { unsigned *buf; uint8_t stackbuf[1024]; // avoid dirtying the cache heap if (mod->type == mod_alias) { if (Cache_Check (&mod->cache)) { mod->needload = NL_PRESENT; return mod; } } else { if (mod->needload == NL_PRESENT) return mod; } // // because the world is so huge, load it one piece at a time // // // load the file // buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); 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 = NL_PRESENT; switch (LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: Mod_LoadAliasModel (mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel (mod, buf); break; default: Mod_LoadBrushModel (mod, buf); break; } return mod; } /* ================== Mod_ForName Loads in a model for the given name ================== */ model_t *Mod_ForName (char *name, bool crash) { model_t *mod; mod = Mod_FindName (name); return Mod_LoadModel (mod, crash); } /* =============================================================================== BRUSHMODEL LOADING =============================================================================== */ uint8_t *mod_base; /* ================= 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; if (!l->filelen) { loadmodel->textures = NULL; return; } m = (dmiptexlump_t *)(mod_base + l->fileofs); m->nummiptex = LittleLong (m->nummiptex); loadmodel->numtextures = m->nummiptex; loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname); for (i=0 ; i<m->nummiptex ; i++) { m->dataofs[i] = LittleLong(m->dataofs[i]); if (m->dataofs[i] == -1) continue; mt = (miptex_t *)((uint8_t *)m + m->dataofs[i]); mt->width = LittleLong (mt->width); mt->height = LittleLong (mt->height); for (j=0 ; j<MIPLEVELS ; j++) mt->offsets[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 = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); loadmodel->textures[i] = tx; memmove (tx->name, mt->name, sizeof(tx->name)); tx->width = mt->width; tx->height = mt->height; for (j=0 ; j<MIPLEVELS ; j++) tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); // the pixels immediately follow the structures memmove ( tx+1, mt+1, pixels); if (!strncmp(mt->name,"sky",3)) R_InitSky (tx); } // // sequence the animations // for (i=0 ; i<m->nummiptex ; 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 ; j<m->nummiptex ; 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 ; j<max ; j++) { tx2 = anims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); 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 ; j<altmax ; j++) { tx2 = altanims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); 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 (!l->filelen) { loadmodel->lightdata = NULL; return; } loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); memmove (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); } /* ================= Mod_LoadVisibility ================= */ void Mod_LoadVisibility (lump_t *l) {