15 Mar 2017

This commit is contained in:
g-cont 2017-03-15 00:00:00 +03:00 committed by Alibek Omarov
parent fdc53c3cc1
commit 72f2dc8782
42 changed files with 1559 additions and 932 deletions

View File

@ -89,6 +89,8 @@ typedef struct
unsigned short max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
short groupid; // to determine equal landscapes from various groups, -1 - no group
vec3_t mins, maxs; // terrain bounds (fill by user)
int reserved[32]; // just for future expansions or mod-makers
} mfaceinfo_t;
@ -102,20 +104,6 @@ typedef struct
int flags; // sky or slime, no lightmap or 256 subdivision
} mtexinfo_t;
// 73 bytes per VBO vertex
// FIXME: align to 32 bytes
typedef struct glvert_s
{
vec3_t vertex; // position
vec3_t normal; // normal
vec2_t stcoord; // ST texture coords
vec2_t lmcoord; // ST lightmap coords
vec2_t sccoord; // ST scissor coords (decals only) - for normalmap coords migration
vec3_t tangent; // tangent
vec3_t binormal; // binormal
byte color[4]; // colors per vertex
} glvert_t;
typedef struct glpoly_s
{
struct glpoly_s *next;
@ -154,13 +142,11 @@ struct decal_s
float dy; //
float scale; // Pixel scale
short texture; // Decal texture
byte flags; // Decal flags FDECAL_*
short flags; // Decal flags FDECAL_*
short entityIndex; // Entity this is attached to
// Xash3D added
// Xash3D specific
vec3_t position; // location of the decal center in world space.
vec3_t saxis; // direction of the s axis in world space
struct msurfmesh_s *mesh; // decal mesh in local space
int reserved[4]; // for future expansions
glpoly_t *polys; // precomputed decal vertices
};
typedef struct mleaf_s
@ -183,6 +169,32 @@ typedef struct mleaf_s
} mleaf_t;
// surface extradata
typedef struct mextrasurf_s
{
vec3_t mins, maxs;
vec3_t origin; // surface origin
struct msurface_s *surf; // upcast to surface
int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps
int mirrortexturenum; // gl texnum
float mirrormatrix[4][4];
struct mextrasurf_s *mirrorchain; // for gl_texsort drawing
struct mextrasurf_s *detailchain; // for detail textures drawing
struct msurface_s *lightmapchain; // lightmapped polys
struct cl_entity_s *parent; // upcast to owner entity
color24 *deluxemap; // note: this is the actual deluxemap data for this surface
// begin userdata
struct grasshdr_s *grass; // grass that linked by this surface
unsigned short grasscount; // number of bushes per polygon (used to determine total VBO size)
unsigned short numverts; // world->vertexes[]
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
int reserved[32]; // just for future expansions or mod-makers
} mextrasurf_t;
typedef struct msurface_s
{
int visframe; // should be drawn when node is crossed
@ -211,44 +223,12 @@ typedef struct msurface_s
int lightmaptexturenum;
byte styles[MAXLIGHTMAPS];
int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
struct msurface_s *lightmapchain; // for new dlights rendering (was cached_dlight)
mextrasurf_t *info; // pointer to surface extradata (was cached_dlight)
color24 *samples; // note: this is the actual lightmap data for this surface
decal_t *pdecals;
} msurface_t;
typedef struct msurfmesh_s
{
unsigned short numVerts;
unsigned short numElems; // ~ 20 000 vertex per one surface. Should be enough
unsigned int startVert; // user-variable. may be used for construct world single-VBO
unsigned int startElem; // user-variable. may be used for construct world single-VBO
glvert_t *verts; // vertexes array
unsigned short *elems; // indices
struct msurface_s *surf; // pointer to parent surface. Just for consistency
struct msurfmesh_s *next; // temporary chain of subdivided surfaces
} msurfmesh_t;
// surface extradata stored in cache.data for all brushmodels
typedef struct mextrasurf_s
{
vec3_t mins, maxs;
vec3_t origin; // surface origin
msurfmesh_t *mesh; // VBO\VA ready surface mesh. Not used by engine but can be used by mod-makers
int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps
int mirrortexturenum; // gl texnum
float mirrormatrix[4][4];
struct mextrasurf_s *mirrorchain; // for gl_texsort drawing
struct mextrasurf_s *detailchain; // for detail textures drawing
color24 *deluxemap; // note: this is the actual deluxemap data for this surface
int reserved[32]; // just for future expansions or mod-makers
} mextrasurf_t;
typedef struct hull_s
{
dclipnode_t *clipnodes;

View File

@ -18,7 +18,7 @@ GNU General Public License for more details.
// list of engine features that can be enabled through callback SV_CheckFeatures
#define ENGINE_WRITE_LARGE_COORD (1<<0) // replace standard message WRITE_COORD with big message for support more than 8192 units in world
#define ENGINE_BUILD_SURFMESHES (1<<1) // bulid surface meshes that goes into mextrasurf->mesh. For mod makers and custom renderers
// reserved
#define ENGINE_LOAD_DELUXEDATA (1<<2) // loading deluxemap for map (if present)
#define ENGINE_TRANSFORM_TRACE_AABB (1<<3) // transform trace bbox into local space of rotating bmodels
#define ENGINE_LARGE_LIGHTMAPS (1<<4) // change lightmap sizes from 128x128 to 256x256

View File

@ -30,9 +30,6 @@ GNU General Public License for more details.
#define CL_RENDER_INTERFACE_VERSION 36
#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals
#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces))
#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data))
// render info parms
#define PARM_TEX_WIDTH 1 // all parms with prefix 'TEX_' receive arg as texnum
#define PARM_TEX_HEIGHT 2 // otherwise it's not used
@ -220,7 +217,6 @@ typedef struct render_api_s
int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare );
void (*Host_Error)( const char *error, ... ); // cause Host Error
int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load
void (*TessPolygon)( struct msurface_s *surf, struct model_s *mod, float tessSize );
struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e );
const struct ref_overview_s *( *GetOverviewParms )( void );
void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents)

View File

@ -40,6 +40,8 @@ cvar_t defaultteam = {"mp_defaultteam","0" };
cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER };
cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER };
cvar_t saved1 = { "saved_cvar", "0", FCVAR_ARCHIVE };
// Engine Cvars
cvar_t *g_psv_gravity = NULL;
@ -480,6 +482,7 @@ void GameDLLInit( void )
CVAR_REGISTER (&allowmonsters);
CVAR_REGISTER (&mp_chattime);
CVAR_REGISTER (&saved1);
// REGISTER CVARS FOR SKILL LEVEL STUFF
// Agrunt

137
engine/alias.h Normal file
View File

@ -0,0 +1,137 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef ALIAS_H
#define ALIAS_H
/*
==============================================================================
ALIAS MODELS
Alias models are position independent, so the cache manager can move them.
==============================================================================
*/
#define IDALIASHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I') // little-endian "IDPO"
#define ALIAS_VERSION 6
// must match definition in sprite.h
#ifndef SYNCTYPE_T
#define SYNCTYPE_T
typedef enum
{
ST_SYNC = 0,
ST_RAND
} synctype_t;
#endif
typedef enum
{
ALIAS_SINGLE = 0,
ALIAS_GROUP
} aliasframetype_t;
typedef enum
{
ALIAS_SKIN_SINGLE = 0,
ALIAS_SKIN_GROUP
} aliasskintype_t;
typedef struct
{
int ident;
int version;
vec3_t scale;
vec3_t scale_origin;
float boundingradius;
vec3_t eyeposition;
int numskins;
int skinwidth;
int skinheight;
int numverts;
int numtris;
int numframes;
synctype_t synctype;
int flags;
float size;
} daliashdr_t;
// TODO: could be shorts
typedef struct
{
int onseam;
int s;
int t;
} stvert_t;
typedef struct dtriangle_s
{
int facesfront;
int vertindex[3];
} dtriangle_t;
#define DT_FACES_FRONT 0x0010
#define ALIAS_ONSEAM 0x0020
// This mirrors trivert_t in trilib.h, is present so Quake knows how to
// load this data
typedef struct
{
byte v[3];
byte lightnormalindex;
} trivertex_t;
typedef struct
{
trivertex_t bboxmin; // lightnormal isn't used
trivertex_t bboxmax; // lightnormal isn't used
char name[16]; // frame name from grabbing
} daliasframe_t;
typedef struct
{
int numframes;
trivertx_t bboxmin; // lightnormal isn't used
trivertx_t bboxmax; // lightnormal isn't used
} daliasgroup_t;
typedef struct
{
int numskins;
} daliasskingroup_t;
typedef struct
{
float interval;
} daliasinterval_t;
typedef struct
{
float interval;
} daliasskininterval_t;
typedef struct
{
aliasframetype_t type;
} daliasframetype_t;
typedef struct
{
aliasskintype_t type;
} daliasskintype_t;
#endif//ALIAS_H

View File

@ -125,7 +125,7 @@ void CL_PlayCDTrack_f( void )
if( paused ) Msg( "Paused %s track %u\n", looped ? "looping" : "playing", track );
else Msg( "Currently %s track %u\n", looped ? "looping" : "playing", track );
}
Msg( "Volume is %f\n", Cvar_VariableValue( "musicvolume" ));
Msg( "Volume is %f\n", Cvar_VariableValue( "MP3Volume" ));
return;
}
else Msg( "cd: unknown command %s\n", command );

View File

@ -137,6 +137,7 @@ qboolean CL_EntityCustomLerp( cl_entity_t *e )
case MOVETYPE_STEP:
case MOVETYPE_WALK:
case MOVETYPE_FLY:
case MOVETYPE_COMPOUND:
return false;
}
@ -1057,7 +1058,7 @@ void CL_LinkPacketEntities( frame_t *frame )
parametric = ( ent->curstate.impacttime != 0.0f && ent->curstate.starttime != 0.0f );
if( !parametric )
if( !parametric && ent->curstate.movetype != MOVETYPE_COMPOUND )
{
if( ent->curstate.animtime == ent->prevstate.animtime && !VectorCompare( ent->curstate.origin, ent->prevstate.origin ))
ent->lastmove = cl.time + 0.2;
@ -1133,7 +1134,7 @@ void CL_LinkPacketEntities( frame_t *frame )
continue;
}
if( ent->curstate.aiment != 0 )
if( ent->curstate.aiment != 0 && ent->curstate.movetype != MOVETYPE_COMPOUND )
ent->curstate.movetype = MOVETYPE_FOLLOW;
if( FBitSet( ent->curstate.effects, EF_NOINTERP ))

View File

