1
0
Fork 0
forked from fte/fteqw
fteqw/engine/sw/sw_model.c
Spoike ce3c561cfe CSQC is standard now, and secure via the same md4 as a map currently has.
Particle system functions renamed a bit, a few other cleanups in that area.
Console handling tweeked. Better rules for subconsoles and plugins. Commands are coloured if it'll be execed, which should help reduce occurences of chat being commands. tab compleation tweeked, partial compleation no longer changes the suggestion.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@895 fc73d0e0-1445-4013-8a0c-d673dee63da5
2005-03-10 03:55:18 +00:00

3620 lines
86 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
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.
#include "quakedef.h"
#include "r_local.h"
model_t *loadmodel;
char loadname[32]; // for hunk tags
void SWMod_LoadSpriteModel (model_t *mod, void *buffer);
void SWMod_LoadSprite2Model (model_t *mod, void *buffer);
void SWMod_LoadBrushModel (model_t *mod, void *buffer);
void Mod_LoadQ2BrushModel (model_t *mod, void *buffer);
void SWMod_LoadAliasModel (model_t *mod, void *buffer);
void SWMod_LoadAlias2Model (model_t *mod, void *buffer);
void SWMod_LoadAlias3Model (model_t *mod, void *buffer);
model_t *SWMod_LoadModel (model_t *mod, qboolean crash);
int Mod_ReadFlagsFromMD1(char *name, int md3version);
qbyte mod_novis[MAX_MAP_LEAFS/8];
#define MAX_MOD_KNOWN 1024
model_t mod_known[MAX_MOD_KNOWN];
int mod_numknown;
#ifdef SERVERONLY
#define SWMod_FindName Mod_FindName
#define SWMod_ForName Mod_ForName
#define SWMod_LeafPVS Mod_LeafPVS
#define SWMod_PointInLeaf Mod_PointInLeaf
#define SWMod_ClearAll Mod_ClearAll
#define SWMod_Init Mod_Init
#endif
/*
===============
Mod_Init
===============
*/
void SWMod_Init (void)
{
mod_numknown = 0;
memset (mod_novis, 0xff, sizeof(mod_novis));
Cmd_RemoveCommand("mod_texturelist");
}
void SWMod_Think(void)
{
}
/*
===============
Mod_Init
Caches the data if needed
===============
*/
void *SWMod_Extradata (model_t *mod)
{
void *r;
r = Cache_Check (&mod->cache);
if (r)
return r;
SWMod_LoadModel (mod, true);
if (!mod->cache.data)
Sys_Error ("Mod_Extradata: caching failed");
return mod->cache.data;
}
/*
===============
Mod_PointInLeaf
===============
*/
int SWMod_LeafForPoint (vec3_t p, model_t *model)
{
mnode_t *node;
float d;
mplane_t *plane;
#ifdef Q2BSPS
if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3)
{
return CM_PointLeafnum(p);
}
#endif
if (!model || !model->nodes)
Sys_Error ("Mod_PointInLeaf: bad model");
node = model->nodes;
while (1)
{
if (node->contents < 0)
return (mleaf_t *)node - model->leafs;
plane = node->plane;
d = DotProduct (p,plane->normal) - plane->dist;
if (d > 0)
node = node->children[0];
else
node = node->children[1];
}
return 0; // never reached
}
mleaf_t *SWMod_PointInLeaf (vec3_t p, model_t *model)
{
return model->leafs + SWMod_LeafForPoint(p, model);
}
/*
===================
Mod_DecompressVis
===================
*/
qbyte *SWMod_DecompressVis (qbyte *in, model_t *model, qbyte *decompressed)
{
int c;
qbyte *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;
}
qbyte *SWMod_LeafPVS (mleaf_t *leaf, model_t *model, qbyte *buffer)
{
static qbyte decompressed[MAX_MAP_LEAFS/8];
if (leaf == model->leafs)
return mod_novis;
if (!buffer)
buffer = decompressed;
return SWMod_DecompressVis (leaf->compressed_vis, model, buffer);
}
qbyte *SWMod_LeafnumPVS (int ln, model_t *model, qbyte *buffer)
{
return SWMod_LeafPVS(model->leafs + ln, model, buffer);
}
/*
===================
Mod_ClearAll
===================
*/
void SWMod_ClearAll (void)
{
int i;
model_t *mod;
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
if (mod->type != mod_alias)
mod->needload = true;
}
/*
==================
Mod_FindName
==================
*/
model_t *SWMod_FindName (char *name)
{
int i;
model_t *mod;
// if (!name[0]) //this is allowed to happen for q2 cinematics. :(
// 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 (i == mod_numknown)
{
if (mod_numknown == MAX_MOD_KNOWN)
Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
memset(mod, 0, sizeof(model_t)); //clear the old model as the renderers use the same globals
strcpy (mod->name, name);
mod->needload = true;
mod_numknown++;
mod->particleeffect = -1;
mod->nodefaulttrail = false;
}
return mod;
}
/*
==================
Mod_TouchModel
==================
*/
void SWMod_TouchModel (char *name)
{
model_t *mod;
mod = SWMod_FindName (name);
if (!mod->needload)
{
if (mod->type == mod_alias)
Cache_Check (&mod->cache);
}
}
/*
==================
Mod_LoadModel
Loads a model into the cache
==================
*/
model_t *SWMod_LoadModel (model_t *mod, qboolean crash)
{
void *d;
unsigned *buf = NULL;
qbyte stackbuf[1024]; // avoid dirtying the cache heap
char *ext;
if (!mod->needload)
{
if (mod->type == mod_alias)
{
d = Cache_Check (&mod->cache);
if (d)
return mod;
}
else
return mod; // not cached at all
}
#ifdef Q2BSPS
if (!*mod->name)
{
loadmodel = mod;
mod->needload = false;
Mod_LoadQ2BrushModel(mod, NULL);
P_DefaultTrail(mod);
return mod;
}
#endif
//
// because the world is so huge, load it one piece at a time
//
//look for a replacement
ext = COM_FileExtension(mod->name);
#ifndef CLIENTONLY
if (!isDedicated && (!Q_strcasecmp(ext, "mdl") || !Q_strcasecmp(ext, "bsp")))
{
char mdlbase[MAX_QPATH];
COM_StripExtension(mod->name, mdlbase);
if (!buf)
buf = (unsigned *)COM_LoadStackFile (va("%s.md3", mdlbase), stackbuf, sizeof(stackbuf));
if (!buf)
buf = (unsigned *)COM_LoadStackFile (va("%s.md2", mdlbase), stackbuf, sizeof(stackbuf));
}
#endif
if (!buf)
{
//
// 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);
mod->type = mod_dummy;
mod->mins[0] = -16;
mod->mins[1] = -16;
mod->mins[2] = -16;
mod->maxs[0] = 16;
mod->maxs[1] = 16;
mod->maxs[2] = 16;
mod->needload = true;
P_DefaultTrail(mod);
return mod;
return NULL;
}
}
//
// allocate a new model
//
COM_FileBase (mod->name, loadname);
loadmodel = mod;
#ifndef SERVERONLY
if (cl.model_precache[1]) //not the world.
Validation_IncludeFile(mod->name, (char *)buf, com_filesize);
#endif
//
// fill it in
//
// call the apropriate loader
mod->needload = false;
switch (LittleLong(*(unsigned *)buf))
{
#ifndef SERVERONLY
case IDPOLYHEADER:
SWMod_LoadAliasModel (mod, buf);
break;
case MD2IDALIASHEADER:
SWMod_LoadAlias2Model (mod, buf);
break;
case MD3_IDENT:
SWMod_LoadAlias3Model (mod, buf);
break;
case IDSPRITEHEADER:
SWMod_LoadSpriteModel (mod, buf);
break;
case IDSPRITE2HEADER:
SWMod_LoadSprite2Model (mod, buf);
break;
#endif
#ifdef Q2BSPS
case IDBSPHEADER: //looks like id switched to have proper ids
Mod_LoadQ2BrushModel (mod, buf);
break;
#endif
case BSPVERSIONHL:
case BSPVERSION: //hmm.
SWMod_LoadBrushModel (mod, buf);
break;
default: //some telejano mods can do this
if (crash)
Sys_Error ("Mod_NumForName: %s not found", mod->name);
mod->type = mod_dummy;
mod->mins[0] = -16;
mod->mins[1] = -16;
mod->mins[2] = -16;
mod->maxs[0] = 16;
mod->maxs[1] = 16;
mod->maxs[2] = 16;
mod->needload = true;
P_DefaultTrail(mod);
return mod;
}
P_DefaultTrail(mod);
return mod;
}
/*
==================
Mod_ForName
Loads in a model for the given name
==================
*/
model_t *SWMod_ForName (char *name, qboolean crash)
{
model_t *mod;
mod = SWMod_FindName (name);
return SWMod_LoadModel (mod, crash);
}
/*
===============================================================================
BRUSHMODEL LOADING
===============================================================================
*/
qbyte *mod_base;
/*
=================
Mod_LoadTextures
=================
*/
#ifndef SERVERONLY
void SWMod_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 *)((qbyte *)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);
if (!mt->offsets[0]) //external hl texture.
{
int pb;
if (r_usinglits) //allocate enough mem
pb = 4;
else
pb = 1;
pixels = mt->width*pb*mt->height/64*85;
tx = Hunk_AllocName (sizeof(texture_t) +pixels, mt->name ); //allocate enough to cover it.
tx->pixbytes = pb;
loadmodel->textures[i] = tx;
memcpy (tx->name, mt->name, sizeof(tx->name));
tx->width = mt->width;
tx->height = mt->height;
for (j=0 ; j<MIPLEVELS ; j++)
tx->offsets[j] = 0;//mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
// the pixels immediately follow the structures
memset ( tx+1, 7, pixels); //set it all to 7 for no particular reason.
R_AddBulleten(tx);
continue;
}
else if (loadmodel->fromgame == fg_halflife) //internal hl texture
{
qboolean alphaed;
int pb;
if (r_usinglits) //allocate enough mem
pb = 4;
else
pb = 1;
pixels = (mt->width*pb*mt->height)*85/64;
tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
tx->pixbytes = pb;
loadmodel->textures[i] = tx;
memcpy (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(miptex_t))*4 + sizeof(texture_t);
// the pixels immediately follow the structures
if (pb == 4)
{
memcpy ( tx+1, W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed), pixels);
}
else
{ //need to convert it down
int k;
qbyte *in;
qbyte *out;
out = (qbyte *)(tx+1);
in = W_ConvertWAD3Texture(mt, &mt->width, &mt->height, &alphaed);
tx->offsets[0] = (char *)out - (char *)tx;
for (j = 0; j < mt->width*mt->height; j++, in+=4)
{
if (in[3] == 0)
*out++ = 255;
else
*out++ = GetPalette(in[0], in[1], in[2]);
}
in = out-mt->width*mt->height; //shrink mips.
tx->offsets[1] = (char *)out - (char *)tx;
for (j = 0; j < tx->height; j+=2) //we could convert mip[1], but shrinking is probably faster.
for (k = 0; k < tx->width; k+=2)
*out++ = in[k + tx->width*j];
tx->offsets[2] = (char *)out - (char *)tx;
for (j = 0; j < tx->height; j+=4)
for (k = 0; k < tx->width; k+=4)
*out++ = in[k + tx->width*j];
tx->offsets[3] = (char *)out - (char *)tx;
for (j = 0; j < tx->height; j+=8)
for (k = 0; k < tx->width; k+=8)
*out++ = in[k + tx->width*j];
}
// if (!Q_strncmp(mt->name,"sky",3))
// R_InitSky (tx);
#ifdef PEXT_BULLETENS
// else
R_AddBulleten(tx);
#endif
continue;
}
//internal 8bit texture
pixels = mt->width*mt->height/64*85;
tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
tx->pixbytes = 1;
loadmodel->textures[i] = tx;
memcpy (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
memcpy ( tx+1, mt+1, pixels);
if (!Q_strncmp(mt->name,"sky",3))
R_InitSky (tx);
#ifdef PEXT_BULLETENS
else R_AddBulleten(tx);
#endif
}
//
// 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];
}
}
}
void SWMod_NowLoadExternal(void)
{
int i, j, m, x, y;
texture_t *tx;
qbyte *in;
qbyte *out;
qboolean alphaed;
unsigned int *out32;
int width;
int height;
int t;
for (t=0 ; t<loadmodel->numtextures ; t++)
{
tx = loadmodel->textures[t];
if (tx && !tx->offsets[0])
{
in = W_GetTexture(tx->name, &width, &height, &alphaed);
i=0;
tx->offsets[0] = sizeof(texture_t);
tx->offsets[1] = tx->offsets[0] + tx->width*tx->pixbytes*tx->height;
tx->offsets[2] = tx->offsets[1] + (tx->width*tx->pixbytes*tx->height)/4;
tx->offsets[3] = tx->offsets[2] + (tx->width*tx->pixbytes*tx->height)/16;
if (!in)
{
if (tx->pixbytes == 4)
{
// out32 = (unsigned int *)((qbyte *)tx+tx->offsets[0]);
// memset(out32, 255, tx->width*tx->pixbytes*tx->height*85/64);
for (m=0 ; m<4 ; m++)
{
out32 = (int *)((qbyte *)tx + tx->offsets[m]);
for (y=0 ; y< (tx->height>>m) ; y++)
for (x=0 ; x< (tx->width>>m) ; x++)
{
if ((y/2+x/2)&1)
*out32++ = 0;
else if (y/2&1&&x/2&1)
*out32++ = 0x00007700;
else
*out32++ = 0x00000077;
}
}
}
else
{
// out = (qbyte *)tx+tx->offsets[0];
// memset(out32, 15, tx->width*tx->height*85/64); //usually white, anyway...
for (m=0 ; m<4 ; m++)
{
out = (qbyte *)tx + tx->offsets[m];
for (y=0 ; y< (tx->height>>m) ; y++)
for (x=0 ; x< (tx->width>>m) ; x++)
{
if ((y+x)&1)
*out++ = 0;
else
*out++ = 0xff;
}
}
}
continue; //bother.
}
if (tx->pixbytes == 4)
{
out32 = (unsigned int *)((qbyte *)tx+tx->offsets[0]);
memcpy(out32, in, tx->width*tx->pixbytes*tx->height*85/64);
}
else
{
out = (qbyte *)tx+tx->offsets[0];
for (i=0; i < tx->width*tx->height; i++) //downgrade colour
{
if (in[3] == 0)
*out++ = 255;
else
*out++ = GetPalette(in[0], in[1], in[2]);
in += 4;
}
in = (qbyte *)tx+tx->offsets[0]; //shrink mips.
for (j = 0; j < tx->height; j+=2) //we could convert mip[1], but shrinking is probably faster.
for (i = 0; i < tx->width; i+=2)
*out++ = in[i + tx->width*j];
for (j = 0; j < tx->height; j+=4)
for (i = 0; i < tx->width; i+=4)
*out++ = in[i + tx->width*j];
for (j = 0; j < tx->height; j+=8)
for (i = 0; i < tx->width; i+=8)
*out++ = in[i + tx->width*j];
}
}
}
}
/*
=================
Mod_LoadLighting
=================
*/
void SWMod_LoadLighting (lump_t *l)
{
extern cvar_t r_loadlits;
if (!l->filelen)
{
loadmodel->lightdata = NULL;
return;
}
if (r_pixbytes == 4) //using 24 bit lighting
{
r_usinglits = true;
if (r_loadlits.value && r_usinglits)
{
char litname[MAX_QPATH];
qbyte *litdata = NULL;
if (!litdata)
{
strcpy(litname, loadmodel->name);
COM_StripExtension(loadmodel->name, litname);
COM_DefaultExtension(litname, ".lit");
litdata = COM_LoadHunkFile(litname);
}
if (!litdata)
{
strcpy(litname, "lits/");
COM_StripExtension(COM_SkipPath(loadmodel->name), litname+5);
strcat(litname, ".lit");
litdata = COM_LoadHunkFile(litname);
}
if (litdata)
{
if (l->filelen != (com_filesize-8)/3)
Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname);
else if (litdata[0] == 'Q' && litdata[1] == 'L' && litdata[2] == 'I' && litdata[3] == 'T')
{
if (LittleLong(*(int *)&litdata[4]) == 1)
{
float prop;
int i;
qbyte *normal;
// qbyte max;
loadmodel->lightdata = litdata+8;
//now some cheat protection.
normal = mod_base + l->fileofs;
litdata = loadmodel->lightdata;
for (i = 0; i < l->filelen; i++) //force it to the same intensity. (or less, depending on how you see it...)
{
#define m(a, b, c) (a>(b>c?b:c)?a:(b>c?b:c))
prop = *normal / (float)m(litdata[0], litdata[1], litdata[2]);
litdata[0] *= prop;
litdata[1] *= prop;
litdata[2] *= prop;
normal++;
litdata+=3;
}
//end anti-cheat
return;
}
else
Con_Printf("\"%s\" isn't a standard version 1 lit\n", litname);
}
else
Con_Printf("lit \"%s\" isn't a lit\n", litname);
}
}
if (loadmodel->fromgame == fg_halflife || loadmodel->fromgame == fg_quake2 || loadmodel->fromgame == fg_quake3) //half-life levels use 24 bit anyway.
{
loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
}
else if (!r_usinglits)
{
loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
}
else
{ //expand to 24 bit
int i;
qbyte *dest, *src = mod_base + l->fileofs;
loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, loadname);
dest = loadmodel->lightdata;
for (i = 0; i<l->filelen; i++)
{
dest[0] = *src;
dest[1] = *src;
dest[2] = *src;
src++;
dest+=3;
}
}
}
else
{
r_usinglits = false;
if (loadmodel->fromgame == fg_halflife || loadmodel->fromgame == fg_quake2 || loadmodel->fromgame == fg_quake3)
{
int i;
qbyte *out;
qbyte *in;
out = loadmodel->lightdata = Hunk_AllocName ( l->filelen/3, loadname);
in = mod_base + l->fileofs; //24 bit to luminance.
for (i = 0; i < l->filelen; i+=3)
*out++ = ((int)in[i] + (int)in[i] + (int)in[i])/3;
}
else
{//standard Quake
loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
}
}
}
#endif
/*
=================
Mod_LoadVisibility
=================
*/
void SWMod_LoadVisibility (lump_t *l)
{
if (!l->filelen)
{
loadmodel->visdata = NULL;
return;
}
loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);
memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
}
/*
=================
Mod_LoadEntities
=================
*/
void SWMod_LoadEntities (lump_t *l)
{
if (!l->filelen)
{
loadmodel->entities = NULL;
return;
}
loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);
memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
}
/*
=================
Mod_LoadVertexes
=================
*/
void SWMod_LoadVertexes (lump_t *l)
{
dvertex_t *in;
mvertex_t *out;
int i, count;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count+8)*sizeof(*out), loadname); //spare for skybox
loadmodel->vertexes = out;
loadmodel->numvertexes = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
out->position[0] = LittleFloat (in->point[0]);
out->position[1] = LittleFloat (in->point[1]);
out->position[2] = LittleFloat (in->point[2]);
}
}
static qboolean hexen2map;
/*
=================
Mod_LoadSubmodels
=================
*/
void SWMod_LoadSubmodels (lump_t *l)
{
dq1model_t *inq;
dh2model_t *inh;
mmodel_t *out;
int i, j, count;
//this is crazy!
inq = (void *)(mod_base + l->fileofs);
inh = (void *)(mod_base + l->fileofs);
if (!inq->numfaces)
{
hexen2map = true;
if (l->filelen % sizeof(*inh))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*inh);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->submodels = out;
loadmodel->numsubmodels = count;
for ( i=0 ; i<count ; i++, inh++, out++)
{
for (j=0 ; j<3 ; j++)
{ // spread the mins / maxs by a pixel
out->mins[j] = LittleFloat (inh->mins[j]) - 1;
out->maxs[j] = LittleFloat (inh->maxs[j]) + 1;
out->origin[j] = LittleFloat (inh->origin[j]);
}
for (j=0 ; j<MAX_MAP_HULLSDH2 ; j++)
{
out->headnode[j] = LittleLong (inh->headnode[j]);
}
for ( ; j<MAX_MAP_HULLSM ; j++)
out->headnode[j] = 0;
for (j=0 ; j<MAX_MAP_HULLSDH2 ; j++)
out->hullavailable[j] = true;
for ( ; j<MAX_MAP_HULLSM ; j++)
out->hullavailable[j] = false;
out->visleafs = LittleLong (inh->visleafs);
out->firstface = LittleLong (inh->firstface);
out->numfaces = LittleLong (inh->numfaces);
}
}
else
{
hexen2map = false;
if (l->filelen % sizeof(*inq))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*inq);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->submodels = out;
loadmodel->numsubmodels = count;
for ( i=0 ; i<count ; i++, inq++, out++)
{
for (j=0 ; j<3 ; j++)
{ // spread the mins / maxs by a pixel
out->mins[j] = LittleFloat (inq->mins[j]) - 1;
out->maxs[j] = LittleFloat (inq->maxs[j]) + 1;
out->origin[j] = LittleFloat (inq->origin[j]);
}
for (j=0 ; j<MAX_MAP_HULLSDQ1 ; j++)
{
out->headnode[j] = LittleLong (inq->headnode[j]);
}
for ( ; j<MAX_MAP_HULLSM ; j++)
out->headnode[j] = 0;
for (j=0 ; j<3 ; j++)
out->hullavailable[j] = true;
for ( ; j<MAX_MAP_HULLSM ; j++)
out->hullavailable[j] = false;
out->visleafs = LittleLong (inq->visleafs);
out->firstface = LittleLong (inq->firstface);
out->numfaces = LittleLong (inq->numfaces);
}
}
}
/*
=================
Mod_LoadEdges
=================
*/
void SWMod_LoadEdges (lump_t *l)
{
dedge_t *in;
medge_t *out;
int i, count;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count + 1 + 12) * sizeof(*out), loadname); //spare for skybox
loadmodel->edges = out;
loadmodel->numedges = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
out->v[0] = (unsigned short)LittleShort(in->v[0]);
out->v[1] = (unsigned short)LittleShort(in->v[1]);
}
}
/*
=================
Mod_LoadTexinfo
=================
*/
#ifndef SERVERONLY
void SWMod_LoadTexinfo (lump_t *l)
{
texinfo_t *in;
mtexinfo_t *out;
int i, j, count;
int miptex;
float len1, len2;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->texinfo = out;
loadmodel->numtexinfo = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
for (j=0 ; j<8 ; j++)
out->vecs[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 / floor( (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;
}
else if (!strncmp(out->texture->name, "sky", 3))
{
out->flags |= SURF_SKY;
}
else if (!strncmp(out->texture->name, "glass", 5)) //halflife levels
{
out->flags |= SURF_TRANS66;
}
else if (*out->texture->name == '{') //halflife levels
{
// out->flags |= SURF_TRANS66;
}
else if (*out->texture->name == '!') //halflife levels
{
out->flags |= SURF_WARP | SURF_TRANS33;
}
}
}
}
#endif
/*
================
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 ; i<s->numedges ; 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] = floor(mins[i]/16);
bmaxs[i] = ceil(maxs[i]/16);
s->texturemins[i] = bmins[i] * 16;
s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
if (s->extents[i] < 16)
s->extents[i] = 16; // take at least one cache block
// if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
// Sys_Error ("Bad surface extents");
}
}
*/
/*
=================
Mod_LoadFaces
=================
*/
#ifndef SERVERONLY
void SWMod_LoadFaces (lump_t *l)
{
dface_t *in;
msurface_t *out;
int i, count, surfnum;
int planenum, side;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count+6)*sizeof(*out), loadname); //spare for skybox
loadmodel->surfaces = out;
loadmodel->numsurfaces = count;
for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
{
out->firstedge = 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);
if (!out->texinfo->texture)
out->texinfo->texture = r_notexture_mip;
CalcSurfaceExtents (out);
// lighting info
for (i=0 ; i<MAXLIGHTMAPS ; i++)
out->styles[i] = in->styles[i];
i = LittleLong(in->lightofs);
if (i == -1)
out->samples = NULL;
else if (r_usinglits)
{
if (loadmodel->fromgame == fg_halflife)
out->samples = loadmodel->lightdata + i;
else
out->samples = loadmodel->lightdata + i*3;
}
else
{
if (loadmodel->fromgame == fg_halflife)
out->samples = loadmodel->lightdata + i/3;
else
out->samples = loadmodel->lightdata + i;
}
// set the drawing flags flag
if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky
{
if (loadmodel->fromgame == fg_halflife)
out->flags |= SURF_DRAWBACKGROUND;
else
out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
continue;
}
if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent
{
out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
for (i=0 ; i<2 ; i++)
{
out->extents[i] = 16384;
out->texturemins[i] = -8192;
}
continue;
}
}
}
#endif
/*
=================
Mod_SetParent
=================
*/
void SWMod_SetParent (mnode_t *node, mnode_t *parent)
{
node->parent = parent;
if (node->contents < 0)
return;
SWMod_SetParent (node->children[0], node);
SWMod_SetParent (node->children[1], node);
}
/*
=================
Mod_LoadNodes
=================
*/
void SWMod_LoadNodes (lump_t *l)
{
int i, j, count, p;
dnode_t *in;
mnode_t *out;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->nodes = out;
loadmodel->numnodes = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
for (j=0 ; j<3 ; j++)
{
out->minmaxs[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));
}
}
SWMod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
}
/*
=================
Mod_LoadLeafs
=================
*/
void SWMod_LoadLeafs (lump_t *l)
{
dleaf_t *in;
mleaf_t *out;
int i, j, count, p;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->leafs = out;
loadmodel->numleafs = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
for (j=0 ; j<3 ; j++)
{
out->minmaxs[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];
}
}
//these are used to boost other info sizes
int numsuplementryplanes;
int numsuplementryclipnodes;
void *suplementryclipnodes;
void *suplementryplanes;
void *crouchhullfile;
qbyte *COM_LoadMallocFile (char *path);
void SWMod_LoadCrouchHull(void)
{
int i;
int numsm;
char crouchhullname[MAX_QPATH];
int *data;
// dclipnode_t *cn;
numsuplementryplanes = numsuplementryclipnodes = 0;
//find a name for a ccn and try to load it.
strcpy(crouchhullname, loadmodel->name);
COM_StripExtension(loadmodel->name, crouchhullname);
COM_DefaultExtension(crouchhullname, ".crh"); //crouch hull
crouchhullfile = COM_LoadMallocFile(crouchhullname); //or otherwise temporary storage. load on hunk if you want, but that would be a waste.
if (!crouchhullfile)
return;
if (LittleLong(((int *)crouchhullfile)[0]) != ('Q') + ('C'<<8) + ('C'<<16) + ('N'<<24)) //make sure it's the right version
return;
if (LittleLong(((int *)crouchhullfile)[1]) != 0) //make sure it's the right version
return;
numsm = LittleLong(((int *)crouchhullfile)[2]);
if (numsm != loadmodel->numsubmodels) //not compatable
return;
numsuplementryplanes = LittleLong(((int *)crouchhullfile)[3]);
numsuplementryclipnodes = LittleLong(((int *)crouchhullfile)[4]);
data = &((int *)crouchhullfile)[5];
for (i = 0; i < numsm; i++) //load headnode references
{
loadmodel->submodels[i].headnode[3] = LittleLong(*data)+1;
data++;
}
suplementryplanes = data;
suplementryclipnodes = (qbyte*)data + sizeof(dplane_t)*numsuplementryplanes;
}
/*
=================
Mod_LoadClipnodes
=================
*/
void SWMod_LoadClipnodes (lump_t *l)
{
dclipnode_t *in, *out;
int i, count;
hull_t *hull;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count+numsuplementryclipnodes)*sizeof(*out), loadname);//space for both
loadmodel->clipnodes = out;
loadmodel->numclipnodes = count+numsuplementryclipnodes;
if (hexen2map)
{ //hexen2.
hexen2map=false;
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->available = true;
hull = &loadmodel->hulls[2];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count-1;
hull->planes = loadmodel->planes;
hull->clip_mins[0] = -24;
hull->clip_mins[1] = -24;
hull->clip_mins[2] = -20;
hull->clip_maxs[0] = 24;
hull->clip_maxs[1] = 24;
hull->clip_maxs[2] = 20;
hull->available = true;
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] = -12;
hull->clip_maxs[0] = 16;
hull->clip_maxs[1] = 16;
hull->clip_maxs[2] = 16;
hull->available = true;
hull = &loadmodel->hulls[4];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count-1;
hull->planes = loadmodel->planes;
hull->clip_mins[0] = -40;
hull->clip_mins[1] = -40;
hull->clip_mins[2] = -42;
hull->clip_maxs[0] = 40;
hull->clip_maxs[1] = 40;
hull->clip_maxs[2] = 42;
hull->available = true;
hull = &loadmodel->hulls[5];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count-1;
hull->planes = loadmodel->planes;
hull->clip_mins[0] = -48;
hull->clip_mins[1] = -48;
hull->clip_mins[2] = -50;
hull->clip_maxs[0] = 48;
hull->clip_maxs[1] = 48;
hull->clip_maxs[2] = 50;
hull->available = true;
}
else if (loadmodel->fromgame == fg_halflife)
{
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->available = true;
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->available = true;
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;
hull->available = true;
}
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->available = true;
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;
hull->available = true;
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] = -6;
hull->clip_maxs[0] = 16;
hull->clip_maxs[1] = 16;
hull->clip_maxs[2] = 30;
hull->available = false;
}
for (i=0 ; i<count ; i++, out++, in++)
{
out->planenum = LittleLong(in->planenum);
out->children[0] = LittleShort(in->children[0]);
out->children[1] = LittleShort(in->children[1]);
}
if (numsuplementryclipnodes) //now load the crouch ones.
{
in = suplementryclipnodes;
hull->planes = suplementryplanes;
hull->clipnodes = out-1;
hull->lastclipnode = numsuplementryclipnodes;
hull->available = true;
for (i=0 ; i<numsuplementryclipnodes ; i++, out++, in++)
{
out->planenum = LittleLong(in->planenum);
out->children[0] = LittleShort(in->children[0]);
out->children[0] += out->children[0]>=0?1:0;
out->children[1] = LittleShort(in->children[1]);
out->children[1] += out->children[1]>=0?1:0;
}
}
}
/*
=================
Mod_MakeHull0
Deplicate the drawing hull structure as a clipping hull
=================
*/
void SWMod_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 = Hunk_AllocName ( count*sizeof(*out), loadname);
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count-1;
hull->planes = loadmodel->planes;
for (i=0 ; i<count ; i++, out++, in++)
{
out->planenum = 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 SWMod_LoadMarksurfaces (lump_t *l)
{
int i, j, count;
short *in;
msurface_t **out;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
loadmodel->marksurfaces = out;
loadmodel->nummarksurfaces = count;
for ( i=0 ; i<count ; i++)
{
j = LittleShort(in[i]);
if (j >= loadmodel->numsurfaces)
Sys_Error ("Mod_ParseMarksurfaces: bad surface number");
out[i] = loadmodel->surfaces + j;
}
}
/*
=================
Mod_LoadSurfedges
=================
*/
void SWMod_LoadSurfedges (lump_t *l)
{
int i, count;
int *in, *out;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count+24)*sizeof(*out), loadname); //spare for skybox
loadmodel->surfedges = out;
loadmodel->numsurfedges = count;
for ( i=0 ; i<count ; i++)
out[i] = LittleLong (in[i]);
}
/*
=================
Mod_LoadPlanes
=================
*/
void SWMod_LoadPlanes (lump_t *l)
{
int i, j;
mplane_t *out;
dplane_t *in;
int count;
int bits;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
count = l->filelen / sizeof(*in);
out = Hunk_AllocName ( (count+numsuplementryplanes)*2*sizeof(*out), loadname);
loadmodel->planes = out;
loadmodel->numplanes = count+numsuplementryplanes;
for ( i=0 ; i<count ; i++, in++, out++)
{
bits = 0;
for (j=0 ; j<3 ; j++)
{
out->normal[j] = LittleFloat (in->normal[j]);
if (out->normal[j] < 0)
bits |= 1<<j;
}
out->dist = LittleFloat (in->dist);
out->type = LittleLong (in->type);
out->signbits = bits;
}
if (numsuplementryplanes)
{
in = suplementryplanes;
suplementryplanes = out;
for ( i=0 ; i<numsuplementryplanes ; i++, in++, out++)
{
bits = 0;
for (j=0 ; j<3 ; j++)
{
out->normal[j] = LittleFloat (in->normal[j]);
if (out->normal[j] < 0)
bits |= 1<<j;
}
out->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] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
}
return Length (corner);
}
*/
void Q1BSP_MarkLights (dlight_t *light, int bit, mnode_t *node);
#ifndef CLIENTONLY
void Q1BSP_FatPVS (vec3_t org, qboolean add);
qboolean Q1BSP_EdictInFatPVS(edict_t *ent);
void Q1BSP_FindTouchedLeafs(edict_t *ent);
#endif
void SWQ1BSP_LightPointValues(vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir);
void SWR_Q1BSP_StainNode (mnode_t *node, float *parms);
/*
=================
Mod_LoadBrushModel
=================
*/
void SWMod_LoadBrushModel (model_t *mod, void *buffer)
{
int i, j;
dheader_t *header;
mmodel_t *bm;
loadmodel->type = mod_brush;
header = (dheader_t *)buffer;
i = LittleLong (header->version);
if (i == BSPVERSION)
loadmodel->fromgame = fg_quake;
else if (i == BSPVERSIONHL)
loadmodel->fromgame = fg_halflife;
else
Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
// if (i != BSPVERSION)
// Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
// swap all the lumps
mod_base = (qbyte *)header;
for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
mod->checksum = 0;
mod->checksum2 = 0;
// checksum all of the map, except for entities
for (i = 0; i < HEADER_LUMPS; i++) {
if (i == LUMP_ENTITIES)
continue;
mod->checksum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs,
header->lumps[i].filelen);
if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
continue;
mod->checksum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs,
header->lumps[i].filelen);
}
// load into heap
#ifndef CLIENTONLY
if (!isDedicated)
#endif
{
SWMod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
SWMod_LoadEdges (&header->lumps[LUMP_EDGES]);
SWMod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
SWMod_LoadLighting (&header->lumps[LUMP_LIGHTING]); //DMW, made lighting load first. (so we know if lighting is rgb or luminance)
SWMod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
}
SWMod_LoadSubmodels (&header->lumps[LUMP_MODELS]); //needs to come before we set the headnodes[3]
SWMod_LoadCrouchHull ();
SWMod_LoadPlanes (&header->lumps[LUMP_PLANES]);
#ifndef CLIENTONLY
if (!isDedicated)
#endif
{
SWMod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
SWMod_LoadFaces (&header->lumps[LUMP_FACES]);
SWMod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
}
SWMod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
SWMod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
SWMod_LoadNodes (&header->lumps[LUMP_NODES]);
SWMod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
SWMod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
if (crouchhullfile)
{
BZ_Free(crouchhullfile);
crouchhullfile=NULL;
}
#ifndef CLIENTONLY
mod->funcs.FatPVS = Q1BSP_FatPVS;
mod->funcs.EdictInFatPVS = Q1BSP_EdictInFatPVS;
mod->funcs.FindTouchedLeafs_Q1 = Q1BSP_FindTouchedLeafs;
#endif
mod->funcs.LightPointValues = SWQ1BSP_LightPointValues;
mod->funcs.StainNode = SWR_Q1BSP_StainNode;
mod->funcs.MarkLights = Q1BSP_MarkLights;
mod->funcs.LeafForPoint = SWMod_LeafForPoint;
mod->funcs.LeafPVS = SWMod_LeafnumPVS;
//We ONLY do this for the world model
#ifndef SERVERONLY
#ifndef CLIENTONLY
if (sv.state) //if the server is running
{
if (!strcmp(loadmodel->name, va("maps/%s.bsp", sv.name)))
Mod_ParseInfoFromEntityLump(mod_base + header->lumps[LUMP_ENTITIES].fileofs);
}
else
#endif
{
if (!cl.model_precache[1]) //not copied across yet
Mod_ParseInfoFromEntityLump(mod_base + header->lumps[LUMP_ENTITIES].fileofs);
}
#endif
SWMod_MakeHull0 ();
mod->numframes = 2; // regular and alternate animation
//
// set up the submodels (FIXME: this is confusing)
//
for (i=0 ; i<mod->numsubmodels ; i++)
{
bm = &mod->submodels[i];
mod->hulls[0].firstclipnode = bm->headnode[0];
Q1BSP_SetHullFuncs(&mod->hulls[0]);
for (j=1 ; j<MAX_MAP_HULLSM ; j++)
{
mod->hulls[j].firstclipnode = bm->headnode[j];
mod->hulls[j].lastclipnode = mod->numclipnodes-1;
Q1BSP_SetHullFuncs(&mod->hulls[j]);
}
mod->firstmodelsurface = bm->firstface;
mod->nummodelsurfaces = bm->numfaces;
mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
VectorCopy (bm->maxs, mod->maxs);
VectorCopy (bm->mins, mod->mins);
mod->numleafs = bm->visleafs;
if (i < mod->numsubmodels-1)
{ // duplicate the basic information
char name[10];
sprintf (name, "*%i", i+1);
loadmodel = SWMod_FindName (name);
*loadmodel = *mod;
strcpy (loadmodel->name, name);
mod = loadmodel;
P_DefaultTrail(mod);
}
}
}
#ifndef SERVERONLY
/*
==============================================================================
ALIAS MODELS
==============================================================================
*/
/*
=================
Mod_LoadAliasFrame
=================
*/
void * SWMod_LoadAliasFrame (void * pin, int *pframeindex, int numv,
dtrivertx_t *pbboxmin, dtrivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
{
dtrivertx_t *pframe, *pinframe;
int i, j;
daliasframe_t *pdaliasframe;
pdaliasframe = (daliasframe_t *)pin;
strcpy (name, pdaliasframe->name);
for (i=0 ; i<3 ; i++)
{
// these are qbyte values, so we don't have to worry about
// endianness
pbboxmin->v[i] = pdaliasframe->bboxmin.v[i];
pbboxmax->v[i] = pdaliasframe->bboxmax.v[i];
}
pinframe = (dtrivertx_t *)(pdaliasframe + 1);
pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname);
*pframeindex = (qbyte *)pframe - (qbyte *)pheader;
for (j=0 ; j<numv ; j++)
{
int k;
// these are all qbyte values, so no need to deal with endianness
pframe[j].lightnormalindex = pinframe[j].lightnormalindex;
for (k=0 ; k<3 ; k++)
{
pframe[j].v[k] = pinframe[j].v[k];
}
}
pinframe += numv;
return (void *)pinframe;
}
/*
=================
Mod_LoadAliasGroup
=================
*/
void * SWMod_LoadAliasGroup (void * pin, int *pframeindex, int numv,
dtrivertx_t *pbboxmin, dtrivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
{
daliasgroup_t *pingroup;
maliasgroup_t *paliasgroup;
int i, numframes;
daliasinterval_t *pin_intervals;
float *poutintervals;
void *ptemp;
pingroup = (daliasgroup_t *)pin;
numframes = LittleLong (pingroup->numframes);
paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) +
(numframes - 1) * sizeof (paliasgroup->frames[0]), loadname);
paliasgroup->numframes = numframes;
for (i=0 ; i<3 ; i++)
{
// these are qbyte values, so we don't have to worry about endianness
pbboxmin->v[i] = pingroup->bboxmin.v[i];
pbboxmax->v[i] = pingroup->bboxmax.v[i];
}
*pframeindex = (qbyte *)paliasgroup - (qbyte *)pheader;
pin_intervals = (daliasinterval_t *)(pingroup + 1);
poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
paliasgroup->intervals = (qbyte *)poutintervals - (qbyte *)pheader;
for (i=0 ; i<numframes ; i++)
{
*poutintervals = LittleFloat (pin_intervals->interval);
if (*poutintervals <= 0.0)
Sys_Error ("Mod_LoadAliasGroup: interval<=0");
poutintervals++;
pin_intervals++;
}
ptemp = (void *)pin_intervals;
for (i=0 ; i<numframes ; i++)
{
ptemp = SWMod_LoadAliasFrame (ptemp,
&paliasgroup->frames[i].frame,
numv,
&paliasgroup->frames[i].bboxmin,
&paliasgroup->frames[i].bboxmax,
pheader, name);
}
return ptemp;
}
/*
=================
Mod_LoadAliasSkin
=================
*/
void * SWMod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize,
aliashdr_t *pheader)
{
int i;
qbyte *pskin, *pinskin;
// unsigned short *pusskin;
unsigned int *p32skin;
pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
pinskin = (qbyte *)pin;
*pskinindex = (qbyte *)pskin - (qbyte *)pheader;
if (r_pixbytes == 1 || r_pixbytes == 2)
{
Q_memcpy (pskin, pinskin, skinsize);
}
else if (r_pixbytes == 4)
{
extern qbyte *host_basepal;
p32skin = (unsigned int *)pskin;
for (i=0 ; i<skinsize ; i++)
p32skin[i] = (255<<24) | (host_basepal[pinskin[i]*3+0]<<16) | (host_basepal[pinskin[i]*3+1]<<8) | (host_basepal[pinskin[i]*3+2]<<0);//d_8to32table[pinskin[i]];
}
else
{
Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n",
r_pixbytes);
}
pinskin += skinsize;
return ((void *)pinskin);
}
void * SWMod_LoadAlias2Skin (void * pin, int *pskinindex, int skinsize,
aliashdr_t *pheader)
{
return ((void *)pin);
}
/*
=================
Mod_LoadAliasSkinGroup
=================
*/
void * SWMod_LoadAliasSkinGroup (void * pin, int *pskinindex, int skinsize,
aliashdr_t *pheader)
{
daliasskingroup_t *pinskingroup;
maliasskingroup_t *paliasskingroup;
int i, numskins;
daliasskininterval_t *pinskinintervals;
float *poutskinintervals;
void *ptemp;
pinskingroup = (daliasskingroup_t *)pin;
numskins = LittleLong (pinskingroup->numskins);
paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) +
(numskins - 1) * sizeof (paliasskingroup->skindescs[0]),
loadname);
paliasskingroup->numskins = numskins;
*pskinindex = (qbyte *)paliasskingroup - (qbyte *)pheader;
pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname);
paliasskingroup->intervals = (qbyte *)poutskinintervals - (qbyte *)pheader;
for (i=0 ; i<numskins ; i++)
{
*poutskinintervals = LittleFloat (pinskinintervals->interval);
if (*poutskinintervals <= 0)
Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");
poutskinintervals++;
pinskinintervals++;
}
ptemp = (void *)pinskinintervals;
for (i=0 ; i<numskins ; i++)
{
ptemp = SWMod_LoadAliasSkin (ptemp,
&paliasskingroup->skindescs[i].skin, skinsize, pheader);
}
return ptemp;
}
/*
=================
Mod_LoadAliasModel
=================
*/
void SWMod_LoadAliasModel (model_t *mod, void *buffer)
{
int i;
mmdl_t *pmodel;
dmdl_t *pinmodel;
mstvert_t *pstverts;
dstvert_t *pinstverts;
aliashdr_t *pheader;
mtriangle_t *ptri;
dtriangle_t *pintriangles;
int version, numframes, numskins;
int size;
daliasframetype_t *pframetype;
daliasskintype_t *pskintype;
maliasskindesc_t *pskindesc;
int skinsize;
int start, end, total;
if (!strcmp(loadmodel->name, "progs/player.mdl") ||
!strcmp(loadmodel->name, "progs/eyes.mdl")) {
unsigned short crc;
qbyte *p;
int len;
char st[40];
CRC_Init(&crc);
for (len = com_filesize, p = buffer; len; len--, p++)
CRC_ProcessByte(&crc, *p);
sprintf(st, "%d", (int) crc);
Info_SetValueForKey (cls.userinfo,
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
st, MAX_INFO_STRING);
if (cls.state >= ca_connected)
{
CL_SendClientCommand("setinfo %s %d",
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
(int)crc);
}
}
start = Hunk_LowMark ();
pinmodel = (dmdl_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]) +
sizeof (mmdl_t) +
LittleLong (pinmodel->numverts)*2 * sizeof (mstvert_t) +
LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);
pheader = Hunk_AllocName (size, loadname);
pmodel = (mmdl_t *) ((qbyte *)&pheader[1] +
(LittleLong (pinmodel->numframes) - 1) *
sizeof (pheader->frames[0]));
// mod->cache.data = pheader;
mod->flags = LittleLong (pinmodel->flags);
//
// endian-adjust and copy the data, starting with the alias model header
//
pmodel->boundingradius = LittleFloat (pinmodel->boundingradius);
pmodel->numskins = LittleLong (pinmodel->numskins);
pmodel->skinwidth = LittleLong (pinmodel->skinwidth);
pmodel->skinheight = LittleLong (pinmodel->skinheight);
if (pmodel->skinheight > MAX_LBM_HEIGHT)
Sys_Error ("model %s has a skin taller than %d", mod->name,
MAX_LBM_HEIGHT);
pmodel->numstverts = pmodel->numverts = LittleLong (pinmodel->numverts);
if (pmodel->numverts <= 0)
Sys_Error ("model %s has no vertices", mod->name);
if (pmodel->numverts > MAXALIASVERTS)
Sys_Error ("model %s has too many vertices", mod->name);
pmodel->numtris = LittleLong (pinmodel->numtris);
if (pmodel->numtris <= 0)
Sys_Error ("model %s has no triangles", mod->name);
pmodel->numframes = LittleLong (pinmodel->numframes);
pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
mod->synctype = LittleLong (pinmodel->synctype);
mod->numframes = pmodel->numframes;
for (i=0 ; i<3 ; i++)
{
pmodel->scale[i] = LittleFloat (pinmodel->scale[i]);
pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
}
numskins = pmodel->numskins;
numframes = pmodel->numframes;
if (pmodel->skinwidth & 0x03)
Sys_Error ("Mod_LoadAliasModel: \"%s\" skinwidth not multiple of 4", loadmodel->name);
pheader->model = (qbyte *)pmodel - (qbyte *)pheader;
//
// load the skins
//
skinsize = pmodel->skinheight * pmodel->skinwidth;
if (numskins < 1)
Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
pskintype = (daliasskintype_t *)&pinmodel[1];
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader;
for (i=0 ; i<numskins ; i++)
{
aliasskintype_t skintype;
skintype = LittleLong (pskintype->type);
pskindesc[i].type = skintype;
if (skintype == ALIAS_SKIN_SINGLE)
{
pskintype = (daliasskintype_t *)
SWMod_LoadAliasSkin (pskintype + 1,
&pskindesc[i].skin,
skinsize, pheader);
}
else
{
pskintype = (daliasskintype_t *)
SWMod_LoadAliasSkinGroup (pskintype + 1,
&pskindesc[i].skin,
skinsize, pheader);
}
}
//
// set base s and t vertices
//
pstverts = (mstvert_t *)&pmodel[1];
pinstverts = (dstvert_t *)pskintype;
pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader;
for (i=0 ; i<pmodel->numverts ; i++) //fixme: really, we only need to duplicate the onseem ones.
{
// put s and t in 16.16 format
pstverts[i].s = LittleLong (pinstverts[i].s) << 16;
pstverts[i].t = LittleLong (pinstverts[i].t) << 16;
if (LittleLong (pinstverts[i].onseam))
pstverts[i+pmodel->numverts].s = pstverts[i].s + ((pmodel->skinwidth>>1) << 16);
else
pstverts[i+pmodel->numverts].s = pstverts[i].s; //FIXME: prevent duplication.
pstverts[i+pmodel->numverts].t = pstverts[i].t;
}
pmodel->numstverts = pmodel->numverts*2;
//
// set up the triangles
//
ptri = (mtriangle_t *)&pstverts[pmodel->numstverts];
pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts];
pheader->triangles = (qbyte *)ptri - (qbyte *)pheader;
for (i=0 ; i<pmodel->numtris ; i++)
{
int j;
for (j=0 ; j<3 ; j++)
{
ptri[i].xyz_index[j] =
LittleLong (pintriangles[i].vertindex[j]);
if (LittleLong (pintriangles[i].facesfront))
ptri[i].st_index[j] = ptri[i].xyz_index[j];
else
ptri[i].st_index[j] = ptri[i].xyz_index[j]+pmodel->numverts;
}
}
//
// load the frames
//
if (numframes < 1)
Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris];
for (i=0 ; i<numframes ; i++)
{
aliasframetype_t frametype;
frametype = LittleLong (pframetype->type);
pheader->frames[i].type = frametype;
VectorCopy(pmodel->scale_origin, pheader->frames[i].scale_origin);
VectorCopy(pmodel->scale, pheader->frames[i].scale);
if (frametype == ALIAS_SINGLE)
{
pframetype = (daliasframetype_t *)
SWMod_LoadAliasFrame (pframetype + 1,
&pheader->frames[i].frame,
pmodel->numverts,
&pheader->frames[i].bboxmin,
&pheader->frames[i].bboxmax,
pheader, pheader->frames[i].name);
}
else
{
pframetype = (daliasframetype_t *)
SWMod_LoadAliasGroup (pframetype + 1,
&pheader->frames[i].frame,
pmodel->numverts,
&pheader->frames[i].bboxmin,
&pheader->frames[i].bboxmax,
pheader, pheader->frames[i].name);
}
}
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;
*/
VectorCopy (pmodel->scale_origin, mod->mins);
VectorMA (mod->mins, 255, pmodel->scale, mod->maxs);
//
// 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 (mod->cache.data, pheader, total);
Hunk_FreeToLowMark (start);
}
typedef struct
{
float scale[3]; // multiply qbyte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
dtrivertx_t verts[1]; // variable sized
} dmd2aliasframe_t;
void SWMod_LoadAlias2Model (model_t *mod, void *buffer)
{
int i, j;
mmdl_t *pmodel;
md2_t *pinmodel;
mstvert_t *pstverts;
dmd2stvert_t *pinstverts;
aliashdr_t *pheader;
mtriangle_t *ptri;
dmd2triangle_t *pintriangles;
int version, numframes, numskins;
int size;
dmd2aliasframe_t *pinframe;
maliasframedesc_t *poutframe;
maliasskindesc_t *pskindesc;
int skinsize;
int start, end, total;
dtrivertx_t *frameverts;
vec3_t mins, maxs;
if (!strcmp(loadmodel->name, "progs/player.mdl") ||
!strcmp(loadmodel->name, "progs/eyes.mdl")) {
unsigned short crc;
qbyte *p;
int len;
char st[40];
CRC_Init(&crc);
for (len = com_filesize, p = buffer; len; len--, p++)
CRC_ProcessByte(&crc, *p);
sprintf(st, "%d", (int) crc);
Info_SetValueForKey (cls.userinfo,
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
st, MAX_INFO_STRING);
if (cls.state >= ca_connected)
{
CL_SendClientCommand("setinfo %s %d",
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
(int)crc);
}
}
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);
//
// allocate space for a working header, plus all the data except the frames,
// skin and group info
//
size = sizeof (aliashdr_t) + (LittleLong (pinmodel->num_frames) - 1) *
sizeof (pheader->frames[0]) +
sizeof (mmdl_t) +
LittleLong (pinmodel->num_st) * sizeof (mstvert_t) +
LittleLong (pinmodel->num_tris) * sizeof (mtriangle_t);
pheader = Hunk_AllocName (size, loadname);
pmodel = (mmdl_t *) ((qbyte *)&pheader[1] +
(LittleLong (pinmodel->num_frames) - 1) *
sizeof (pheader->frames[0]));
mod->flags = 0;//LittleLong (pinmodel->flags);
//
// endian-adjust and copy the data, starting with the alias model header
//
pmodel->boundingradius = 100;//LittleFloat (pinmodel->boundingradius);
pmodel->numskins = LittleLong (pinmodel->num_skins);
pmodel->skinwidth = LittleLong (pinmodel->skinwidth);
pmodel->skinheight = LittleLong (pinmodel->skinheight);
if (pmodel->skinheight > MAX_LBM_HEIGHT)
Sys_Error ("model %s has a skin taller than %d", mod->name,
MAX_LBM_HEIGHT);
pmodel->numverts = LittleLong (pinmodel->num_xyz);
pmodel->numstverts = LittleLong (pinmodel->num_st);
if (pmodel->numverts <= 0)
Sys_Error ("model %s has no vertices", mod->name);
if (pmodel->numverts > MAXALIASVERTS)
Sys_Error ("model %s has too many vertices", mod->name);
pmodel->numtris = LittleLong (pinmodel->num_tris);
if (pmodel->numtris <= 0)
Sys_Error ("model %s has no triangles", mod->name);
pmodel->numframes = LittleLong (pinmodel->num_frames);
pmodel->size = 1000;//LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
mod->synctype = 1;//LittleLong (pinmodel->synctype);
mod->numframes = pmodel->numframes;
for (i=0 ; i<3 ; i++)
{
pmodel->scale[i] = 0;
pmodel->scale_origin[i] = 0;
pmodel->eyeposition[i] = 0;
}
numskins = pmodel->numskins;
numframes = pmodel->numframes;
if (pmodel->skinwidth & 0x03)
Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");
pheader->model = (qbyte *)pmodel - (qbyte *)pheader;
//
// set base s and t vertices
//
pstverts = (mstvert_t *)&pmodel[1];
pinstverts = (dmd2stvert_t *)((qbyte *)pinmodel + LittleLong(pinmodel->ofs_st));
pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader;
for (i=0 ; i<pmodel->numstverts ; i++)
{
// put s and t in 16.16 format
pstverts[i].s = LittleShort (pinstverts[i].s)<<16;
pstverts[i].t = LittleShort (pinstverts[i].t)<<16;
}
//
// set up the triangles
//
ptri = (mtriangle_t *)&pstverts[pmodel->numstverts];
pintriangles = (dmd2triangle_t *)((qbyte *)pinmodel + LittleLong(pinmodel->ofs_tris));
pheader->triangles = (qbyte *)ptri - (qbyte *)pheader;
for (i=0 ; i<pmodel->numtris ; i++)
{
int j;
for (j=0 ; j<3 ; j++)
{
ptri[i].xyz_index[j] = LittleShort (pintriangles[i].xyz_index[j]);
ptri[i].st_index[j] = LittleShort (pintriangles[i].st_index[j]);
}
}
//
// load the frames
//
if (numframes < 1)
Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
for (i=0 ; i<numframes ; i++)
{
pinframe = (dmd2aliasframe_t *) ((qbyte *)pinmodel
+ LittleLong(pinmodel->ofs_frames) + i * LittleLong(pinmodel->framesize));
poutframe = &pheader->frames[i];
memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
for (j=0 ; j<3 ; j++)
{
poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
poutframe->scale_origin[j] = LittleFloat (pinframe->translate[j]);
}
VectorCopy (poutframe->scale_origin, mins); //work out precise size.
VectorMA (mins, 255, poutframe->scale, maxs);
poutframe->bboxmin.v[0] = poutframe->bboxmin.v[1] = poutframe->bboxmin.v[2] = 0;
poutframe->bboxmax.v[0] = poutframe->bboxmax.v[1] = poutframe->bboxmax.v[2] = 255;
if (i == 0)
{
VectorCopy (mins, mod->mins); //first frame - nothing to compare against.
VectorCopy (maxs, mod->maxs);
}
else
{
for (j = 0; j < 3; j++)
{
if (mod->mins[j] > mins[j]) //and make sure that the biggest ends up as the model size.
mod->mins[j] = mins[j];
if (mod->maxs[j] < maxs[j])
mod->maxs[j] = maxs[j];
}
}
// verts are all 8 bit, so no swapping needed
frameverts = Hunk_AllocName(pmodel->numverts*sizeof(dtrivertx_t), loadname);
poutframe->frame = (qbyte *)frameverts - (qbyte *)pheader;
for (j = 0; j < pmodel->numverts; j++)
{
frameverts[j].lightnormalindex = pinframe->verts[j].lightnormalindex;
frameverts[j].v[0] = pinframe->verts[j].v[0];
frameverts[j].v[1] = pinframe->verts[j].v[1];
frameverts[j].v[2] = pinframe->verts[j].v[2];
}
}
VectorCopy (mod->mins, pmodel->scale_origin); //work out global scale
pmodel->scale[0] = (mod->maxs[0] - mod->mins[0])/255;
pmodel->scale[1] = (mod->maxs[1] - mod->mins[1])/255;
pmodel->scale[2] = (mod->maxs[2] - mod->mins[2])/255;
{
int width;
int height;
int j;
qbyte *buffer;
qbyte *texture;
char *skinnames;
qbyte *skin;
pmodel->numskins = 0;
skinnames = Hunk_AllocName(numskins*MAX_SKINNAME, loadname);
memcpy(skinnames, (qbyte *)pinmodel + LittleLong(pinmodel->ofs_skins), numskins*MAX_SKINNAME);
skinsize = pmodel->skinheight * pmodel->skinwidth;
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader;
for (i=0 ; i<numskins ; i++, skinnames+=MAX_SKINNAME)
{
buffer = COM_LoadTempFile(skinnames);
if (!buffer)
{
Con_Printf("Skin %s not found\n", skinnames);
continue;
}
texture = ReadPCXFile(buffer, com_filesize, &width, &height);
// BZ_Free(buffer);
if (!texture)
{
Con_Printf("Skin %s not a pcx\n", skinnames);
continue;
}
if (width != pmodel->skinwidth || height != pmodel->skinheight) //FIXME: scale
{
BZ_Free(texture);
Con_Printf("Skin %s not same size as model specifies it should be\n", skinnames);
continue;
}
skin = Hunk_AllocName(skinsize*r_pixbytes, loadname);
if (r_pixbytes == 4)
{
for (j = 0; j < skinsize*4; j+=4)
{
skin[j+0] = texture[j+2];
skin[j+1] = texture[j+1];
skin[j+2] = texture[j+0];
skin[j+3] = texture[j+3];
}
}
else
{
for (j = 0; j < skinsize; j++) //you know when you've been palettized.
{
skin[j+0] = GetPalette(texture[j*4+0], texture[j*4+1], texture[j*4+2]);
}
}
BZ_Free(texture);
pskindesc[pmodel->numskins].type = ALIAS_SKIN_SINGLE;
pskindesc[pmodel->numskins].skin = (qbyte *)skin - (qbyte *)pheader;
pmodel->numskins++;
}
}
mod->type = mod_alias;
//
// 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 (mod->cache.data, pheader, total);
Hunk_FreeToLowMark (start);
}
//structures from Tenebrae
typedef struct {
int ident;
int version;
char name[MAX_QPATH];
int flags; //Does anyone know what these are?
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames;
int ofsTags;
int ofsSurfaces;
int ofsEnd;
} md3Header_t;
//then has header->numFrames of these at header->ofs_Frames
typedef struct md3Frame_s {
vec3_t bounds[2];
vec3_t localOrigin;
float radius;
char name[16];
} md3Frame_t;
//there are header->numSurfaces of these at header->ofsSurfaces, following from ofsEnd
typedef struct {
int ident; //
char name[MAX_QPATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
//at surf+surf->ofsXyzNormals
typedef struct {
short xyz[3];
unsigned short normal;
} md3XyzNormal_t;
//surf->numTriangles at surf+surf->ofsTriangles
typedef struct {
int indexes[3];
} md3Triangle_t;
//surf->numVerts at surf+surf->ofsSt
typedef struct {
float s;
float t;
} md3St_t;
typedef struct {
char name[MAX_QPATH];
int shaderIndex;
} md3Shader_t;
//End of Tenebrae 'assistance'
typedef struct {
char name[MAX_QPATH];
vec3_t org;
float ang[3][3];
} md3tag_t;
void SWMod_LoadAlias3Model (model_t *mod, void *buffer)
{
int i, j;
mmdl_t *pmodel;
aliashdr_t *pheader;
md3Header_t *pinmodel;
mstvert_t *pstverts;
md3St_t *pinstverts;
mtriangle_t *ptri;
md3Triangle_t *pintriangles;
int version, numframes, numskins;
int size;
md3Frame_t *pinframe;
maliasframedesc_t *poutframe;
maliasskindesc_t *pskindesc;
int skinsize;
int start, end, total;
dtrivertx_t *frameverts;
md3XyzNormal_t *pinverts;
md3Surface_t *surface;
vec3_t mins, maxs;
if (!strcmp(loadmodel->name, "progs/player.mdl") ||
!strcmp(loadmodel->name, "progs/eyes.mdl")) {
unsigned short crc;
qbyte *p;
int len;
char st[40];
CRC_Init(&crc);
for (len = com_filesize, p = buffer; len; len--, p++)
CRC_ProcessByte(&crc, *p);
sprintf(st, "%d", (int) crc);
Info_SetValueForKey (cls.userinfo,
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
st, MAX_INFO_STRING);
if (cls.state >= ca_connected)
{
CL_SendClientCommand("setinfo %s %d",
!strcmp(loadmodel->name, "progs/player.mdl") ? pmodel_name : emodel_name,
(int)crc);
}
}
start = Hunk_LowMark ();
pinmodel = (md3Header_t *)buffer;
version = LittleLong (pinmodel->version);
// if (version != MD3ALIAS_VERSION)
// Sys_Error ("%s has wrong version number (%i should be %i)",
// mod->name, version, MD3ALIAS_VERSION);
surface = (md3Surface_t*)((qbyte *)pinmodel + pinmodel->ofsSurfaces);
//
// 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]) +
sizeof (mmdl_t) +
LittleLong (surface->numVerts) * sizeof (mstvert_t) +
LittleLong (surface->numTriangles) * sizeof (mtriangle_t);
pheader = Hunk_AllocName (size, loadname);
pmodel = (mmdl_t *) ((qbyte *)&pheader[1] +
(LittleLong (surface->numFrames) - 1) *
sizeof (pheader->frames[0]));
mod->flags = 0;//LittleLong (pinmodel->flags);
//
// endian-adjust and copy the data, starting with the alias model header
//
pmodel->boundingradius = 100;//LittleFloat (pinmodel->boundingradius);
pmodel->numskins = LittleLong (surface->numShaders);
// pmodel->skinwidth = LittleLong (pinmodel->skinwidth); //fill in later.
// pmodel->skinheight = LittleLong (pinmodel->skinheight);
if (pmodel->skinheight > MAX_LBM_HEIGHT)
Sys_Error ("model %s has a skin taller than %d", mod->name,
MAX_LBM_HEIGHT);
pmodel->numverts = LittleLong (surface->numVerts);
pmodel->numstverts = LittleLong (surface->numVerts);
if (surface->numVerts <= 0)
Sys_Error ("model %s has no vertices", mod->name);
if (pmodel->numverts > MAXALIASVERTS)
Sys_Error ("model %s has too many vertices", mod->name);
pmodel->numtris = LittleLong (surface->numTriangles);
if (pmodel->numtris <= 0)
Sys_Error ("model %s has no triangles", mod->name);
pmodel->numframes = LittleLong (surface->numFrames);
pmodel->size = 1000;//LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
mod->synctype = 1;//LittleLong (pinmodel->synctype);
mod->numframes = pmodel->numframes;
for (i=0 ; i<3 ; i++)
{
pmodel->scale[i] = 0;
pmodel->scale_origin[i] = 0;
pmodel->eyeposition[i] = 0;
}
numskins = pmodel->numskins;
numframes = pmodel->numframes;
pheader->model = (qbyte *)pmodel - (qbyte *)pheader;
{
int width;
int height;
int j;
qbyte *buffer;
qbyte *texture;
md3Shader_t *pinskin;
qbyte *skin;
pmodel->numskins = 0;
pinskin = (md3Shader_t *)((qbyte *)surface + surface->ofsShaders);
skinsize = pmodel->skinheight * pmodel->skinwidth;
pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
loadname);
pheader->skindesc = (qbyte *)pskindesc - (qbyte *)pheader;
for (i=0 ; i<numskins ; i++, pinskin++)
{
buffer = COM_LoadMallocFile(pinskin->name);
if (!buffer)
{
char altname[256];
strcpy(altname, mod->name); //backup
strcpy(COM_SkipPath(altname), COM_SkipPath(pinskin->name));
buffer = COM_LoadMallocFile(altname);
}
if (!buffer)
{
Con_Printf("Skin %s not found\n", pinskin->name);
continue;
}
texture = ReadTargaFile(buffer, com_filesize, &width, &height, false);
#ifdef AVAIL_JPEGLIB
if (!texture)
texture = ReadJPEGFile(buffer, com_filesize, &width, &height);
#endif
#ifdef AVAIL_PNGLIB
if (!texture)
texture = ReadPNGFile(buffer, com_filesize, &width, &height);
#endif
if (!texture)
texture = ReadPCXFile(buffer, com_filesize, &width, &height);
BZ_Free(buffer);
if (!texture)
{
Con_Printf("Skin %s filetype not recognised\n", pinskin->name);
continue;
}
if (!pmodel->numskins) //this is the first skin.
{
pmodel->skinwidth = width;
pmodel->skinheight = height;
}
skinsize = width*height;
if (width != pmodel->skinwidth || height != pmodel->skinheight) //FIXME: scale
{
BZ_Free(texture);
Con_Printf("Skin %s not same size as model specifies it should be\n", pinskin->name);
continue;
}
skin = Hunk_AllocName(skinsize*r_pixbytes, loadname);
if (r_pixbytes == 4)
{
for (j = 0; j < skinsize*4; j+=4)
{
skin[j+0] = texture[j+2];
skin[j+1] = texture[j+1];
skin[j+2] = texture[j+0];
skin[j+3] = texture[j+3];
}
}
else
{
for (j = 0; j < skinsize; j++) //you know when you've been palettized.
{
skin[j+0] = GetPalette(texture[j*4+0], texture[j*4+1], texture[j*4+2]);
}
}
BZ_Free(texture);
pskindesc[pmodel->numskins].type = ALIAS_SKIN_SINGLE;
pskindesc[pmodel->numskins].skin = (qbyte *)skin - (qbyte *)pheader;
pmodel->numskins++;
}
}
if (!pmodel->numskins)
Con_Printf("model %s has no skins\n", loadmodel->name);
if (pmodel->skinwidth & 0x03)
Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");
//
// set base s and t vertices
//
pstverts = (mstvert_t *)&pmodel[1];
pinstverts = (md3St_t *)((qbyte *)surface + LittleLong(surface->ofsSt));
pheader->stverts = (qbyte *)pstverts - (qbyte *)pheader;
for (i=0 ; i<pmodel->numstverts ; i++)
{
// put s and t in 16.16 format
pstverts[i].s = (int)(LittleFloat (pinstverts[i].s)*pmodel->skinwidth)<<16;
pstverts[i].t = (int)(LittleFloat (pinstverts[i].t)*pmodel->skinheight)<<16;
}
//
// set up the triangles
//
ptri = (mtriangle_t *)&pstverts[pmodel->numstverts];
pintriangles = (md3Triangle_t *)((qbyte *)surface + LittleLong(surface->ofsTriangles));
pheader->triangles = (qbyte *)ptri - (qbyte *)pheader;
for (i=0 ; i<pmodel->numtris ; i++)
{
int j;
for (j=0 ; j<3 ; j++)
{
ptri[i].st_index[j] = ptri[i].xyz_index[j] = LittleLong (pintriangles[i].indexes[j]);
}
}
//
// load the frames
//
if (numframes < 1)
Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
pinverts = (md3XyzNormal_t *)((qbyte *)surface + surface->ofsXyzNormals);
for (i=0 ; i<numframes ; i++)
{
pinframe = (md3Frame_t *) ((qbyte *)pinmodel
+ LittleLong(pinmodel->ofsFrames) + i * sizeof(md3Frame_t));
poutframe = &pheader->frames[i];
memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
for (j=0 ; j<3 ; j++)
{
poutframe->scale_origin[j] = LittleFloat (pinframe->bounds[0][j]);
poutframe->scale[j] = (LittleFloat (pinframe->bounds[1][j])-poutframe->scale_origin[j])/255;
}
VectorCopy (poutframe->scale_origin, mins); //work out precise size.
VectorMA (mins, 255, poutframe->scale, maxs);
poutframe->bboxmin.v[0] = poutframe->bboxmin.v[1] = poutframe->bboxmin.v[2] = 0;
poutframe->bboxmax.v[0] = poutframe->bboxmax.v[1] = poutframe->bboxmax.v[2] = 255;
if (i == 0)
{
VectorCopy (mins, mod->mins); //first frame - nothing to compare against.
VectorCopy (maxs, mod->maxs);
}
else
{
for (j = 0; j < 3; j++)
{
if (mod->mins[j] > mins[j]) //and make sure that the biggest ends up as the model size.
mod->mins[j] = mins[j];
if (mod->maxs[j] < maxs[j])
mod->maxs[j] = maxs[j];
}
}
// verts are all 8 bit, so no swapping needed
frameverts = Hunk_AllocName(pmodel->numverts*sizeof(dtrivertx_t), loadname);
poutframe->frame = (qbyte *)frameverts - (qbyte *)pheader;
for (j = 0; j < pmodel->numverts; j++)
{
frameverts[j].lightnormalindex = LittleShort(pinverts->normal)/256;
//scale down to 0 - 255 within the scaleorigin and scaleorigin+scale*255
// i/64 = scaleorigin+scale*o
// i/64-scaleorigin = scale*o
// i/64-scaleorigin/scale = 0
frameverts[j].v[0] = ((double)LittleShort(pinverts[j].xyz[0])/64.0-poutframe->scale_origin[0])/(poutframe->scale[0]);
frameverts[j].v[1] = ((double)LittleShort(pinverts[j].xyz[1])/64.0-poutframe->scale_origin[1])/(poutframe->scale[1]);
frameverts[j].v[2] = ((double)LittleShort(pinverts[j].xyz[2])/64.0-poutframe->scale_origin[2])/(poutframe->scale[2]);
}
pinverts += pmodel->numverts;
}
VectorCopy (mod->mins, pmodel->scale_origin); //work out global scale
pmodel->scale[0] = (mod->maxs[0] - mod->mins[0])/255;
pmodel->scale[1] = (mod->maxs[1] - mod->mins[1])/255;
pmodel->scale[2] = (mod->maxs[2] - mod->mins[2])/255;
mod->type = mod_alias;
//
// 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 (mod->cache.data, pheader, total);
Hunk_FreeToLowMark (start);
#ifdef RGLQUAKE
mod->flags = Mod_ReadFlagsFromMD1(mod->name, 0);
#endif
}
//=============================================================================
/*
=================
Mod_LoadSpriteFrame
=================
*/
void * SWMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int version)
{
dspriteframe_t *pinframe;
mspriteframe_t *pspriteframe;
int i, width, height, size, origin[2];
pinframe = (dspriteframe_t *)pin;
width = LittleLong (pinframe->width);
height = LittleLong (pinframe->height);
size = width * height;
pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes,
loadname);
Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size);
*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];
if (r_pixbytes == 1)
{
qbyte *ppixout, *ppixin;
if (version == SPRITE32_VERSION)
{ //downgrade quality
ppixin = (unsigned char *)(pinframe + 1);
ppixout = (unsigned char *)&pspriteframe->pixels[0];
for (i=0 ; i<size ; i++)
{
if (ppixin[i*4+3] < 128)
ppixout[i] = 255; //transparent.
else
ppixout[i] = GetPalette(ppixin[i*4], ppixin[i*4+1], ppixin[i*4+2]);
}
}
else
Q_memcpy (&pspriteframe->pixels[0], (qbyte *)(pinframe + 1), size);
}
else if (r_pixbytes == 2)
{
qbyte *ppixin;
unsigned short *p16out;
if (version == SPRITE32_VERSION)
{ //downgrade quality
ppixin = (unsigned char *)(pinframe + 1);
p16out = (unsigned short *)&pspriteframe->pixels[0];
for (i=0 ; i<size ; i++)
{
if (ppixin[i*4+3] < 128)
p16out[i] = 0xffff; //transparent.
else
p16out[i] = ((ppixin[i*4]*32/255)<<10) + ((ppixin[i*4+1]*32/255)<<5) + ((ppixin[i*4+2]*32/255)<<0);
}
}
else
{
ppixin = (unsigned char *)(pinframe + 1);
p16out = (unsigned short *)&pspriteframe->pixels[0];
for (i=0 ; i<size ; i++)
{
if (ppixin[i] == 255)
p16out[i] = 0xffff; //transparent.
else
p16out[i] = d_8to16table[ppixin[i]];
}
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32out;
if (version == SPRITE32_VERSION)
{ //copy accross
unsigned int *p32in;
p32in = (unsigned int *)(pinframe + 1);
p32out = (unsigned int *)&pspriteframe->pixels[0];
for (i=0 ; i<size ; i++)
p32out[i] = p32in[i];
}
else
{ //upgrade
qbyte *ppixin;
ppixin = (qbyte *)(pinframe + 1);
p32out = (unsigned int *)&pspriteframe->pixels[0];
for (i=0 ; i<size ; i++)
p32out[i] = d_8to32table[ppixin[i]];
}
}
else
{
Sys_Error ("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n",
r_pixbytes);
}
return (void *)((qbyte *)pinframe + sizeof (dspriteframe_t) + size);
}
/*
=================
Mod_LoadSpriteGroup
=================
*/
void * SWMod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int version)
{
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 = 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 = Hunk_AllocName (numframes * sizeof (float), loadname);
pspritegroup->intervals = poutintervals;
for (i=0 ; i<numframes ; i++)
{
*poutintervals = LittleFloat (pin_intervals->interval);
if (*poutintervals <= 0.0)
Sys_Error ("Mod_LoadSpriteGroup: interval<=0");
poutintervals++;
pin_intervals++;
}
ptemp = (void *)pin_intervals;
for (i=0 ; i<numframes ; i++)
{
ptemp = SWMod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], version);
}
return ptemp;
}
/*
=================
Mod_LoadSpriteModel
=================
*/
void SWMod_LoadSpriteModel (model_t *mod, void *buffer)
{
int i;
int version;
dsprite_t *pin;
msprite_t *psprite;
int numframes;
int size;
dspriteframetype_t *pframetype;
pin = (dsprite_t *)buffer;
version = LittleLong (pin->version);
if (version != SPRITE32_VERSION)
if (version != SPRITE_VERSION)
Sys_Error ("%s has wrong version number "
"(%i should be %i)", mod->name, version, SPRITE_VERSION);
numframes = LittleLong (pin->numframes);
size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames);
psprite = Hunk_AllocName (size, loadname);
mod->cache.data = psprite;
psprite->type = LittleLong (pin->type);
psprite->maxwidth = LittleLong (pin->width);
psprite->maxheight = LittleLong (pin->height);
psprite->beamlength = LittleFloat (pin->beamlength);
mod->synctype = LittleLong (pin->synctype);
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);
mod->numframes = numframes;
pframetype = (dspriteframetype_t *)(pin + 1);
for (i=0 ; i<numframes ; i++)
{
spriteframetype_t frametype;
frametype = LittleLong (pframetype->type);
psprite->frames[i].type = frametype;
if (frametype == SPR_SINGLE)
{
pframetype = (dspriteframetype_t *)
SWMod_LoadSpriteFrame (pframetype + 1,
&psprite->frames[i].frameptr, version);
}
else
{
pframetype = (dspriteframetype_t *)
SWMod_LoadSpriteGroup (pframetype + 1,
&psprite->frames[i].frameptr, version);
}
}
mod->type = mod_sprite;
}
void SWMod_LoadSprite2Model (model_t *mod, void *buffer)
{
int i, j;
int version;
dmd2sprite_t *pin;
msprite_t *psprite;
int numframes;
int size;
dmd2sprframe_t *pframetype;
mspriteframe_t *frame;
float origin[2];
int width;
int height;
qbyte *framefile;
qbyte *framedata;
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);
numframes = LittleLong (pin->numframes);
size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames);
psprite = Hunk_AllocName (size, loadname);
mod->cache.data = psprite;
psprite->type = SPR_VP_PARALLEL;
psprite->maxwidth = 1;
psprite->maxheight = 1;
psprite->beamlength = 1;
mod->synctype = 0;
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);
mod->numframes = 0;
pframetype = pin->frames;
for (i=0 ; i<numframes ; i++)
{
psprite->frames[mod->numframes].type = SPR_SINGLE;
width = LittleLong(pframetype->width);
height = LittleLong(pframetype->height);
framefile = COM_LoadMallocFile(pframetype->name);
if (!framefile)
{
Con_Printf("Couldn't open sprite frame %s\n", pframetype->name);
continue; //skip this frame - is this a bad idea?
}
framedata = ReadPCXFile(framefile, com_filesize, &width, &height);
BZ_Free(framefile);
if (!framedata)
{
Con_Printf("Sprite frame %s is not a pcx\n", pframetype->name);
continue; //skip this frame - is this a bad idea?
}
frame = psprite->frames[mod->numframes].frameptr = Hunk_AllocName(sizeof(mspriteframe_t)+width*r_pixbytes*height, loadname);
frame->width = width;
frame->height = height;
origin[0] = LittleLong (pframetype->origin_x);
origin[1] = LittleLong (pframetype->origin_y);
frame->up = -origin[1];
frame->down = frame->height - origin[1];
frame->left = -origin[0];
frame->right = frame->width - origin[0];
if (r_pixbytes == 4)
{
for (j = 0; j < width*height; j++)
{
frame->pixels[j*4+0] = framedata[j*4+2];
frame->pixels[j*4+1] = framedata[j*4+1];
frame->pixels[j*4+2] = framedata[j*4+0];
frame->pixels[j*4+3] = framedata[j*4+3];
}
}
else
{
for (j = 0; j < width*height; j++)
{
if (!framedata[j*4+3]) //make sure
frame->pixels[j] = 255;
else
frame->pixels[j] = GetPalette(framedata[j*4+0], framedata[j*4+1], framedata[j*4+2]);
}
}
BZ_Free(framedata);
mod->numframes++;
}
mod->type = mod_sprite;
}
//=============================================================================
#endif
/*
================
Mod_Print
================
*/
void SWMod_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);
}
}