mirror of
https://github.com/FWGS/xash3d-fwgs
synced 2024-11-22 01:45:19 +01:00
242 lines
6.9 KiB
C
242 lines
6.9 KiB
C
/*
|
|
mod_alias.c - alias model loading
|
|
Copyright (C) 2010 Uncle Mike
|
|
Copyright (C) 2024 Alibek Omarov
|
|
|
|
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 3 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.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "alias.h"
|
|
#if !XASH_DEDICATED
|
|
#include "ref_common.h"
|
|
#endif // XASH_DEDICATED
|
|
#include "mod_local.h"
|
|
#include "xash3d_mathlib.h"
|
|
|
|
static int g_posenum = 0;
|
|
static const trivertex_t *g_poseverts[MAXALIASFRAMES];
|
|
|
|
static const void *Mod_LoadAliasFrame( const daliasframe_t *pdaliasframe, maliasframedesc_t *frame, const aliashdr_t *aliashdr )
|
|
{
|
|
const trivertex_t *pinframe;
|
|
int i;
|
|
|
|
Q_strncpy( frame->name, pdaliasframe->name, sizeof( frame->name ));
|
|
frame->firstpose = g_posenum;
|
|
frame->numposes = 1;
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
|
|
frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i];
|
|
}
|
|
|
|
pinframe = (const trivertex_t *)(pdaliasframe + 1);
|
|
|
|
g_poseverts[g_posenum] = pinframe;
|
|
g_posenum++;
|
|
|
|
pinframe += aliashdr->numverts;
|
|
|
|
return (void *)pinframe;
|
|
}
|
|
|
|
static const void *Mod_LoadAliasGroup( const daliasgroup_t *pingroup, maliasframedesc_t *frame, const aliashdr_t *aliashdr )
|
|
{
|
|
const daliasinterval_t *pin_intervals;
|
|
const void *ptemp;
|
|
int i, numframes;
|
|
|
|
frame->firstpose = g_posenum;
|
|
frame->numposes = numframes = pingroup->numframes;
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
|
|
frame->bboxmax.v[i] = pingroup->bboxmax.v[i];
|
|
}
|
|
|
|
pin_intervals = (const daliasinterval_t *)(pingroup + 1);
|
|
|
|
// all the intervals are always equal 0.1 so we don't care about them
|
|
frame->interval = pin_intervals->interval;
|
|
pin_intervals += numframes;
|
|
ptemp = (void *)pin_intervals;
|
|
|
|
for( i = 0; i < numframes; i++ )
|
|
{
|
|
g_poseverts[g_posenum] = (const trivertex_t *)((const daliasframe_t *)ptemp + 1);
|
|
ptemp = g_poseverts[g_posenum] + aliashdr->numverts;
|
|
g_posenum++;
|
|
}
|
|
|
|
return ptemp;
|
|
}
|
|
|
|
static void Mod_CalcAliasBounds( model_t *mod, const aliashdr_t *aliashdr )
|
|
{
|
|
int i, j, k;
|
|
float radius;
|
|
float dist;
|
|
vec3_t v;
|
|
|
|
ClearBounds( mod->mins, mod->maxs );
|
|
radius = 0.0f;
|
|
|
|
// process verts
|
|
for( i = 0; i < aliashdr->numposes; i++ )
|
|
{
|
|
for( j = 0; j < aliashdr->numverts; j++ )
|
|
{
|
|
for( k = 0; k < 3; k++ )
|
|
v[k] = g_poseverts[i][j].v[k] * aliashdr->scale[k] + aliashdr->scale_origin[k];
|
|
|
|
AddPointToBounds( v, mod->mins, mod->maxs );
|
|
dist = DotProduct( v, v );
|
|
|
|
if( radius < dist )
|
|
radius = dist;
|
|
}
|
|
}
|
|
|
|
mod->radius = sqrt( radius );
|
|
}
|
|
|
|
static const void *Mod_LoadAllSkins( model_t *mod, int numskins, const daliasskintype_t *pskintype, const aliashdr_t *aliashdr )
|
|
{
|
|
int i, size;
|
|
|
|
if(( numskins < 1 ) || ( numskins > MAX_SKINS ))
|
|
Host_Error( "%s: Invalid # of skins: %d\n", __func__, numskins );
|
|
|
|
size = aliashdr->skinwidth * aliashdr->skinheight;
|
|
|
|
// just skipping textures, renderer will take care of them later
|
|
for( i = 0; i < numskins; i++ )
|
|
{
|
|
if( pskintype->type == ALIAS_SKIN_SINGLE )
|
|
{
|
|
const byte *ptexture = (const byte *)&pskintype[1];
|
|
|
|
pskintype = (const daliasskintype_t *)( ptexture + size );
|
|
}
|
|
else
|
|
{
|
|
const daliasskingroup_t *pinskingroup = (const daliasskingroup_t *)&pskintype[1];
|
|
const daliasskininterval_t *pinskinintervals = (const daliasskininterval_t *)&pinskingroup[1];
|
|
const byte *ptexture = (const byte *)&pinskinintervals[pinskingroup->numskins];
|
|
|
|
pskintype = (const daliasskintype_t *)( ptexture + size );
|
|
}
|
|
}
|
|
|
|
return pskintype;
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
Mod_LoadAliasModel
|
|
|
|
load alias model
|
|
====================
|
|
*/
|
|
void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
|
|
{
|
|
const daliasframetype_t *pframetype;
|
|
const daliasskintype_t *pskintype;
|
|
const dtriangle_t *pintriangles;
|
|
const daliashdr_t *pinmodel;
|
|
const stvert_t *pinstverts;
|
|
aliashdr_t *m_pAliasHeader;
|
|
size_t size;
|
|
char poolname[MAX_VA_STRING];
|
|
int i;
|
|
|
|
if( loaded ) *loaded = false;
|
|
pinmodel = (const daliashdr_t *)buffer;
|
|
i = pinmodel->version;
|
|
|
|
if( i != ALIAS_VERSION )
|
|
{
|
|
Con_DPrintf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION );
|
|
return;
|
|
}
|
|
|
|
if( pinmodel->numverts <= 0 || pinmodel->numtris <= 0 || pinmodel->numframes <= 0 )
|
|
return; // how is it possible to make that?
|
|
|
|
Q_snprintf( poolname, sizeof( poolname ), "^2%s^7", mod->name );
|
|
mod->mempool = Mem_AllocPool( poolname );
|
|
|
|
size = sizeof( aliashdr_t ) + (pinmodel->numframes - 1) * sizeof( maliasframedesc_t );
|
|
mod->cache.data = m_pAliasHeader = Mem_Calloc( mod->mempool, size );
|
|
|
|
// endian-adjust and copy the data, starting with the alias model header
|
|
m_pAliasHeader->numverts = pinmodel->numverts;
|
|
|
|
if( m_pAliasHeader->numverts > MAXALIASVERTS )
|
|
{
|
|
Con_DPrintf( S_ERROR "model %s has too many vertices\n", mod->name );
|
|
return;
|
|
}
|
|
|
|
mod->flags = pinmodel->flags; // share effects flags
|
|
m_pAliasHeader->boundingradius = pinmodel->boundingradius;
|
|
m_pAliasHeader->numskins = pinmodel->numskins;
|
|
m_pAliasHeader->skinwidth = pinmodel->skinwidth;
|
|
m_pAliasHeader->skinheight = pinmodel->skinheight;
|
|
m_pAliasHeader->numtris = pinmodel->numtris;
|
|
mod->numframes = m_pAliasHeader->numframes = pinmodel->numframes;
|
|
m_pAliasHeader->size = pinmodel->size;
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
m_pAliasHeader->scale[i] = pinmodel->scale[i];
|
|
m_pAliasHeader->scale_origin[i] = pinmodel->scale_origin[i];
|
|
m_pAliasHeader->eyeposition[i] = pinmodel->eyeposition[i];
|
|
}
|
|
|
|
// load the skins
|
|
pskintype = (const daliasskintype_t *)&pinmodel[1];
|
|
pskintype = Mod_LoadAllSkins( mod, m_pAliasHeader->numskins, pskintype, m_pAliasHeader );
|
|
// will be done at renderer side...
|
|
|
|
// load base s and t vertices
|
|
pinstverts = (const stvert_t *)pskintype;
|
|
// will be done at renderer side...
|
|
|
|
// load triangle lists
|
|
pintriangles = (const dtriangle_t *)&pinstverts[m_pAliasHeader->numverts];
|
|
// will be done at renderer side
|
|
|
|
// load the frames
|
|
pframetype = (const daliasframetype_t *)&pintriangles[m_pAliasHeader->numtris];
|
|
m_pAliasHeader->pposeverts = g_poseverts; // store the pointer to be accessed by renderer
|
|
g_posenum = 0;
|
|
|
|
for( i = 0; i < m_pAliasHeader->numframes; i++ )
|
|
{
|
|
aliasframetype_t frametype = pframetype->type;
|
|
|
|
if( frametype == ALIAS_SINGLE )
|
|
pframetype = (const daliasframetype_t *)Mod_LoadAliasFrame((const daliasframe_t *)&pframetype[1], &m_pAliasHeader->frames[i], m_pAliasHeader );
|
|
else pframetype = (const daliasframetype_t *)Mod_LoadAliasGroup(( const daliasgroup_t *)&pframetype[1], &m_pAliasHeader->frames[i], m_pAliasHeader );
|
|
}
|
|
|
|
m_pAliasHeader->numposes = g_posenum;
|
|
Mod_CalcAliasBounds( mod, m_pAliasHeader );
|
|
mod->type = mod_alias;
|
|
|
|
if( loaded ) *loaded = true; // done
|
|
}
|