@ -518,7 +518,7 @@ void SCR_InstallParticlePalette( void )
if( !pic ) pic = FS_LoadImage( "gfx/palette.pal", NULL, 0 );
// NOTE: imagelib required this fakebuffer for loading internal palette
if( !pic ) pic = FS_LoadImage( "#valve.pal", ((byte *)&i), 768 );
if( !pic ) pic = FS_LoadImage( "#valve.pal", (byte *)&i, 768 );
if( pic )
{
@ -545,11 +545,11 @@ void SCR_InstallParticlePalette( void )
void SCR_RegisterTextures( void )
{
// register gfx.wad images
cls.pauseIcon = GL_LoadTexture( "gfx.wad/paused.lmp", NULL, 0, TF_IMAGE, NULL );
cls.pauseIcon = GL_LoadTexture( "gfx/paused.lmp", NULL, 0, TF_IMAGE, NULL );
if( cl_allow_levelshots->value )
cls.loadingBar = GL_LoadTexture( "gfx.wad/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE, NULL );
else cls.loadingBar = GL_LoadTexture( "gfx.wad/lambda.lmp", NULL, 0, TF_IMAGE, NULL );
cls.tileImage = GL_LoadTexture( "gfx.wad/backtile.lmp", NULL, 0, TF_IMAGE, NULL );
cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE, NULL );
else cls.loadingBar = GL_LoadTexture( "gfx/lambda.lmp", NULL, 0, TF_IMAGE, NULL );
cls.tileImage = GL_LoadTexture( "gfx/backtile.lmp", NULL, 0, TF_IMAGE, NULL );
}
/*

View File

@ -2838,7 +2838,7 @@ normal temporary decal
*/
void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags )
{
R_DecalShoot( textureIndex, entityIndex, modelIndex, pos, flags, NULL, 1.0f );
R_DecalShoot( textureIndex, entityIndex, modelIndex, pos, flags, 1.0f );
}
/*
@ -2850,7 +2850,7 @@ custom temporary decal
*/
void CL_FireCustomDecal( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags, float scale )
{
R_DecalShoot( textureIndex, entityIndex, modelIndex, pos, flags, NULL, scale );
R_DecalShoot( textureIndex, entityIndex, modelIndex, pos, flags, scale );
}
/*
@ -2862,7 +2862,7 @@ spray custom colored decal (clan logo etc)
*/
void CL_PlayerDecal( int textureIndex, int entityIndex, float *pos )
{
R_DecalShoot( textureIndex, entityIndex, 0, pos, 0, NULL, 1.0f );
R_DecalShoot( textureIndex, entityIndex, 0, pos, 0, 1.0f );
}
/*

960
engine/client/gl_alias.c Normal file
View File

@ -0,0 +1,960 @@
/*
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"
/*
=================================================================
ALIAS MODEL DISPLAY LIST GENERATION
=================================================================
*/
model_t *aliasmodel;
aliashdr_t *paliashdr;
qboolean used[8192];
// the command list holds counts and s/t values that are valid for
// every frame
int commands[8192];
int numcommands;
// all frames will have their vertexes rearranged and expanded
// so they are in the order expected by the command list
int vertexorder[8192];
int numorder;
int allverts, alltris;
int stripverts[128];
int striptris[128];
int stripcount;
/*
================
StripLength
================
*/
int StripLength (int starttri, int startv)
{
int m1, m2;
int j;
mtriangle_t *last, *check;
int k;
used[starttri] = 2;
last = &triangles[starttri];
stripverts[0] = last->vertindex[(startv)%3];
stripverts[1] = last->vertindex[(startv+1)%3];
stripverts[2] = last->vertindex[(startv+2)%3];
striptris[0] = starttri;
stripcount = 1;
m1 = last->vertindex[(startv+2)%3];
m2 = last->vertindex[(startv+1)%3];
// look for a matching triangle
nexttri:
for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
{
if (check->facesfront != last->facesfront)
continue;
for (k=0 ; k<3 ; k++)
{
if (check->vertindex[k] != m1)
continue;
if (check->vertindex[ (k+1)%3 ] != m2)
continue;
// this is the next part of the fan
// if we can't use this triangle, this tristrip is done
if (used[j])
goto done;
// the new edge
if (stripcount & 1)
m2 = check->vertindex[ (k+2)%3 ];
else
m1 = check->vertindex[ (k+2)%3 ];
stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ];
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
goto nexttri;
}
}
done:
// clear the temp used flags
for (j=starttri+1 ; j<pheader->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
===========
FanLength
===========
*/
int FanLength (int starttri, int startv)
{
int m1, m2;
int j;
mtriangle_t *last, *check;
int k;
used[starttri] = 2;
last = &triangles[starttri];
stripverts[0] = last->vertindex[(startv)%3];
stripverts[1] = last->vertindex[(startv+1)%3];
stripverts[2] = last->vertindex[(startv+2)%3];
striptris[0] = starttri;
stripcount = 1;
m1 = last->vertindex[(startv+0)%3];
m2 = last->vertindex[(startv+2)%3];
// look for a matching triangle
nexttri:
for (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)
{
if (check->facesfront != last->facesfront)
continue;
for (k=0 ; k<3 ; k++)
{
if (check->vertindex[k] != m1)
continue;
if (check->vertindex[ (k+1)%3 ] != m2)
continue;
// this is the next part of the fan
// if we can't use this triangle, this tristrip is done
if (used[j])
goto done;
// the new edge
m2 = check->vertindex[ (k+2)%3 ];
stripverts[stripcount+2] = m2;
striptris[stripcount] = j;
stripcount++;
used[j] = 2;
goto nexttri;
}
}
done:
// clear the temp used flags
for (j=starttri+1 ; j<pheader->numtris ; j++)
if (used[j] == 2)
used[j] = 0;
return stripcount;
}
/*
================
BuildTris
Generate a list of trifans or strips
for the model, which holds for all frames
================
*/
void BuildTris (void)
{
int i, j, k;
int startv;
mtriangle_t *last, *check;
int m1, m2;
int striplength;
trivertx_t *v;
mtriangle_t *tv;
float s, t;
int index;
int len, bestlen, besttype;
int bestverts[1024];
int besttris[1024];
int type;
//
// build tristrips
//
numorder = 0;
numcommands = 0;
memset (used, 0, sizeof(used));
for (i=0 ; i<pheader->numtris ; i++)
{
// pick an unused triangle and start the trifan
if (used[i])
continue;
bestlen = 0;
for (type = 0 ; type < 2 ; type++)
// type = 1;
{
for (startv =0 ; startv < 3 ; startv++)
{
if (type == 1)
len = StripLength (i, startv);
else
len = FanLength (i, startv);
if (len > bestlen)
{
besttype = type;
bestlen = len;
for (j=0 ; j<bestlen+2 ; j++)
bestverts[j] = stripverts[j];
for (j=0 ; j<bestlen ; j++)
besttris[j] = striptris[j];
}
}
}
// mark the tris on the best strip as used
for (j=0 ; j<bestlen ; j++)
used[besttris[j]] = 1;
if (besttype == 1)
commands[numcommands++] = (bestlen+2);
else
commands[numcommands++] = -(bestlen+2);
for (j=0 ; j<bestlen+2 ; j++)
{
// emit a vertex into the reorder buffer
k = bestverts[j];
vertexorder[numorder++] = k;
// emit s/t coords into the commands stream
s = stverts[k].s;
t = stverts[k].t;
if (!triangles[besttris[0]].facesfront && stverts[k].onseam)
s += pheader->skinwidth / 2; // on back side
s = (s + 0.5) / pheader->skinwidth;
t = (t + 0.5) / pheader->skinheight;
*(float *)&commands[numcommands++] = s;
*(float *)&commands[numcommands++] = t;
}
}
commands[numcommands++] = 0; // end of list marker
Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands);
allverts += numorder;
alltris += pheader->numtris;
}
/*
================
GL_MakeAliasModelDisplayLists
================
*/
void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr)
{
int i, j;
maliasgroup_t *paliasgroup;
int *cmds;
trivertx_t *verts;
char cache[MAX_QPATH], fullpath[MAX_OSPATH], *c;
FILE *f;
int len;
byte *data;
float hscale, vscale; //johnfitz -- padded skins
int count; //johnfitz -- precompute texcoords for padded skins
int *loadcmds; //johnfitz
//johnfitz -- padded skins
hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth);
vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight);
//johnfitz
aliasmodel = m;
paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m);
//johnfitz -- generate meshes
#if 1 //always regenerate meshes
Con_DPrintf ("meshing %s...\n",m->name);
BuildTris ();
#else //conditional regeneration
if (gl_alwaysmesh.value) // build it from scratch, and don't bother saving it to disk
{
Con_DPrintf ("meshing %s...\n",m->name);
BuildTris ();
}
else // check disk cache, and rebuild it and save to disk if necessary
{
//create directories
sprintf (gldir, "%s/glquake", com_gamedir);
Sys_mkdir (com_gamedir);
Sys_mkdir (gldir);
//
// look for a cached version
//
strcpy (cache, "glquake/");
COM_StripExtension (m->name+strlen("progs/"), cache+strlen("glquake/"));
strcat (cache, ".ms2");
COM_FOpenFile (cache, &f);
if (f)
{
fread (&numcommands, 4, 1, f);
fread (&numorder, 4, 1, f);
fread (&commands, numcommands * sizeof(commands[0]), 1, f);
fread (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);
fclose (f);
}
else
{
//
// build it from scratch
//
Con_Printf ("meshing %s...\n",m->name);
BuildTris ();
//
// save out the cached version
//
sprintf (fullpath, "%s/%s", com_gamedir, cache);
f = fopen (fullpath, "wb");
if (f)
{
fwrite (&numcommands, 4, 1, f);
fwrite (&numorder, 4, 1, f);
fwrite (&commands, numcommands * sizeof(commands[0]), 1, f);
fwrite (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f);
fclose (f);
}
}
}
#endif
//johnfitz
// save the data out
paliashdr->poseverts = numorder;
cmds = Hunk_Alloc (numcommands * 4);
paliashdr->commands = (byte *)cmds - (byte *)paliashdr;
//johnfitz -- precompute texcoords for padded skins
loadcmds = commands;
while(1)
{
*cmds++ = count = *loadcmds++;
if (!count)
break;
if (count < 0)
count = -count;
do
{
*(float *)cmds++ = hscale * (*(float *)loadcmds++);
*(float *)cmds++ = vscale * (*(float *)loadcmds++);
} while (--count);
}
//johnfitz
verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts * sizeof(trivertx_t));
paliashdr->posedata = (byte *)verts - (byte *)paliashdr;
for (i=0 ; i<paliashdr->numposes ; i++)
for (j=0 ; j<numorder ; j++)
*verts++ = poseverts[i][vertexorder[j]];
}
/*
==============================================================================
ALIAS MODELS
==============================================================================
*/
aliashdr_t *pheader;
stvert_t stverts[MAXALIASVERTS];
mtriangle_t triangles[MAXALIASTRIS];
// a pose is a single set of vertexes. a frame may be
// an animating sequence of poses
trivertx_t *poseverts[MAXALIASFRAMES];
int posenum;
byte **player_8bit_texels_tbl;
byte *player_8bit_texels;
/*
=================
Mod_LoadAliasFrame
=================
*/
void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame)
{
trivertx_t *pframe, *pinframe;
int i, j;
daliasframe_t *pdaliasframe;
pdaliasframe = (daliasframe_t *)pin;
strcpy (frame->name, pdaliasframe->name);
frame->firstpose = posenum;
frame->numposes = 1;
for (i=0 ; i<3 ; i++)
{
// these are byte values, so we don't have to worry about
// endianness
frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i];
}
pinframe = (trivertx_t *)(pdaliasframe + 1);
poseverts[posenum] = pinframe;
posenum++;
pinframe += pheader->numverts;
return (void *)pinframe;
}
/*
=================
Mod_LoadAliasGroup
=================
*/
void *Mod_LoadAliasGroup (void * pin, maliasframedesc_t *frame)
{
daliasgroup_t *pingroup;
int i, numframes;
daliasinterval_t *pin_intervals;
void *ptemp;
pingroup = (daliasgroup_t *)pin;
numframes = LittleLong (pingroup->numframes);
frame->firstpose = posenum;
frame->numposes = numframes;
for (i=0 ; i<3 ; i++)
{
// these are byte values, so we don't have to worry about endianness
frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
frame->bboxmax.v[i] = pingroup->bboxmax.v[i];
}
pin_intervals = (daliasinterval_t *)(pingroup + 1);
frame->interval = LittleFloat (pin_intervals->interval);
pin_intervals += numframes;
ptemp = (void *)pin_intervals;
for (i=0 ; i<numframes ; i++)
{
poseverts[posenum] = (trivertx_t *)((daliasframe_t *)ptemp + 1);
posenum++;
ptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts;
}
return ptemp;
}
//=========================================================
/*
=================
Mod_FloodFillSkin
Fill background pixels so mipmapping doesn't have haloes - Ed
=================
*/
typedef struct
{
short x, y;
} floodfill_t;
extern unsigned d_8to24table[];
// must be a power of 2
#define FLOODFILL_FIFO_SIZE 0x1000
#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
#define FLOODFILL_STEP( off, dx, dy ) \
{ \
if (pos[off] == fillcolor) \
{ \
pos[off] = 255; \
fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
} \
else if (pos[off] != 255) fdc = pos[off]; \
}
void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
{
byte fillcolor = *skin; // assume this is the pixel to fill
floodfill_t fifo[FLOODFILL_FIFO_SIZE];
int inpt = 0, outpt = 0;
int filledcolor = -1;
int i;
if (filledcolor == -1)
{
filledcolor = 0;
// attempt to find opaque black
for (i = 0; i < 256; ++i)
if (d_8to24table[i] == (255 << 0)) // alpha 1.0
{
filledcolor = i;
break;
}
}
// can't fill to filled color or to transparent color (used as visited marker)
if ((fillcolor == filledcolor) || (fillcolor == 255))
{
//printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
return;
}
fifo[inpt].x = 0, fifo[inpt].y = 0;
inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
while (outpt != inpt)
{
int x = fifo[outpt].x, y = fifo[outpt].y;
int fdc = filledcolor;
byte *pos = &skin[x + skinwidth * y];
outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
if (x > 0) FLOODFILL_STEP( -1, -1, 0 );
if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 );
if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 );
if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 );
skin[x + skinwidth * y] = fdc;
}
}
/*
===============
Mod_LoadAllSkins
===============
*/
void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype)
{
int i, j, k, size, groupskins;
char name[32];
byte *copy, *skin, *texels;
daliasskingroup_t *pinskingroup;
daliasskininterval_t *pinskinintervals;
int padx, pady, ii, jj; //johnfitz -- padded player skin
char fbr_mask_name[64]; //johnfitz -- added for fullbright support
unsigned offset; //johnfitz
skin = (byte *)(pskintype + 1);
if (numskins < 1 || numskins > MAX_SKINS)
Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
size = pheader->skinwidth * pheader->skinheight;
for (i=0 ; i<numskins ; i++)
{
if (pskintype->type == ALIAS_SKIN_SINGLE)
{
Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
// save 8 bit texels for the player model to remap
texels = Hunk_AllocName(size, loadname);
pheader->texels[i] = texels - (byte *)pheader;
memcpy (texels, (byte *)(pskintype + 1), size);
//johnfitz -- rewritten
sprintf (name, "%s:frame%i", loadmodel->name, i);
offset = (unsigned)(pskintype+1) - (unsigned)mod_base;
if (Mod_CheckFullbrights ((byte *)(pskintype+1), size))
{
pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT);
sprintf (fbr_mask_name, "%s:frame%i_glow", loadmodel->name, i);
pheader->fbtextures[i][0] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT);
}
else
{
pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD);
pheader->fbtextures[i][0] = NULL;
}
pheader->gltextures[i][3] = pheader->gltextures[i][2] = pheader->gltextures[i][1] = pheader->gltextures[i][0];
pheader->fbtextures[i][3] = pheader->fbtextures[i][2] = pheader->fbtextures[i][1] = pheader->fbtextures[i][0];
//johnfitz
pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + size);
}
else
{
// animating skin group. yuck.
pskintype++;
pinskingroup = (daliasskingroup_t *)pskintype;
groupskins = LittleLong (pinskingroup->numskins);
pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
pskintype = (void *)(pinskinintervals + groupskins);
for (j=0 ; j<groupskins ; j++)
{
Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
if (j == 0) {
texels = Hunk_AllocName(size, loadname);
pheader->texels[i] = texels - (byte *)pheader;
memcpy (texels, (byte *)(pskintype), size);
}
//johnfitz -- rewritten
sprintf (name, "%s:frame%i_%i", loadmodel->name, i,j);
offset = (unsigned)(pskintype) - (unsigned)mod_base; //johnfitz
if (Mod_CheckFullbrights ((byte *)(pskintype), size))
{
pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT);
sprintf (fbr_mask_name, "%s:frame%i_%i_glow", loadmodel->name, i,j);
pheader->fbtextures[i][j&3] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT);
}
else
{
pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight,
SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD);
pheader->fbtextures[i][j&3] = NULL;
}
//johnfitz
pskintype = (daliasskintype_t *)((byte *)(pskintype) + size);
}
k = j;
for (/* */; j < 4; j++)
pheader->gltextures[i][j&3] =
pheader->gltextures[i][j - k];
}
}
return (void *)pskintype;
}
//=========================================================================
/*
=================
Mod_CalcAliasBounds -- johnfitz -- calculate bounds of alias model for nonrotated, yawrotated, and fullrotated cases
=================
*/
void Mod_CalcAliasBounds (aliashdr_t *a)
{
int i,j,k;
float dist, yawradius, radius;
vec3_t v;
//clear out all data
for (i=0; i<3;i++)
{
loadmodel->mins[i] = loadmodel->ymins[i] = loadmodel->rmins[i] = 999999;
loadmodel->maxs[i] = loadmodel->ymaxs[i] = loadmodel->rmaxs[i] = -999999;
radius = yawradius = 0;
}
//process verts
for (i=0 ; i<a->numposes; i++)
for (j=0; j<a->numverts; j++)
{
for (k=0; k<3;k++)
v[k] = poseverts[i][j].v[k] * pheader->scale[k] + pheader->scale_origin[k];
for (k=0; k<3;k++)
{
loadmodel->mins[k] = min (loadmodel->mins[k], v[k]);
loadmodel->maxs[k] = max (loadmodel->maxs[k], v[k]);
}
dist = v[0] * v[0] + v[1] * v[1];
if (yawradius < dist)
yawradius = dist;
dist += v[2] * v[2];
if (radius < dist)
radius = dist;
}
//rbounds will be used when entity has nonzero pitch or roll
radius = sqrt(radius);
loadmodel->rmins[0] = loadmodel->rmins[1] = loadmodel->rmins[2] = -radius;
loadmodel->rmaxs[0] = loadmodel->rmaxs[1] = loadmodel->rmaxs[2] = radius;
//ybounds will be used when entity has nonzero yaw
yawradius = sqrt(yawradius);
loadmodel->ymins[0] = loadmodel->ymins[1] = -yawradius;
loadmodel->ymaxs[0] = loadmodel->ymaxs[1] = yawradius;
loadmodel->ymins[2] = loadmodel->mins[2];
loadmodel->ymaxs[2] = loadmodel->maxs[2];
}
/*
=================
Mod_SetExtraFlags -- johnfitz -- set up extra flags that aren't in the mdl
=================
*/
void Mod_SetExtraFlags (model_t *mod)
{
extern cvar_t r_nolerp_list;
char *s;
int i;
if (!mod || !mod->name || mod->type != mod_alias)
return;
mod->flags &= 0xFF; //only preserve first byte
// nolerp flag
for (s=r_nolerp_list.string; *s; s += i+1, i=0)
{
//search forwards to the next comma or end of string
for (i=0; s[i] != ',' && s[i] != 0; i++) ;
//compare it to the model name
if (!strncmp(mod->name, s, i))
{
mod->flags |= MOD_NOLERP;
break;
}
}
// noshadow flag (TODO: make this a cvar list)
if (!strcmp (mod->name, "progs/flame2.mdl") ||
!strcmp (mod->name, "progs/flame.mdl") ||
!strcmp (mod->name, "progs/bolt1.mdl") ||
!strcmp (mod->name, "progs/bolt2.mdl") ||
!strcmp (mod->name, "progs/bolt3.mdl") ||
!strcmp (mod->name, "progs/laser.mdl"))
mod->flags |= MOD_NOSHADOW;
// fullbright hack (TODO: make this a cvar list)
if (!strcmp (mod->name, "progs/flame2.mdl") ||
!strcmp (mod->name, "progs/flame.mdl") ||
!strcmp (mod->name, "progs/boss.mdl"))
mod->flags |= MOD_FBRIGHTHACK;
}
/*
=================
Mod_LoadAliasModel
=================
*/
void Mod_LoadAliasModel (model_t *mod, void *buffer)
{
int i, j;
mdl_t *pinmodel;
stvert_t *pinstverts;
dtriangle_t *pintriangles;
int version, numframes, numskins;
int size;
daliasframetype_t *pframetype;
daliasskintype_t *pskintype;
int start, end, total;
start = Hunk_LowMark ();
pinmodel = (mdl_t *)buffer;
mod_base = (byte *)buffer; //johnfitz
version = LittleLong (pinmodel->version);
if (version != ALIAS_VERSION)
Sys_Error ("%s has wrong version number (%i should be %i)",
mod->name, version, ALIAS_VERSION);
//
// allocate space for a working header, plus all the data except the frames,
// skin and group info
//
size = sizeof (aliashdr_t)
+ (LittleLong (pinmodel->numframes) - 1) *
sizeof (pheader->frames[0]);
pheader = Hunk_AllocName (size, loadname);
mod->flags = LittleLong (pinmodel->flags);
//
// endian-adjust and copy the data, starting with the alias model header
//
pheader->boundingradius = LittleFloat (pinmodel->boundingradius);
pheader->numskins = LittleLong (pinmodel->numskins);
pheader->skinwidth = LittleLong (pinmodel->skinwidth);
pheader->skinheight = LittleLong (pinmodel->skinheight);
if (pheader->skinheight > MAX_LBM_HEIGHT)
Sys_Error ("model %s has a skin taller than %d", mod->name,
MAX_LBM_HEIGHT);
pheader->numverts = LittleLong (pinmodel->numverts);
if (pheader->numverts <= 0)
Sys_Error ("model %s has no vertices", mod->name);
if (pheader->numverts > MAXALIASVERTS)
Sys_Error ("model %s has too many vertices", mod->name);
pheader->numtris = LittleLong (pinmodel->numtris);
if (pheader->numtris <= 0)
Sys_Error ("model %s has no triangles", mod->name);
pheader->numframes = LittleLong (pinmodel->numframes);
numframes = pheader->numframes;
if (numframes < 1)
Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
mod->synctype = LittleLong (pinmodel->synctype);
mod->numframes = pheader->numframes;
for (i=0 ; i<3 ; i++)
{
pheader->scale[i] = LittleFloat (pinmodel->scale[i]);
pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
}
//
// load the skins
//
pskintype = (daliasskintype_t *)&pinmodel[1];
pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype);
//
// load base s and t vertices
//
pinstverts = (stvert_t *)pskintype;
for (i=0 ; i<pheader->numverts ; i++)
{
stverts[i].onseam = LittleLong (pinstverts[i].onseam);
stverts[i].s = LittleLong (pinstverts[i].s);
stverts[i].t = LittleLong (pinstverts[i].t);
}
//
// load triangle lists
//
pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts];
for (i=0 ; i<pheader->numtris ; i++)
{
triangles[i].facesfront = LittleLong (pintriangles[i].facesfront);
for (j=0 ; j<3 ; j++)
{
triangles[i].vertindex[j] =
LittleLong (pintriangles[i].vertindex[j]);
}
}
//
// load the frames
//
posenum = 0;
pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris];
for (i=0 ; i<numframes ; i++)
{
aliasframetype_t frametype;
frametype = LittleLong (pframetype->type);
if (frametype == ALIAS_SINGLE)
pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]);
else
pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]);
}
pheader->numposes = posenum;
mod->type = mod_alias;
Mod_SetExtraFlags (mod); //johnfitz
Mod_CalcAliasBounds (pheader); //johnfitz
//
// build the draw lists
//
GL_MakeAliasModelDisplayLists (mod, pheader);
//
// move the complete, relocatable alias model to the cache
//
end = Hunk_LowMark ();
total = end - start;
Cache_Alloc (&mod->cache, total, loadname);
if (!mod->cache.data)
return;
memcpy (mod->cache.data, pheader, total);
Hunk_FreeToLowMark (start);
}

