2017-03-14 22:00:00 +01:00
|
|
|
/*
|
|
|
|
gl_alias.c - alias model renderer
|
|
|
|
Copyright (C) 2017 Uncle Mike
|
|
|
|
|
|
|
|
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 "client.h"
|
|
|
|
#include "mathlib.h"
|
|
|
|
#include "const.h"
|
|
|
|
#include "r_studioint.h"
|
|
|
|
#include "triangleapi.h"
|
|
|
|
#include "alias.h"
|
|
|
|
#include "pm_local.h"
|
|
|
|
#include "gl_local.h"
|
|
|
|
#include "cl_tent.h"
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
extern cvar_t r_shadows;
|
|
|
|
|
|
|
|
#define NUMVERTEXNORMALS 162
|
|
|
|
#define SHADEDOT_QUANT 16
|
|
|
|
|
|
|
|
float r_avertexnormals[NUMVERTEXNORMALS][3] = {
|
|
|
|
#include "anorms.h"
|
|
|
|
};
|
|
|
|
|
|
|
|
// precalculated dot products for quantized angles
|
|
|
|
float r_avertexnormal_dots[SHADEDOT_QUANT][256] =
|
|
|
|
#include "anorm_dots.h"
|
|
|
|
;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
double time;
|
|
|
|
double frametime;
|
|
|
|
int framecount; // studio framecount
|
|
|
|
} alias_draw_state_t;
|
|
|
|
|
|
|
|
static alias_draw_state_t g_alias; // global alias state
|
|
|
|
|
2017-03-14 22:00:00 +01:00
|
|
|
/*
|
|
|
|
=================================================================
|
|
|
|
|
|
|
|
ALIAS MODEL DISPLAY LIST GENERATION
|
|
|
|
|
|
|
|
=================================================================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
static model_t *aliasmodel;
|
|
|
|
static aliashdr_t *paliashdr;
|
|
|
|
static aliashdr_t *pheader;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
static mtrivertex_t *g_poseverts[MAXALIASFRAMES];
|
|
|
|
static mtriangle_t g_triangles[MAXALIASTRIS];
|
|
|
|
static stvert_t g_stverts[MAXALIASVERTS];
|
|
|
|
static qboolean g_used[8192];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// a pose is a single set of vertexes. a frame may be
|
|
|
|
// an animating sequence of poses
|
|
|
|
int g_posenum;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// the command list holds counts and s/t values that are valid for
|
|
|
|
// every frame
|
2017-06-23 23:00:00 +02:00
|
|
|
static int g_commands[8192];
|
|
|
|
static int g_numcommands;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// all frames will have their vertexes rearranged and expanded
|
|
|
|
// so they are in the order expected by the command list
|
2017-06-23 23:00:00 +02:00
|
|
|
static int g_vertexorder[8192];
|
|
|
|
static int g_numorder;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
static int g_allverts, g_alltris;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
static int g_stripverts[128];
|
|
|
|
static int g_striptris[128];
|
|
|
|
static int g_stripcount;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
StripLength
|
|
|
|
================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
static int StripLength( int starttri, int startv )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
int m1, m2, j, k;
|
2017-03-14 22:00:00 +01:00
|
|
|
mtriangle_t *last, *check;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_used[starttri] = 2;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
last = &g_triangles[starttri];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_stripverts[0] = last->vertindex[(startv+0) % 3];
|
|
|
|
g_stripverts[1] = last->vertindex[(startv+1) % 3];
|
|
|
|
g_stripverts[2] = last->vertindex[(startv+2) % 3];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_striptris[0] = starttri;
|
|
|
|
g_stripcount = 1;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
m1 = last->vertindex[(startv+2)%3];
|
|
|
|
m2 = last->vertindex[(startv+1)%3];
|
|
|
|
|
|
|
|
nexttri:
|
2017-06-23 23:00:00 +02:00
|
|
|
// look for a matching triangle
|
|
|
|
for( j = starttri + 1, check = &g_triangles[starttri + 1]; j < pheader->numtris; j++, check++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->facesfront != last->facesfront )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
2017-06-23 23:00:00 +02:00
|
|
|
|
|
|
|
for( k = 0; k < 3; k++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->vertindex[k] != m1 )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->vertindex[(k+1) % 3] != m2 )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// this is the next part of the fan
|
|
|
|
|
|
|
|
// if we can't use this triangle, this tristrip is done
|
2017-06-23 23:00:00 +02:00
|
|
|
if( g_used[j] ) goto done;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// the new edge
|
2017-06-23 23:00:00 +02:00
|
|
|
if( g_stripcount & 1 )
|
|
|
|
m2 = check->vertindex[(k+2) % 3];
|
|
|
|
else m1 = check->vertindex[(k+2) % 3];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_stripverts[g_stripcount+2] = check->vertindex[(k+2) % 3];
|
|
|
|
g_striptris[g_stripcount] = j;
|
|
|
|
g_stripcount++;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_used[j] = 2;
|
2017-03-14 22:00:00 +01:00
|
|
|
goto nexttri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
// clear the temp used flags
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = starttri + 1; j < pheader->numtris; j++ )
|
|
|
|
{
|
|
|
|
if( g_used[j] == 2 )
|
|
|
|
g_used[j] = 0;
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
return g_stripcount;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===========
|
|
|
|
FanLength
|
|
|
|
===========
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
static int FanLength( int starttri, int startv )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
int m1, m2, j, k;
|
2017-03-14 22:00:00 +01:00
|
|
|
mtriangle_t *last, *check;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_used[starttri] = 2;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
last = &g_triangles[starttri];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_stripverts[0] = last->vertindex[(startv+0) % 3];
|
|
|
|
g_stripverts[1] = last->vertindex[(startv+1) % 3];
|
|
|
|
g_stripverts[2] = last->vertindex[(startv+2) % 3];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_striptris[0] = starttri;
|
|
|
|
g_stripcount = 1;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
m1 = last->vertindex[(startv+0) % 3];
|
|
|
|
m2 = last->vertindex[(startv+2) % 3];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
nexttri:
|
2017-06-23 23:00:00 +02:00
|
|
|
// look for a matching triangle
|
|
|
|
for( j = starttri + 1, check = &g_triangles[starttri + 1]; j < pheader->numtris; j++, check++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->facesfront != last->facesfront )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
2017-06-23 23:00:00 +02:00
|
|
|
|
|
|
|
for( k = 0; k < 3; k++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->vertindex[k] != m1 )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
2017-06-23 23:00:00 +02:00
|
|
|
if( check->vertindex[(k+1) % 3] != m2 )
|
2017-03-14 22:00:00 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// this is the next part of the fan
|
|
|
|
// if we can't use this triangle, this tristrip is done
|
2017-06-23 23:00:00 +02:00
|
|
|
if( g_used[j] ) goto done;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// the new edge
|
2017-06-23 23:00:00 +02:00
|
|
|
m2 = check->vertindex[(k+2) % 3];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_stripverts[g_stripcount + 2] = m2;
|
|
|
|
g_striptris[g_stripcount] = j;
|
|
|
|
g_stripcount++;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_used[j] = 2;
|
2017-03-14 22:00:00 +01:00
|
|
|
goto nexttri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
// clear the temp used flags
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = starttri + 1; j < pheader->numtris; j++ )
|
|
|
|
{
|
|
|
|
if( g_used[j] == 2 )
|
|
|
|
g_used[j] = 0;
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
return g_stripcount;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
BuildTris
|
|
|
|
|
|
|
|
Generate a list of trifans or strips
|
|
|
|
for the model, which holds for all frames
|
|
|
|
================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void BuildTris( void )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
int len, bestlen, besttype;
|
|
|
|
int bestverts[1024];
|
|
|
|
int besttris[1024];
|
|
|
|
int type, startv;
|
|
|
|
int i, j, k;
|
2017-03-14 22:00:00 +01:00
|
|
|
float s, t;
|
|
|
|
|
|
|
|
//
|
|
|
|
// build tristrips
|
|
|
|
//
|
2017-06-23 23:00:00 +02:00
|
|
|
memset( g_used, 0, sizeof( g_used ));
|
|
|
|
g_numcommands = 0;
|
|
|
|
g_numorder = 0;
|
|
|
|
|
|
|
|
for( i = 0; i < pheader->numtris; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
// pick an unused triangle and start the trifan
|
2017-06-23 23:00:00 +02:00
|
|
|
if( g_used[i] ) continue;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
bestlen = 0;
|
2017-06-23 23:00:00 +02:00
|
|
|
for( type = 0; type < 2; type++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
for( startv = 0; startv < 3; startv++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( type == 1 ) len = StripLength( i, startv );
|
|
|
|
else len = FanLength( i, startv );
|
|
|
|
|
|
|
|
if( len > bestlen )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
besttype = type;
|
|
|
|
bestlen = len;
|
2017-06-23 23:00:00 +02:00
|
|
|
|
|
|
|
for( j = 0; j < bestlen + 2; j++ )
|
|
|
|
bestverts[j] = g_stripverts[j];
|
|
|
|
|
|
|
|
for( j = 0; j < bestlen; j++ )
|
|
|
|
besttris[j] = g_striptris[j];
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mark the tris on the best strip as used
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = 0; j < bestlen; j++ )
|
|
|
|
g_used[besttris[j]] = 1;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( besttype == 1 )
|
|
|
|
g_commands[g_numcommands++] = (bestlen + 2);
|
|
|
|
else g_commands[g_numcommands++] = -(bestlen + 2);
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = 0; j < bestlen + 2; j++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
// emit a vertex into the reorder buffer
|
|
|
|
k = bestverts[j];
|
2017-06-23 23:00:00 +02:00
|
|
|
g_vertexorder[g_numorder++] = k;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// emit s/t coords into the commands stream
|
2017-06-23 23:00:00 +02:00
|
|
|
s = g_stverts[k].s;
|
|
|
|
t = g_stverts[k].t;
|
|
|
|
|
|
|
|
if( !g_triangles[besttris[0]].facesfront && g_stverts[k].onseam )
|
2017-03-14 22:00:00 +01:00
|
|
|
s += pheader->skinwidth / 2; // on back side
|
2017-06-23 23:00:00 +02:00
|
|
|
s = (s + 0.5f) / pheader->skinwidth;
|
|
|
|
t = (t + 0.5f) / pheader->skinheight;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// Carmack use floats and Valve use shorts here...
|
|
|
|
*(float *)&g_commands[g_numcommands++] = s;
|
|
|
|
*(float *)&g_commands[g_numcommands++] = t;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_commands[g_numcommands++] = 0; // end of list marker
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
MsgDev( D_REPORT, "%3i tri %3i vert %3i cmd\n", pheader->numtris, g_numorder, g_numcommands );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_alltris += pheader->numtris;
|
|
|
|
g_allverts += g_numorder;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
GL_MakeAliasModelDisplayLists
|
|
|
|
================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void GL_MakeAliasModelDisplayLists( model_t *m, aliashdr_t *hdr )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
mtrivertex_t *verts;
|
2017-03-14 22:00:00 +01:00
|
|
|
int i, j;
|
|
|
|
|
|
|
|
aliasmodel = m;
|
|
|
|
paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m);
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
BuildTris( );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// save the data out
|
2017-06-23 23:00:00 +02:00
|
|
|
paliashdr->poseverts = g_numorder;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
paliashdr->commands = Mem_Alloc( m->mempool, g_numcommands * 4 );
|
|
|
|
memcpy( paliashdr->commands, g_commands, g_numcommands * 4 );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
paliashdr->posedata = verts = Mem_Alloc( m->mempool, paliashdr->numposes * paliashdr->poseverts * sizeof( mtrivertex_t ));
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( i = 0; i < paliashdr->numposes; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = 0; j < g_numorder; j++ )
|
|
|
|
*verts++ = g_poseverts[i][g_vertexorder[j]];
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
ALIAS MODELS
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Mod_LoadAliasFrame
|
|
|
|
=================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void *Mod_LoadAliasFrame( void *pin, maliasframedesc_t *frame )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
dtrivertex_t *pinframe;
|
2017-03-14 22:00:00 +01:00
|
|
|
daliasframe_t *pdaliasframe;
|
2017-06-23 23:00:00 +02:00
|
|
|
int i;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
pdaliasframe = (daliasframe_t *)pin;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
Q_strncpy( frame->name, pdaliasframe->name, sizeof( frame->name ));
|
|
|
|
frame->firstpose = g_posenum;
|
2017-03-14 22:00:00 +01:00
|
|
|
frame->numposes = 1;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( i = 0; i < 3; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
|
|
|
|
frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i];
|
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
pinframe = (dtrivertex_t *)(pdaliasframe + 1);
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
g_poseverts[g_posenum] = (mtrivertex_t *)pinframe;
|
|
|
|
g_posenum++;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
pinframe += pheader->numverts;
|
|
|
|
|
|
|
|
return (void *)pinframe;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Mod_LoadAliasGroup
|
|
|
|
=================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void *Mod_LoadAliasGroup( void *pin, maliasframedesc_t *frame )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
daliasgroup_t *pingroup;
|
|
|
|
int i, numframes;
|
2017-03-14 22:00:00 +01:00
|
|
|
daliasinterval_t *pin_intervals;
|
2017-06-23 23:00:00 +02:00
|
|
|
void *ptemp;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
pingroup = (daliasgroup_t *)pin;
|
2017-06-23 23:00:00 +02:00
|
|
|
numframes = pingroup->numframes;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
frame->firstpose = g_posenum;
|
2017-03-14 22:00:00 +01:00
|
|
|
frame->numposes = numframes;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( i = 0; i < 3; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
|
|
|
|
frame->bboxmax.v[i] = pingroup->bboxmax.v[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
pin_intervals = (daliasinterval_t *)(pingroup + 1);
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
frame->interval = pin_intervals->interval;
|
2017-03-14 22:00:00 +01:00
|
|
|
pin_intervals += numframes;
|
|
|
|
ptemp = (void *)pin_intervals;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( i = 0; i < numframes; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
g_poseverts[g_posenum] = (mtrivertex_t *)((daliasframe_t *)ptemp + 1);
|
|
|
|
g_posenum++;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
ptemp = ((daliasframe_t *)ptemp + 1) + pheader->numverts;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return ptemp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-06-23 23:00:00 +02:00
|
|
|
=================================================================
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
SKIN REFLOODING
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
=================================================================
|
|
|
|
*/
|
2017-03-14 22:00:00 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
short x, y;
|
2017-03-14 22:00:00 +01:00
|
|
|
} floodfill_t;
|
|
|
|
|
|
|
|
// must be a power of 2
|
2017-06-23 23:00:00 +02:00
|
|
|
#define FLOODFILL_FIFO_SIZE 0x1000
|
|
|
|
#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
#define FLOODFILL_STEP( off, dx, dy ) \
|
|
|
|
{ \
|
2017-06-23 23:00:00 +02:00
|
|
|
if( pos[off] == fillcolor ) \
|
2017-03-14 22:00:00 +01:00
|
|
|
{ \
|
|
|
|
pos[off] = 255; \
|
|
|
|
fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
|
|
|
|
inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
|
|
|
|
} \
|
2017-06-23 23:00:00 +02:00
|
|
|
else if( pos[off] != 255 ) fdc = pos[off]; \
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Mod_FloodFillSkin
|
|
|
|
|
|
|
|
Fill background pixels so mipmapping doesn't have haloes - Ed
|
|
|
|
=================
|
|
|
|
*/
|
2017-03-14 22:00:00 +01:00
|
|
|
void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
|
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
byte fillcolor = *skin; // assume this is the pixel to fill
|
|
|
|
floodfill_t fifo[FLOODFILL_FIFO_SIZE];
|
|
|
|
int inpt = 0, outpt = 0;
|
|
|
|
int filledcolor = 0; // g-cont. opaque black is probably always 0-th index
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
// can't fill to filled color or to transparent color (used as visited marker)
|
2017-06-23 23:00:00 +02:00
|
|
|
if(( fillcolor == filledcolor ) || ( fillcolor == 255 ))
|
2017-03-14 22:00:00 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
fifo[inpt].x = 0, fifo[inpt].y = 0;
|
|
|
|
inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
while( outpt != inpt )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
int x = fifo[outpt].x, y = fifo[outpt].y;
|
|
|
|
byte *pos = &skin[x + skinwidth * y];
|
|
|
|
int fdc = filledcolor;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( x > 0 ) FLOODFILL_STEP( -1, -1, 0 );
|
|
|
|
if( x < skinwidth - 1 ) FLOODFILL_STEP( 1, 1, 0 );
|
|
|
|
if( y > 0 ) FLOODFILL_STEP( -skinwidth, 0, -1 );
|
|
|
|
if( y < skinheight - 1 ) FLOODFILL_STEP( skinwidth, 0, 1 );
|
2017-03-14 22:00:00 +01:00
|
|
|
skin[x + skinwidth * y] = fdc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Mod_CreateSkinData
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
rgbdata_t *Mod_CreateSkinData( byte *data, int width, int height )
|
|
|
|
{
|
|
|
|
static rgbdata_t skin;
|
|
|
|
|
|
|
|
skin.width = width;
|
|
|
|
skin.height = height;
|
|
|
|
skin.depth = 1;
|
|
|
|
skin.type = PF_INDEXED_24;
|
|
|
|
SetBits( skin.flags, IMAGE_HAS_COLOR );
|
|
|
|
skin.encode = DXT_ENCODE_DEFAULT;
|
|
|
|
skin.numMips = 1;
|
|
|
|
skin.buffer = data;
|
|
|
|
skin.palette = (byte *)&clgame.palette;
|
|
|
|
skin.size = width * height;
|
|
|
|
|
|
|
|
// make an copy
|
|
|
|
return FS_CopyImage( &skin );
|
|
|
|
}
|
|
|
|
|
2017-03-14 22:00:00 +01:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Mod_LoadAllSkins
|
|
|
|
===============
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void *Mod_LoadAllSkins( int numskins, daliasskintype_t *pskintype )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
char name[32];
|
2017-03-14 22:00:00 +01:00
|
|
|
daliasskingroup_t *pinskingroup;
|
|
|
|
daliasskininterval_t *pinskinintervals;
|
2017-06-23 23:00:00 +02:00
|
|
|
int size, groupskins;
|
|
|
|
int i, j, k;
|
|
|
|
byte *skin;
|
|
|
|
rgbdata_t *pic;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
skin = (byte *)(pskintype + 1);
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( numskins < 1 || numskins > MAX_SKINS )
|
|
|
|
Host_Error( "Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
size = pheader->skinwidth * pheader->skinheight;
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( i = 0; i < numskins; i++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
if( pskintype->type == ALIAS_SKIN_SINGLE )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
|
|
|
|
|
|
|
|
// save 8 bit texels for the player model to remap
|
2017-06-23 23:00:00 +02:00
|
|
|
pheader->texels[i] = Mem_Alloc( loadmodel->mempool, size );
|
|
|
|
memcpy( pheader->texels[i], (byte *)(pskintype + 1), size );
|
|
|
|
|
|
|
|
Q_snprintf( name, sizeof( name ), "%s:frame%i", loadmodel->name, i );
|
|
|
|
pic = Mod_CreateSkinData( (byte *)(pskintype + 1), pheader->skinwidth, pheader->skinheight );
|
|
|
|
|
|
|
|
pheader->gl_texturenum[i][0] =
|
|
|
|
pheader->gl_texturenum[i][1] =
|
|
|
|
pheader->gl_texturenum[i][2] =
|
|
|
|
pheader->gl_texturenum[i][3] = GL_LoadTextureInternal( name, pic, 0, false );
|
|
|
|
FS_FreeImage( pic );
|
|
|
|
pskintype = (daliasskintype_t *)((byte *)(pskintype + 1) + size);
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// animating skin group. yuck.
|
|
|
|
pskintype++;
|
|
|
|
pinskingroup = (daliasskingroup_t *)pskintype;
|
2017-06-23 23:00:00 +02:00
|
|
|
groupskins = pinskingroup->numskins;
|
2017-03-14 22:00:00 +01:00
|
|
|
pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
|
|
|
|
pskintype = (void *)(pinskinintervals + groupskins);
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
for( j = 0; j < groupskins; j++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
|
|
|
Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
|
2017-06-23 23:00:00 +02:00
|
|
|
if( j == 0 )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
pheader->texels[i] = Mem_Alloc( loadmodel->mempool, size );
|
|
|
|
memcpy( pheader->texels[i], (byte *)(pskintype), size );
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
2017-06-23 23:00:00 +02:00
|
|
|
Q_snprintf( name, sizeof( name ), "%s_%i_%i", loadmodel->name, i, j );
|
|
|
|
pic = Mod_CreateSkinData( (byte *)(pskintype), pheader->skinwidth, pheader->skinheight );
|
|
|
|
pheader->gl_texturenum[i][j & 3] = GL_LoadTextureInternal( name, pic, 0, false );
|
2017-03-14 22:00:00 +01:00
|
|
|
pskintype = (daliasskintype_t *)((byte *)(pskintype) + size);
|
2017-06-23 23:00:00 +02:00
|
|
|
FS_FreeImage( pic );
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
2017-06-23 23:00:00 +02:00
|
|
|
|
|
|
|
for( k = j; j < 4; j++ )
|
|
|
|
pheader->gl_texturenum[i][j & 3] = pheader->gl_texturenum[i][j - k];
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (void *)pskintype;
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================================
|
|
|
|
/*
|
|
|
|
=================
|
2017-06-23 23:00:00 +02:00
|
|
|
Mod_CalcAliasBounds
|
2017-03-14 22:00:00 +01:00
|
|
|
=================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void Mod_CalcAliasBounds( aliashdr_t *a )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
int i, j, k;
|
|
|
|
float radius;
|
|
|
|
float dist;
|
|
|
|
vec3_t v;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
ClearBounds( loadmodel->mins, loadmodel->maxs );
|
|
|
|
radius = 0.0f;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// process verts
|
|
|
|
for( i = 0; i < a->numposes; i++ )
|
|
|
|
{
|
|
|
|
for( j = 0; j < a->numverts; j++ )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
for( k = 0; k < 3; k++ )
|
|
|
|
v[k] = g_poseverts[i][j].v[k] * pheader->scale[k] + pheader->scale_origin[k];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
AddPointToBounds( v, loadmodel->mins, loadmodel->maxs );
|
|
|
|
dist = DotProduct( v, v );
|
|
|
|
|
|
|
|
if( radius < dist )
|
2017-03-14 22:00:00 +01:00
|
|
|
radius = dist;
|
|
|
|
}
|
2017-06-23 23:00:00 +02:00
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
loadmodel->radius = sqrt( radius );
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
2017-06-23 23:00:00 +02:00
|
|
|
Mod_LoadAliasModel
|
2017-03-14 22:00:00 +01:00
|
|
|
=================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
daliashdr_t *pinmodel;
|
|
|
|
stvert_t *pinstverts;
|
|
|
|
dtriangle_t *pintriangles;
|
|
|
|
int numframes, size;
|
|
|
|
daliasframetype_t *pframetype;
|
|
|
|
daliasskintype_t *pskintype;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
if( loaded ) *loaded = false;
|
|
|
|
pinmodel = (daliashdr_t *)buffer;
|
|
|
|
i = pinmodel->version;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( i != ALIAS_VERSION )
|
|
|
|
{
|
|
|
|
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)\n", mod->name, i, ALIAS_VERSION );
|
2017-03-14 22:00:00 +01:00
|
|
|
return;
|
2017-06-23 23:00:00 +02:00
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// allocate space for a working header, plus all the data except the frames,
|
|
|
|
// skin and group info
|
|
|
|
size = sizeof( aliashdr_t ) + (pinmodel->numframes - 1) * sizeof( pheader->frames[0] );
|
|
|
|
|
|
|
|
pheader = Mem_Alloc( mod->mempool, size );
|
|
|
|
mod->flags = pinmodel->flags; // share effects flags
|
|
|
|
|
|
|
|
// endian-adjust and copy the data, starting with the alias model header
|
|
|
|
pheader->boundingradius = pinmodel->boundingradius;
|
|
|
|
pheader->numskins = pinmodel->numskins;
|
|
|
|
pheader->skinwidth = pinmodel->skinwidth;
|
|
|
|
pheader->skinheight = pinmodel->skinheight;
|
|
|
|
pheader->numverts = pinmodel->numverts;
|
|
|
|
|
|
|
|
if( pheader->numverts <= 0 )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
MsgDev( D_ERROR, "model %s has no vertices\n", mod->name );
|
|
|
|
return;
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( pheader->numverts > MAXALIASVERTS )
|
|
|
|
{
|
|
|
|
MsgDev( D_ERROR, "model %s has too many vertices\n", mod->name );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pheader->numtris = pinmodel->numtris;
|
|
|
|
|
|
|
|
if( pheader->numtris <= 0 )
|
|
|
|
{
|
|
|
|
MsgDev( D_ERROR, "model %s has no triangles\n", mod->name );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pheader->numframes = pinmodel->numframes;
|
|
|
|
numframes = pheader->numframes;
|
|
|
|
|
|
|
|
if( numframes < 1 )
|
|
|
|
{
|
|
|
|
MsgDev( D_ERROR, "Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pheader->size = pinmodel->size;
|
|
|
|
// mod->synctype = pinmodel->synctype;
|
|
|
|
mod->numframes = pheader->numframes;
|
|
|
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
pheader->scale[i] = pinmodel->scale[i];
|
|
|
|
pheader->scale_origin[i] = pinmodel->scale_origin[i];
|
|
|
|
pheader->eyeposition[i] = pinmodel->eyeposition[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// load the skins
|
|
|
|
pskintype = (daliasskintype_t *)&pinmodel[1];
|
|
|
|
pskintype = Mod_LoadAllSkins( pheader->numskins, pskintype );
|
|
|
|
|
|
|
|
// load base s and t vertices
|
|
|
|
pinstverts = (stvert_t *)pskintype;
|
|
|
|
|
|
|
|
for( i = 0; i < pheader->numverts; i++ )
|
|
|
|
{
|
|
|
|
g_stverts[i].onseam = pinstverts[i].onseam;
|
|
|
|
g_stverts[i].s = pinstverts[i].s;
|
|
|
|
g_stverts[i].t = pinstverts[i].t;
|
|
|
|
}
|
|
|
|
|
|
|
|
// load triangle lists
|
|
|
|
pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts];
|
|
|
|
|
|
|
|
for( i = 0; i < pheader->numtris; i++ )
|
|
|
|
{
|
|
|
|
g_triangles[i].facesfront = pintriangles[i].facesfront;
|
|
|
|
|
|
|
|
for( j = 0; j < 3; j++ )
|
|
|
|
g_triangles[i].vertindex[j] = pintriangles[i].vertindex[j];
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// load the frames
|
|
|
|
pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris];
|
|
|
|
g_posenum = 0;
|
|
|
|
|
|
|
|
for( i = 0; i < numframes; i++ )
|
|
|
|
{
|
|
|
|
aliasframetype_t frametype = pframetype->type;
|
|
|
|
|
|
|
|
if( frametype == ALIAS_SINGLE )
|
|
|
|
pframetype = (daliasframetype_t *)Mod_LoadAliasFrame( pframetype + 1, &pheader->frames[i] );
|
|
|
|
else pframetype = (daliasframetype_t *)Mod_LoadAliasGroup( pframetype + 1, &pheader->frames[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
pheader->numposes = g_posenum;
|
|
|
|
Mod_CalcAliasBounds( pheader );
|
|
|
|
mod->type = mod_alias;
|
|
|
|
|
|
|
|
// build the draw lists
|
|
|
|
GL_MakeAliasModelDisplayLists( mod, pheader );
|
|
|
|
|
|
|
|
// move the complete, relocatable alias model to the cache
|
|
|
|
loadmodel->cache.data = pheader;
|
|
|
|
|
|
|
|
if( loaded ) *loaded = true; // done
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
2017-06-23 23:00:00 +02:00
|
|
|
Mod_UnloadAliasModel
|
2017-03-14 22:00:00 +01:00
|
|
|
=================
|
|
|
|
*/
|
2017-06-23 23:00:00 +02:00
|
|
|
void Mod_UnloadAliasModel( model_t *mod )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
aliashdr_t *palias;
|
|
|
|
int i;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
ASSERT( mod != NULL );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( mod->type != mod_alias )
|
|
|
|
return; // not an alias
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
palias = mod->cache.data;
|
|
|
|
if( !palias ) return; // already freed
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
// FIXME: check animating groups too?
|
|
|
|
for( i = 0; i < MAX_SKINS; i++ )
|
|
|
|
{
|
|
|
|
if( !palias->gl_texturenum[i][0] )
|
|
|
|
continue;
|
|
|
|
GL_FreeTexture( palias->gl_texturenum[i][0] );
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
Mem_FreePool( &mod->mempool );
|
|
|
|
memset( mod, 0, sizeof( *mod ));
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
=============================================================
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
ALIAS MODELS
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
=============================================================
|
|
|
|
*/
|
|
|
|
vec3_t shadevector;
|
|
|
|
float shadelight, ambientlight;
|
|
|
|
float *shadedots = r_avertexnormal_dots[0];
|
|
|
|
colorVec lightColor;
|
|
|
|
vec3_t lightspot;
|
|
|
|
int lastposenum;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GL_DrawAliasFrame
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GL_DrawAliasFrame( aliashdr_t *paliashdr, int posenum )
|
|
|
|
{
|
|
|
|
float l;
|
|
|
|
mtrivertex_t *verts;
|
|
|
|
int *order;
|
|
|
|
int count;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
lastposenum = posenum;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
verts = paliashdr->posedata;
|
|
|
|
verts += posenum * paliashdr->poseverts;
|
|
|
|
order = paliashdr->commands;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
while( 1 )
|
|
|
|
{
|
|
|
|
// get the vertex count and primitive type
|
|
|
|
count = *order++;
|
|
|
|
if( !count ) break; // done
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( count < 0 )
|
|
|
|
{
|
|
|
|
pglBegin( GL_TRIANGLE_FAN );
|
|
|
|
count = -count;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pglBegin( GL_TRIANGLE_STRIP );
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
// texture coordinates come from the draw list
|
|
|
|
pglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
|
|
|
|
order += 2;
|
|
|
|
|
|
|
|
// normals and vertexes come from the frame list
|
|
|
|
l = shadedots[verts->lightnormalindex] * shadelight;
|
|
|
|
pglColor3f( l, l, l );
|
|
|
|
pglVertex3f( verts->v[0], verts->v[1], verts->v[2] );
|
|
|
|
verts++;
|
|
|
|
} while( --count );
|
|
|
|
|
|
|
|
pglEnd();
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
2017-06-23 23:00:00 +02:00
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GL_DrawAliasShadow
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GL_DrawAliasShadow( aliashdr_t *paliashdr, int posenum )
|
|
|
|
{
|
|
|
|
mtrivertex_t *verts;
|
|
|
|
int *order;
|
|
|
|
vec3_t point;
|
|
|
|
float height, lheight;
|
|
|
|
int count;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
lheight = RI.currententity->origin[2] - lightspot[2];
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
height = 0;
|
|
|
|
verts = paliashdr->posedata;
|
|
|
|
verts += posenum * paliashdr->poseverts;
|
|
|
|
order = paliashdr->commands;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
height = -lheight + 1.0;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
while( 1 )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
// get the vertex count and primitive type
|
|
|
|
count = *order++;
|
|
|
|
if( !count ) break; // done
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( count < 0 )
|
|
|
|
{
|
|
|
|
pglBegin( GL_TRIANGLE_FAN );
|
|
|
|
count = -count;
|
|
|
|
}
|
|
|
|
else
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
pglBegin( GL_TRIANGLE_STRIP );
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
2017-06-23 23:00:00 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// texture coordinates come from the draw list
|
|
|
|
// (skipped for shadows) pglTexCoord2fv ((float *)order);
|
|
|
|
order += 2;
|
|
|
|
|
|
|
|
// normals and vertexes come from the frame list
|
|
|
|
point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];
|
|
|
|
point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];
|
|
|
|
point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];
|
|
|
|
|
|
|
|
point[0] -= shadevector[0] * (point[2] + lheight);
|
|
|
|
point[1] -= shadevector[1] * (point[2] + lheight);
|
|
|
|
point[2] = height;
|
|
|
|
// height -= 0.001f;
|
|
|
|
pglVertex3fv( point );
|
|
|
|
|
|
|
|
verts++;
|
|
|
|
} while( --count );
|
|
|
|
|
|
|
|
pglEnd();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_SetupAliasFrame
|
|
|
|
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_SetupAliasFrame( int frame, aliashdr_t *paliashdr )
|
|
|
|
{
|
|
|
|
int pose, numposes;
|
|
|
|
float interval;
|
|
|
|
|
|
|
|
if(( frame >= paliashdr->numframes ) || ( frame < 0 ))
|
|
|
|
{
|
|
|
|
MsgDev( D_ERROR, "R_AliasSetupFrame: no such frame %d\n", frame );
|
|
|
|
frame = 0;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
pose = paliashdr->frames[frame].firstpose;
|
|
|
|
numposes = paliashdr->frames[frame].numposes;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
if( numposes > 1 )
|
2017-03-14 22:00:00 +01:00
|
|
|
{
|
2017-06-23 23:00:00 +02:00
|
|
|
interval = paliashdr->frames[frame].interval;
|
|
|
|
pose += (int)(cl.time / interval) % numposes;
|
2017-03-14 22:00:00 +01:00
|
|
|
}
|
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
GL_DrawAliasFrame( paliashdr, pose );
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_DrawAliasModel
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_DrawAliasModel( cl_entity_t *e )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int lnum;
|
|
|
|
vec3_t dist, p1;
|
|
|
|
float add;
|
|
|
|
model_t *clmodel;
|
|
|
|
vec3_t absmin, absmax;
|
|
|
|
aliashdr_t *paliashdr;
|
|
|
|
float an;
|
|
|
|
int anim;
|
|
|
|
|
|
|
|
clmodel = RI.currententity->model;
|
|
|
|
|
|
|
|
VectorAdd( RI.currententity->origin, clmodel->mins, absmin );
|
|
|
|
VectorAdd( RI.currententity->origin, clmodel->maxs, absmax );
|
|
|
|
|
|
|
|
if( R_CullModel( e, absmin, absmax ))
|
|
|
|
return;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
//
|
|
|
|
// get lighting information
|
|
|
|
//
|
|
|
|
VectorSet( p1, RI.currententity->origin[0], RI.currententity->origin[1], RI.currententity->origin[2] - 2048.0f );
|
|
|
|
lightColor = R_LightVec( RI.currententity->origin, p1, lightspot );
|
|
|
|
|
|
|
|
ambientlight = shadelight = 0; // FIXME: compute light
|
|
|
|
|
|
|
|
// allways give the gun some light
|
|
|
|
if (e == &clgame.viewent && ambientlight < 24)
|
|
|
|
ambientlight = shadelight = 24;
|
|
|
|
|
|
|
|
for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
|
|
|
|
{
|
|
|
|
if (cl_dlights[lnum].die >= cl.time)
|
|
|
|
{
|
|
|
|
VectorSubtract (e->origin,
|
|
|
|
cl_dlights[lnum].origin,
|
|
|
|
dist);
|
|
|
|
add = cl_dlights[lnum].radius - VectorLength(dist);
|
|
|
|
|
|
|
|
if (add > 0) {
|
|
|
|
ambientlight += add;
|
|
|
|
//ZOID models should be affected by dlights as well
|
|
|
|
shadelight += add;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// clamp lighting so it doesn't overbright as much
|
|
|
|
if (ambientlight > 128)
|
|
|
|
ambientlight = 128;
|
|
|
|
if (ambientlight + shadelight > 192)
|
|
|
|
shadelight = 192 - ambientlight;
|
|
|
|
|
|
|
|
// ZOID: never allow players to go totally black
|
|
|
|
i = e - clgame.entities;
|
|
|
|
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
|
|
|
|
if (ambientlight < 8)
|
|
|
|
ambientlight = shadelight = 8;
|
|
|
|
|
|
|
|
if( FBitSet( e->curstate.effects, EF_FULLBRIGHT ))
|
|
|
|
ambientlight = shadelight = 256;
|
|
|
|
|
|
|
|
shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
|
|
|
|
shadelight = shadelight / 200.0;
|
|
|
|
|
|
|
|
an = e->angles[1]/180*M_PI;
|
|
|
|
shadevector[0] = cos(-an);
|
|
|
|
shadevector[1] = sin(-an);
|
|
|
|
shadevector[2] = 1;
|
|
|
|
VectorNormalize (shadevector);
|
2017-03-14 22:00:00 +01:00
|
|
|
|
|
|
|
//
|
2017-06-23 23:00:00 +02:00
|
|
|
// locate the proper data
|
2017-03-14 22:00:00 +01:00
|
|
|
//
|
2017-06-23 23:00:00 +02:00
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata( RI.currententity->model );
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
r_stats.c_alias_polys += paliashdr->numtris;
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
//
|
|
|
|
// draw all the triangles
|
|
|
|
//
|
|
|
|
|
|
|
|
R_RotateForEntity( e );
|
|
|
|
|
|
|
|
pglTranslatef( paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] );
|
|
|
|
pglScalef( paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2] );
|
|
|
|
|
|
|
|
anim = (int)(cl.time*10) & 3;
|
|
|
|
GL_Bind( GL_TEXTURE0, paliashdr->gl_texturenum[RI.currententity->curstate.skin][anim]);
|
|
|
|
#if 0
|
|
|
|
// we can't dynamically colormap textures, so they are cached
|
|
|
|
// seperately for the players. Heads are just uncolored.
|
|
|
|
if (RI.currententity->colormap != vid.colormap && !gl_nocolors.value)
|
|
|
|
{
|
|
|
|
i = currententity - cl_entities;
|
|
|
|
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
|
|
|
|
GL_Bind(playertextures - 1 + i);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
pglShadeModel( GL_SMOOTH );
|
|
|
|
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
|
|
|
|
|
|
R_SetupAliasFrame( RI.currententity->curstate.frame, paliashdr );
|
|
|
|
|
|
|
|
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
|
|
|
|
|
|
|
pglShadeModel( GL_FLAT );
|
|
|
|
R_LoadIdentity();
|
|
|
|
|
|
|
|
if( r_shadows.value )
|
|
|
|
{
|
|
|
|
pglPushMatrix ();
|
|
|
|
R_RotateForEntity (e);
|
|
|
|
pglDisable (GL_TEXTURE_2D);
|
|
|
|
pglEnable (GL_BLEND);
|
|
|
|
pglColor4f (0,0,0,0.5);
|
|
|
|
GL_DrawAliasShadow (paliashdr, lastposenum);
|
|
|
|
pglEnable (GL_TEXTURE_2D);
|
|
|
|
pglDisable (GL_BLEND);
|
|
|
|
pglColor4f (1,1,1,1);
|
|
|
|
pglPopMatrix ();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-03-14 22:00:00 +01:00
|
|
|
|
2017-06-23 23:00:00 +02:00
|
|
|
//==================================================================================
|