View File

@ -168,10 +168,7 @@ qboolean R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags
}
if( frustum )
{
mextrasurf_t *info = SURF_INFO( surf, RI.currentmodel );
return GL_FrustumCullBox( frustum, info->mins, info->maxs, clipflags );
}
return GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags );
return false;
}

View File

@ -40,7 +40,6 @@ GNU General Public License for more details.
typedef struct
{
vec3_t m_Position; // world coordinates of the decal center
vec3_t m_SAxis; // the s axis for the decal in world coordinates
model_t *m_pModel; // the model the decal is going to be applied in
int m_iTexture; // The decal material
int m_Size; // Size of the decal (in world coords)
@ -92,13 +91,11 @@ static void R_DecalUnlink( decal_t *pdecal )
}
}
if( pdecal->mesh )
{
Mem_Free( pdecal->mesh );
}
if( pdecal->polys )
Mem_Free( pdecal->polys );
pdecal->psurface = NULL;
pdecal->mesh = NULL;
pdecal->polys = NULL;
}
// Just reuse next decal in list
@ -126,7 +123,7 @@ static decal_t *R_DecalAlloc( decal_t *pdecal )
pdecal = &gDecalPool[gDecalCount]; // reuse next decal
gDecalCount++;
count++;
} while(( pdecal->flags & FDECAL_PERMANENT ) && count < limit );
} while( FBitSet( pdecal->flags, FDECAL_PERMANENT ) && count < limit );
}
// if decal is already linked to a surface, unlink it.
@ -147,9 +144,9 @@ static void R_GetDecalDimensions( int texture, int *width, int *height )
}
//-----------------------------------------------------------------------------
// compute the decal basis based on surface normal, and preferred saxis
// compute the decal basis based on surface normal
//-----------------------------------------------------------------------------
void R_DecalComputeBasis( msurface_t *surf, vec3_t pSAxis, vec3_t textureSpaceBasis[3] )
void R_DecalComputeBasis( msurface_t *surf, vec3_t textureSpaceBasis[3] )
{
vec3_t surfaceNormal;
@ -158,44 +155,17 @@ void R_DecalComputeBasis( msurface_t *surf, vec3_t pSAxis, vec3_t textureSpaceBa
VectorNegate( surf->plane->normal, surfaceNormal );
else VectorCopy( surf->plane->normal, surfaceNormal );
VectorCopy( surfaceNormal, textureSpaceBasis[2] );
if( pSAxis )
{
// T = S cross N
CrossProduct( pSAxis, textureSpaceBasis[2], textureSpaceBasis[1] );
// Name sure they aren't parallel or antiparallel
// In that case, fall back to the normal algorithm.
if( DotProduct( textureSpaceBasis[1], textureSpaceBasis[1] ) > 1e-6 )
{
// S = N cross T
CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
VectorNormalizeFast( textureSpaceBasis[0] );
VectorNormalizeFast( textureSpaceBasis[1] );
return;
}
// Fall through to the standard algorithm for parallel or antiparallel
}
// original Half-Life algorithm: get textureBasis from linked surface
VectorCopy( surf->texinfo->vecs[0], textureSpaceBasis[0] );
VectorCopy( surf->texinfo->vecs[1], textureSpaceBasis[1] );
VectorNormalizeFast( textureSpaceBasis[0] );
VectorNormalizeFast( textureSpaceBasis[1] );
VectorNormalize2( surf->texinfo->vecs[0], textureSpaceBasis[0] );
VectorNormalize2( surf->texinfo->vecs[1], textureSpaceBasis[1] );
VectorNormalize2( surfaceNormal, textureSpaceBasis[2] );
}
void R_SetupDecalTextureSpaceBasis( decal_t *pDecal, msurface_t *surf, int texture, vec3_t textureSpaceBasis[3], float decalWorldScale[2] )
{
float *sAxis = NULL;
int width, height;
if( pDecal->flags & FDECAL_USESAXIS )
sAxis = pDecal->saxis;
// Compute the non-scaled decal basis
R_DecalComputeBasis( surf, sAxis, textureSpaceBasis );
R_DecalComputeBasis( surf, textureSpaceBasis );
R_GetDecalDimensions( texture, &width, &height );
// world width of decal = ptexture->width / pDecal->scale
@ -511,79 +481,41 @@ static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int
/*
====================
R_BuildMeshForDecal
R_DecalCreatePoly
creates mesh for decal on first rendering
====================
*/
msurfmesh_t *R_DecalCreateMesh( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t *surf )
glpoly_t *R_DecalCreatePoly( decalinfo_t *decalinfo, decal_t *pdecal, msurface_t *surf )
{
int lnumverts;
glpoly_t *poly;
float *v;
uint i, bufSize;
qboolean createSTverts = false;
int numVerts, numElems;
byte *buffer;
msurfmesh_t *mesh;
int i;
if( pdecal->mesh )
if( pdecal->polys ) // already created?
return pdecal->polys;
v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &lnumverts );
if( !lnumverts ) return NULL; // probably this never happens
// allocate glpoly
poly = Mem_Alloc( com_studiocache, sizeof( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof( float ));
poly->next = pdecal->polys;
poly->flags = surf->flags;
pdecal->polys = poly;
poly->numverts = lnumverts;
for( i = 0; i < lnumverts; i++, v += VERTEXSIZE )
{
// already have mesh
return pdecal->mesh;
VectorCopy( v, poly->verts[i] );
poly->verts[i][3] = v[3];
poly->verts[i][4] = v[4];
poly->verts[i][5] = v[5];
poly->verts[i][6] = v[6];
}
v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &numVerts );
if( !numVerts ) return NULL; // probably this never happens
// allocate mesh
numElems = (numVerts - 2) * 3;
bufSize = sizeof( msurfmesh_t ) + numVerts * sizeof( glvert_t ) + numElems * sizeof( word );
buffer = Mem_Alloc( cls.mempool, bufSize );
mesh = (msurfmesh_t *)buffer;
buffer += sizeof( msurfmesh_t );
mesh->numVerts = numVerts;
mesh->numElems = numElems;
// setup pointers
mesh->verts = (glvert_t *)buffer;
buffer += numVerts * sizeof( glvert_t );
mesh->elems = (word *)buffer;
buffer += numElems * sizeof( word );
mesh->surf = surf; // NOTE: meshchains can be linked with one surface
// create indices
for( i = 0; i < mesh->numVerts - 2; i++ )
{
mesh->elems[i*3+0] = 0;
mesh->elems[i*3+1] = i + 1;
mesh->elems[i*3+2] = i + 2;
}
// fill the mesh
for( i = 0; i < numVerts; i++, v += VERTEXSIZE )
{
glvert_t *out = &mesh->verts[i];
VectorCopy( v, out->vertex );
VectorCopy( decalinfo->m_Basis[0], out->tangent );
VectorCopy( decalinfo->m_Basis[1], out->binormal );
VectorCopy( decalinfo->m_Basis[2], out->normal );
out->stcoord[0] = v[3];
out->stcoord[1] = v[4];
out->lmcoord[0] = v[5];
out->lmcoord[1] = v[6];
out->sccoord[0] = (( DotProduct( v , surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] ) / surf->texinfo->texture->width );
out->sccoord[1] = (( DotProduct( v , surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] ) / surf->texinfo->texture->height );
// clear colors (it can be used for vertex lighting)
memset( out->color, 0xFF, sizeof( out->color ));
}
pdecal->mesh = mesh;
return mesh;
return poly;
}
// Add the decal to the surface's list of decals.
@ -612,9 +544,8 @@ static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t
// and will be culled, drawing and sorting
// together with surface
// build mesh for decal if allowed
if( host.features & ENGINE_BUILD_SURFMESHES )
pdecal->mesh = R_DecalCreateMesh( decalinfo, pdecal, surf );
// alloc clipped poly for decal
R_DecalCreatePoly( decalinfo, pdecal, surf );
}
static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, float y )
@ -638,16 +569,13 @@ static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, fl
VectorCopy( decalinfo->m_Position, pdecal->position );
if( pdecal->flags & FDECAL_USESAXIS )
VectorCopy( decalinfo->m_SAxis, pdecal->saxis );
pdecal->dx = x;
pdecal->dy = y;
pdecal->texture = decalinfo->m_iTexture;
// set scaling
pdecal->scale = decalinfo->m_scale;
pdecal->entityIndex = decalinfo->m_Entity;
pdecal->texture = decalinfo->m_iTexture;
// check to see if the decal actually intersects the surface
// if not, then remove the decal
@ -667,10 +595,9 @@ void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo )
{
// get the texture associated with this surface
mtexinfo_t *tex = surf->texinfo;
vec4_t textureU, textureV;
float *sAxis = NULL;
float s, t, w, h;
decal_t *decal = surf->pdecals;
vec4_t textureU, textureV;
float s, t, w, h;
// we in restore mode
if( cls.state == ca_connected )
@ -695,11 +622,7 @@ void R_DecalSurface( msurface_t *surf, decalinfo_t *decalinfo )
// Determine the decal basis (measured in world space)
// Note that the decal basis vectors 0 and 1 will always lie in the same
// plane as the texture space basis vectorstextureVecsTexelsPerWorldUnits.
if( decalinfo->m_Flags & FDECAL_USESAXIS )
sAxis = decalinfo->m_SAxis;
R_DecalComputeBasis( surf, sAxis, decalinfo->m_Basis );
R_DecalComputeBasis( surf, decalinfo->m_Basis );
// Compute an effective width and height (axis aligned) in the parent texture space
// How does this work? decalBasis[0] represents the u-direction (width)
@ -806,13 +729,13 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo )
}
// Shoots a decal onto the surface of the BSP. position is the center of the decal in world coords
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, vec3_t saxis, float scale )
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale )
{
decalinfo_t decalInfo;
hull_t *hull;
cl_entity_t *ent = NULL;
model_t *model = NULL;
int width, height;
hull_t *hull;
if( textureIndex <= 0 || textureIndex >= MAX_TEXTURES )
{
@ -869,13 +792,6 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
VectorCopy( pos, decalInfo.m_Position );
}
// deal with the s axis if one was passed in
if( saxis )
{
flags |= FDECAL_USESAXIS;
VectorCopy( saxis, decalInfo.m_SAxis );
}
// this decal must use landmark for correct transition
if(!( model->flags & MODEL_HAS_ORIGIN ))
{
@ -906,23 +822,24 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
// triangles the same way.
float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount )
{
float *v;
glpoly_t *p = pDecal->polys;
int i, count;
float *v, *v2;
if( pDecal->mesh )
if( p )
{
count = pDecal->mesh->numVerts;
v = g_DecalClipVerts[0];
count = p->numverts;
v2 = p->verts[0];
// if we have mesh so skip clipping and just copy vertexes out (perf)
for( i = 0, v = g_DecalClipVerts[0]; i < count; i++, v += VERTEXSIZE )
for( i = 0; i < count; i++, v += VERTEXSIZE, v2 += VERTEXSIZE )
{
glvert_t *p = &pDecal->mesh->verts[i];
VectorCopy( p->vertex, v );
v[3] = p->stcoord[0];
v[4] = p->stcoord[1];
v[5] = p->lmcoord[0];
v[6] = p->lmcoord[1];
VectorCopy( v2, v );
v[3] = v2[3];
v[4] = v2[4];
v[5] = v2[5];
v[6] = v2[6];
}
// restore pointer

View File

@ -480,7 +480,7 @@ void GL_SetRenderMode( int mode );
void R_RunViewmodelEvents( void );
void R_DrawViewModel( void );
int R_GetSpriteTexture( const struct model_s *m_pSpriteModel, int frame );
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, vec3_t saxis, float scale );
void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale );
void R_RemoveEfrags( struct cl_entity_s *ent );
void R_AddEfrags( struct cl_entity_s *ent );
void R_DecalRemoveAll( int texture );

View File

@ -30,11 +30,9 @@ void R_BeginDrawMirror( msurface_t *fa )
{
matrix4x4 m1, m2, matrix;
GLfloat genVector[4][4];
mextrasurf_t *es;
int i;
es = SURF_INFO( fa, RI.currentmodel );
Matrix4x4_Copy( matrix, es->mirrormatrix );
Matrix4x4_Copy( matrix, fa->info->mirrormatrix );
Matrix4x4_LoadIdentity( m1 );
Matrix4x4_ConcatScale( m1, 0.5f );
@ -205,7 +203,7 @@ void R_DrawMirrors( void )
RI.currententity = e = tr.mirror_entities[i].ent;
RI.currentmodel = m = RI.currententity->model;
surf = INFO_SURF( es, m );
surf = es->surf;
ASSERT( RI.currententity != NULL );
ASSERT( RI.currentmodel != NULL );
@ -218,7 +216,7 @@ void R_DrawMirrors( void )
{
for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain )
{
surf2 = INFO_SURF( tmp, m );
surf2 = tmp->surf;
if( !tmp->mirrortexturenum )
continue; // not filled?
@ -343,7 +341,6 @@ R_RecursiveMirrorNode
*/
void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
{
mextrasurf_t *extrasurf;
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
@ -402,15 +399,14 @@ void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
// draw stuff
for( c = node->numsurfaces, surf = cl.worldmodel->surfaces + node->firstsurface; c; c--, surf++ )
{
if(!( surf->flags & SURF_REFLECT ))
if( !FBitSet( surf->flags, SURF_REFLECT ))
continue;
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
extrasurf = SURF_INFO( surf, RI.currentmodel );
extrasurf->mirrorchain = tr.mirror_entities[0].chain;
tr.mirror_entities[0].chain = extrasurf;
surf->info->mirrorchain = tr.mirror_entities[0].chain;
tr.mirror_entities[0].chain = surf->info;
}
// recurse down the back side
@ -426,7 +422,6 @@ Check all bmodel surfaces and make personal mirror chain
*/
void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
{
mextrasurf_t *extrasurf;
vec3_t mins, maxs;
msurface_t *psurf;
model_t *clmodel;
@ -493,9 +488,8 @@ void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
if( R_CullSurface( psurf, frustum, 0 ))
continue;
extrasurf = SURF_INFO( psurf, RI.currentmodel );
extrasurf->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain;
tr.mirror_entities[tr.num_mirror_entities].chain = extrasurf;
psurf->info->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain;
tr.mirror_entities[tr.num_mirror_entities].chain = psurf->info;
}
// store new mirror entity

View File

@ -133,9 +133,7 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
mextrasurf_t *info = SURF_INFO( surf, RI.currentmodel );
if( !BoundsAndSphereIntersect( info->mins, info->maxs, light->origin, light->radius ))
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
continue; // no intersection
if( surf->dlightframe != tr.dlightframecount )

View File

@ -1463,7 +1463,6 @@ static render_api_t gRenderAPI =
COM_CompareFileTime,
Host_Error,
pfnSPR_LoadExt,
Mod_TesselatePolygon,
R_StudioGetTexture,
GL_GetOverviewParms,
S_FadeMusicVolume,

View File

@ -829,7 +829,6 @@ R_BlendLightmaps
void R_BlendLightmaps( void )
{
msurface_t *surf, *newsurf = NULL;
mextrasurf_t *info;
int i;
if( r_fullbright->value || !cl.worldmodel->lightdata )
@ -876,7 +875,7 @@ void R_BlendLightmaps( void )
{
GL_Bind( GL_TEXTURE0, tr.lightmapTextures[i] );
for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->lightmapchain )
for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->info->lightmapchain )
{
if( surf->polys ) DrawGLPolyChain( surf->polys, 0.0f, 0.0f );
}
@ -894,7 +893,7 @@ void R_BlendLightmaps( void )
newsurf = gl_lms.dynamic_surfaces;
for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->lightmapchain )
for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->info->lightmapchain )
{
int smax, tmax;
int sample_size;
@ -903,12 +902,11 @@ void R_BlendLightmaps( void )
sample_size = Mod_SampleSizeForFace( surf );
smax = ( surf->extents[0] / sample_size ) + 1;
tmax = ( surf->extents[1] / sample_size ) + 1;
info = SURF_INFO( surf, RI.currentmodel );
if( LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
if( LM_AllocBlock( smax, tmax, &surf->info->dlight_s, &surf->info->dlight_t ))
{
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
@ -920,15 +918,13 @@ void R_BlendLightmaps( void )
LM_UploadBlock( true );
// draw all surfaces that use this lightmap
for( drawsurf = newsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain )
for( drawsurf = newsurf; drawsurf != surf; drawsurf = drawsurf->info->lightmapchain )
{
if( drawsurf->polys )
{
info = SURF_INFO( drawsurf, RI.currentmodel );
DrawGLPolyChain( drawsurf->polys,
( drawsurf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ),
( drawsurf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE ));
( drawsurf->light_s - drawsurf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ),
( drawsurf->light_t - drawsurf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE ));
}
}
@ -937,14 +933,12 @@ void R_BlendLightmaps( void )
// clear the block
LM_InitBlock();
info = SURF_INFO( surf, RI.currentmodel );
// try uploading the block now
if( !LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
if( !LM_AllocBlock( smax, tmax, &surf->info->dlight_s, &surf->info->dlight_t ))
Host_Error( "AllocBlock: full\n" );
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
base += ( surf->info->dlight_t * BLOCK_SIZE + surf->info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
@ -953,15 +947,13 @@ void R_BlendLightmaps( void )
// draw remainder of dynamic lightmaps that haven't been uploaded yet
if( newsurf ) LM_UploadBlock( true );
for( surf = newsurf; surf != NULL; surf = surf->lightmapchain )
for( surf = newsurf; surf != NULL; surf = surf->info->lightmapchain )
{
if( surf->polys )
{
info = SURF_INFO( surf, RI.currentmodel );
DrawGLPolyChain( surf->polys,
( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ),
( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE ));
( surf->light_s - surf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE ),
( surf->light_t - surf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE ));
}
}
}
@ -1068,7 +1060,7 @@ void R_RenderDetails( void )
for( p = es; p; p = p->detailchain )
{
fa = INFO_SURF( p, RI.currentmodel );
fa = p->surf;
glt = R_GetTexture( fa->texinfo->texture->gl_texturenum ); // get texture scale
DrawGLPoly( fa->polys, glt->xscale, glt->yscale );
}
@ -1112,9 +1104,9 @@ void R_RenderBrushPoly( msurface_t *fa )
if( RP_NORMALPASS() && fa->flags & SURF_REFLECT )
{
if( SURF_INFO( fa, RI.currentmodel )->mirrortexturenum )
if( fa->info->mirrortexturenum )
{
GL_Bind( GL_TEXTURE0, SURF_INFO( fa, RI.currentmodel )->mirrortexturenum );
GL_Bind( GL_TEXTURE0, fa->info->mirrortexturenum );
is_mirror = true;
// BEGIN WATER STUFF
@ -1128,7 +1120,7 @@ void R_RenderBrushPoly( msurface_t *fa )
else GL_Bind( GL_TEXTURE0, t->gl_texturenum ); // dummy
// DEBUG: reset the mirror texture after drawing
SURF_INFO( fa, RI.currentmodel )->mirrortexturenum = 0;
fa->info->mirrortexturenum = 0;
}
else GL_Bind( GL_TEXTURE0, t->gl_texturenum );
@ -1151,8 +1143,6 @@ void R_RenderBrushPoly( msurface_t *fa )
if( r_detailtextures->value )
{
mextrasurf_t *es = SURF_INFO( fa, RI.currentmodel );
if( RI.fogEnabled || RI.fogCustom )
{
// don't apply detail textures for windows in the fog
@ -1160,22 +1150,22 @@ void R_RenderBrushPoly( msurface_t *fa )
{
if( t->dt_texturenum )
{
es->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = es;
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
}
else
{
// draw stub detail texture for underwater surfaces
es->detailchain = detail_surfaces[tr.grayTexture];
detail_surfaces[tr.grayTexture] = es;
fa->info->detailchain = detail_surfaces[tr.grayTexture];
detail_surfaces[tr.grayTexture] = fa->info;
}
draw_details = true;
}
}
else if( t->dt_texturenum )
{
es->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = es;
fa->info->detailchain = detail_surfaces[t->dt_texturenum];
detail_surfaces[t->dt_texturenum] = fa->info;
draw_details = true;
}
}
@ -1227,18 +1217,18 @@ dynamic:
pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax,
GL_RGBA, GL_UNSIGNED_BYTE, temp );
fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
}
else
{
fa->lightmapchain = gl_lms.dynamic_surfaces;
fa->info->lightmapchain = gl_lms.dynamic_surfaces;
gl_lms.dynamic_surfaces = fa;
}
}
else
{
fa->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
fa->info->lightmapchain = gl_lms.lightmap_surfaces[fa->lightmaptexturenum];
gl_lms.lightmap_surfaces[fa->lightmaptexturenum] = fa;
}
}
@ -1373,18 +1363,14 @@ compare translucent surfaces
static int R_SurfaceCompare( const msurface_t **a, const msurface_t **b )
{
msurface_t *surf1, *surf2;
mextrasurf_t *info1, *info2;
vec3_t org1, org2;
float len1, len2;
surf1 = (msurface_t *)*a;
surf2 = (msurface_t *)*b;
info1 = SURF_INFO( surf1, RI.currentmodel );
info2 = SURF_INFO( surf2, RI.currentmodel );
VectorAdd( RI.currententity->origin, info1->origin, org1 );
VectorAdd( RI.currententity->origin, info2->origin, org2 );
VectorAdd( RI.currententity->origin, surf1->info->origin, org1 );
VectorAdd( RI.currententity->origin, surf2->info->origin, org2 );
// compare by plane dists
len1 = DotProduct( org1, RI.vforward ) - RI.viewplanedist;
@ -1875,7 +1861,7 @@ void R_DrawTriangleOutlines( void )
// render static surfaces first
for( i = 0; i < MAX_LIGHTMAPS; i++ )
{
for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->lightmapchain )
for( surf = gl_lms.lightmap_surfaces[i]; surf != NULL; surf = surf->info->lightmapchain )
{
p = surf->polys;
for( ; p != NULL; p = p->chain )
@ -1890,7 +1876,7 @@ void R_DrawTriangleOutlines( void )
}
// render surfaces with dynamic lightmaps
for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->lightmapchain )
for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->info->lightmapchain )
{
p = surf->polys;
@ -2049,10 +2035,6 @@ void GL_CreateSurfaceLightmap( msurface_t *surf )
R_SetCacheState( surf );
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, false );
// moved here in case we need valid lightmap coords
if( host.features & ENGINE_BUILD_SURFMESHES )
Mod_BuildSurfacePolygons( surf, SURF_INFO( surf, loadmodel ));
}
/*

View File

@ -161,10 +161,12 @@ load sprite model
*/
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags )
{
dsprite_q1_t *pinq1;
dsprite_hl_t *pinhl;
dsprite_t *pin;
short *numi;
msprite_t *psprite;
short *numi = NULL;
dframetype_t *pframetype;
msprite_t *psprite;
int i, size;
if( loaded ) *loaded = false;
@ -179,29 +181,54 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
return;
}
if( i != SPRITE_VERSION )
if( i != SPRITE_VERSION_Q1 && i != SPRITE_VERSION_HL )
{
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)\n", mod->name, i, SPRITE_VERSION );
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i or %i)\n", mod->name, i, SPRITE_VERSION_Q1, SPRITE_VERSION_HL );
return;
}
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
size = sizeof( msprite_t ) + ( pin->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pin->type;
psprite->texFormat = pin->texFormat;
psprite->numframes = mod->numframes = pin->numframes;
psprite->facecull = pin->facetype;
psprite->radius = pin->boundingradius;
psprite->synctype = pin->synctype;
mod->mins[0] = mod->mins[1] = -pin->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pin->bounds[0] * 0.5f;
mod->mins[2] = -pin->bounds[1] * 0.5f;
mod->maxs[2] = pin->bounds[1] * 0.5f;
numi = (short *)(pin + 1);
if( i == SPRITE_VERSION_Q1 )
{
pinq1 = (dsprite_q1_t *)buffer;
size = sizeof( msprite_t ) + ( pinq1->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinq1->type;
psprite->texFormat = SPR_ADDITIVE; //SPR_ALPHTEST;
psprite->numframes = mod->numframes = pinq1->numframes;
psprite->facecull = SPR_CULL_FRONT;
psprite->radius = pinq1->boundingradius;
psprite->synctype = pinq1->synctype;
mod->mins[0] = mod->mins[1] = -pinq1->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pinq1->bounds[0] * 0.5f;
mod->mins[2] = -pinq1->bounds[1] * 0.5f;
mod->maxs[2] = pinq1->bounds[1] * 0.5f;
numi = NULL;
}
else if( i == SPRITE_VERSION_HL )
{
pinhl = (dsprite_hl_t *)buffer;
size = sizeof( msprite_t ) + ( pinhl->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinhl->type;
psprite->texFormat = pinhl->texFormat;
psprite->numframes = mod->numframes = pinhl->numframes;
psprite->facecull = pinhl->facetype;
psprite->radius = pinhl->boundingradius;
psprite->synctype = pinhl->synctype;
mod->mins[0] = mod->mins[1] = -pinhl->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pinhl->bounds[0] * 0.5f;
mod->mins[2] = -pinhl->bounds[1] * 0.5f;
mod->maxs[2] = pinhl->bounds[1] * 0.5f;
numi = (short *)(pinhl + 1);
}
if( host.type == HOST_DEDICATED )
{
@ -211,7 +238,15 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
return;
}
if( *numi == 256 )
if( numi == NULL )
{
rgbdata_t *pal;
pal = FS_LoadImage( "#id.pal", (byte *)&i, 768 );
pframetype = (dframetype_t *)(pinq1 + 1);
FS_FreeImage( pal ); // palette installed, no reason to keep this data
}
else if( *numi == 256 )
{
byte *src = (byte *)(numi+1);
rgbdata_t *pal;
@ -235,17 +270,17 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
}
else
{
MsgDev( D_ERROR, "%s has wrong number of palette colors %i (should be 256)\n", mod->name, numi );
MsgDev( D_ERROR, "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
return;
}
if( pin->numframes < 1 )
if( mod->numframes < 1 )
{
MsgDev( D_ERROR, "%s has invalid # of frames: %d\n", mod->name, pin->numframes );
MsgDev( D_ERROR, "%s has invalid # of frames: %d\n", mod->name, mod->numframes );
return;
}
for( i = 0; i < pin->numframes; i++ )
for( i = 0; i < mod->numframes; i++ )
{
frametype_t frametype = pframetype->type;
psprite->frames[i].type = frametype;

View File

@ -1598,8 +1598,12 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight )
{
int sequence = bound( 0, ent->curstate.sequence, m_pStudioHeader->numseq - 1 );
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + sequence;
vec3_t size;
if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING ) && !pseqdesc->activity && m_pStudioHeader->numseq > 1 )
VectorSubtract( pseqdesc->bbmax, pseqdesc->bbmin, size );
total = Q_max( size[0], Q_max( size[1], size[2] ));
if( !FBitSet( pseqdesc->flags, STUDIO_LOOPING ) && !pseqdesc->activity && m_pStudioHeader->numseq > 1 && total > 128.0f )
Matrix3x4_OriginFromMatrix( g_studio.lighttransform[0], origin );
else Matrix3x4_OriginFromMatrix( g_studio.rotationmatrix, origin );
}
@ -1634,9 +1638,9 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *plight )
{
VectorSet( lightDir, mv->skyvec_x, mv->skyvec_y, mv->skyvec_z );
light.r = LightToTexGamma( mv->skycolor_r );
light.g = LightToTexGamma( mv->skycolor_g );
light.b = LightToTexGamma( mv->skycolor_b );
light.r = mv->skycolor_r;
light.g = mv->skycolor_g;
light.b = mv->skycolor_b;
}
}
@ -3394,11 +3398,16 @@ void R_DrawStudioModel( cl_entity_t *e )
}
else
{
if( e->curstate.movetype == MOVETYPE_FOLLOW )
if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 )
{
RI.currententity = CL_GetEntityByIndex( e->curstate.aiment );
R_StudioDrawModelInternal( RI.currententity, 0 );
RI.currententity = e;
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment );
if( parent && parent->model && parent->model->type == mod_studio )
{
RI.currententity = parent;
R_StudioDrawModelInternal( RI.currententity, 0 );
RI.currententity = e;
}
}
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );

View File

@ -2131,7 +2131,7 @@ qboolean S_Init( void )
}
s_volume = Cvar_Get( "volume", "0.7", FCVAR_ARCHIVE, "sound volume" );
s_musicvolume = Cvar_Get( "musicvolume", "1.0", FCVAR_ARCHIVE, "background music volume" );
s_musicvolume = Cvar_Get( "MP3Volume", "1.0", FCVAR_ARCHIVE, "background music volume" );
s_mixahead = Cvar_Get( "_snd_mixahead", "0.12", 0, "how much sound to mix ahead of time" );
s_show = Cvar_Get( "s_show", "0", FCVAR_ARCHIVE, "show playing sounds" );
s_lerping = Cvar_Get( "s_lerping", "0", FCVAR_ARCHIVE, "apply interpolation to sound output" );

View File

@ -962,31 +962,41 @@ void Cmd_ExecuteString( char *text )
// execute the command line
Cmd_TokenizeString( text );
if( !Cmd_Argc()) return; // no tokens
if( !Cmd_Argc( )) return; // no tokens
// check aliases
for( a = cmd_alias; a; a = a->next )
if( !host.apply_game_config )
{
if( !Q_stricmp( cmd_argv[0], a->name ))
// check aliases
for( a = cmd_alias; a; a = a->next )
{
Cbuf_InsertText( a->value );
return;
if( !Q_stricmp( cmd_argv[0], a->name ))
{
Cbuf_InsertText( a->value );
return;
}
}
}
// check functions
for( cmd = cmd_functions; cmd; cmd = cmd->next )
// special mode for restore game.dll archived cvars
if( !host.apply_game_config || !Q_strcmp( cmd_argv[0], "exec" ))
{
if( !Q_stricmp( cmd_argv[0], cmd->name ) && cmd->function )
// check functions
for( cmd = cmd_functions; cmd; cmd = cmd->next )
{
cmd->function();
return;
if( !Q_stricmp( cmd_argv[0], cmd->name ) && cmd->function )
{
cmd->function();
return;
}
}
}
// check cvars
if( Cvar_Command( )) return;
if( host.apply_game_config )
return; // don't send nothing to server: we is a server!
// forward the command line to the server, so the entity DLL can parse it
if( host.type == HOST_NORMAL )
{

View File

@ -332,6 +332,7 @@ typedef struct host_parm_s
qboolean overview_loading; // another nasty hack to tell imagelib about ovierview
qboolean force_draw_version; // used when fraps is loaded
qboolean write_to_clipboard; // put image to clipboard instead of disk
qboolean apply_game_config; // when true apply only to game cvars and ignore all other commands
qboolean crashed; // set to true if crashed
// some settings were changed and needs to global update

View File

@ -987,7 +987,7 @@ void Host_WriteServerConfig( const char *name )
{
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\t\t\tCopyright XashXT Group %s ©\n", Q_timestamp( TIME_YEAR_ONLY ));
FS_Printf( f, "//\t\tsettings.rc - multiplayer server temporare config\n" );
FS_Printf( f, "//\t\tgame.cfg - multiplayer server temporare config\n" );
FS_Printf( f, "//=======================================================================\n" );
Cvar_WriteVariables( f, FCVAR_SERVER );
FS_Close( f );

View File

@ -2163,6 +2163,10 @@ void Con_VidInit( void )
}
}
if( !con.background ) // last chance - quake conback image
con.background = GL_LoadTexture( "gfx/conback.lmp", NULL, 0, TF_IMAGE, NULL );
// missed console image will be replaced as gray background like X-Ray or Crysis
if( con.background == tr.defaultTexture || con.background == 0 )
con.background = tr.grayTexture;

View File

@ -375,7 +375,7 @@ void Cvar_DirectSet( convar_t *var, const char *value )
if( !var ) return; // ???
// lookup for registration
if( CVAR_CHECK_SENTINEL( var ) || var->next == NULL )
if( CVAR_CHECK_SENTINEL( var ) || ( var->next == NULL && !FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED )))
{
// need to registering cvar fisrt
MsgDev( D_WARN, "Cvar_DirectSet: called for unregistered cvar '%s'\n", var->name );
@ -472,8 +472,10 @@ void Cvar_Set( const char *var_name, const char *value )
convar_t *var = Cvar_FindVar( var_name );
if( !var )
{ // there is an error in C code if this happens
MsgDev( D_ERROR, "Cvar_Set: variable '%s' not found\n", var_name );
{
// there is an error in C code if this happens
if( host.type != HOST_DEDICATED )
MsgDev( D_ERROR, "Cvar_Set: variable '%s' not found\n", var_name );
return;
}
@ -602,6 +604,12 @@ qboolean Cvar_Command( void )
return true;
}
if( host.apply_game_config )
{
if( !FBitSet( v->flags, FCVAR_EXTDLL ))
return true; // only game.dll cvars passed
}
if( FBitSet( v->flags, FCVAR_SPONLY ) && CL_GetMaxClients() > 1 )
{
Msg( "can't set \"%s\" in multiplayer\n", v->name );

View File

@ -74,9 +74,6 @@ void Host_PrintEngineFeatures( void )
if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
MsgDev( D_REPORT, "^3EXT:^7 big world support enabled\n" );
if( FBitSet( host.features, ENGINE_BUILD_SURFMESHES ))
MsgDev( D_REPORT, "^3EXT:^7 surfmeshes enabled\n" );
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
MsgDev( D_REPORT, "^3EXT:^7 deluxemap support enabled\n" );
@ -258,9 +255,9 @@ void Host_Exec_f( void )
return;
}
if( !Q_stricmp( "settings.rc", Cmd_Argv( 1 )))
if( !Q_stricmp( "game.cfg", Cmd_Argv( 1 )))
{
// don't execute settings.rc in singleplayer
// don't execute game.cfg in singleplayer
if( SV_GetMaxClients() == 1 )
return;
}
@ -281,7 +278,9 @@ void Host_Exec_f( void )
Q_strncat( txt, "\n", len + 2 );
Mem_Free( f );
MsgDev( D_INFO, "execing %s\n", Cmd_Argv( 1 ));
if( host.apply_game_config )
MsgDev( D_INFO, "execing ^2%s^7\n", Cmd_Argv( 1 ));
else MsgDev( D_INFO, "execing %s\n", Cmd_Argv( 1 ));
Cbuf_InsertText( txt );
Mem_Free( txt );
}
@ -637,6 +636,7 @@ void Host_Print( const char *txt )
Q_strcat( host.rd.buffer, txt );
return;
}
Con_Print( txt ); // echo to client console
}
@ -753,12 +753,16 @@ static void Host_Crash_f( void )
Host_InitCommon
=================
*/
void Host_InitCommon( const char *progname, qboolean bChangeGame )
void Host_InitCommon( const char *hostname, qboolean bChangeGame )
{
MEMORYSTATUS lpBuffer;
char dev_level[4];
char progname[128];
char cmdline[128];
qboolean parse_cmdline = false;
char szTemp[MAX_SYSPATH];
string szRootPath;
char *in, *out;
lpBuffer.dwLength = sizeof( MEMORYSTATUS );
GlobalMemoryStatus( &lpBuffer );
@ -777,10 +781,30 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
Memory_Init(); // init memory subsystem
// some commands may turn engine into infinity loop,
// e.g. xash.exe +game xash -game xash
// so we clearing all cmd_args, but leave dbg states as well
Sys_ParseCommandLine( GetCommandLine( ));
progname[0] = cmdline[0] = '\0';
in = (char *)hostname;
out = progname;
while( *in != '\0' )
{
if( parse_cmdline )
{
*out++ = *in++;
}
else
{
if( *in == ' ' )
{
parse_cmdline = true;
*out++ = '\0';
out = cmdline;
}
else *out++ = *in++;
}
}
*out = '\0'; // write terminator
Sys_ParseCommandLine( GetCommandLine( ), false );
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
host.mempool = Mem_AllocPool( "Zone Engine" );
@ -823,6 +847,9 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
}
else Q_strncpy( SI.ModuleName, progname, sizeof( SI.ModuleName ));
if( Sys_CheckParm( "-dedicated" ))
host.type = HOST_DEDICATED;
if( host.type == HOST_DEDICATED )
{
// check for duplicate dedicated server
@ -835,7 +862,7 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
return;
}
Sys_MergeCommandLine( GetCommandLine( ));
Sys_MergeCommandLine( cmdline );
CloseHandle( host.hMutex );
host.hMutex = CreateSemaphore( NULL, 0, 1, "Xash Dedicated Server" );
@ -955,21 +982,10 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
Cmd_AddCommand( "quit", Sys_Quit, "quit the game" );
Cmd_AddCommand( "exit", Sys_Quit, "quit the game" );
// dedicated servers using settings from server.cfg file
Cbuf_AddText( va( "exec %s\n", "settings.rc" ));
Cbuf_Execute();
Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "defaultmap" )));
}
else
{
Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
Cbuf_AddText( "exec config.cfg\n" );
}
else Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
host.errorframe = 0;
Cbuf_Execute();
// post initializations
switch( host.type )
@ -978,6 +994,7 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
Con_ShowConsole( false ); // hide console
// execute startup config and cmdline
Cbuf_AddText( va( "exec %s.rc\n", SI.ModuleName ));
Cbuf_AddText( "exec config.cfg\n" );
// intentional fallthrough
case HOST_DEDICATED:
// if stuffcmds wasn't run, then init.rc is probably missing, use default
@ -992,7 +1009,6 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
Cmd_RemoveCommand( "setgl" );
// we need to execute it again here
Cmd_ExecuteString( "exec config.cfg\n" );
oldtime = Sys_DoubleTime() - 0.1;
SCR_CheckStartupVids(); // must be last

View File

@ -260,7 +260,9 @@ enum
LUMP_NORMAL = 0, // no alpha
LUMP_MASKED, // 1-bit alpha channel masked texture
LUMP_GRADIENT, // gradient image (decals)
LUMP_EXTENDED // bmp images have extened palette with alpha-channel
LUMP_EXTENDED, // bmp images have extened palette with alpha-channel
LUMP_HALFLIFE, // get predefined half-life palette
LUMP_QUAKE1 // get predefined quake palette
};
enum

View File

@ -348,28 +348,28 @@ void Image_SetPalette( const byte *pal, uint *d_table )
void Image_GetPaletteQ1( void )
{
image.d_rendermode = LUMP_NORMAL;
if( !q1palette_init )
{
image.d_rendermode = LUMP_NORMAL;
Image_SetPalette( palette_q1, d_8toQ1table );
d_8toQ1table[255] = 0; // 255 is transparent
q1palette_init = true;
}
image.d_rendermode = LUMP_QUAKE1;
image.d_currentpal = d_8toQ1table;
}
void Image_GetPaletteHL( void )
{
image.d_rendermode = LUMP_NORMAL;
if( !hlpalette_init )
{
image.d_rendermode = LUMP_NORMAL;
Image_SetPalette( palette_hl, d_8toHLtable );
hlpalette_init = true;
}
image.d_rendermode = LUMP_HALFLIFE;
image.d_currentpal = d_8toHLtable;
}
@ -393,7 +393,22 @@ void Image_GetPaletteLMP( const byte *pal, int rendermode )
Image_SetPalette( pal, d_8to24table );
image.d_currentpal = d_8to24table;
}
else Image_GetPaletteHL(); // default half-life palette
else
{
switch( rendermode )
{
case LUMP_QUAKE1:
Image_GetPaletteQ1();
break;
case LUMP_HALFLIFE:
Image_GetPaletteHL(); // default half-life palette
break;
default:
MsgDev( D_ERROR, "Image_GetPaletteLMP: invalid palette specified\n" );
Image_GetPaletteHL(); // defaulting to half-life palette
break;
}
}
}
void Image_ConvertPalTo24bit( rgbdata_t *pic )

View File

@ -45,7 +45,15 @@ qboolean Image_LoadPAL( const char *name, const byte *buffer, size_t filesize )
else if( Q_stristr( name, "gradient" ))
rendermode = LUMP_GRADIENT;
else if( Q_stristr( name, "valve" ))
{
rendermode = LUMP_HALFLIFE;
buffer = NULL; // force to get HL palette
}
else if( Q_stristr( name, "id" ))
{
rendermode = LUMP_QUAKE1;
buffer = NULL; // force to get Q1 palette
}
}
// NOTE: image.d_currentpal not cleared with Image_Reset()
@ -219,6 +227,7 @@ qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize )
{
case LUMP_GRADIENT:
case LUMP_MASKED:
case LUMP_QUAKE1:
SetBits( image.flags, IMAGE_HAS_ALPHA );
break;
}

View File

@ -40,9 +40,6 @@ GNU General Public License for more details.
#define LM_SAMPLE_SIZE world.lm_sample_size // lightmap resoultion
#define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces))
#define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data))
#define CHECKVISBIT( vis, b ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] & (1 << ((b) & 7))) : (byte)false )
#define SETVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] |= (1 << ((b) & 7))) : (byte)false )
#define CLEARVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] &= ~(1 << ((b) & 7))) : (byte)false )
@ -140,14 +137,12 @@ model_t *Mod_ForName( const char *name, qboolean world );
qboolean Mod_RegisterModel( const char *name, int index );
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, short *lastleaf );
void Mod_TesselatePolygon( msurface_t *surf, model_t *mod, float tessSize );
int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *lastleaf );
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info );
void Mod_AmbientLevels( const vec3_t p, byte *pvolumes );
int Mod_SampleSizeForFace( msurface_t *surf );
byte *Mod_GetPVSForPoint( const vec3_t p );

View File

@ -1348,7 +1348,7 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
e = loadmodel->surfedges[surf->firstedge + i];
if( e >= loadmodel->numedges || e <= -loadmodel->numedges )
Host_Error( "Mod_CalcSurfaceBounds: bad edge\n" );
Host_Error( "Mod_CalcSurfaceExtents: bad edge\n" );
if( e >= 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
@ -1381,12 +1381,12 @@ Mod_CalcSurfaceBounds
fills in surf->mins and surf->maxs
=================
*/
static void Mod_CalcSurfaceBounds( msurface_t *surf, mextrasurf_t *info )
static void Mod_CalcSurfaceBounds( msurface_t *surf )
{
int i, e;
mvertex_t *v;
ClearBounds( info->mins, info->maxs );
ClearBounds( surf->info->mins, surf->info->maxs );
for( i = 0; i < surf->numedges; i++ )
{
@ -1397,506 +1397,10 @@ static void Mod_CalcSurfaceBounds( msurface_t *surf, mextrasurf_t *info )
if( e >= 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
AddPointToBounds( v->position, info->mins, info->maxs );
AddPointToBounds( v->position, surf->info->mins, surf->info->maxs );
}
VectorAverage( info->mins, info->maxs, info->origin );
}
/*
=================
Mod_BuildPolygon
=================
*/
static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts, const float *verts )
{
float s, t;
uint bufSize;
vec3_t normal, tangent, binormal;
mtexinfo_t *texinfo = surf->texinfo;
int i, numElems, sample_size;
byte *buffer;
msurfmesh_t *mesh;
// allocate mesh
numElems = (numVerts - 2) * 3;
bufSize = sizeof( msurfmesh_t ) + numVerts * sizeof( glvert_t ) + numElems * sizeof( word );
buffer = Mem_Alloc( loadmodel->mempool, bufSize );
sample_size = Mod_SampleSizeForFace( surf );
mesh = (msurfmesh_t *)buffer;
buffer += sizeof( msurfmesh_t );
mesh->numVerts = numVerts;
mesh->numElems = numElems;
// calc tangent space
if( surf->flags & SURF_PLANEBACK )
VectorNegate( surf->plane->normal, normal );
else VectorCopy( surf->plane->normal, normal );
VectorCopy( surf->texinfo->vecs[0], tangent );
VectorNegate( surf->texinfo->vecs[1], binormal );
VectorNormalize( normal ); // g-cont. this is even needed?
VectorNormalize( tangent );
VectorNormalize( binormal );
// setup pointers
mesh->verts = (glvert_t *)buffer;
buffer += numVerts * sizeof( glvert_t );
mesh->elems = (word *)buffer;
buffer += numElems * sizeof( word );
mesh->next = info->mesh;
mesh->surf = surf; // NOTE: meshchains can be linked with one surface
info->mesh = mesh;
// create indices
for( i = 0; i < mesh->numVerts - 2; i++ )
{
mesh->elems[i*3+0] = 0;
mesh->elems[i*3+1] = i + 1;
mesh->elems[i*3+2] = i + 2;
}
for( i = 0; i < numVerts; i++, verts += 3 )
{
glvert_t *out = &mesh->verts[i];
// vertex
VectorCopy( verts, out->vertex );
VectorCopy( tangent, out->tangent );
VectorCopy( binormal, out->binormal );
VectorCopy( normal, out->normal );
// texture coordinates
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3];
s /= texinfo->texture->width;
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3];
t /= texinfo->texture->height;
out->stcoord[0] = s;
out->stcoord[1] = t;
// lightmap texture coordinates
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
s += surf->light_s * sample_size;
s += sample_size >> 1;
s /= BLOCK_SIZE * sample_size;
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
t += surf->light_t * sample_size;
t += sample_size >> 1;
t /= BLOCK_SIZE * sample_size;
out->lmcoord[0] = s;
out->lmcoord[1] = t;
// clear colors (it can be used for vertex lighting)
memset( out->color, 0xFF, sizeof( out->color ));
}
}
/*
=================
Mod_SubdividePolygon
=================
*/
static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numVerts, float *verts, float tessSize )
{
vec3_t vTotal, nTotal, tTotal, bTotal;
vec3_t front[MAX_SIDE_VERTS], back[MAX_SIDE_VERTS];
float *v, m, oneDivVerts, dist, dists[MAX_SIDE_VERTS];
qboolean lightmap = (surf->flags & SURF_DRAWTILED) ? false : true;
vec3_t normal, tangent, binormal, mins, maxs;
mtexinfo_t *texinfo = surf->texinfo;
vec2_t totalST, totalLM;
int sample_size;
float s, t, scale;
int i, j, f, b;
uint bufSize;
byte *buffer;
msurfmesh_t *mesh;
ClearBounds( mins, maxs );
for( i = 0, v = verts; i < numVerts; i++, v += 3 )
AddPointToBounds( v, mins, maxs );
sample_size = Mod_SampleSizeForFace( surf );
for( i = 0; i < 3; i++ )
{
m = tessSize * (float)floor((( mins[i] + maxs[i] ) * 0.5f ) / tessSize + 0.5f );
if( maxs[i] - m < 8.0f ) continue;
if( m - mins[i] < 8.0f ) continue;
// cut it
for( j = 0, v = verts + i; j < numVerts; j++, v += 3 )
dists[j] = *v - m;
// wrap cases
dists[j] = dists[0];
v -= i;
VectorCopy( verts, v );
for( f = j = b = 0, v = verts; j < numVerts; j++, v += 3 )
{
if( dists[j] >= 0.0f )
{
VectorCopy( v, front[f] );
f++;
}
if( dists[j] <= 0.0f )
{
VectorCopy( v, back[b] );
b++;
}
if( dists[j] == 0.0f || dists[j+1] == 0.0f )
continue;
if(( dists[j] > 0.0f ) != ( dists[j+1] > 0.0f ))
{
// clip point
dist = dists[j] / (dists[j] - dists[j+1]);
front[f][0] = back[b][0] = v[0] + (v[3] - v[0]) * dist;
front[f][1] = back[b][1] = v[1] + (v[4] - v[1]) * dist;
front[f][2] = back[b][2] = v[2] + (v[5] - v[2]) * dist;
f++, b++;
}
}
Mod_SubdividePolygon( info, surf, f, front[0], tessSize );
Mod_SubdividePolygon( info, surf, b, back[0], tessSize );
return;
}
bufSize = sizeof( msurfmesh_t ) + ( numVerts + 2 ) * sizeof( glvert_t ); // temp buffer has no indices
buffer = Mem_Alloc( loadmodel->mempool, bufSize );
mesh = (msurfmesh_t *)buffer;
buffer += sizeof( msurfmesh_t );
// create vertices
mesh->numVerts = numVerts + 2;
mesh->numElems = numVerts * 3;
// calc tangent space
if( surf->flags & SURF_PLANEBACK )
VectorNegate( surf->plane->normal, normal );
else VectorCopy( surf->plane->normal, normal );
VectorCopy( surf->texinfo->vecs[0], tangent );
VectorNegate( surf->texinfo->vecs[1], binormal );
VectorNormalize( normal ); // g-cont. this is even needed?
VectorNormalize( tangent );
VectorNormalize( binormal );
// setup pointers
mesh->verts = (glvert_t *)buffer;
buffer += numVerts * sizeof( glvert_t );
VectorClear( vTotal );
VectorClear( nTotal );
VectorClear( bTotal );
VectorClear( tTotal );
totalST[0] = totalST[1] = 0;
totalLM[0] = totalLM[1] = 0;
scale = ( 1.0f / tessSize );
for( i = 0; i < numVerts; i++, verts += 3 )
{
glvert_t *out = &mesh->verts[i+1];
// vertex
VectorCopy( verts, out->vertex );
VectorCopy( normal, out->normal );
VectorCopy( tangent, out->tangent );
VectorCopy( binormal, out->binormal );
VectorAdd( vTotal, verts, vTotal );
VectorAdd( nTotal, normal, nTotal );
VectorAdd( tTotal, tangent, tTotal );
VectorAdd( bTotal, binormal, bTotal );
if( lightmap )
{
// texture coordinates
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3];
s /= texinfo->texture->width;
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3];
t /= texinfo->texture->height;
}
else
{
// texture coordinates
s = DotProduct( verts, texinfo->vecs[0] ) * scale;
t = DotProduct( verts, texinfo->vecs[1] ) * scale;
}
out->stcoord[0] = s;
out->stcoord[1] = t;
totalST[0] += s;
totalST[1] += t;
if( lightmap )
{
// lightmap texture coordinates
s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
s += surf->light_s * sample_size;
s += sample_size >> 1;
s /= BLOCK_SIZE * sample_size;
t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
t += surf->light_t * sample_size;
t += sample_size >> 1;
t /= BLOCK_SIZE * sample_size;
}
else
{
s = t = 0.0f;
}
out->lmcoord[0] = s;
out->lmcoord[1] = t;
totalLM[0] += s;
totalLM[1] += t;
// clear colors (it can be used for vertex lighting)
memset( out->color, 0xFF, sizeof( out->color ));
}
// vertex
oneDivVerts = ( 1.0f / (float)numVerts );
VectorScale( vTotal, oneDivVerts, mesh->verts[0].vertex );
VectorScale( nTotal, oneDivVerts, mesh->verts[0].normal );
VectorScale( tTotal, oneDivVerts, mesh->verts[0].tangent );
VectorScale( bTotal, oneDivVerts, mesh->verts[0].binormal );
VectorNormalize( mesh->verts[0].normal );
VectorNormalize( mesh->verts[0].tangent );
VectorNormalize( mesh->verts[0].binormal );
// texture coordinates
mesh->verts[0].stcoord[0] = totalST[0] * oneDivVerts;
mesh->verts[0].stcoord[1] = totalST[1] * oneDivVerts;
// lightmap texture coordinates
mesh->verts[0].lmcoord[0] = totalLM[0] * oneDivVerts;
mesh->verts[0].lmcoord[1] = totalLM[1] * oneDivVerts;
// copy first vertex to last
memcpy( &mesh->verts[i+1], &mesh->verts[1], sizeof( glvert_t ));
mesh->next = info->mesh;
mesh->surf = surf; // NOTE: meshchains can be linked with one surface
info->mesh = mesh;
}
/*
================
Mod_ConvertSurface
turn the polychain into one subdivided surface
================
*/
static void Mod_ConvertSurface( mextrasurf_t *info, msurface_t *surf )
{
msurfmesh_t *poly, *next, *mesh;
int numElems, numVerts;
glvert_t *outVerts;
word *outElems;
int i, bufSize;
byte *buffer;
// find the total vertex count and index count
numElems = numVerts = 0;
// determine count of indices and vertices
for( poly = info->mesh; poly; poly = poly->next )
{
numElems += ( poly->numVerts - 2 ) * 3;
numVerts += poly->numVerts;
}
// unsigned short limit
if( numVerts >= 65536 ) Host_Error( "Mod_ConvertSurface: vertex count %i exceeds 65535\n", numVerts );
if( numElems >= 65536 ) Host_Error( "Mod_ConvertSurface: index count %i exceeds 65535\n", numElems );
bufSize = sizeof( msurfmesh_t ) + numVerts * sizeof( glvert_t ) + numElems * sizeof( word );
buffer = Mem_Alloc( loadmodel->mempool, bufSize );
mesh = (msurfmesh_t *)buffer;
buffer += sizeof( msurfmesh_t );
mesh->numVerts = numVerts;
mesh->numElems = numElems;
// setup pointers
mesh->verts = (glvert_t *)buffer;
buffer += numVerts * sizeof( glvert_t );
mesh->elems = (word *)buffer;
buffer += numElems * sizeof( word );
// setup moving pointers
outVerts = (glvert_t *)mesh->verts;
outElems = (word *)mesh->elems;
// store vertex data
numElems = numVerts = 0;
for( poly = info->mesh; poly; poly = poly->next )
{
// indexes
outElems = mesh->elems + numElems;
outVerts = mesh->verts + numVerts;
for( i = 0; i < poly->numVerts - 2; i++ )
{
outElems[i*3+0] = numVerts;
outElems[i*3+1] = numVerts + i + 1;
outElems[i*3+2] = numVerts + i + 2;
}
memcpy( outVerts, poly->verts, sizeof( glvert_t ) * poly->numVerts );
numElems += (poly->numVerts - 2) * 3;
numVerts += poly->numVerts;
}
// release the old polys crap
for( poly = info->mesh; poly; poly = next )
{
next = poly->next;
Mem_Free( poly );
}
ASSERT( mesh->numVerts == numVerts );
ASSERT( mesh->numElems == numElems );
mesh->next = info->mesh;
mesh->surf = surf; // NOTE: meshchains can be linked with one surface
info->mesh = mesh;
}
/*
=================
Mod_BuildSurfacePolygons
=================
*/
void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info )
{
vec3_t verts[MAX_SIDE_VERTS];
char *texname;
int i, e;
mvertex_t *v;
if( info->mesh ) return; // already exist
// convert edges back to a normal polygon
for( i = 0; i < surf->numedges; i++ )
{
if( i == MAX_SIDE_VERTS )
{
MsgDev( D_ERROR, "BuildSurfMesh: poly %i exceeded %i vertexes!\n", surf - loadmodel->surfaces, MAX_SIDE_VERTS );
break; // too big polygon ?
}
e = loadmodel->surfedges[surf->firstedge + i];
if( e > 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
VectorCopy( v->position, verts[i] );
}
// subdivide water or sky sphere for Quake1 maps
if( surf->flags & SURF_DRAWTURB && !( surf->flags & SURF_REFLECT ))
{
Mod_SubdividePolygon( info, surf, surf->numedges, verts[0], 64.0f );
Mod_ConvertSurface( info, surf );
}
else
{
Mod_BuildPolygon( info, surf, surf->numedges, verts[0] );
}
if( info->mesh ) return; // all done
if( surf->texinfo && surf->texinfo->texture )
texname = surf->texinfo->texture->name;
else texname = "notexture";
MsgDev( D_ERROR, "BuildSurfMesh: surface %i (%s) failed to build surfmesh\n", surf - loadmodel->surfaces, texname );
}
/*
=================
Mod_TesselatePolygon
tesselate specified polygon
by user request
=================
*/
void Mod_TesselatePolygon( msurface_t *surf, model_t *mod, float tessSize )
{
mextrasurf_t *info;
model_t *old = loadmodel;
vec3_t verts[MAX_SIDE_VERTS];
char *texname;
int i, e;
mvertex_t *v;
if( !surf || !mod ) return; // bad arguments?
tessSize = bound( 8.0f, tessSize, 256.0f );
info = SURF_INFO( surf, mod );
loadmodel = mod;
// release old mesh
if( info->mesh )
{
Mem_Free( info->mesh );
info->mesh = NULL;
}
// convert edges back to a normal polygon
for( i = 0; i < surf->numedges; i++ )
{
if( i == MAX_SIDE_VERTS )
{
MsgDev( D_ERROR, "BuildSurfMesh: poly %i exceeded %i vertexes!\n", surf - loadmodel->surfaces, MAX_SIDE_VERTS );
break; // too big polygon ?
}
e = loadmodel->surfedges[surf->firstedge + i];
if( e > 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
VectorCopy( v->position, verts[i] );
}
Mod_SubdividePolygon( info, surf, surf->numedges, verts[0], tessSize );
Mod_ConvertSurface( info, surf );
// restore loadmodel value
loadmodel = old;
if( info->mesh ) return; // all done
if( surf->texinfo && surf->texinfo->texture )
texname = surf->texinfo->texture->name;
else texname = "notexture";
MsgDev( D_ERROR, "BuildSurfMesh: surface %i (%s) failed to build surfmesh\n", surf - loadmodel->surfaces, texname );
VectorAverage( surf->info->mins, surf->info->maxs, surf->info->origin );
}
/*
@ -1918,15 +1422,17 @@ static void Mod_LoadSurfaces( const dlump_t *l )
count = l->filelen / sizeof( *in );
loadmodel->numsurfaces = count;
loadmodel->surfaces = Mem_Alloc( loadmodel->mempool, count * sizeof( msurface_t ));
loadmodel->cache.data = Mem_Alloc( loadmodel->mempool, count * sizeof( mextrasurf_t ));
out = loadmodel->surfaces;
info = loadmodel->cache.data;
loadmodel->surfaces = out = Mem_Alloc( loadmodel->mempool, count * sizeof( msurface_t ));
info = Mem_Alloc( loadmodel->mempool, count * sizeof( mextrasurf_t ));
for( i = 0; i < count; i++, in++, out++, info++ )
{
texture_t *tex;
// setup crosslinks between two parts of msurface_t
out->info = info;
info->surf = out;
if(( in->firstedge + in->numedges ) > loadmodel->numsurfedges )
{
MsgDev( D_ERROR, "Bad surface %i from %i\n", i, count );
@ -1947,12 +1453,7 @@ static void Mod_LoadSurfaces( const dlump_t *l )
out->flags |= (SURF_DRAWTILED|SURF_DRAWSKY);
if(( tex->name[0] == '*' && Q_stricmp( tex->name, "*default" )) || tex->name[0] == '!' )
{
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED);
if( !( host.features & ENGINE_BUILD_SURFMESHES ))
out->flags |= SURF_NOCULL;
}
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED|SURF_NOCULL);
if( !Q_strncmp( tex->name, "water", 5 ) || !Q_strnicmp( tex->name, "laser", 5 ))
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED|SURF_NOCULL);
@ -1978,7 +1479,7 @@ static void Mod_LoadSurfaces( const dlump_t *l )
if( out->texinfo->flags & TEX_SPECIAL )
out->flags |= SURF_DRAWTILED;
Mod_CalcSurfaceBounds( out, info );
Mod_CalcSurfaceBounds( out );
Mod_CalcSurfaceExtents( out );
if( loadmodel->lightdata && in->lightofs != -1 )
@ -1989,16 +1490,12 @@ static void Mod_LoadSurfaces( const dlump_t *l )
// if deluxemap is present setup it too
if( world.deluxedata )
info->deluxemap = world.deluxedata + (in->lightofs / 3);
out->info->deluxemap = world.deluxedata + (in->lightofs / 3);
}
for( j = 0; j < MAXLIGHTMAPS; j++ )
out->styles[j] = in->styles[j];
// build polygons for non-lightmapped surfaces
if( host.features & ENGINE_BUILD_SURFMESHES && (( out->flags & SURF_DRAWTILED ) || !out->samples ))
Mod_BuildSurfacePolygons( out, info );
if( out->flags & SURF_DRAWTURB )
GL_SubdivideSurface( out ); // cut up polygon for warps
}
@ -2813,7 +2310,6 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
for( j = 0; i != 0 && j < mod->nummodelsurfaces; j++ )
{
msurface_t *surf = mod->surfaces + mod->firstmodelsurface + j;
mextrasurf_t *info = SURF_INFO( surf, mod );
if( surf->flags & SURF_CONVEYOR )
mod->flags |= MODEL_CONVEYOR;
@ -2826,7 +2322,7 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
if( surf->plane->type == PLANE_Z )
{
// kill bottom plane too
if( info->mins[2] == bm->mins[2] + 1.0f )
if( surf->info->mins[2] == bm->mins[2] + 1.0f )
surf->flags |= SURF_WATERCSG;
}
else

View File

@ -148,7 +148,7 @@ GNU General Public License for more details.
#define FDECAL_DONTSAVE 0x04 // Decal was loaded from adjacent level, don't save it for this level
// reserved 0x08
// reserved 0x10
#define FDECAL_USESAXIS 0x20 // Uses the s axis field to determine orientation (footprints)
// reserved 0x20
#define FDECAL_STUDIO 0x40 // Indicates a studio decal
#define FDECAL_LOCAL_SPACE 0x80 // decal is in local space (any decal after serialization)

View File

@ -478,7 +478,7 @@ void Sys_InitLog( void )
{
const char *mode;
if( host.change_game )
if( host.change_game && host.type != HOST_DEDICATED )
mode = "a";
else mode = "w";

View File

@ -165,7 +165,7 @@ Sys_ParseCommandLine
==================
*/
void Sys_ParseCommandLine( LPSTR lpCmdLine )
void Sys_ParseCommandLine( LPSTR lpCmdLine, qboolean uncensored )
{
const char *blank = "censored";
static char commandline[MAX_SYSPATH];
@ -208,7 +208,8 @@ void Sys_ParseCommandLine( LPSTR lpCmdLine )
}
}
if( !host.change_game ) return;
if( uncensored || !host.change_game )
return;
for( i = 0; i < host.argc; i++ )
{
@ -233,16 +234,42 @@ Sys_MergeCommandLine
*/
void Sys_MergeCommandLine( LPSTR lpCmdLine )
{
const char *blank = "censored";
int i;
static char commandline[MAX_SYSPATH];
if( !host.change_game ) return;
for( i = 0; i < host.argc; i++ )
Q_strncpy( commandline, lpCmdLine, Q_strlen( lpCmdLine ) + 1 );
lpCmdLine = commandline; // to prevent modify original commandline
while( *lpCmdLine && ( host.argc < MAX_NUM_ARGVS ))
{
// second call
if( host.type == HOST_DEDICATED && !Q_strnicmp( "+menu_", host.argv[i], 6 ))
host.argv[i] = (char *)blank;
while( *lpCmdLine && *lpCmdLine <= ' ' )
lpCmdLine++;
if( !*lpCmdLine ) break;
if( *lpCmdLine == '\"' )
{
// quoted string
lpCmdLine++;
host.argv[host.argc] = lpCmdLine;
host.argc++;
while( *lpCmdLine && ( *lpCmdLine != '\"' ))
lpCmdLine++;
}
else
{
// unquoted word
host.argv[host.argc] = lpCmdLine;
host.argc++;
while( *lpCmdLine && *lpCmdLine > ' ')
lpCmdLine++;
}
if( *lpCmdLine )
{
*lpCmdLine = 0;
lpCmdLine++;
}
}
}

View File

@ -75,7 +75,7 @@ void Sys_Error( const char *error, ... );
qboolean Sys_LoadLibrary( dll_info_t *dll );
void* Sys_GetProcAddress( dll_info_t *dll, const char* name );
qboolean Sys_FreeLibrary( dll_info_t *dll );
void Sys_ParseCommandLine( LPSTR lpCmdLine );
void Sys_ParseCommandLine( LPSTR lpCmdLine, qboolean uncensored );
void Sys_MergeCommandLine( LPSTR lpCmdLine );
long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo );
void Sys_SetClipboardData( const byte *buffer, size_t size );

View File

@ -323,6 +323,7 @@ typedef struct
int gmsgHudText; // -1 if not catched (e.g. mod not registered this message)
void *hInstance; // pointer to game.dll
qboolean config_executed; // should to execute config.cfg once time to restore FCVAR_ARCHIVE that specified in hl.dll
union
{

View File

@ -2301,6 +2301,27 @@ void pfnServerCommand( const char* str )
else MsgDev( D_ERROR, "bad server command %s\n", str );
}
/*
=========
pfnServerExecute
=========
*/
void pfnServerExecute( void )
{
Cbuf_Execute();
if( svgame.config_executed )
return;
// here we restore arhcived cvars only from game.dll
host.apply_game_config = true;
Cbuf_AddText( "exec config.cfg\n" );
Cbuf_Execute();
host.apply_game_config = false;
svgame.config_executed = true;
}
/*
=========
pfnClientCommand
@ -4418,7 +4439,7 @@ static enginefuncs_t gEngfuncs =
pfnTraceSphere,
pfnGetAimVector,
pfnServerCommand,
Cbuf_Execute,
pfnServerExecute,
pfnClientCommand,
pfnParticleEffect,
pfnLightStyle,

View File

@ -31,7 +31,7 @@ CVAR_DEFINE_AUTO( rcon_password, "", 0, "remote connect password" );
CVAR_DEFINE_AUTO( sv_filterban, "1", 0, "filter banned users" );
CVAR_DEFINE_AUTO( sv_cheats, "0", FCVAR_SERVER, "allow cheats on server" );
CVAR_DEFINE_AUTO( sv_instancedbaseline, "1", 0, "allow to use instanced baselines to saves network overhead" );
CVAR_DEFINE_AUTO( sv_contact, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "server techincal support contact address or web-page" );
CVAR_DEFINE_AUTO( sv_contact, "", FCVAR_ARCHIVE|FCVAR_SERVER, "server techincal support contact address or web-page" );
CVAR_DEFINE_AUTO( sv_minupdaterate, "10.0", FCVAR_ARCHIVE, "minimal value for 'cl_updaterate' window" );
CVAR_DEFINE_AUTO( sv_maxupdaterate, "30.0", FCVAR_ARCHIVE, "maximal value for 'cl_updaterate' window" );
CVAR_DEFINE_AUTO( sv_minrate, "0", FCVAR_SERVER, "min bandwidth rate allowed on server, 0 == unlimited" );
@ -698,7 +698,6 @@ void SV_Init( void )
SV_InitHostCommands();
Cvar_Get ("protocol", va( "%i", PROTOCOL_VERSION ), FCVAR_READ_ONLY, "displays server protocol version" );
Cvar_Get ("defaultmap", "", FCVAR_SERVER, "holds the multiplayer mapname" );
Cvar_Get ("suitvolume", "0.25", FCVAR_ARCHIVE, "HEV suit volume" );
Cvar_Get ("sv_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" );
Cvar_Get( "gamedir", GI->gamefolder, FCVAR_SERVER|FCVAR_READ_ONLY, "game folder" );
@ -760,9 +759,9 @@ void SV_Init( void )
Cvar_RegisterVariable (&sv_friction);
Cvar_RegisterVariable (&sv_edgefriction);
Cvar_RegisterVariable (&sv_stopspeed);
sv_maxclients = Cvar_Get( "maxplayers", "1", FCVAR_LATCH|FCVAR_SERVER|FCVAR_UNLOGGED, "server max capacity" );
sv_maxclients = Cvar_Get( "maxplayers", "1", FCVAR_LATCH, "server max capacity" );
sv_check_errors = Cvar_Get( "sv_check_errors", "0", FCVAR_ARCHIVE, "check edicts for errors" );
public_server = Cvar_Get ("public", "0", FCVAR_SERVER, "change server type from private to public" );
public_server = Cvar_Get ("public", "0", 0, "change server type from private to public" );
sv_lighting_modulate = Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "lightstyles modulate scale" );
sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", FCVAR_ARCHIVE, "max reconnect attempts" );
Cvar_RegisterVariable (&sv_failuretime );

View File

@ -1067,6 +1067,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
soundlist_t soundInfo[MAX_CHANNELS];
string curtrack, looptrack;
int soundCount = 0;
byte decalFlags;
Q_snprintf( name, sizeof( name ), "save/%s.HL2", level );
@ -1110,12 +1111,13 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
nameSize = Q_strlen( entry->name ) + 1;
decalScale = (entry->scale * 4096);
decalFlags = entry->flags;
FS_Write( pFile, localPos, sizeof( localPos ));
FS_Write( pFile, &nameSize, sizeof( nameSize ));
FS_Write( pFile, entry->name, nameSize );
FS_Write( pFile, &entry->entityIndex, sizeof( entry->entityIndex ));
FS_Write( pFile, &entry->flags, sizeof( entry->flags ));
FS_Write( pFile, &decalFlags, sizeof( decalFlags ));
FS_Write( pFile, &decalScale, sizeof( decalScale ));
FS_Write( pFile, entry->impactPlaneNormal, sizeof( entry->impactPlaneNormal ));
@ -1238,6 +1240,7 @@ void SV_LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboolean
ClientSections_t sections;
soundlist_t soundInfo[MAX_CHANNELS];
int soundCount;
byte decalFlags;
Q_snprintf( name, sizeof( name ), "save/%s.HL2", level );
@ -1286,7 +1289,7 @@ void SV_LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboolean
FS_Read( pFile, &nameSize, sizeof( nameSize ));
FS_Read( pFile, entry->name, nameSize );
FS_Read( pFile, &entry->entityIndex, sizeof( entry->entityIndex ));
FS_Read( pFile, &entry->flags, sizeof( entry->flags ));
FS_Read( pFile, &decalFlags, sizeof( decalFlags ));
FS_Read( pFile, &decalScale, sizeof( decalScale ));
FS_Read( pFile, entry->impactPlaneNormal, sizeof( entry->impactPlaneNormal ));
@ -1295,6 +1298,7 @@ void SV_LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboolean
else VectorCopy( localPos, entry->position );
entry->scale = ((float)decalScale / 4096.0f);
entry->flags = decalFlags;
if( entry->flags & FDECAL_STUDIO )
{

View File

@ -26,13 +26,19 @@ SPRITE MODELS
*/
#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP"
#define SPRITE_VERSION 2 // Half-Life sprites
#define SPRITE_VERSION_Q1 1 // Quake sprites
#define SPRITE_VERSION_HL 2 // Half-Life sprites
// must match definition in alias.h
#ifndef SYNCTYPE_T
#define SYNCTYPE_T
typedef enum
{
ST_SYNC = 0,
ST_RAND
} synctype_t;
#endif
typedef enum
{
@ -64,6 +70,25 @@ typedef enum
SPR_CULL_NONE, // oriented sprite will be draw back face too
} facetype_t;
// generic helper
typedef struct
{
int ident; // LittleLong 'ISPR'
int version; // current version 2
} dsprite_t;
typedef struct
{
int ident; // LittleLong 'ISPR'
int version; // current version 2
int type; // camera align
float boundingradius; // quick face culling
int bounds[2]; // mins\maxs
int numframes; // including groups
float beamlength; // ???
synctype_t synctype; // animation synctype
} dsprite_q1_t;
typedef struct
{
int ident; // LittleLong 'ISPR'
@ -75,7 +100,7 @@ typedef struct
int numframes; // including groups
facetype_t facetype; // cullface (Xash3D ext)
synctype_t synctype; // animation synctype
} dsprite_t;
} dsprite_hl_t;
typedef struct
{

View File

@ -70,7 +70,7 @@ UI_Audio_GetConfig
static void UI_Audio_GetConfig( void )
{
uiAudio.soundVolume.curValue = CVAR_GET_FLOAT( "volume" );
uiAudio.musicVolume.curValue = CVAR_GET_FLOAT( "musicvolume" );
uiAudio.musicVolume.curValue = CVAR_GET_FLOAT( "MP3Volume" );
uiAudio.suitVolume.curValue = CVAR_GET_FLOAT( "suitvolume" );
if( CVAR_GET_FLOAT( "s_lerping" ))
@ -93,7 +93,7 @@ UI_Audio_SetConfig
static void UI_Audio_SetConfig( void )
{
CVAR_SET_FLOAT( "volume", uiAudio.soundVolume.curValue );
CVAR_SET_FLOAT( "musicvolume", uiAudio.musicVolume.curValue );
CVAR_SET_FLOAT( "MP3Volume", uiAudio.musicVolume.curValue );
CVAR_SET_FLOAT( "suitvolume", uiAudio.suitVolume.curValue );
CVAR_SET_FLOAT( "s_lerping", uiAudio.lerping.enabled );
CVAR_SET_FLOAT( "dsp_off", uiAudio.noDSP.enabled );
@ -107,7 +107,7 @@ UI_Audio_UpdateConfig
static void UI_Audio_UpdateConfig( void )
{
CVAR_SET_FLOAT( "volume", uiAudio.soundVolume.curValue );
CVAR_SET_FLOAT( "musicvolume", uiAudio.musicVolume.curValue );
CVAR_SET_FLOAT( "MP3Volume", uiAudio.musicVolume.curValue );
CVAR_SET_FLOAT( "suitvolume", uiAudio.suitVolume.curValue );
CVAR_SET_FLOAT( "s_lerping", uiAudio.lerping.enabled );
CVAR_SET_FLOAT( "dsp_off", uiAudio.noDSP.enabled );

View File

@ -36,8 +36,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ID_MAXCLIENTS 7
#define ID_HOSTNAME 8
#define ID_PASSWORD 9
#define ID_HLTV 10
#define ID_DEDICATED 11
#define ID_DEDICATED 10
#define ID_MSGBOX 12
#define ID_MSGTEXT 13
@ -64,7 +63,6 @@ typedef struct
menuField_s maxClients;
menuField_s hostName;
menuField_s password;
menuCheckBox_s hltv;
menuCheckBox_s dedicatedServer;
// newgame prompt dialog
@ -88,35 +86,35 @@ UI_CreateGame_Begin
*/
static void UI_CreateGame_Begin( void )
{
if( !MAP_IS_VALID( uiCreateGame.mapName[uiCreateGame.mapsList.curItem] ))
char *pMapName = uiCreateGame.mapName[uiCreateGame.mapsList.curItem];
int maxPlayers = atoi( uiCreateGame.maxClients.buffer );
if( !MAP_IS_VALID( pMapName ))
return; // bad map
CVAR_SET_STRING( "hostname", uiCreateGame.hostName.buffer );
HOST_WRITECONFIG ( "game.cfg" );
if( CVAR_GET_FLOAT( "host_serverstate" ) && CVAR_GET_FLOAT( "maxplayers" ) == 1 )
HOST_ENDGAME( "end of the game" );
CVAR_SET_FLOAT( "deathmatch", 1.0f ); // start deathmatch as default
CVAR_SET_FLOAT( "maxplayers", atoi( uiCreateGame.maxClients.buffer ));
CVAR_SET_STRING( "hostname", uiCreateGame.hostName.buffer );
CVAR_SET_STRING( "defaultmap", uiCreateGame.mapName[uiCreateGame.mapsList.curItem] );
CVAR_SET_FLOAT( "hltv", uiCreateGame.hltv.enabled );
BACKGROUND_TRACK( NULL, NULL );
HOST_WRITECONFIG ( "settings.rc" );
CVAR_SET_FLOAT( "deathmatch", 1.0f ); // start deathmatch as default
CVAR_SET_FLOAT( "maxplayers", maxPlayers );
BACKGROUND_TRACK ( NULL, NULL );
// all done, start server
if( uiCreateGame.dedicatedServer.enabled )
{
char cmd[128];
sprintf( cmd, "#%s", gMenu.m_gameinfo.gamefolder );
char cmd[128], msg[128];
sprintf( cmd, "#%s +maxplayers %i +map %s", gMenu.m_gameinfo.gamefolder, maxPlayers, pMapName );
sprintf( msg, "startup dedicated server from '%s'", gMenu.m_gameinfo.gamefolder );
// NOTE: dedicated server will be executed "defaultmap"
// from engine after restarting
HOST_CHANGEGAME( cmd, "Starting dedicated server...\n" );
HOST_CHANGEGAME( cmd, msg );
}
else
{
char cmd[128];
sprintf( cmd, "exec %s\nmap %s\n", "settings.rc", CVAR_GET_STRING( "defaultmap" ));
sprintf( cmd, "map %s\n", pMapName );
CLIENT_COMMAND( FALSE, cmd );
}
@ -139,7 +137,6 @@ static void UI_PromptDialog( void )
uiCreateGame.hostName.generic.flags ^= QMF_INACTIVE;
uiCreateGame.password.generic.flags ^= QMF_INACTIVE;
uiCreateGame.dedicatedServer.generic.flags ^= QMF_INACTIVE;
uiCreateGame.hltv.generic.flags ^= QMF_INACTIVE;
uiCreateGame.mapsList.generic.flags ^= QMF_INACTIVE;
uiCreateGame.msgBox.generic.flags ^= QMF_HIDDEN;
@ -229,7 +226,6 @@ static void UI_CreateGame_Callback( void *self, int event )
switch( item->id )
{
case ID_HLTV:
case ID_DEDICATED:
if( event == QM_PRESSED )
((menuCheckBox_s *)self)->focusPic = UI_CHECKBOX_PRESSED;
@ -337,15 +333,6 @@ static void UI_CreateGame_Init( void )
uiCreateGame.dedicatedServer.generic.callback = UI_CreateGame_Callback;
uiCreateGame.dedicatedServer.generic.statusText = "faster, but you can't join the server from this machine";
uiCreateGame.hltv.generic.id = ID_HLTV;
uiCreateGame.hltv.generic.type = QMTYPE_CHECKBOX;
uiCreateGame.hltv.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_ACT_ONRELEASE|QMF_MOUSEONLY|QMF_DROPSHADOW;
uiCreateGame.hltv.generic.name = "HLTV";
uiCreateGame.hltv.generic.x = 72;
uiCreateGame.hltv.generic.y = 635;
uiCreateGame.hltv.generic.callback = UI_CreateGame_Callback;
uiCreateGame.hltv.generic.statusText = "enable hltv mode in multiplayer";
uiCreateGame.hintMessage.generic.id = ID_TABLEHINT;
uiCreateGame.hintMessage.generic.type = QMTYPE_ACTION;
uiCreateGame.hintMessage.generic.flags = QMF_INACTIVE|QMF_SMALLFONT;
@ -454,7 +441,6 @@ static void UI_CreateGame_Init( void )
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.hostName );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.password );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.dedicatedServer );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.hltv );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.hintMessage );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.mapsList );
UI_AddItem( &uiCreateGame.menu, (void *)&uiCreateGame.msgBox );