Pure engine source code(LF line endings, UTF8 encoded)

This commit is contained in:
Alibek Omarov 2018-04-13 19:23:45 +03:00
commit 8d6e3b7f79
197 changed files with 125800 additions and 0 deletions

60
common/beamdef.h Normal file
View File

@ -0,0 +1,60 @@
/***
*
* 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 BEAMDEF_H
#define BEAMDEF_H
#define FBEAM_STARTENTITY 0x00000001
#define FBEAM_ENDENTITY 0x00000002
#define FBEAM_FADEIN 0x00000004
#define FBEAM_FADEOUT 0x00000008
#define FBEAM_SINENOISE 0x00000010
#define FBEAM_SOLID 0x00000020
#define FBEAM_SHADEIN 0x00000040
#define FBEAM_SHADEOUT 0x00000080
#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet?
#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet?
#define FBEAM_ISACTIVE 0x40000000
#define FBEAM_FOREVER 0x80000000
typedef struct beam_s BEAM;
struct beam_s
{
BEAM *next;
int type;
int flags;
vec3_t source;
vec3_t target;
vec3_t delta;
float t; // 0 .. 1 over lifetime of beam
float freq;
float die;
float width;
float amplitude;
float r, g, b;
float brightness;
float speed;
float frameRate;
float frame;
int segments;
int startEntity;
int endEntity;
int modelIndex;
int frameCount;
struct model_s *pFollowModel;
struct particle_s *particles;
};
#endif//BEAMDEF_H

321
common/bspfile.h Normal file
View File

@ -0,0 +1,321 @@
/*
bspfile.h - BSP format included q1, hl1 support
Copyright (C) 2010 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.
*/
#ifndef BSPFILE_H
#define BSPFILE_H
//#define SUPPORT_BSP2_FORMAT // allow to loading Darkplaces BSP2 maps (with broke binary compatibility)
/*
==============================================================================
BRUSH MODELS
.bsp contain level static geometry with including PVS and lightning info
==============================================================================
*/
// header
#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28)
#define HLBSP_VERSION 30 // half-life regular version
#define QBSP2_VERSION (('B' << 0) | ('S' << 8) | ('P' << 16) | ('2'<<24))
#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH"
#define EXTRA_VERSION 4 // ver. 1 was occupied by old versions of XashXT, ver. 2 was occupied by old vesrions of P2:savior
// ver. 3 was occupied by experimental versions of P2:savior change fmt
#define DELUXEMAP_VERSION 1
#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT"
// worldcraft predefined angles
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// bmodel limits
#define MAX_MAP_HULLS 4 // MAX_HULLS
#define SURF_PLANEBACK BIT( 1 ) // plane should be negated
#define SURF_DRAWSKY BIT( 2 ) // sky surface
#define SURF_DRAWTURB_QUADS BIT( 3 ) // all subidivided polygons are quads
#define SURF_DRAWTURB BIT( 4 ) // warp surface
#define SURF_DRAWTILED BIT( 5 ) // face without lighmap
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
#define SURF_UNDERWATER BIT( 7 ) // caustics
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
// lightstyle management
#define LM_STYLES 4 // MAXLIGHTMAPS
#define LS_NORMAL 0x00
#define LS_UNUSED 0xFE
#define LS_NONE 0xFF
// these limis not using by modelloader but only for displaying 'mapstats' correctly
#ifdef SUPPORT_BSP2_FORMAT
#define MAX_MAP_MODELS 2048 // embedded models
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
#define MAX_MAP_PLANES 131072 // can be increased without problems
#define MAX_MAP_NODES 262144 // can be increased without problems
#define MAX_MAP_CLIPNODES 524288 // can be increased without problems
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
#define MAX_MAP_VERTS 524288 // can be increased without problems
#define MAX_MAP_FACES 262144 // can be increased without problems
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#else
#define MAX_MAP_MODELS 768 // embedded models
#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough
#define MAX_MAP_PLANES 65536 // can be increased without problems
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
#define MAX_MAP_CLIPNODES 32767 // because negative shorts are contents
#define MAX_MAP_LEAFS 32767 // signed short limit
#define MAX_MAP_VERTS 65535 // unsigned short limit
#define MAX_MAP_FACES 65535 // unsigned short limit
#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit
#endif
#define MAX_MAP_ENTITIES 8192 // network limit
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
#define MAX_MAP_EDGES 0x100000 // can be increased but not needs
#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needs
#define MAX_MAP_TEXTURES 2048 // can be increased but not needs
#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data
#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps)
#define MAX_MAP_VISIBILITY 0x1000000 // 16 Mb visdata
#define MAX_MAP_FACEINFO 8192 // can be increased but not needs
// quake lump ordering
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_TEXTURES 2 // internal textures
#define LUMP_VERTEXES 3
#define LUMP_VISIBILITY 4
#define LUMP_NODES 5
#define LUMP_TEXINFO 6
#define LUMP_FACES 7
#define LUMP_LIGHTING 8
#define LUMP_CLIPNODES 9
#define LUMP_LEAFS 10
#define LUMP_MARKSURFACES 11
#define LUMP_EDGES 12
#define LUMP_SURFEDGES 13
#define LUMP_MODELS 14 // internal submodels
#define HEADER_LUMPS 15
// extra lump ordering
#define LUMP_LIGHTVECS 0 // deluxemap data
#define LUMP_FACEINFO 1 // landscape and lightmap resolution info
#define LUMP_CUBEMAPS 2 // cubemap description
#define LUMP_VERTNORMALS 3 // phong shaded vertex normals
#define LUMP_VERTEX_LIGHT 4 // contain compressed light cubes per empty leafs
#define LUMP_WORLDLIGHTS 5 // list of all the virtual and real lights (used to relight models in-game)
#define LUMP_COLLISION 6 // physics engine collision hull dump
#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp
#define LUMP_SHADOWMAP 8 // contains shadow map for direct light
#define LUMP_UNUSED1 9 // one lump reserved for me
#define LUMP_UNUSED2 10 // one lump reserved for me
#define LUMP_UNUSED3 11 // one lump reserved for me
#define EXTRA_LUMPS 12 // count of the extra lumps
// texture flags
#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision
#define TEX_WORLD_LUXELS BIT( 1 ) // alternative lightmap matrix will be used (luxels per world units instead of luxels per texels)
#define TEX_AXIAL_LUXELS BIT( 2 ) // force world luxels to axial positive scales
#define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel
// ambient sound types
enum
{
AMBIENT_WATER = 0, // waterfall
AMBIENT_SKY, // wind
AMBIENT_SLIME, // never used in quake
AMBIENT_LAVA, // never used in quake
NUM_AMBIENTS, // automatic ambient sounds
};
//
// BSP File Structures
//
typedef struct
{
int fileofs;
int filelen;
} dlump_t;
typedef struct
{
int version;
dlump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
int id; // must be little endian XASH
int version;
dlump_t lumps[EXTRA_LUMPS];
} dextrahdr_t;
typedef struct
{
vec3_t mins;
vec3_t maxs;
vec3_t origin; // for sounds or lights
int headnode[MAX_MAP_HULLS];
int visleafs; // not including the solid leaf 0
int firstface;
int numfaces;
} dmodel_t;
typedef struct
{
int nummiptex;
int dataofs[4]; // [nummiptex]
} dmiptexlump_t;
typedef struct
{
vec3_t point;
} dvertex_t;
typedef struct
{
vec3_t normal;
float dist;
int type; // PLANE_X - PLANE_ANYZ ?
} dplane_t;
typedef struct
{
int planenum;
short children[2]; // negative numbers are -(leafs + 1), not nodes
short mins[3]; // for sphere culling
short maxs[3];
word firstface;
word numfaces; // counting both sides
} dnode_t;
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
float mins[3]; // for sphere culling
float maxs[3];
int firstface;
int numfaces; // counting both sides
} dnode32_t;
// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
short mins[3]; // for frustum culling
short maxs[3];
word firstmarksurface;
word nummarksurfaces;
// automatic ambient sounds
byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255)
} dleaf_t;
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
float mins[3]; // for frustum culling
float maxs[3];
int firstmarksurface;
int nummarksurfaces;
byte ambient_level[NUM_AMBIENTS];
} dleaf32_t;
typedef struct
{
int planenum;
short children[2]; // negative numbers are contents
} dclipnode_t;
typedef struct
{
int planenum;
int children[2]; // negative numbers are contents
} dclipnode32_t;
typedef struct
{
float vecs[2][4]; // texmatrix [s/t][xyz offset]
int miptex;
short flags;
short faceinfo; // -1 no face info otherwise dfaceinfo_t
} dtexinfo_t;
typedef struct
{
char landname[16]; // name of decsription in mapname_land.txt
unsigned short texture_step; // default is 16, pixels\luxels ratio
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
} dfaceinfo_t;
typedef word dmarkface_t; // leaf marksurfaces indexes
typedef int dmarkface32_t; // leaf marksurfaces indexes
typedef int dsurfedge_t; // map surfedges
// NOTE: that edge 0 is never used, because negative edge nums
// are used for counterclockwise use of the edge in a face
typedef struct
{
word v[2]; // vertex numbers
} dedge_t;
typedef struct
{
int v[2]; // vertex numbers
} dedge32_t;
typedef struct
{
word planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[LM_STYLES];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
typedef struct
{
int planenum;
int side;
int firstedge; // we must support > 64k edges
int numedges;
int texinfo;
// lighting info
byte styles[LM_STYLES];
int lightofs; // start of [numstyles*surfsize] samples
} dface32_t;
#endif//BSPFILE_H

105
common/cl_entity.h Normal file
View File

@ -0,0 +1,105 @@
/***
*
* 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 CL_ENTITY_H
#define CL_ENTITY_H
typedef struct efrag_s
{
struct mleaf_s *leaf;
struct efrag_s *leafnext;
struct cl_entity_s *entity;
struct efrag_s *entnext;
} efrag_t;
typedef struct
{
byte mouthopen; // 0 = mouth closed, 255 = mouth agape
byte sndcount; // counter for running average
int sndavg; // running average
} mouth_t;
typedef struct
{
float prevanimtime;
float sequencetime;
byte prevseqblending[2];
vec3_t prevorigin;
vec3_t prevangles;
int prevsequence;
float prevframe;
byte prevcontroller[4];
byte prevblending[2];
} latchedvars_t;
typedef struct
{
// Time stamp for this movement
float animtime;
vec3_t origin;
vec3_t angles;
} position_history_t;
typedef struct cl_entity_s cl_entity_t;
#define HISTORY_MAX 64 // Must be power of 2
#define HISTORY_MASK ( HISTORY_MAX - 1 )
#include "entity_state.h"
#include "event_args.h"
struct cl_entity_s
{
int index; // Index into cl_entities ( should match actual slot, but not necessarily )
qboolean player; // True if this entity is a "player"
entity_state_t baseline; // The original state from which to delta during an uncompressed message
entity_state_t prevstate; // The state information from the penultimate message received from the server
entity_state_t curstate; // The state information from the last message received from server
int current_position; // Last received history update index
position_history_t ph[HISTORY_MAX]; // History of position and angle updates for this player
mouth_t mouth; // For synchronizing mouth movements.
latchedvars_t latched; // Variables used by studio model rendering routines
// Information based on interplocation, extrapolation, prediction, or just copied from last msg received.
//
float lastmove;
// Actual render position and angles
vec3_t origin;
vec3_t angles;
// Attachment points
vec3_t attachment[4];
// Other entity local information
int trivial_accept;
struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model
struct efrag_s *efrag; // linked list of efrags
struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split
float syncbase; // for client-side animations -- used by obsolete alias animation system, remove?
int visframe; // last frame this entity was found in an active leaf
colorVec cvFloorColor;
};
#endif//CL_ENTITY_H

497
common/com_model.h Normal file
View File

@ -0,0 +1,497 @@
/*
com_model.h - cient model structures
Copyright (C) 2010 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.
*/
#ifndef COM_MODEL_H
#define COM_MODEL_H
#include "bspfile.h" // we need some declarations from it
typedef vec_t vec2_t[2];
typedef vec_t vec4_t[4];
/*
==============================================================================
ENGINE MODEL FORMAT
==============================================================================
*/
#define STUDIO_RENDER 1
#define STUDIO_EVENTS 2
#define ZISCALE ((float)0x8000)
#define MIPLEVELS 4
#define VERTEXSIZE 7
#define MAXLIGHTMAPS 4
#define NUM_AMBIENTS 4 // automatic ambient sounds
// model types
typedef enum
{
mod_bad = -1,
mod_brush,
mod_sprite,
mod_alias,
mod_studio
} modtype_t;
typedef struct mplane_s
{
vec3_t normal;
float dist;
byte type; // for fast side tests
byte signbits; // signx + (signy<<1) + (signz<<1)
byte pad[2];
} mplane_t;
typedef struct
{
vec3_t position;
} mvertex_t;
typedef struct
{
int planenum;
#ifdef SUPPORT_BSP2_FORMAT
int children[2]; // negative numbers are contents
#else
short children[2]; // negative numbers are contents
#endif
} mclipnode_t;
// size is matched but representation is not
typedef struct
{
#ifdef SUPPORT_BSP2_FORMAT
unsigned int v[2];
#else
unsigned short v[2];
unsigned int cachededgeoffset;
#endif
} medge_t;
typedef struct texture_s
{
char name[16];
unsigned int width, height;
int gl_texturenum;
struct msurface_s *texturechain; // for gl_texsort drawing
int anim_total; // total tenths in sequence ( 0 = no)
int anim_min, anim_max; // time for this frame min <=time< max
struct texture_s *anim_next; // in the animation sequence
struct texture_s *alternate_anims; // bmodels in frame 1 use these
unsigned short fb_texturenum; // auto-luma texturenum
unsigned short dt_texturenum; // detail-texture binding
unsigned int unused[3]; // reserved
} texture_t;
typedef struct
{
char landname[16]; // name of decsription in mapname_land.txt
unsigned short texture_step; // default is 16, pixels\luxels ratio
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;
typedef struct
{
float vecs[2][4]; // [s/t] unit vectors in world space.
// [i][3] is the s/t offset relative to the origin.
// s or t = dot( 3Dpoint, vecs[i] ) + vecs[i][3]
mfaceinfo_t *faceinfo; // pointer to landscape info and lightmap resolution (may be NULL)
texture_t *texture;
int flags; // sky or slime, no lightmap or 256 subdivision
} mtexinfo_t;
typedef struct glpoly_s
{
struct glpoly_s *next;
struct glpoly_s *chain;
int numverts;
int flags; // for SURF_UNDERWATER
float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2)
} glpoly_t;
typedef struct mnode_s
{
// common with leaf
int contents; // 0, to differentiate from leafs
int visframe; // node needs to be traversed if current
float minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// node specific
mplane_t *plane;
struct mnode_s *children[2];
#ifdef SUPPORT_BSP2_FORMAT
int firstsurface;
int numsurfaces;
#else
unsigned short firstsurface;
unsigned short numsurfaces;
#endif
} mnode_t;
typedef struct msurface_s msurface_t;
typedef struct decal_s decal_t;
// JAY: Compress this as much as possible
struct decal_s
{
decal_t *pnext; // linked list for each surface
msurface_t *psurface; // Surface id for persistence / unlinking
float dx; // local texture coordinates
float dy; //
float scale; // Pixel scale
short texture; // Decal texture
short flags; // Decal flags FDECAL_*
short entityIndex; // Entity this is attached to
// Xash3D specific
vec3_t position; // location of the decal center in world space.
glpoly_t *polys; // precomputed decal vertices
};
typedef struct mleaf_s
{
// common with node
int contents;
int visframe; // node needs to be traversed if current
float minmaxs[6]; // for bounding box culling
struct mnode_s *parent;
// leaf specific
byte *compressed_vis;
struct efrag_s *efrags;
msurface_t **firstmarksurface;
int nummarksurfaces;
int cluster; // helper to acess to uncompressed visdata
byte ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;
// surface extradata
typedef struct mextrasurf_s
{
vec3_t mins, maxs;
vec3_t origin; // surface origin
struct msurface_s *surf; // upcast to surface
// extended light info
int dlight_s, dlight_t; // gl lightmap coordinates for dynamic lightmaps
short lightmapmins[2]; // lightmatrix
short lightextents[2];
float lmvecs[2][4];
color24 *deluxemap; // note: this is the actual deluxemap data for this surface
byte *shadowmap; // note: occlusion map for this surface
// begin userdata
struct msurface_s *lightmapchain; // lightmapped polys
struct mextrasurf_s *detailchain; // for detail textures drawing
struct mextrasurf_s *mirrorchain; // for gl_texsort drawing
struct mextrasurf_s *lumachain; // draw fullbrights
struct cl_entity_s *parent; // upcast to owner entity
int mirrortexturenum; // gl texnum
float mirrormatrix[4][4];
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
mplane_t *plane; // pointer to shared plane
int flags; // see SURF_ #defines
int firstedge; // look up in model->surfedges[], negative numbers
int numedges; // are backwards edges
short texturemins[2];
short extents[2];
int light_s, light_t; // gl lightmap coordinates
glpoly_t *polys; // multiple if warped
struct msurface_s *texturechain;
mtexinfo_t *texinfo;
// lighting info
int dlightframe; // last frame the surface was checked by an animated light
int dlightbits; // dynamically generated. Indicates if the surface illumination
// is modified by an animated light.
int lightmaptexturenum;
byte styles[MAXLIGHTMAPS];
int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
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 hull_s
{
mclipnode_t *clipnodes;
mplane_t *planes;
int firstclipnode;
int lastclipnode;
vec3_t clip_mins;
vec3_t clip_maxs;
} hull_t;
#ifndef CACHE_USER
#define CACHE_USER
typedef struct cache_user_s
{
void *data; // extradata
} cache_user_t;
#endif
typedef struct model_s
{
char name[64]; // model name
qboolean needload; // bmodels and sprites don't cache normally
// shared modelinfo
modtype_t type; // model type
int numframes; // sprite's framecount
byte *mempool; // private mempool (was synctype)
int flags; // hl compatibility
//
// volume occupied by the model
//
vec3_t mins, maxs; // bounding box at angles '0 0 0'
float radius;
// brush model
int firstmodelsurface;
int nummodelsurfaces;
int numsubmodels;
dmodel_t *submodels; // or studio animations
int numplanes;
mplane_t *planes;
int numleafs; // number of visible leafs, not counting 0
mleaf_t *leafs;
int numvertexes;
mvertex_t *vertexes;
int numedges;
medge_t *edges;
int numnodes;
mnode_t *nodes;
int numtexinfo;
mtexinfo_t *texinfo;
int numsurfaces;
msurface_t *surfaces;
int numsurfedges;
int *surfedges;
int numclipnodes;
mclipnode_t *clipnodes;
int nummarksurfaces;
msurface_t **marksurfaces;
hull_t hulls[MAX_MAP_HULLS];
int numtextures;
texture_t **textures;
byte *visdata;
color24 *lightdata;
char *entities;
//
// additional model data
//
cache_user_t cache; // only access through Mod_Extradata
} model_t;
typedef struct alight_s
{
int ambientlight; // clip at 128
int shadelight; // clip at 192 - ambientlight
vec3_t color;
float *plightvec;
} alight_t;
typedef struct auxvert_s
{
float fv[3]; // viewspace x, y
} auxvert_t;
#define MAX_SCOREBOARDNAME 32
#define MAX_INFO_STRING 256
#include "custom.h"
typedef struct player_info_s
{
int userid; // User id on server
char userinfo[MAX_INFO_STRING]; // User info string
char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo)
int spectator; // Spectator or not, unused
int ping;
int packet_loss;
// skin information
char model[64];
int topcolor;
int bottomcolor;
// last frame rendered
int renderframe;
// Gait frame estimation
int gaitsequence;
float gaitframe;
float gaityaw;
vec3_t prevgaitorigin;
customization_t customdata;
// hashed cd key
char hashedcdkey[16];
} player_info_t;
//
// sprite representation in memory
//
typedef enum { SPR_SINGLE = 0, SPR_GROUP, SPR_ANGLED } spriteframetype_t;
typedef struct mspriteframe_s
{
int width;
int height;
float up, down, left, right;
int gl_texturenum;
} mspriteframe_t;
typedef struct
{
int numframes;
float *intervals;
mspriteframe_t *frames[1];
} mspritegroup_t;
typedef struct
{
spriteframetype_t type;
mspriteframe_t *frameptr;
} mspriteframedesc_t;
typedef struct
{
short type;
short texFormat;
int maxwidth;
int maxheight;
int numframes;
int radius;
int facecull;
int synctype;
mspriteframedesc_t frames[1];
} msprite_t;
/*
==============================================================================
ALIAS MODELS
Alias models are position independent, so the cache manager can move them.
==============================================================================
*/
#define MAXALIASVERTS 2048
#define MAXALIASFRAMES 256
#define MAXALIASTRIS 4096
#define MAX_SKINS 32
// 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
{
int firstpose;
int numposes;
trivertex_t bboxmin;
trivertex_t bboxmax;
float interval;
char name[16];
} maliasframedesc_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;
int synctype;
int flags;
float size;
int reserved[8]; // VBO offsets
int numposes;
int poseverts;
trivertex_t *posedata; // numposes * poseverts trivert_t
int *commands; // gl command list with embedded s/t
unsigned short gl_texturenum[MAX_SKINS][4];
unsigned short fb_texturenum[MAX_SKINS][4];
unsigned short gl_reserved0[MAX_SKINS][4]; // detail tex
unsigned short gl_reserved1[MAX_SKINS][4]; // normalmap
unsigned short gl_reserved2[MAX_SKINS][4]; // glossmap
maliasframedesc_t frames[1]; // variable sized
} aliashdr_t;
#endif//COM_MODEL_H

25
common/con_nprint.h Normal file
View File

@ -0,0 +1,25 @@
/***
*
* 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 CON_NPRINT_H
#define CON_NPRINT_H
typedef struct con_nprint_s
{
int index; // Row #
float time_to_live; // # of seconds before it dissappears
float color[3]; // RGB colors ( 0.0 -> 1.0 scale )
} con_nprint_t;
#endif//CON_NPRINT_H

779
common/const.h Normal file
View File

@ -0,0 +1,779 @@
/***
*
* 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 CONST_H
#define CONST_H
//
// Constants shared by the engine and dlls
// This header file included by engine files and DLL files.
// Most came from server.h
// edict->flags
#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground
#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water)
#define FL_CONVEYOR (1<<2)
#define FL_CLIENT (1<<3)
#define FL_INWATER (1<<4)
#define FL_MONSTER (1<<5)
#define FL_GODMODE (1<<6)
#define FL_NOTARGET (1<<7)
#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself
#define FL_ONGROUND (1<<9) // At rest / on the ground
#define FL_PARTIALGROUND (1<<10) // not all corners are valid
#define FL_WATERJUMP (1<<11) // player jumping out of water
#define FL_FROZEN (1<<12) // Player is frozen for 3rd person camera
#define FL_FAKECLIENT (1<<13) // JAC: fake client, simulated server side; don't send network messages to them
#define FL_DUCKING (1<<14) // Player flag -- Player is fully crouched
#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water
#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection
// UNDONE: Do we need these?
#define FL_IMMUNE_WATER (1<<17)
#define FL_IMMUNE_SLIME (1<<18)
#define FL_IMMUNE_LAVA (1<<19)
#define FL_PROXY (1<<20) // This is a spectator proxy
#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path)
#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum)
#define FL_MONSTERCLIP (1<<23) // Only collide in with monsters who have FL_MONSTERCLIP set
#define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction.
#define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something)
#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc.
#define FL_LASERDOT (1<<27) // Predicted laser spot from rocket launcher
#define FL_CUSTOMENTITY (1<<29) // This is a custom entity
#define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time
#define FL_DORMANT (1<<31) // Entity is dormant, no updates to client
// Goes into globalvars_t.trace_flags
#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box
#define FTRACE_IGNORE_GLASS (1<<1) // traceline will be ignored entities with rendermode != kRenderNormal
// walkmove modes
#define WALKMOVE_NORMAL 0 // normal walkmove
#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type
#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers
// edict->movetype values
#define MOVETYPE_NONE 0 // never moves
//#define MOVETYPE_ANGLENOCLIP 1
//#define MOVETYPE_ANGLECLIP 2
#define MOVETYPE_WALK 3 // Player only - moving on the ground
#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this
#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff
#define MOVETYPE_TOSS 6 // gravity/collisions
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces
#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity
#define MOVETYPE_FOLLOW 12 // track movement of aiment
#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision)
#define MOVETYPE_COMPOUND 14 // glue two entities together (simple movewith)
// edict->solid values
// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves
// SOLID only effects OTHER entities colliding with this one when they move - UGH!
#define SOLID_NOT 0 // no interaction with other objects
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
#define SOLID_BBOX 2 // touch on edge, block
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
#define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CUSTOM 5 // call external callbacks for tracing
#define SOLID_PORTAL 6 // borrowed from FTE
// edict->deadflag values
#define DEAD_NO 0 // alive
#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground
#define DEAD_DEAD 2 // dead. lying still.
#define DEAD_RESPAWNABLE 3
#define DEAD_DISCARDBODY 4
#define DAMAGE_NO 0
#define DAMAGE_YES 1
#define DAMAGE_AIM 2
// entity effects
#define EF_BRIGHTFIELD 1 // swirling cloud of particles
#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0
#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin
#define EF_DIMLIGHT 8 // player flashlight
#define EF_INVLIGHT 16 // get lighting from ceiling
#define EF_NOINTERP 32 // don't interpolate the next frame
#define EF_LIGHT 64 // rocket flare glow sprite
#define EF_NODRAW 128 // don't draw entity
#define EF_WATERSIDES (1<<26) // Do not remove sides for func_water entity
#define EF_FULLBRIGHT (1<<27) // Just get fullbright
#define EF_NOSHADOW (1<<28) // ignore shadow for this entity
#define EF_MERGE_VISIBILITY (1<<29) // this entity allowed to merge vis (e.g. env_sky or portal camera)
#define EF_REQUEST_PHS (1<<30) // This entity requested phs bitvector instead of pvsbitvector in AddToFullPack calls
// g-cont. one reserved bit here for me
// entity flags
#define EFLAG_SLERP 1 // do studio interpolation of this entity
//
// temp entity events
//
#define TE_BEAMPOINTS 0 // beam effect between two points
// coord coord coord (start position)
// coord coord coord (end position)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_BEAMENTPOINT 1 // beam effect between point and entity
// short (start entity)
// coord coord coord (end position)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_GUNSHOT 2 // particle effect plus ricochet sound
// coord coord coord (position)
#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps
// coord coord coord (position)
// short (sprite index)
// byte (scale in 0.1's)
// byte (framerate)
// byte (flags)
//
// The Explosion effect has some flags to control performance/aesthetic features:
#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion
#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite)
#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights
#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound
#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles
#define TE_EXPLFLAG_DRAWALPHA 16 // sprite will be drawn alpha
#define TE_EXPLFLAG_ROTATE 32 // rotate the sprite randomly
#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound
// coord coord coord (position)
#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps
// coord coord coord (position)
// short (sprite index)
// byte (scale in 0.1's)
// byte (framerate)
#define TE_TRACER 6 // tracer effect from point to point
// coord, coord, coord (start)
// coord, coord, coord (end)
#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters
// coord, coord, coord (start)
// coord, coord, coord (end)
// byte (life in 0.1's)
// byte (width in 0.1's)
// byte (amplitude in 0.01's)
// short (sprite model index)
#define TE_BEAMENTS 8
// short (start entity)
// short (end entity)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite
// coord coord coord (position)
#define TE_LAVASPLASH 10 // Quake1 lava splash
// coord coord coord (position)
#define TE_TELEPORT 11 // Quake1 teleport splash
// coord coord coord (position)
#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound
// coord coord coord (position)
// byte (starting color)
// byte (num colors)
#define TE_BSPDECAL 13 // Decal from the .BSP file
// coord, coord, coord (x,y,z), decal position (center of texture in world)
// short (texture index of precached decal texture name)
// short (entity index)
// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity)
#define TE_IMPLOSION 14 // tracers moving toward a point
// coord, coord, coord (position)
// byte (radius)
// byte (count)
// byte (life in 0.1's)
#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions
// coord, coord, coord (start)
// coord, coord, coord (end)
// short (sprite index)
// byte (count)
// byte (life in 0.1's)
// byte (scale in 0.1's)
// byte (velocity along vector in 10's)
// byte (randomness of velocity in 10's)
#define TE_BEAM 16 // obsolete
#define TE_SPRITE 17 // additive sprite, plays 1 cycle
// coord, coord, coord (position)
// short (sprite index)
// byte (scale in 0.1's)
// byte (brightness)
#define TE_BEAMSPRITE 18 // A beam with a sprite at the end
// coord, coord, coord (start position)
// coord, coord, coord (end position)
// short (beam sprite index)
// short (end sprite index)
#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime
// coord coord coord (center position)
// coord coord coord (axis and radius)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime
// coord coord coord (center position)
// coord coord coord (axis and radius)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime
// coord coord coord (center position)
// coord coord coord (axis and radius)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving
// short (entity:attachment to follow)
// short (sprite index)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte,byte,byte (color)
// byte (brightness)
#define TE_GLOWSPRITE 23
// coord, coord, coord (pos) short (model index) byte (scale / 10)
#define TE_BEAMRING 24 // connect a beam ring to two entities
// short (start entity)
// short (end entity)
// short (sprite index)
// byte (starting frame)
// byte (frame rate in 0.1's)
// byte (life in 0.1's)
// byte (line width in 0.1's)
// byte (noise amplitude in 0.01's)
// byte,byte,byte (color)
// byte (brightness)
// byte (scroll speed in 0.1's)
#define TE_STREAK_SPLASH 25 // oriented shower of tracers
// coord coord coord (start position)
// coord coord coord (direction vector)
// byte (color)
// short (count)
// short (base speed)
// short (random velocity)
#define TE_BEAMHOSE 26 // obsolete
#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect
// coord, coord, coord (pos)
// byte (radius in 10's)
// byte byte byte (color)
// byte (life in 10's)
// byte (decay rate in 10's)
#define TE_ELIGHT 28 // point entity light, no world effect
// short (entity:attachment to follow)
// coord coord coord (initial position)
// coord (radius)
// byte byte byte (color)
// byte (life in 0.1's)
// coord (decay rate)
#define TE_TEXTMESSAGE 29
// short 1.2.13 x (-1 = center)
// short 1.2.13 y (-1 = center)
// byte Effect 0 = fade in/fade out
// 1 is flickery credits
// 2 is write out (training room)
// 4 bytes r,g,b,a color1 (text color)
// 4 bytes r,g,b,a color2 (effect color)
// ushort 8.8 fadein time
// ushort 8.8 fadeout time
// ushort 8.8 hold time
// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2)
// string text message (512 chars max sz string)
#define TE_LINE 30
// coord, coord, coord startpos
// coord, coord, coord endpos
// short life in 0.1 s
// 3 bytes r, g, b
#define TE_BOX 31
// coord, coord, coord boxmins
// coord, coord, coord boxmaxs
// short life in 0.1 s
// 3 bytes r, g, b
#define TE_KILLBEAM 99 // kill all beams attached to entity
// short (entity)
#define TE_LARGEFUNNEL 100
// coord coord coord (funnel position)
// short (sprite index)
// short (flags)
#define TE_BLOODSTREAM 101 // particle spray
// coord coord coord (start position)
// coord coord coord (spray vector)
// byte (color)
// byte (speed)
#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds
// coord coord coord (start position)
// coord coord coord (end position)
#define TE_BLOOD 103 // particle spray
// coord coord coord (start position)
// coord coord coord (spray vector)
// byte (color)
// byte (speed)
#define TE_DECAL 104 // Decal applied to a brush entity (not the world)
// coord, coord, coord (x,y,z), decal position (center of texture in world)
// byte (texture index of precached decal texture name)
// short (entity index)
#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards
// short (entity)
// short (sprite index)
// byte (density)
#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits
// coord, coord, coord (position)
// coord, coord, coord (velocity)
// angle (initial yaw)
// short (model index)
// byte (bounce sound type)
// byte (life in 0.1's)
#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set
// coord, coord, coord (origin)
// coord (velocity)
// short (model index)
// short (count)
// byte (life in 0.1's)
#define TE_BREAKMODEL 108 // box of models or sprites
// coord, coord, coord (position)
// coord, coord, coord (size)
// coord, coord, coord (velocity)
// byte (random velocity in 10's)
// short (sprite or model index)
// byte (count)
// byte (life in 0.1 secs)
// byte (flags)
#define TE_GUNSHOTDECAL 109 // decal and ricochet sound
// coord, coord, coord (position)
// short (entity index???)
// byte (decal???)
#define TE_SPRITE_SPRAY 110 // spay of alpha sprites
// coord, coord, coord (position)
// coord, coord, coord (velocity)
// short (sprite index)
// byte (count)
// byte (speed)
// byte (noise)
#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound.
// coord, coord, coord (position)
// byte (scale in 0.1's)
#define TE_PLAYERDECAL 112 // ???
// byte (playerindex)
// coord, coord, coord (position)
// short (entity???)
// byte (decal number???)
// [optional] short (model index???)
#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards
// coord, coord, coord (min start position)
// coord, coord, coord (max start position)
// coord (float height)
// short (model index)
// byte (count)
// coord (speed)
#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards
// coord, coord, coord (min start position)
// coord, coord, coord (max start position)
// coord (float height)
// short (model index)
// byte (count)
// coord (speed)
#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent)
// coord, coord, coord (position)
// short (sprite1 index)
// short (sprite2 index)
// byte (color)
// byte (scale)
#define TE_WORLDDECAL 116 // Decal applied to the world brush
// coord, coord, coord (x,y,z), decal position (center of texture in world)
// byte (texture index of precached decal texture name)
#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush
// coord, coord, coord (x,y,z), decal position (center of texture in world)
// byte (texture index of precached decal texture name - 256)
#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256
// coord, coord, coord (x,y,z), decal position (center of texture in world)
// byte (texture index of precached decal texture name - 256)
// short (entity index)
#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent)
// coord, coord, coord (position)
// coord, coord, coord (velocity)
// short (modelindex)
// byte (life)
// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client).
#define TE_SPRAY 120 // Throws a shower of sprites or models
// coord, coord, coord (position)
// coord, coord, coord (direction)
// short (modelindex)
// byte (count)
// byte (speed)
// byte (noise)
// byte (rendermode)
#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!)
// byte (playernum)
// short (sprite modelindex)
// byte (count)
// byte (variance) (0 = no variance in size) (10 = 10% variance in size)
#define TE_PARTICLEBURST 122 // very similar to lavasplash.
// coord (origin)
// short (radius)
// byte (particle color)
// byte (duration * 10) (will be randomized a bit)
#define TE_FIREFIELD 123 // makes a field of fire.
// coord (origin)
// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius)
// short (modelindex)
// byte (count)
// byte (flags)
// byte (duration (in seconds) * 10) (will be randomized a bit)
//
// to keep network traffic low, this message has associated flags that fit into a byte:
#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate
#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance)
#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration.
#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque
#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube.
#define TEFIRE_FLAG_ADDITIVE 32 // if set, sprite is rendered as additive
#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent)
// byte (entity index of player)
// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset )
// short (model index)
// short (life * 10 );
#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player.
// byte (entity index of player)
#define TE_MULTIGUNSHOT 126 // much more compact shotgun message
// This message is used to make a client approximate a 'spray' of gunfire.
// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is
// a good candidate for MULTIGUNSHOT use. (shotguns)
//
// NOTE: This effect makes the client do traces for each bullet, these client traces ignore
// entities that have studio models.Traces are 4096 long.
//
// coord (origin)
// coord (origin)
// coord (origin)
// coord (direction)
// coord (direction)
// coord (direction)
// coord (x noise * 100)
// coord (y noise * 100)
// byte (count)
// byte (bullethole decal texture index)
#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization.
// coord (origin)
// coord (origin)
// coord (origin)
// coord (velocity)
// coord (velocity)
// coord (velocity)
// byte ( life * 10 )
// byte ( color ) this is an index into an array of color vectors in the engine. (0 - )
// byte ( length * 10 )
#define MSG_BROADCAST 0 // unreliable to all
#define MSG_ONE 1 // reliable to one (msg_entity)
#define MSG_ALL 2 // reliable to all
#define MSG_INIT 3 // write to the init string
#define MSG_PVS 4 // Ents in PVS of org
#define MSG_PAS 5 // Ents in PAS of org
#define MSG_PVS_R 6 // Reliable to PVS
#define MSG_PAS_R 7 // Reliable to PAS
#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped )
#define MSG_SPEC 9 // Sends to all spectator proxies
// contents of a spot in the world
#define CONTENTS_EMPTY -1
#define CONTENTS_SOLID -2
#define CONTENTS_WATER -3
#define CONTENTS_SLIME -4
#define CONTENTS_LAVA -5
#define CONTENTS_SKY -6
// These additional contents constants are defined in bspfile.h
#define CONTENTS_ORIGIN -7 // removed at csg time
#define CONTENTS_CLIP -8 // changed to contents_solid
#define CONTENTS_CURRENT_0 -9
#define CONTENTS_CURRENT_90 -10
#define CONTENTS_CURRENT_180 -11
#define CONTENTS_CURRENT_270 -12
#define CONTENTS_CURRENT_UP -13
#define CONTENTS_CURRENT_DOWN -14
#define CONTENTS_TRANSLUCENT -15
#define CONTENTS_LADDER -16
#define CONTENT_FLYFIELD -17
#define CONTENT_GRAVITY_FLYFIELD -18
#define CONTENT_FOG -19
#define CONTENT_EMPTY -1
#define CONTENT_SOLID -2
#define CONTENT_WATER -3
#define CONTENT_SLIME -4
#define CONTENT_LAVA -5
#define CONTENT_SKY -6
// channels
#define CHAN_AUTO 0
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area
#define CHAN_STATIC 6 // allocate channel from the static area
#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network
#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END).
// attenuation values
#define ATTN_NONE 0
#define ATTN_NORM (float)0.8
#define ATTN_IDLE (float)2
#define ATTN_STATIC (float)1.25
// pitch values
#define PITCH_NORM 100 // non-pitch shifted
#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high
#define PITCH_HIGH 120
// volume values
#define VOL_NORM 1.0
// plats
#define PLAT_LOW_TRIGGER 1
// Trains
#define SF_TRAIN_WAIT_RETRIGGER 1
#define SF_TRAIN_START_ON 4 // Train is initially moving
#define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains
// buttons
#define IN_ATTACK (1<<0)
#define IN_JUMP (1<<1)
#define IN_DUCK (1<<2)
#define IN_FORWARD (1<<3)
#define IN_BACK (1<<4)
#define IN_USE (1<<5)
#define IN_CANCEL (1<<6)
#define IN_LEFT (1<<7)
#define IN_RIGHT (1<<8)
#define IN_MOVELEFT (1<<9)
#define IN_MOVERIGHT (1<<10)
#define IN_ATTACK2 (1<<11)
#define IN_RUN (1<<12)
#define IN_RELOAD (1<<13)
#define IN_ALT1 (1<<14)
#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down
// Break Model Defines
#define BREAK_TYPEMASK 0x4F
#define BREAK_GLASS 0x01
#define BREAK_METAL 0x02
#define BREAK_FLESH 0x04
#define BREAK_WOOD 0x08
#define BREAK_SMOKE 0x10
#define BREAK_TRANS 0x20
#define BREAK_CONCRETE 0x40
#define BREAK_2 0x80
// Colliding temp entity sounds
#define BOUNCE_GLASS BREAK_GLASS
#define BOUNCE_METAL BREAK_METAL
#define BOUNCE_FLESH BREAK_FLESH
#define BOUNCE_WOOD BREAK_WOOD
#define BOUNCE_SHRAP 0x10
#define BOUNCE_SHELL 0x20
#define BOUNCE_CONCRETE BREAK_CONCRETE
#define BOUNCE_SHOTSHELL 0x80
// Temp entity bounce sound types
#define TE_BOUNCE_NULL 0
#define TE_BOUNCE_SHELL 1
#define TE_BOUNCE_SHOTSHELL 2
// Rendering constants
enum
{
kRenderNormal, // src
kRenderTransColor, // c*a+dest*(1-a)
kRenderTransTexture, // src*a+dest*(1-a)
kRenderGlow, // src*a+dest -- No Z buffer checks
kRenderTransAlpha, // src*srca+dest*(1-srca)
kRenderTransAdd, // src*a+dest
};
enum
{
kRenderFxNone = 0,
kRenderFxPulseSlow,
kRenderFxPulseFast,
kRenderFxPulseSlowWide,
kRenderFxPulseFastWide,
kRenderFxFadeSlow,
kRenderFxFadeFast,
kRenderFxSolidSlow,
kRenderFxSolidFast,
kRenderFxStrobeSlow,
kRenderFxStrobeFast,
kRenderFxStrobeFaster,
kRenderFxFlickerSlow,
kRenderFxFlickerFast,
kRenderFxNoDissipation,
kRenderFxDistort, // Distort/scale/translate flicker
kRenderFxHologram, // kRenderFxDistort + distance fade
kRenderFxDeadPlayer, // kRenderAmt is the player index
kRenderFxExplode, // Scale up really big!
kRenderFxGlowShell, // Glowing Shell
kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!)
};
typedef int func_t;
typedef int string_t;
typedef unsigned char byte;
typedef unsigned short word;
#undef true
#undef false
#ifndef __cplusplus
typedef enum { false, true } qboolean;
#else
typedef int qboolean;
#endif
typedef struct
{
byte r, g, b;
} color24;
typedef struct
{
unsigned r, g, b, a;
} colorVec;
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
typedef struct edict_s edict_t;
typedef struct
{
vec3_t normal;
float dist;
} plane_t;
typedef struct
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater;
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
plane_t plane; // surface normal at impact
edict_t *ent; // entity the surface is on
int hitgroup; // 0 == generic, non zero is specific body part
} trace_t;
#endif//CONST_H

45
common/cvardef.h Normal file
View File

@ -0,0 +1,45 @@
/***
*
* 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 CVARDEF_H
#define CVARDEF_H
#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc
#define FCVAR_USERINFO (1<<1) // changes the client's info string
#define FCVAR_SERVER (1<<2) // notifies players when changed
#define FCVAR_EXTDLL (1<<3) // defined by external DLL
#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll
#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value
#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server.
#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar
#define FCVAR_MOVEVARS (1<<10) // this cvar is a part of movevars_t struct that shared between client and server
#define FCVAR_LATCH (1<<11) // notify client what this cvar will be applied only after server restart (but don't does more nothing)
#define FCVAR_GLCONFIG (1<<12) // write it into opengl.cfg
#define FCVAR_CHANGED (1<<13) // set each time the cvar is changed
#define FCVAR_GAMEUIDLL (1<<14) // defined by the menu DLL
#define FCVAR_CHEAT (1<<15) // can not be changed if cheats are disabled
typedef struct cvar_s
{
char *name;
char *string;
int flags;
float value;
struct cvar_s *next;
} cvar_t;
#endif//CVARDEF_H

27
common/demo_api.h Normal file
View File

@ -0,0 +1,27 @@
/***
*
* 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 DEMO_API_H
#define DEMO_API_H
typedef struct demo_api_s
{
int (*IsRecording)( void );
int (*IsPlayingback)( void );
int (*IsTimeDemo)( void );
void (*WriteBuffer)( int size, unsigned char *buffer );
} demo_api_t;
#endif//DEMO_API_H

31
common/dlight.h Normal file
View File

@ -0,0 +1,31 @@
/***
*
* 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 DLIGHT_H
#define DLIGHT_H
typedef struct dlight_s
{
vec3_t origin;
float radius;
color24 color;
float die; // stop lighting after this time
float decay; // drop this each second
float minlight; // don't add when contributing less
int key;
qboolean dark; // subtracts light instead of adding
} dlight_t;
#endif//DLIGHT_H

188
common/entity_state.h Normal file
View File

@ -0,0 +1,188 @@
/***
*
* 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 ENTITY_STATE_H
#define ENTITY_STATE_H
// For entityType below
#define ENTITY_NORMAL (1<<0)
#define ENTITY_BEAM (1<<1)
// Entity state is used for the baseline and for delta compression of a packet of
// entities that is sent to a client.
typedef struct entity_state_s entity_state_t;
struct entity_state_s
{
// Fields which are filled in by routines outside of delta compression
int entityType;
// Index into cl_entities array for this entity.
int number;
float msg_time;
// Message number last time the player/entity state was updated.
int messagenum;
// Fields which can be transitted and reconstructed over the network stream
vec3_t origin;
vec3_t angles;
int modelindex;
int sequence;
float frame;
int colormap;
short skin;
short solid;
int effects;
float scale;
byte eflags;
// Render information
int rendermode;
int renderamt;
color24 rendercolor;
int renderfx;
int movetype;
float animtime;
float framerate;
int body;
byte controller[4];
byte blending[4];
vec3_t velocity;
// Send bbox down to client for use during prediction.
vec3_t mins;
vec3_t maxs;
int aiment;
// If owned by a player, the index of that player ( for projectiles ).
int owner;
// Friction, for prediction.
float friction;
// Gravity multiplier
float gravity;
// PLAYER SPECIFIC
int team;
int playerclass;
int health;
qboolean spectator;
int weaponmodel;
int gaitsequence;
// If standing on conveyor, e.g.
vec3_t basevelocity;
// Use the crouched hull, or the regular player hull.
int usehull;
// Latched buttons last time state updated.
int oldbuttons;
// -1 = in air, else pmove entity number
int onground;
int iStepLeft;
// How fast we are falling
float flFallVelocity;
float fov;
int weaponanim;
// Parametric movement overrides
vec3_t startpos;
vec3_t endpos;
float impacttime;
float starttime;
// For mods
int iuser1;
int iuser2;
int iuser3;
int iuser4;
float fuser1;
float fuser2;
float fuser3;
float fuser4;
vec3_t vuser1;
vec3_t vuser2;
vec3_t vuser3;
vec3_t vuser4;
};
#include "pm_info.h"
typedef struct clientdata_s
{
vec3_t origin;
vec3_t velocity;
int viewmodel;
vec3_t punchangle;
int flags;
int waterlevel;
int watertype;
vec3_t view_ofs;
float health;
int bInDuck;
int weapons; // remove?
int flTimeStepSound;
int flDuckTime;
int flSwimTime;
int waterjumptime;
float maxspeed;
float fov;
int weaponanim;
int m_iId;
int ammo_shells;
int ammo_nails;
int ammo_cells;
int ammo_rockets;
float m_flNextAttack;
int tfstate;
int pushmsec;
int deadflag;
char physinfo[MAX_PHYSINFO_STRING];
// For mods
int iuser1;
int iuser2;
int iuser3;
int iuser4;
float fuser1;
float fuser2;
float fuser3;
float fuser4;
vec3_t vuser1;
vec3_t vuser2;
vec3_t vuser3;
vec3_t vuser4;
} clientdata_t;
#include "weaponinfo.h"
#define MAX_LOCAL_WEAPONS 64 // max weapons that can be predicted on the client
typedef struct local_state_s
{
entity_state_t playerstate;
clientdata_t client;
weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
} local_state_t;
#endif//ENTITY_STATE_H

25
common/entity_types.h Normal file
View File

@ -0,0 +1,25 @@
/***
*
* 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 ENTITY_TYPES_H
#define ENTITY_TYPES_H
#define ET_NORMAL 0
#define ET_PLAYER 1
#define ET_TEMPENTITY 2
#define ET_BEAM 3
#define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes
#endif//ENTITY_TYPES_H

56
common/event_api.h Normal file
View File

@ -0,0 +1,56 @@
/***
*
* 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 EVENT_API_H
#define EVENT_API_H
#define EVENT_API_VERSION 1
typedef struct event_api_s
{
int version;
void ( *EV_PlaySound )( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch );
void ( *EV_StopSound )( int ent, int channel, const char *sample );
int ( *EV_FindModelIndex )( const char *pmodel );
int ( *EV_IsLocal )( int playernum );
int ( *EV_LocalPlayerDucking )( void );
void ( *EV_LocalPlayerViewheight )( float * );
void ( *EV_LocalPlayerBounds )( int hull, float *mins, float *maxs );
int ( *EV_IndexFromTrace)( struct pmtrace_s *pTrace );
struct physent_s *( *EV_GetPhysent )( int idx );
void ( *EV_SetUpPlayerPrediction )( int dopred, int bIncludeLocalClient );
void ( *EV_PushPMStates )( void );
void ( *EV_PopPMStates )( void );
void ( *EV_SetSolidPlayers )( int playernum );
void ( *EV_SetTraceHull )( int hull );
void ( *EV_PlayerTrace )( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr );
void ( *EV_WeaponAnimation )( int sequence, int body );
unsigned short ( *EV_PrecacheEvent )( int type, const char* psz );
void ( *EV_PlaybackEvent )( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
const char *( *EV_TraceTexture )( int ground, float *vstart, float *vend );
void ( *EV_StopAllSounds )( int entnum, int entchannel );
void ( *EV_KillEvents )( int entnum, const char *eventname );
// Xash3D extension
void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr );
const char *(*EV_SoundForIndex)( int index );
struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend );
struct movevars_s *( *EV_GetMovevars )( void );
struct pmtrace_s *( *EV_VisTraceLine )( float *start, float *end, int flags );
struct physent_s *( *EV_GetVisent )( int idx );
int ( *EV_TestLine)( const vec3_t start, const vec3_t end, int flags );
} event_api_t;
#endif//EVENT_API_H

47
common/event_args.h Normal file
View File

@ -0,0 +1,47 @@
/***
*
* 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 EVENT_ARGS_H
#define EVENT_ARGS_H
// Event was invoked with stated origin
#define FEVENT_ORIGIN ( 1<<0 )
// Event was invoked with stated angles
#define FEVENT_ANGLES ( 1<<1 )
typedef struct event_args_s
{
int flags;
// Transmitted
int entindex;
float origin[3];
float angles[3];
float velocity[3];
int ducking;
float fparam1;
float fparam2;
int iparam1;
int iparam2;
int bparam1;
int bparam2;
} event_args_t;
#endif//EVENT_ARGS_H

45
common/event_flags.h Normal file
View File

@ -0,0 +1,45 @@
/***
*
* 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 EVENT_FLAGS_H
#define EVENT_FLAGS_H
// Skip local host for event send.
#define FEV_NOTHOST (1<<0)
// Send the event reliably. You must specify the origin and angles and use
// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything
// that depends on the event origin/angles. I.e., the origin/angles are not
// taken from the invoking edict for reliable events.
#define FEV_RELIABLE (1<<1)
// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC
// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ).
#define FEV_GLOBAL (1<<2)
// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate
//
#define FEV_UPDATE (1<<3)
// Only send to entity specified as the invoker
#define FEV_HOSTONLY (1<<4)
// Only send if the event was created on the server.
#define FEV_SERVER (1<<5)
// Only issue event client side ( from shared code )
#define FEV_CLIENT (1<<6)
#endif//EVENT_FLAGS_H

30
common/features.h Normal file
View File

@ -0,0 +1,30 @@
/*
features.h - engine features that can be enabled by mod-maker request
Copyright (C) 2012 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.
*/
#ifndef FEATURES_H
#define FEATURES_H
// 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_QUAKE_COMPATIBLE (1<<1) // make engine compatible with quake (flags and effects)
#define ENGINE_LOAD_DELUXEDATA (1<<2) // loading deluxemap for map (if present)
#define ENGINE_PHYSICS_PUSHER_EXT (1<<3) // enable sets of improvements for MOVETYPE_PUSH physics
#define ENGINE_LARGE_LIGHTMAPS (1<<4) // change lightmap sizes from 128x128 to 1024x1024
#define ENGINE_COMPENSATE_QUAKE_BUG (1<<5) // compensate stupid quake bug (inverse pitch) for mods where this bug is fixed
// reserved
#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
#define ENGINE_FIXED_FRAMERATE (1<<8) // keep constant rate for client and server (but don't clamp renderer calls)
#endif//FEATURES_H

49
common/gameinfo.h Normal file
View File

@ -0,0 +1,49 @@
/*
gameinfo.h - current game info
Copyright (C) 2010 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.
*/
#ifndef GAMEINFO_H
#define GAMEINFO_H
#define GFL_NOMODELS (1<<0)
/*
========================================================================
GAMEINFO stuff
internal shared gameinfo structure (readonly for engine parts)
========================================================================
*/
typedef struct
{
// filesystem info
char gamefolder[64]; // used for change game '-game x'
char startmap[64]; // map to start singleplayer game
char trainmap[64]; // map to start hazard course (if specified)
char title[64]; // Game Main Title
char version[14]; // game version (optional)
short flags; // game flags
// about mod info
char game_url[256]; // link to a developer's site
char update_url[256]; // link to updates page
char type[64]; // single, toolkit, multiplayer etc
char date[64];
char size[64]; // displayed mod size
int gamemode;
} GAMEINFO;
#endif//GAMEINFO_H

59
common/hltv.h Normal file
View File

@ -0,0 +1,59 @@
/***
*
* 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 HLTV_H
#define HLTV_H
#define TYPE_CLIENT 0 // client is a normal HL client (default)
#define TYPE_PROXY 1 // client is another proxy
#define TYPE_COMMENTATOR 3 // client is a commentator
#define TYPE_DEMO 4 // client is a demo file
// sub commands of svc_hltv:
#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands
#define HLTV_STATUS 1 // send status infos about proxy
#define HLTV_LISTEN 2 // tell client to listen to a multicast stream
// sub commands of svc_director:
#define DRC_CMD_NONE 0 // NULL director command
#define DRC_CMD_START 1 // start director mode
#define DRC_CMD_EVENT 2 // informs about director command
#define DRC_CMD_MODE 3 // switches camera modes
#define DRC_CMD_CAMERA 4 // sets camera registers
#define DRC_CMD_TIMESCALE 5 // sets time scale
#define DRC_CMD_MESSAGE 6 // send HUD centerprint
#define DRC_CMD_SOUND 7 // plays a particular sound
#define DRC_CMD_STATUS 8 // status info about broadcast
#define DRC_CMD_BANNER 9 // banner file name for HLTV gui
#define DRC_CMD_FADE 10 // send screen fade command
#define DRC_CMD_SHAKE 11 // send screen shake command
#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command
#define DRC_CMD_LAST 12
// HLTV_EVENT event flags
#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important)
#define DRC_FLAG_SIDE (1<<4) //
#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene
#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo
#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc)
#define DRC_FLAG_INTRO (1<<8) // is a introduction scene
#define DRC_FLAG_FINAL (1<<9) // is a final scene
#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data
#define MAX_DIRECTOR_CMD_PARAMETERS 4
#define MAX_DIRECTOR_CMD_STRING 128
#endif//HLTV_H

38
common/ivoicetweak.h Normal file
View File

@ -0,0 +1,38 @@
/***
*
* 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 IVOICETWEAK_H
#define IVOICETWEAK_H
// These provide access to the voice controls.
typedef enum
{
MicrophoneVolume = 0, // values 0-1.
OtherSpeakerScale // values 0-1. Scales how loud other players are.
} VoiceTweakControl;
typedef struct IVoiceTweak_s
{
// These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back
// without sending to the server.
int (*StartVoiceTweakMode)( void ); // Returns 0 on error.
void (*EndVoiceTweakMode)( void );
// Get/set control values.
void (*SetControlFloat)( VoiceTweakControl iControl, float value );
float (*GetControlFloat)( VoiceTweakControl iControl );
} IVoiceTweak;
#endif//IVOICETWEAK_H

29
common/lightstyle.h Normal file
View File

@ -0,0 +1,29 @@
/*
lightstyle.h - lighstyle description
Copyright (C) 2011 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.
*/
#ifndef LIGHTSTYLE_H
#define LIGHTSTYLE_H
typedef struct
{
char pattern[256];
float map[256];
int length;
float value;
qboolean interp; // allow to interpolate this lightstyle
float time; // local time is gurantee what new style begins from the start, not mid or end of the sequence
} lightstyle_t;
#endif//LIGHTSTYLE_H

95
common/mathlib.h Normal file
View File

@ -0,0 +1,95 @@
/***
*
* 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.
*
****/
// mathlib.h
#include <math.h>
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4]; // x,y,z,w
#ifndef M_PI
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
struct mplane_s;
extern vec3_t vec3_origin;
extern int nanmask;
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
#ifndef VECTOR_H
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#endif
#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;}
void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
int VectorCompare (const vec3_t v1, const vec3_t v2);
float Length (const vec3_t v);
void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross);
float VectorNormalize (vec3_t v); // returns vector length
void VectorInverse (vec3_t v);
void VectorScale (const vec3_t in, vec_t scale, vec3_t out);
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
#define AngleIVectors AngleVectorsTranspose
void AngleMatrix (const vec3_t angles, float (*matrix)[4] );
void AngleIMatrix (const vec3_t angles, float (*matrix)[4] );
void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out);
void NormalizeAngles( vec3_t angles );
void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac );
float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 );
void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up);
void VectorAngles( const vec3_t forward, vec3_t angles );
int InvertMatrix( const float * m, float *out );
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane);
float anglemod(float a);
#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
(((p)->type < 3)? \
( \
((p)->dist <= (emins)[(p)->type])? \
1 \
: \
( \
((p)->dist >= (emaxs)[(p)->type])?\
2 \
: \
3 \
) \
) \
: \
BoxOnPlaneSide( (emins), (emaxs), (p)))

97
common/net_api.h Normal file
View File

@ -0,0 +1,97 @@
/***
*
* 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 NET_API_H
#define NET_API_H
#include "netadr.h"
#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address
#define NETAPI_REQUEST_PING ( 1 )
#define NETAPI_REQUEST_RULES ( 2 )
#define NETAPI_REQUEST_PLAYERS ( 3 )
#define NETAPI_REQUEST_DETAILS ( 4 )
// Set this flag for things like broadcast requests, etc. where the engine should not
// kill the request hook after receiving the first response
#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 )
typedef void (*net_api_response_func_t) ( struct net_response_s *response );
#define NET_SUCCESS ( 0 )
#define NET_ERROR_TIMEOUT ( 1<<0 )
#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 )
#define NET_ERROR_UNDEFINED ( 1<<2 )
typedef struct net_adrlist_s
{
struct net_adrlist_s *next;
netadr_t remote_address;
} net_adrlist_t;
typedef struct net_response_s
{
// NET_SUCCESS or an error code
int error;
// Context ID
int context;
// Type
int type;
// Server that is responding to the request
netadr_t remote_address;
// Response RTT ping time
double ping;
// Key/Value pair string ( separated by backlash \ characters )
// WARNING: You must copy this buffer in the callback function, because it is freed
// by the engine right after the call!!!!
// ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's
void *response;
} net_response_t;
typedef struct net_status_s
{
// Connected to remote server? 1 == yes, 0 otherwise
int connected;
// Client's IP address
netadr_t local_address;
// Address of remote server
netadr_t remote_address;
// Packet Loss ( as a percentage )
int packet_loss;
// Latency, in seconds ( multiply by 1000.0 to get milliseconds )
double latency;
// Connection time, in seconds
double connection_time;
// Rate setting ( for incoming data )
double rate;
} net_status_t;
typedef struct net_api_s
{
// APIs
void (*InitNetworking)( void );
void (*Status )( struct net_status_s *status );
void (*SendRequest)( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response );
void (*CancelRequest)( int context );
void (*CancelAllRequests)( void );
char *(*AdrToString)( struct netadr_s *a );
int ( *CompareAdr)( struct netadr_s *a, struct netadr_s *b );
int ( *StringToAdr)( char *s, struct netadr_s *a );
const char *(*ValueForKey)( const char *s, const char *key );
void (*RemoveKey)( char *s, const char *key );
void (*SetValueForKey)( char *s, const char *key, const char *value, int maxsize );
} net_api_t;
#endif//NET_APIH

37
common/netadr.h Normal file
View File

@ -0,0 +1,37 @@
/***
*
* 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 NETADR_H
#define NETADR_H
typedef enum
{
NA_UNUSED,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IPX,
NA_BROADCAST_IPX
} netadrtype_t;
typedef struct netadr_s
{
netadrtype_t type;
unsigned char ip[4];
unsigned char ipx[10];
unsigned short port;
} netadr_t;
#endif//NETADR_H

53
common/particledef.h Normal file
View File

@ -0,0 +1,53 @@
/***
*
* 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 PARTICLEDEF_H
#define PARTICLEDEF_H
typedef enum
{
pt_static,
pt_grav,
pt_slowgrav,
pt_fire,
pt_explode,
pt_explode2,
pt_blob,
pt_blob2,
pt_vox_slowgrav,
pt_vox_grav,
pt_clientcustom // Must have callback function specified
} ptype_t;
typedef struct particle_s
{
vec3_t org;
short color;
short packedColor;
struct particle_s *next;
vec3_t vel;
float ramp;
float die;
ptype_t type;
void (*deathfunc)( struct particle_s *particle );
// for pt_clientcusttom, we'll call this function each frame
void (*callback)( struct particle_s *particle, float frametime );
// For deathfunc, etc.
unsigned char context;
} particle_t;
#endif//PARTICLEDEF_H

41
common/pmtrace.h Normal file
View File

@ -0,0 +1,41 @@
/***
*
* 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 PM_TRACE_H
#define PM_TRACE_H
typedef struct
{
vec3_t normal;
float dist;
} pmplane_t;
typedef struct pmtrace_s pmtrace_t;
struct pmtrace_s
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater; // End point is in empty space or in water
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
pmplane_t plane; // surface normal at impact
int ent; // entity at impact
vec3_t deltavelocity; // Change in player's velocity caused by impact.
// Only run on server.
int hitgroup;
};
#endif//PM_TRACE_H

38
common/qfont.h Normal file
View File

@ -0,0 +1,38 @@
/***
*
* 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 QFONT_H
#define QFONT_H
// Font stuff
#define NUM_GLYPHS 256
typedef struct
{
short startoffset;
short charwidth;
} charinfo;
typedef struct qfont_s
{
int width, height;
int rowcount;
int rowheight;
charinfo fontinfo[NUM_GLYPHS];
byte data[4];
} qfont_t;
#endif//QFONT_H

195
common/r_efx.h Normal file
View File

@ -0,0 +1,195 @@
/***
*
* 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 R_EFX_H
#define R_EFX_H
// particle_t
#if !defined( PARTICLEDEFH )
#include "particledef.h"
#endif
// BEAM
#if !defined( BEAMDEFH )
#include "beamdef.h"
#endif
// dlight_t
#if !defined ( DLIGHTH )
#include "dlight.h"
#endif
// cl_entity_t
#if !defined( CL_ENTITYH )
#include "cl_entity.h"
#endif
/*
// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one
// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings
color24 gTracerColors[] =
{
{ 255, 255, 255 }, // White
{ 255, 0, 0 }, // Red
{ 0, 255, 0 }, // Green
{ 0, 0, 255 }, // Blue
{ 0, 0, 0 }, // Tracer default, filled in from cvars, etc.
{ 255, 167, 17 }, // Yellow-orange sparks
{ 255, 130, 90 }, // Yellowish streaks (garg)
{ 55, 60, 144 }, // Blue egon streak
{ 255, 130, 90 }, // More Yellowish streaks (garg)
{ 255, 140, 90 }, // More Yellowish streaks (garg)
{ 200, 130, 90 }, // More red streaks (garg)
{ 255, 120, 70 }, // Darker red streaks (garg)
};
*/
// Temporary entity array
#define TENTPRIORITY_LOW 0
#define TENTPRIORITY_HIGH 1
// TEMPENTITY flags
#define FTENT_NONE 0x00000000
#define FTENT_SINEWAVE 0x00000001
#define FTENT_GRAVITY 0x00000002
#define FTENT_ROTATE 0x00000004
#define FTENT_SLOWGRAVITY 0x00000008
#define FTENT_SMOKETRAIL 0x00000010
#define FTENT_COLLIDEWORLD 0x00000020
#define FTENT_FLICKER 0x00000040
#define FTENT_FADEOUT 0x00000080
#define FTENT_SPRANIMATE 0x00000100
#define FTENT_HITSOUND 0x00000200
#define FTENT_SPIRAL 0x00000400
#define FTENT_SPRCYCLE 0x00000800
#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes
#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw
#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything
#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner)
#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed
#define FTENT_SPARKSHOWER 0x00020000
#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things )
#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things )
#define FTENT_SCALE 0x00100000 // An experiment
typedef struct tempent_s TEMPENTITY;
typedef struct tempent_s
{
int flags;
float die;
float frameMax;
float x;
float y;
float z;
float fadeSpeed;
float bounceFactor;
int hitSound;
void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr );
void (*callback)( struct tempent_s *ent, float frametime, float currenttime );
TEMPENTITY *next;
int priority;
short clientIndex; // if attached, this is the index of the client to stick to
// if COLLIDEALL, this is the index of the client to ignore
// TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex!
vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin.
cl_entity_t entity;
// baseline.origin - velocity
// baseline.renderamt - starting fadeout intensity
// baseline.angles - angle velocity
} TEMPENTITY;
typedef struct efx_api_s efx_api_t;
struct efx_api_s
{
particle_t *(*R_AllocParticle)( void (*callback)( struct particle_s *particle, float frametime ));
void (*R_BlobExplosion)( float *org );
void (*R_Blood)( float *org, float *dir, int pcolor, int speed );
void (*R_BloodSprite)( float *org, int colorindex, int modelIndex, int modelIndex2, float size );
void (*R_BloodStream)( float *org, float *dir, int pcolor, int speed );
void (*R_BreakModel)( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags );
void (*R_Bubbles)( float *mins, float *maxs, float height, int modelIndex, int count, float speed );
void (*R_BubbleTrail)( float *start, float *end, float height, int modelIndex, int count, float speed );
void (*R_BulletImpactParticles)( float *pos );
void (*R_EntityParticles)( struct cl_entity_s *ent );
void (*R_Explosion)( float *pos, int model, float scale, float framerate, int flags );
void (*R_FizzEffect)( struct cl_entity_s *pent, int modelIndex, int density );
void (*R_FireField)( float *org, int radius, int modelIndex, int count, int flags, float life );
void (*R_FlickerParticles)( float *org );
void (*R_FunnelSprite)( float *org, int modelIndex, int reverse );
void (*R_Implosion)( float *end, float radius, int count, float life );
void (*R_LargeFunnel)( float *org, int reverse );
void (*R_LavaSplash)( float *org );
void (*R_MultiGunshot)( float *org, float *dir, float *noise, int count, int decalCount, int *decalIndices );
void (*R_MuzzleFlash)( float *pos1, int type );
void (*R_ParticleBox)( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life );
void (*R_ParticleBurst)( float *pos, int size, int color, float life );
void (*R_ParticleExplosion)( float *org );
void (*R_ParticleExplosion2)( float *org, int colorStart, int colorLength );
void (*R_ParticleLine)( float *start, float *end, unsigned char r, unsigned char g, unsigned char b, float life );
void (*R_PlayerSprites)( int client, int modelIndex, int count, int size );
void (*R_Projectile)( float *origin, float *velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) );
void (*R_RicochetSound)( float *pos );
void (*R_RicochetSprite)( float *pos, struct model_s *pmodel, float duration, float scale );
void (*R_RocketFlare)( float *pos );
void (*R_RocketTrail)( float *start, float *end, int type );
void (*R_RunParticleEffect)( float *org, float *dir, int color, int count );
void (*R_ShowLine)( float *start, float *end );
void (*R_SparkEffect)( float *pos, int count, int velocityMin, int velocityMax );
void (*R_SparkShower)( float *pos );
void (*R_SparkStreaks)( float *pos, int count, int velocityMin, int velocityMax );
void (*R_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int spread, int rendermode );
void (*R_Sprite_Explode)( TEMPENTITY *pTemp, float scale, int flags );
void (*R_Sprite_Smoke)( TEMPENTITY *pTemp, float scale );
void (*R_Sprite_Spray)( float *pos, float *dir, int modelIndex, int count, int speed, int iRand );
void (*R_Sprite_Trail)( int type, float *start, float *end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed );
void (*R_Sprite_WallPuff)( TEMPENTITY *pTemp, float scale );
void (*R_StreakSplash)( float *pos, float *dir, int color, int count, float speed, int velocityMin, int velocityMax );
void (*R_TracerEffect)( float *start, float *end );
void (*R_UserTracerParticle)( float *org, float *vel, float life, int colorIndex, float length, unsigned char deathcontext, void (*deathfunc)( struct particle_s *particle ));
particle_t *(*R_TracerParticles)( float *org, float *vel, float life );
void (*R_TeleportSplash)( float *org );
void (*R_TempSphereModel)( float *pos, float speed, float life, int count, int modelIndex );
TEMPENTITY *(*R_TempModel)( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype );
TEMPENTITY *(*R_DefaultSprite)( float *pos, int spriteIndex, float framerate );
TEMPENTITY *(*R_TempSprite)( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags );
int (*Draw_DecalIndex)( int id );
int (*Draw_DecalIndexFromName)( char *name );
void (*R_DecalShoot)( int textureIndex, int entity, int modelIndex, float *position, int flags );
void (*R_AttachTentToPlayer)( int client, int modelIndex, float zoffset, float life );
void (*R_KillAttachedTents)( int client );
BEAM *(*R_BeamCirclePoints)( int type, float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
BEAM *(*R_BeamEntPoint)( int startEnt, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
BEAM *(*R_BeamEnts)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
BEAM *(*R_BeamFollow)( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness );
void (*R_BeamKill)( int deadEntity );
BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed );
BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
dlight_t *(*CL_AllocDlight)( int key );
dlight_t *(*CL_AllocElight)( int key );
TEMPENTITY *(*CL_TempEntAlloc)( float *org, struct model_s *model );
TEMPENTITY *(*CL_TempEntAllocNoModel)( float *org );
TEMPENTITY *(*CL_TempEntAllocHigh)( float *org, struct model_s *model );
TEMPENTITY *(*CL_TentEntAllocCustom)( float *origin, struct model_s *model, int high, void (*callback)( struct tempent_s *ent, float frametime, float currenttime ));
void (*R_GetPackedColor)( short *packed, short color );
short (*R_LookupColor)( unsigned char r, unsigned char g, unsigned char b );
void (*R_DecalRemoveAll)( int textureIndex ); // textureIndex points to the decal index in the array, not the actual texture index.
void (*R_FireCustomDecal)( int textureIndex, int entity, int modelIndex, float *position, int flags, float scale );
};
#endif//R_EFX_H

154
common/r_studioint.h Normal file
View File

@ -0,0 +1,154 @@
/***
*
* 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 R_STUDIOINT_H
#define R_STUDIOINT_H
#define STUDIO_INTERFACE_VERSION 1
typedef struct engine_studio_api_s
{
// Allocate number*size bytes and zero it
void *( *Mem_Calloc )( int number, size_t size );
// Check to see if pointer is in the cache
void *( *Cache_Check )( struct cache_user_s *c );
// Load file into cache ( can be swapped out on demand )
void ( *LoadCacheFile )( char *path, struct cache_user_s *cu );
// Retrieve model pointer for the named model
struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing );
// Retrieve pointer to studio model data block from a model
void *( *Mod_Extradata )( struct model_s *mod );
// Retrieve indexed model from client side model precache list
struct model_s *( *GetModelByIndex )( int index );
// Get entity that is set for rendering
struct cl_entity_s * ( *GetCurrentEntity )( void );
// Get referenced player_info_t
struct player_info_s *( *PlayerInfo )( int index );
// Get most recently received player state data from network system
struct entity_state_s *( *GetPlayerState )( int index );
// Get viewentity
struct cl_entity_s * ( *GetViewEntity )( void );
// Get current frame count, and last two timestampes on client
void ( *GetTimes )( int *framecount, double *current, double *old );
// Get a pointer to a cvar by name
struct cvar_s *( *GetCvar )( const char *name );
// Get current render origin and view vectors ( up, right and vpn )
void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv );
// Get sprite model used for applying chrome effect
struct model_s *( *GetChromeSprite )( void );
// Get model counters so we can incement instrumentation
void ( *GetModelCounters )( int **s, int **a );
// Get software scaling coefficients
void ( *GetAliasScale )( float *x, float *y );
// Get bone, light, alias, and rotation matrices
float ****( *StudioGetBoneTransform )( void );
float ****( *StudioGetLightTransform )( void );
float ***( *StudioGetAliasTransform )( void );
float ***( *StudioGetRotationMatrix )( void );
// Set up body part, and get submodel pointers
void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel );
// Check if entity's bbox is in the view frustum
int ( *StudioCheckBBox )( void );
// Apply lighting effects to model
void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight );
void ( *StudioEntityLight )( struct alight_s *plight );
void ( *StudioSetupLighting )( struct alight_s *plighting );
// Draw mesh vertices
void ( *StudioDrawPoints )( void );
// Draw hulls around bones
void ( *StudioDrawHulls )( void );
// Draw bbox around studio models
void ( *StudioDrawAbsBBox )( void );
// Draws bones
void ( *StudioDrawBones )( void );
// Loads in appropriate texture for model
void ( *StudioSetupSkin )( void *ptexturehdr, int index );
// Sets up for remapped colors
void ( *StudioSetRemapColors )( int top, int bottom );
// Set's player model and returns model pointer
struct model_s *( *SetupPlayerModel )( int index );
// Fires any events embedded in animation
void ( *StudioClientEvents )( void );
// Retrieve/set forced render effects flags
int ( *GetForceFaceFlags )( void );
void ( *SetForceFaceFlags )( int flags );
// Tell engine the value of the studio model header
void ( *StudioSetHeader )( void *header );
// Tell engine which model_t * is being renderered
void ( *SetRenderModel )( struct model_s *model );
// Final state setup and restore for rendering
void ( *SetupRenderer )( int rendermode );
void ( *RestoreRenderer )( void );
// Set render origin for applying chrome effect
void ( *SetChromeOrigin )( void );
// True if using D3D/OpenGL
int ( *IsHardware )( void );
// Only called by hardware interface
void ( *GL_StudioDrawShadow )( void );
void ( *GL_SetRenderMode )( int mode );
void ( *StudioSetRenderamt )( int iRenderamt );
void ( *StudioSetCullState )( int iCull );
void ( *StudioRenderShadow )( int iSprite, float *p1, float *p2, float *p3, float *p4 );
} engine_studio_api_t;
typedef struct server_studio_api_s
{
// Allocate number*size bytes and zero it
void *( *Mem_Calloc )( int number, size_t size );
// Check to see if pointer is in the cache
void *( *Cache_Check )( struct cache_user_s *c );
// Load file into cache ( can be swapped out on demand )
void ( *LoadCacheFile )( char *path, struct cache_user_s *cu );
// Retrieve pointer to studio model data block from a model
void *( *Mod_Extradata )( struct model_s *mod );
} server_studio_api_t;
// client blending
typedef struct r_studio_interface_s
{
int version;
int ( *StudioDrawModel )( int flags );
int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer );
} r_studio_interface_t;
// server blending
#define SV_BLENDING_INTERFACE_VERSION 1
typedef struct sv_blending_interface_s
{
int version;
void ( *SV_StudioSetupBones )( struct model_s *pModel,
float frame,
int sequence,
const vec3_t angles,
const vec3_t origin,
const byte *pcontroller,
const byte *pblending,
int iBone,
const edict_t *pEdict );
} sv_blending_interface_t;
#endif//R_STUDIOINT_H

105
common/ref_params.h Normal file
View File

@ -0,0 +1,105 @@
/***
*
* 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 REF_PARAMS_H
#define REF_PARAMS_H
typedef struct ref_params_s
{
// output
vec3_t vieworg;
vec3_t viewangles;
vec3_t forward;
vec3_t right;
vec3_t up;
// Client frametime;
float frametime;
// Client time
float time;
// Misc
int intermission;
int paused;
int spectator;
int onground;
int waterlevel;
vec3_t simvel;
vec3_t simorg;
vec3_t viewheight;
float idealpitch;
vec3_t cl_viewangles;
int health;
vec3_t crosshairangle;
float viewsize;
vec3_t punchangle;
int maxclients;
int viewentity;
int playernum;
int max_entities;
int demoplayback;
int hardware;
int smoothing;
// Last issued usercmd
struct usercmd_s *cmd;
// Movevars
struct movevars_s *movevars;
int viewport[4]; // the viewport coordinates x, y, width, height
int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview
// so long in cycles until this value is 0 (multiple views)
int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions
} ref_params_t;
// same as ref_params but for overview mode
typedef struct ref_overview_s
{
vec3_t origin;
qboolean rotated;
float xLeft;
float xRight;
float yTop;
float yBottom;
float zFar;
float zNear;
float flZoom;
} ref_overview_t;
// ref_viewpass_t->flags
#define RF_DRAW_WORLD (1<<0) // pass should draw the world (otherwise it's player menu model)
#define RF_DRAW_CUBEMAP (1<<1) // special 6x pass to render cubemap\skybox sides
#define RF_DRAW_OVERVIEW (1<<2) // overview mode is active
#define RF_ONLY_CLIENTDRAW (1<<3) // nothing is drawn by the engine except clientDraw functions
// intermediate struct for viewpass (or just a single frame)
typedef struct ref_viewpass_s
{
int viewport[4]; // size of new viewport
vec3_t vieworigin; // view origin
vec3_t viewangles; // view angles
int viewentity; // entitynum (P2: Savior uses this)
float fov_x, fov_y; // vertical & horizontal FOV
int flags; // if !=0 nothing is drawn by the engine except clientDraw functions
} ref_viewpass_t;
#endif//REF_PARAMS_H

266
common/render_api.h Normal file
View File

@ -0,0 +1,266 @@
/*
render_api.h - Xash3D extension for client interface
Copyright (C) 2011 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.
*/
#ifndef RENDER_API_H
#define RENDER_API_H
#include "lightstyle.h"
#include "dlight.h"
#define CL_RENDER_INTERFACE_VERSION 37 // Xash3D 1.0
#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals
// 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
#define PARM_TEX_SRC_WIDTH 3
#define PARM_TEX_SRC_HEIGHT 4
#define PARM_TEX_SKYBOX 5 // second arg as skybox ordering num
#define PARM_TEX_SKYTEXNUM 6 // skytexturenum for quake sky
#define PARM_TEX_LIGHTMAP 7 // second arg as number 0 - 128
#define PARM_TEX_TARGET 8
#define PARM_TEX_TEXNUM 9
#define PARM_TEX_FLAGS 10
#define PARM_TEX_DEPTH 11 // 3D texture depth or 2D array num layers
//reserved
#define PARM_TEX_GLFORMAT 13 // get a texture GL-format
#define PARM_TEX_ENCODE 14 // custom encoding for DXT image
#define PARM_TEX_MIPCOUNT 15 // count of mipmaps (0 - autogenerated, 1 - disabled of mipmapping)
#define PARM_BSP2_SUPPORTED 16 // tell custom renderer what engine is support BSP2 in this build
#define PARM_SKY_SPHERE 17 // sky is quake sphere ?
//reserved
#define PARM_MAP_HAS_DELUXE 19 // map has deluxedata
#define PARM_MAX_ENTITIES 20
#define PARM_WIDESCREEN 21
#define PARM_FULLSCREEN 22
#define PARM_SCREEN_WIDTH 23
#define PARM_SCREEN_HEIGHT 24
#define PARM_CLIENT_INGAME 25
#define PARM_FEATURES 26 // same as movevars->features
#define PARM_ACTIVE_TMU 27 // for debug
#define PARM_LIGHTSTYLEVALUE 28 // second arg is stylenum
#define PARM_MAX_IMAGE_UNITS 29
#define PARM_CLIENT_ACTIVE 30
#define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change
#define PARM_DEDICATED_SERVER 32
#define PARM_SURF_SAMPLESIZE 33 // lightmap resolution per face (second arg interpret as facenumber)
#define PARM_GL_CONTEXT_TYPE 34 // opengl or opengles
#define PARM_GLES_WRAPPER 35 //
#define PARM_STENCIL_ACTIVE 36
#define PARM_WATER_ALPHA 37
// skybox ordering
enum
{
SKYBOX_RIGHT = 0,
SKYBOX_BACK,
SKYBOX_LEFT,
SKYBOX_FORWARD,
SKYBOX_UP,
SKYBOX_DOWN,
};
typedef enum
{
TF_NEAREST = (1<<0), // disable texfilter
TF_KEEP_SOURCE = (1<<1), // some images keep source
TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20
TF_EXPAND_SOURCE = (1<<3), // Don't keep source as 8-bit expand to RGBA
TF_TEXTURE_2D_ARRAY = (1<<4), // this is 2D texture array (multi-layers)
TF_TEXTURE_RECTANGLE= (1<<5), // this is GL_TEXTURE_RECTANGLE
TF_CUBEMAP = (1<<6), // it's cubemap texture
TF_DEPTHMAP = (1<<7), // custom texture filter used
TF_QUAKEPAL = (1<<8), // image has an quake1 palette
TF_LUMINANCE = (1<<9), // force image to grayscale
TF_SKYSIDE = (1<<10), // this is a part of skybox
TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range
TF_NOMIPMAP = (1<<12), // don't build mips for this image
TF_HAS_LUMA = (1<<13), // sets by GL_UploadTexture
TF_MAKELUMA = (1<<14), // create luma from quake texture (only q1 textures contain luma-pixels)
TF_NORMALMAP = (1<<15), // is a normalmap
TF_HAS_ALPHA = (1<<16), // image has alpha (used only for GL_CreateTexture)
TF_FORCE_COLOR = (1<<17), // force upload monochrome textures as RGB (detail textures)
TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D
TF_BORDER = (1<<19), // zero clamp for projected textures
TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D
TF_ATLAS_PAGE = (1<<21), // bit who indicate lightmap page or deluxemap page
// reserved
// reserved
// reserved
TF_IMG_UPLOADED = (1<<25), // this is set for first time when called glTexImage, otherwise it will be call glTexSubImage
TF_ARB_FLOAT = (1<<26), // float textures
TF_NOCOMPARE = (1<<27), // disable comparing for depth textures
TF_ARB_16BIT = (1<<28), // keep image as 16-bit (not 24)
} texFlags_t;
typedef enum
{
CONTEXT_TYPE_GL = 0,
CONTEXT_TYPE_GLES_1_X,
CONTEXT_TYPE_GLES_2_X
} gl_context_type_t;
typedef enum
{
GLES_WRAPPER_NONE = 0, // native GLES
GLES_WRAPPER_NANOGL, // used on GLES platforms
} gles_wrapper_t;
// 30 bytes here
typedef struct modelstate_s
{
short sequence;
short frame; // 10 bits multiple by 4, should be enough
byte blending[2];
byte controller[4];
byte poseparam[16];
byte body;
byte skin;
short scale; // model scale (multiplied by 16)
} modelstate_t;
typedef struct decallist_s
{
vec3_t position;
char name[64];
short entityIndex;
byte depth;
byte flags;
float scale;
// this is the surface plane that we hit so that
// we can move certain decals across
// transitions if they hit similar geometry
vec3_t impactPlaneNormal;
modelstate_t studio_state; // studio decals only
} decallist_t;
typedef struct render_api_s
{
// Get renderer info (doesn't changes engine state at all)
int (*RenderGetParm)( int parm, int arg ); // generic
void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha );
lightstyle_t* (*GetLightStyle)( int number );
dlight_t* (*GetDynamicLight)( int number );
dlight_t* (*GetEntityLight)( int number );
byte (*LightToTexGamma)( byte color ); // software gamma support
float (*GetFrameTime)( void );
// Set renderer info (tell engine about changes)
void (*R_SetCurrentEntity)( struct cl_entity_s *ent ); // tell engine about both currententity and currentmodel
void (*R_SetCurrentModel)( struct model_s *mod ); // change currentmodel but leave currententity unchanged
int (*R_FatPVS)( const float *org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis );
void (*R_StoreEfrags)( struct efrag_s **ppefrag, int framecount );// store efrags for static entities
// Texture tools
int (*GL_FindTexture)( const char *name );
const char* (*GL_TextureName)( unsigned int texnum );
const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL
int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags );
int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags );
int (*GL_LoadTextureArray)( const char **names, int flags );
int (*GL_CreateTextureArray)( const char *name, int width, int height, int depth, const void *buffer, int flags );
void (*GL_FreeTexture)( unsigned int texnum );
// Decals manipulating (draw & remove)
void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa );
float *(*R_DecalSetupVerts)( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount );
void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
// AVIkit support
void *(*AVI_LoadVideo)( const char *filename );
int (*AVI_GetVideoInfo)( void *Avi, long *xres, long *yres, float *duration );
long (*AVI_GetVideoFrameNumber)( void *Avi, float time );
byte *(*AVI_GetVideoFrame)( void *Avi, long frame );
void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
void (*AVI_FreeVideo)( void *Avi );
int (*AVI_IsActive)( void *Avi );
void (*AVI_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*AVI_Reserved1)( void );
void (*AVI_Reserved2)( void );
// glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client)
void (*GL_Bind)( int tmu, unsigned int texnum );
void (*GL_SelectTexture)( int tmu );
void (*GL_LoadTextureMatrix)( const float *glmatrix );
void (*GL_TexMatrixIdentity)( void );
void (*GL_CleanUpTextureUnits)( int last ); // pass 0 for clear all the texture units
void (*GL_TexGen)( unsigned int coord, unsigned int mode );
void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture
void (*GL_TexCoordArrayMode)( unsigned int texmode );
void* (*GL_GetProcAddress)( const char *name );
void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*GL_Reserved1)( void );
void (*GL_Reserved2)( void );
// Misc renderer functions
void (*GL_DrawParticles)( const struct ref_viewpass_s *rvp, qboolean trans_pass, float frametime );
void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // store skybox into gfx\env folder
int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load
colorVec (*LightVec)( const float *start, const float *end, float *lightspot );
struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e );
const struct ref_overview_s *( *GetOverviewParms )( void );
const char *( *GetFileByIndex )( int fileindex );
void (*R_Reserved1)( void ); // for potential interface expansion without broken compatibility
void (*R_Reserved2)( void );
// static allocations
void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline );
void (*pfnMemFree)( void *mem, const char *filename, const int fileline );
// engine utils (not related with render API but placed here)
char **(*pfnGetFilesList)( const char *pattern, int *numFiles, int gamedironly );
unsigned long (*pfnFileBufferCRC32)( const void *buffer, const int length );
int (*COM_CompareFileTime)( const char *filename1, const char *filename2, int *iCompare );
void (*Host_Error)( const char *error, ... ); // cause Host Error
void* ( *pfnGetModel )( int modelindex );
float (*pfnTime)( void ); // Sys_DoubleTime
void (*Cvar_Set)( char *name, char *value );
void (*S_FadeMusicVolume)( float fadePercent ); // fade background track (0-100 percents)
void (*SetRandomSeed)( long lSeed ); // set custom seed for RANDOM_FLOAT\RANDOM_LONG for predictable random
// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 37
} render_api_t;
// render callbacks
typedef struct render_interface_s
{
int version;
// passed through R_RenderFrame (0 - use engine renderer, 1 - use custom client renderer)
int (*GL_RenderFrame)( const struct ref_viewpass_s *rvp );
// build all the lightmaps on new level or when gamma is changed
void (*GL_BuildLightmaps)( void );
// setup map bounds for ortho-projection when we in dev_overview mode
void (*GL_OrthoBounds)( const float *mins, const float *maxs );
// prepare studio decals for save
int (*R_CreateStudioDecalList)( decallist_t *pList, int count );
// clear decals by engine request (e.g. for demo recording or vid_restart)
void (*R_ClearStudioDecals)( void );
// grab r_speeds message
qboolean (*R_SpeedsMessage)( char *out, size_t size );
// alloc or destroy model custom data
void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer );
// alloc or destroy entity custom data
void (*R_ProcessEntData)( qboolean allocate );
// get visdata for current frame from custom renderer
byte* (*Mod_GetCurrentVis)( void );
// tell the renderer what new map is started
void (*R_NewMap)( void );
// clear the render entities before each frame
void (*R_ClearScene)( void );
} render_interface_t;
#endif//RENDER_API_H

29
common/screenfade.h Normal file
View File

@ -0,0 +1,29 @@
/***
*
* 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 SCREENFADE_H
#define SCREENFADE_H
typedef struct screenfade_s
{
float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out)
float fadeEnd; // When the fading hits maximum
float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT)
float fadeReset; // When to reset to not fading (for fadeout and hold)
byte fader, fadeg, fadeb, fadealpha; // Fade color
int fadeFlags; // Fading flags
} screenfade_t;
#endif//SCREENFADE_H

27
common/studio_event.h Normal file
View File

@ -0,0 +1,27 @@
/***
*
* 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 STUDIO_EVENT_H
#define STUDIO_EVENT_H
typedef struct mstudioevent_s
{
int frame;
int event;
int type;
char options[64];
} mstudioevent_t;
#endif//STUDIO_EVENT_H

62
common/triangleapi.h Normal file
View File

@ -0,0 +1,62 @@
/***
*
* 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 TRIANGLEAPI_H
#define TRIANGLEAPI_H
typedef enum
{
TRI_FRONT = 0,
TRI_NONE = 1,
} TRICULLSTYLE;
#define TRI_API_VERSION 1
#define TRI_TRIANGLES 0
#define TRI_TRIANGLE_FAN 1
#define TRI_QUADS 2
#define TRI_POLYGON 3
#define TRI_LINES 4
#define TRI_TRIANGLE_STRIP 5
#define TRI_QUAD_STRIP 6
#define TRI_POINTS 7 // Xash3D added
typedef struct triangleapi_s
{
int version;
void (*RenderMode)( int mode );
void (*Begin)( int primitiveCode );
void (*End)( void );
void (*Color4f)( float r, float g, float b, float a );
void (*Color4ub)( unsigned char r, unsigned char g, unsigned char b, unsigned char a );
void (*TexCoord2f)( float u, float v );
void (*Vertex3fv)( float *worldPnt );
void (*Vertex3f)( float x, float y, float z );
void (*Brightness)( float brightness );
void (*CullFace)( TRICULLSTYLE style );
int (*SpriteTexture)( struct model_s *pSpriteModel, int frame );
int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped
void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b.
void (*ScreenToWorld)( float *screen, float *world );
void (*GetMatrix)( const int pname, float *matrix );
int (*BoxInPVS)( float *mins, float *maxs );
void (*LightAtPoint)( float *pos, float *value );
void (*Color4fRendermode)( float r, float g, float b, float a, int rendermode );
void (*FogParams)( float flDensity, int iFogSkybox );
} triangleapi_t;
#endif//TRIANGLEAPI_H

39
common/usercmd.h Normal file
View File

@ -0,0 +1,39 @@
/***
*
* 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 USERCMD_H
#define USERCMD_H
typedef struct usercmd_s
{
short lerp_msec; // Interpolation time on client
byte msec; // Duration in ms of command
vec3_t viewangles; // Command view angles
// intended velocities
float forwardmove; // Forward velocity
float sidemove; // Sideways velocity
float upmove; // Upward velocity
byte lightlevel; // Light level at spot where we are standing.
unsigned short buttons; // Attack and move buttons
byte impulse; // Impulse command issued
byte weaponselect; // Current weapon id
// Experimental player impact stuff.
int impact_index;
vec3_t impact_position;
} usercmd_t;
#endif//USERCMD_H

97
common/wadfile.h Normal file
View File

@ -0,0 +1,97 @@
/***
*
* 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 WADFILE_H
#define WADFILE_H
/*
========================================================================
.WAD archive format (WhereAllData - WAD)
List of compressed files, that can be identify only by TYP_*
<format>
header: dwadinfo_t[dwadinfo_t]
file_1: byte[dwadinfo_t[num]->disksize]
file_2: byte[dwadinfo_t[num]->disksize]
file_3: byte[dwadinfo_t[num]->disksize]
...
file_n: byte[dwadinfo_t[num]->disksize]
infotable dlumpinfo_t[dwadinfo_t->numlumps]
========================================================================
*/
#define IDWAD2HEADER (('2'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD2" quake wads
#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads
// dlumpinfo_t->attribs
#define ATTR_NONE 0 // allow to read-write
#define ATTR_READONLY BIT( 0 ) // don't overwrite this lump in anyway
#define ATTR_COMPRESSED BIT( 1 ) // not used for now, just reserved
#define ATTR_HIDDEN BIT( 2 ) // not used for now, just reserved
#define ATTR_SYSTEM BIT( 3 ) // not used for now, just reserved
// dlumpinfo_t->type
#define TYP_ANY -1 // any type can be accepted
#define TYP_NONE 0 // unknown lump type
#define TYP_LABEL 1 // legacy from Doom1. Empty lump - label (like P_START, P_END etc)
#define TYP_PALETTE 64 // quake or half-life palette (768 bytes)
#define TYP_DDSTEX 65 // contain DDS texture
#define TYP_GFXPIC 66 // menu or hud image (not contain mip-levels)
#define TYP_MIPTEX 67 // quake1 and half-life in-game textures with four miplevels
#define TYP_SCRIPT 68 // contain script files
#define TYP_COLORMAP2 69 // old stuff. build palette from LBM file (not used)
#define TYP_QFONT 70 // half-life font (qfont_t)
// dlumpinfo_t->img_type
#define IMG_DIFFUSE 0 // same as default pad1 always equal 0
#define IMG_ALPHAMASK 1 // alpha-channel that stored separate as luminance texture
#define IMG_NORMALMAP 2 // indexed normalmap
#define IMG_GLOSSMAP 3 // luminance or color specularity map
#define IMG_GLOSSPOWER 4 // gloss power map (each value is a specular pow)
#define IMG_HEIGHTMAP 5 // heightmap (for parallax occlusion mapping or source of normalmap)
#define IMG_LUMA 6 // luma or glow texture with self-illuminated parts
#define IMG_DECAL_ALPHA 7 // it's a decal texture (last color in palette is base color, and other colors his graduations)
#define IMG_DECAL_COLOR 8 // decal without alpha-channel uses base, like 127 127 127 as transparent color
/*
========================================================================
.LMP image format (Half-Life gfx.wad lumps)
========================================================================
*/
typedef struct lmp_s
{
unsigned int width;
unsigned int height;
} lmp_t;
/*
========================================================================
.MIP image format (half-Life textures)
========================================================================
*/
typedef struct mip_s
{
char name[16];
unsigned int width;
unsigned int height;
unsigned int offsets[4]; // four mip maps stored
} mip_t;
#endif//WADFILE_H

50
common/weaponinfo.h Normal file
View File

@ -0,0 +1,50 @@
/***
*
* 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 WEAPONINFO_H
#define WEAPONINFO_H
// Info about weapons player might have in his/her possession
typedef struct weapon_data_s
{
int m_iId;
int m_iClip;
float m_flNextPrimaryAttack;
float m_flNextSecondaryAttack;
float m_flTimeWeaponIdle;
int m_fInReload;
int m_fInSpecialReload;
float m_flNextReload;
float m_flPumpTime;
float m_fReloadTime;
float m_fAimedDamage;
float m_fNextAimBonus;
int m_fInZoom;
int m_iWeaponState;
int iuser1;
int iuser2;
int iuser3;
int iuser4;
float fuser1;
float fuser2;
float fuser3;
float fuser4;
} weapon_data_t;
#endif//WEAPONINFO_H

24
common/wrect.h Normal file
View File

@ -0,0 +1,24 @@
/*
wrect.h - rectangle definition
Copyright (C) 2010 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.
*/
#ifndef WRECT_H
#define WRECT_H
typedef struct wrect_s
{
int left, right, top, bottom;
} wrect_t;
#endif//WRECT_H

138
engine/alias.h Normal file
View File

@ -0,0 +1,138 @@
/***
*
* 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
// client-side model flags
#define ALIAS_ROCKET 0x0001 // leave a trail
#define ALIAS_GRENADE 0x0002 // leave a trail
#define ALIAS_GIB 0x0004 // leave a trail
#define ALIAS_ROTATE 0x0008 // rotate (bonus items)
#define ALIAS_TRACER 0x0010 // green split trail
#define ALIAS_ZOMGIB 0x0020 // small blood trail
#define ALIAS_TRACER2 0x0040 // orange split trail + rotate
#define ALIAS_TRACER3 0x0080 // purple trail
// 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;
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
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;
trivertex_t bboxmin; // lightnormal isn't used
trivertex_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

177
engine/anorms.h Normal file
View File

@ -0,0 +1,177 @@
/***
*
* 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.
*
****/
{-0.525731, 0.000000, 0.850651},
{-0.442863, 0.238856, 0.864188},
{-0.295242, 0.000000, 0.955423},
{-0.309017, 0.500000, 0.809017},
{-0.162460, 0.262866, 0.951056},
{0.000000, 0.000000, 1.000000},
{0.000000, 0.850651, 0.525731},
{-0.147621, 0.716567, 0.681718},
{0.147621, 0.716567, 0.681718},
{0.000000, 0.525731, 0.850651},
{0.309017, 0.500000, 0.809017},
{0.525731, 0.000000, 0.850651},
{0.295242, 0.000000, 0.955423},
{0.442863, 0.238856, 0.864188},
{0.162460, 0.262866, 0.951056},
{-0.681718, 0.147621, 0.716567},
{-0.809017, 0.309017, 0.500000},
{-0.587785, 0.425325, 0.688191},
{-0.850651, 0.525731, 0.000000},
{-0.864188, 0.442863, 0.238856},
{-0.716567, 0.681718, 0.147621},
{-0.688191, 0.587785, 0.425325},
{-0.500000, 0.809017, 0.309017},
{-0.238856, 0.864188, 0.442863},
{-0.425325, 0.688191, 0.587785},
{-0.716567, 0.681718, -0.147621},
{-0.500000, 0.809017, -0.309017},
{-0.525731, 0.850651, 0.000000},
{0.000000, 0.850651, -0.525731},
{-0.238856, 0.864188, -0.442863},
{0.000000, 0.955423, -0.295242},
{-0.262866, 0.951056, -0.162460},
{0.000000, 1.000000, 0.000000},
{0.000000, 0.955423, 0.295242},
{-0.262866, 0.951056, 0.162460},
{0.238856, 0.864188, 0.442863},
{0.262866, 0.951056, 0.162460},
{0.500000, 0.809017, 0.309017},
{0.238856, 0.864188, -0.442863},
{0.262866, 0.951056, -0.162460},
{0.500000, 0.809017, -0.309017},
{0.850651, 0.525731, 0.000000},
{0.716567, 0.681718, 0.147621},
{0.716567, 0.681718, -0.147621},
{0.525731, 0.850651, 0.000000},
{0.425325, 0.688191, 0.587785},
{0.864188, 0.442863, 0.238856},
{0.688191, 0.587785, 0.425325},
{0.809017, 0.309017, 0.500000},
{0.681718, 0.147621, 0.716567},
{0.587785, 0.425325, 0.688191},
{0.955423, 0.295242, 0.000000},
{1.000000, 0.000000, 0.000000},
{0.951056, 0.162460, 0.262866},
{0.850651, -0.525731, 0.000000},
{0.955423, -0.295242, 0.000000},
{0.864188, -0.442863, 0.238856},
{0.951056, -0.162460, 0.262866},
{0.809017, -0.309017, 0.500000},
{0.681718, -0.147621, 0.716567},
{0.850651, 0.000000, 0.525731},
{0.864188, 0.442863, -0.238856},
{0.809017, 0.309017, -0.500000},
{0.951056, 0.162460, -0.262866},
{0.525731, 0.000000, -0.850651},
{0.681718, 0.147621, -0.716567},
{0.681718, -0.147621, -0.716567},
{0.850651, 0.000000, -0.525731},
{0.809017, -0.309017, -0.500000},
{0.864188, -0.442863, -0.238856},
{0.951056, -0.162460, -0.262866},
{0.147621, 0.716567, -0.681718},
{0.309017, 0.500000, -0.809017},
{0.425325, 0.688191, -0.587785},
{0.442863, 0.238856, -0.864188},
{0.587785, 0.425325, -0.688191},
{0.688191, 0.587785, -0.425325},
{-0.147621, 0.716567, -0.681718},
{-0.309017, 0.500000, -0.809017},
{0.000000, 0.525731, -0.850651},
{-0.525731, 0.000000, -0.850651},
{-0.442863, 0.238856, -0.864188},
{-0.295242, 0.000000, -0.955423},
{-0.162460, 0.262866, -0.951056},
{0.000000, 0.000000, -1.000000},
{0.295242, 0.000000, -0.955423},
{0.162460, 0.262866, -0.951056},
{-0.442863, -0.238856, -0.864188},
{-0.309017, -0.500000, -0.809017},
{-0.162460, -0.262866, -0.951056},
{0.000000, -0.850651, -0.525731},
{-0.147621, -0.716567, -0.681718},
{0.147621, -0.716567, -0.681718},
{0.000000, -0.525731, -0.850651},
{0.309017, -0.500000, -0.809017},
{0.442863, -0.238856, -0.864188},
{0.162460, -0.262866, -0.951056},
{0.238856, -0.864188, -0.442863},
{0.500000, -0.809017, -0.309017},
{0.425325, -0.688191, -0.587785},
{0.716567, -0.681718, -0.147621},
{0.688191, -0.587785, -0.425325},
{0.587785, -0.425325, -0.688191},
{0.000000, -0.955423, -0.295242},
{0.000000, -1.000000, 0.000000},
{0.262866, -0.951056, -0.162460},
{0.000000, -0.850651, 0.525731},
{0.000000, -0.955423, 0.295242},
{0.238856, -0.864188, 0.442863},
{0.262866, -0.951056, 0.162460},
{0.500000, -0.809017, 0.309017},
{0.716567, -0.681718, 0.147621},
{0.525731, -0.850651, 0.000000},
{-0.238856, -0.864188, -0.442863},
{-0.500000, -0.809017, -0.309017},
{-0.262866, -0.951056, -0.162460},
{-0.850651, -0.525731, 0.000000},
{-0.716567, -0.681718, -0.147621},
{-0.716567, -0.681718, 0.147621},
{-0.525731, -0.850651, 0.000000},
{-0.500000, -0.809017, 0.309017},
{-0.238856, -0.864188, 0.442863},
{-0.262866, -0.951056, 0.162460},
{-0.864188, -0.442863, 0.238856},
{-0.809017, -0.309017, 0.500000},
{-0.688191, -0.587785, 0.425325},
{-0.681718, -0.147621, 0.716567},
{-0.442863, -0.238856, 0.864188},
{-0.587785, -0.425325, 0.688191},
{-0.309017, -0.500000, 0.809017},
{-0.147621, -0.716567, 0.681718},
{-0.425325, -0.688191, 0.587785},
{-0.162460, -0.262866, 0.951056},
{0.442863, -0.238856, 0.864188},
{0.162460, -0.262866, 0.951056},
{0.309017, -0.500000, 0.809017},
{0.147621, -0.716567, 0.681718},
{0.000000, -0.525731, 0.850651},
{0.425325, -0.688191, 0.587785},
{0.587785, -0.425325, 0.688191},
{0.688191, -0.587785, 0.425325},
{-0.955423, 0.295242, 0.000000},
{-0.951056, 0.162460, 0.262866},
{-1.000000, 0.000000, 0.000000},
{-0.850651, 0.000000, 0.525731},
{-0.955423, -0.295242, 0.000000},
{-0.951056, -0.162460, 0.262866},
{-0.864188, 0.442863, -0.238856},
{-0.951056, 0.162460, -0.262866},
{-0.809017, 0.309017, -0.500000},
{-0.864188, -0.442863, -0.238856},
{-0.951056, -0.162460, -0.262866},
{-0.809017, -0.309017, -0.500000},
{-0.681718, 0.147621, -0.716567},
{-0.681718, -0.147621, -0.716567},
{-0.850651, 0.000000, -0.525731},
{-0.688191, 0.587785, -0.425325},
{-0.587785, 0.425325, -0.688191},
{-0.425325, 0.688191, -0.587785},
{-0.425325, -0.688191, -0.587785},
{-0.587785, -0.425325, -0.688191},
{-0.688191, -0.587785, -0.425325},

67
engine/cdll_exp.h Normal file
View File

@ -0,0 +1,67 @@
/*
cdll_exp.h - exports for client
Copyright (C) 2013 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.
*/
#ifndef CDLL_EXP_H
#define CDLL_EXP_H
// NOTE: ordering is important!
typedef struct cldll_func_s
{
int (*pfnInitialize)( cl_enginefunc_t *pEnginefuncs, int iVersion );
void (*pfnInit)( void );
int (*pfnVidInit)( void );
int (*pfnRedraw)( float flTime, int intermission );
int (*pfnUpdateClientData)( client_data_t *cdata, float flTime );
void (*pfnReset)( void );
void (*pfnPlayerMove)( struct playermove_s *ppmove, int server );
void (*pfnPlayerMoveInit)( struct playermove_s *ppmove );
char (*pfnPlayerMoveTexture)( char *name );
void (*IN_ActivateMouse)( void );
void (*IN_DeactivateMouse)( void );
void (*IN_MouseEvent)( int mstate );
void (*IN_ClearStates)( void );
void (*IN_Accumulate)( void );
void (*CL_CreateMove)( float frametime, struct usercmd_s *cmd, int active );
int (*CL_IsThirdPerson)( void );
void (*CL_CameraOffset)( float *ofs ); // unused
void *(*KB_Find)( const char *name );
void (*CAM_Think)( void ); // camera stuff
void (*pfnCalcRefdef)( ref_params_t *pparams );
int (*pfnAddEntity)( int type, cl_entity_t *ent, const char *modelname );
void (*pfnCreateEntities)( void );
void (*pfnDrawNormalTriangles)( void );
void (*pfnDrawTransparentTriangles)( void );
void (*pfnStudioEvent)( const struct mstudioevent_s *event, const cl_entity_t *entity );
void (*pfnPostRunCmd)( struct local_state_s *from, struct local_state_s *to, usercmd_t *cmd, int runfuncs, double time, unsigned int random_seed );
void (*pfnShutdown)( void );
void (*pfnTxferLocalOverrides)( entity_state_t *state, const clientdata_t *client );
void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src );
void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd );
void (*pfnDemo_ReadBuffer)( int size, byte *buffer );
int (*pfnConnectionlessPacket)( const struct netadr_s *net_from, const char *args, char *buffer, int *size );
int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs );
void (*pfnFrame)( double time );
int (*pfnKey_Event)( int eventcode, int keynum, const char *pszCurrentBinding );
void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ));
cl_entity_t *(*pfnGetUserEntity)( int index );
void (*pfnVoiceStatus)( int entindex, qboolean bTalking );
void (*pfnDirectorMessage)( int iSize, void *pbuf );
int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio );
void (*pfnChatInputPosition)( int *x, int *y );
// Xash3D extension
int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback );
void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
} cldll_func_t;
#endif//CDLL_EXP_H

259
engine/cdll_int.h Normal file
View File

@ -0,0 +1,259 @@
/***
*
* 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.
*
****/
//
// cdll_int.h
//
// 4-23-98
// JOHN: client dll interface declarations
//
#ifndef CDLL_INT_H
#define CDLL_INT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "const.h"
// this file is included by both the engine and the client-dll,
// so make sure engine declarations aren't done twice
typedef int HSPRITE; // handle to a graphic
typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf );
#include "wrect.h"
#define SCRINFO_SCREENFLASH 1
#define SCRINFO_STRETCHED 2
typedef struct SCREENINFO_s
{
int iSize;
int iWidth;
int iHeight;
int iFlags;
int iCharHeight;
short charWidths[256];
} SCREENINFO;
typedef struct client_data_s
{
// fields that cannot be modified (ie. have no effect if changed)
vec3_t origin;
// fields that can be changed by the cldll
vec3_t viewangles;
int iWeaponBits;
float fov; // field of view
} client_data_t;
typedef struct client_sprite_s
{
char szName[64];
char szSprite[64];
int hspr;
int iRes;
wrect_t rc;
} client_sprite_t;
typedef struct client_textmessage_s
{
int effect;
byte r1, g1, b1, a1; // 2 colors for effects
byte r2, g2, b2, a2;
float x;
float y;
float fadein;
float fadeout;
float holdtime;
float fxtime;
const char *pName;
const char *pMessage;
} client_textmessage_t;
typedef struct hud_player_info_s
{
char *name;
short ping;
byte thisplayer; // TRUE if this is the calling player
// stuff that's unused at the moment, but should be done
byte spectator;
byte packetloss;
char *model;
short topcolor;
short bottomcolor;
} hud_player_info_t;
typedef struct cl_enginefuncs_s
{
// sprite handlers
HSPRITE (*pfnSPR_Load)( const char *szPicName );
int (*pfnSPR_Frames)( HSPRITE hPic );
int (*pfnSPR_Height)( HSPRITE hPic, int frame );
int (*pfnSPR_Width)( HSPRITE hPic, int frame );
void (*pfnSPR_Set)( HSPRITE hPic, int r, int g, int b );
void (*pfnSPR_Draw)( int frame, int x, int y, const wrect_t *prc );
void (*pfnSPR_DrawHoles)( int frame, int x, int y, const wrect_t *prc );
void (*pfnSPR_DrawAdditive)( int frame, int x, int y, const wrect_t *prc );
void (*pfnSPR_EnableScissor)( int x, int y, int width, int height );
void (*pfnSPR_DisableScissor)( void );
client_sprite_t *(*pfnSPR_GetList)( char *psz, int *piCount );
// screen handlers
void (*pfnFillRGBA)( int x, int y, int width, int height, int r, int g, int b, int a );
int (*pfnGetScreenInfo)( SCREENINFO *pscrinfo );
void (*pfnSetCrosshair)( HSPRITE hspr, wrect_t rc, int r, int g, int b );
// cvar handlers
struct cvar_s *(*pfnRegisterVariable)( char *szName, char *szValue, int flags );
float (*pfnGetCvarFloat)( char *szName );
char* (*pfnGetCvarString)( char *szName );
// command handlers
int (*pfnAddCommand)( char *cmd_name, void (*function)(void) );
int (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn );
int (*pfnServerCmd)( char *szCmdString );
int (*pfnClientCmd)( char *szCmdString );
void (*pfnGetPlayerInfo)( int ent_num, hud_player_info_t *pinfo );
// sound handlers
void (*pfnPlaySoundByName)( char *szSound, float volume );
void (*pfnPlaySoundByIndex)( int iSound, float volume );
// vector helpers
void (*pfnAngleVectors)( const float *vecAngles, float *forward, float *right, float *up );
// text message system
client_textmessage_t *(*pfnTextMessageGet)( const char *pName );
int (*pfnDrawCharacter)( int x, int y, int number, int r, int g, int b );
int (*pfnDrawConsoleString)( int x, int y, char *string );
void (*pfnDrawSetTextColor)( float r, float g, float b );
void (*pfnDrawConsoleStringLen)( const char *string, int *length, int *height );
void (*pfnConsolePrint)( const char *string );
void (*pfnCenterPrint)( const char *string );
// Added for user input processing
int (*GetWindowCenterX)( void );
int (*GetWindowCenterY)( void );
void (*GetViewAngles)( float * );
void (*SetViewAngles)( float * );
int (*GetMaxClients)( void );
void (*Cvar_SetValue)( char *cvar, float value );
int (*Cmd_Argc)( void );
char *(*Cmd_Argv)( int arg );
void (*Con_Printf)( char *fmt, ... );
void (*Con_DPrintf)( char *fmt, ... );
void (*Con_NPrintf)( int pos, char *fmt, ... );
void (*Con_NXPrintf)( struct con_nprint_s *info, char *fmt, ... );
const char* (*PhysInfo_ValueForKey)( const char *key );
const char* (*ServerInfo_ValueForKey)( const char *key );
float (*GetClientMaxspeed)( void );
int (*CheckParm)( char *parm, char **ppnext );
void (*Key_Event)( int key, int down );
void (*GetMousePosition)( int *mx, int *my );
int (*IsNoClipping)( void );
struct cl_entity_s *(*GetLocalPlayer)( void );
struct cl_entity_s *(*GetViewModel)( void );
struct cl_entity_s *(*GetEntityByIndex)( int idx );
float (*GetClientTime)( void );
void (*V_CalcShake)( void );
void (*V_ApplyShake)( float *origin, float *angles, float factor );
int (*PM_PointContents)( float *point, int *truecontents );
int (*PM_WaterEntity)( float *p );
struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehull, int ignore_pe );
struct model_s *(*CL_LoadModel)( const char *modelname, int *index );
int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent );
const struct model_s* (*GetSpritePointer)( HSPRITE hSprite );
void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin );
unsigned short (*pfnPrecacheEvent)( int type, const char* psz );
void (*pfnPlaybackEvent)( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
void (*pfnWeaponAnim)( int iAnim, int body );
float (*pfnRandomFloat)( float flLow, float flHigh );
long (*pfnRandomLong)( long lLow, long lHigh );
void (*pfnHookEvent)( char *name, void ( *pfnEvent )( struct event_args_s *args ));
int (*Con_IsVisible) ();
const char *(*pfnGetGameDirectory)( void );
struct cvar_s *(*pfnGetCvarPointer)( const char *szName );
const char *(*Key_LookupBinding)( const char *pBinding );
const char *(*pfnGetLevelName)( void );
void (*pfnGetScreenFade)( struct screenfade_s *fade );
void (*pfnSetScreenFade)( struct screenfade_s *fade );
void* (*VGui_GetPanel)( );
void (*VGui_ViewportPaintBackground)( int extents[4] );
byte* (*COM_LoadFile)( char *path, int usehunk, int *pLength );
char* (*COM_ParseFile)( char *data, char *token );
void (*COM_FreeFile)( void *buffer );
struct triangleapi_s *pTriAPI;
struct efx_api_s *pEfxAPI;
struct event_api_s *pEventAPI;
struct demo_api_s *pDemoAPI;
struct net_api_s *pNetAPI;
struct IVoiceTweak_s *pVoiceTweak;
// returns 1 if the client is a spectator only (connected to a proxy), 0 otherwise or 2 if in dev_overview mode
int (*IsSpectateOnly)( void );
struct model_s *(*LoadMapSprite)( const char *filename );
// file search functions
void (*COM_AddAppDirectoryToSearchPath)( const char *pszBaseDir, const char *appName );
int (*COM_ExpandFilename)( const char *fileName, char *nameOutBuffer, int nameOutBufferSize );
// User info
// playerNum is in the range (1, MaxClients)
// returns NULL if player doesn't exit
// returns "" if no value is set
const char *( *PlayerInfo_ValueForKey )( int playerNum, const char *key );
void (*PlayerInfo_SetValueForKey )( const char *key, const char *value );
// Gets a unique ID for the specified player. This is the same even if you see the player on a different server.
// iPlayer is an entity index, so client 0 would use iPlayer=1.
// Returns false if there is no player on the server in the specified slot.
qboolean (*GetPlayerUniqueID)(int iPlayer, char playerID[16]);
// TrackerID access
int (*GetTrackerIDForPlayer)(int playerSlot);
int (*GetPlayerForTrackerID)(int trackerID);
// Same as pfnServerCmd, but the message goes in the unreliable stream so it can't clog the net stream
// (but it might not get there).
int ( *pfnServerCmdUnreliable )( char *szCmdString );
void (*pfnGetMousePos)( struct tagPOINT *ppt );
void (*pfnSetMousePos)( int x, int y );
void (*pfnSetMouseEnable)( qboolean fEnable );
} cl_enginefunc_t;
#define CLDLL_INTERFACE_VERSION 7
#ifdef __cplusplus
}
#endif
#endif//CDLL_INT_H

507
engine/client/cl_cmds.c Normal file
View File

@ -0,0 +1,507 @@
/*
cl_cmds.c - client console commnds
Copyright (C) 2007 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 "gl_local.h"
/*
====================
CL_PlayVideo_f
movie <moviename>
====================
*/
void CL_PlayVideo_f( void )
{
string path;
if( Cmd_Argc() != 2 && Cmd_Argc() != 3 )
{
Con_Printf( S_USAGE "movie <moviename> [full]\n" );
return;
}
if( cls.state == ca_active )
{
Con_Printf( "Can't play movie while connected to a server.\nPlease disconnect first.\n" );
return;
}
switch( Cmd_Argc( ))
{
case 2: // simple user version
Q_snprintf( path, sizeof( path ), "media/%s.avi", Cmd_Argv( 1 ));
SCR_PlayCinematic( path );
break;
case 3: // sequenced cinematics used this
SCR_PlayCinematic( Cmd_Argv( 1 ));
break;
}
}
/*
===============
CL_PlayCDTrack_f
Emulate audio-cd system
===============
*/
void CL_PlayCDTrack_f( void )
{
const char *command;
const char *pszTrack;
static int track = 0;
static qboolean paused = false;
static qboolean looped = false;
static qboolean enabled = true;
if( Cmd_Argc() < 2 ) return;
command = Cmd_Argv( 1 );
pszTrack = Cmd_Argv( 2 );
if( !enabled && Q_stricmp( command, "on" ))
return; // CD-player is disabled
if( !Q_stricmp( command, "play" ))
{
if( Q_isdigit( pszTrack ))
{
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
S_StartBackgroundTrack( clgame.cdtracks[track-1], NULL, 0, false );
}
else S_StartBackgroundTrack( pszTrack, NULL, 0, true );
paused = false;
looped = false;
}
else if( !Q_stricmp( command, "loop" ))
{
if( Q_isdigit( pszTrack ))
{
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1], 0, false );
}
else S_StartBackgroundTrack( pszTrack, pszTrack, 0, true );
paused = false;
looped = true;
}
else if( !Q_stricmp( command, "pause" ))
{
S_StreamSetPause( true );
paused = true;
}
else if( !Q_stricmp( command, "resume" ))
{
S_StreamSetPause( false );
paused = false;
}
else if( !Q_stricmp( command, "stop" ))
{
S_StopBackgroundTrack();
paused = false;
looped = false;
track = 0;
}
else if( !Q_stricmp( command, "on" ))
{
enabled = true;
}
else if( !Q_stricmp( command, "off" ))
{
enabled = false;
}
else if( !Q_stricmp( command, "info" ))
{
int i, maxTrack;
for( maxTrack = i = 0; i < MAX_CDTRACKS; i++ )
if( Q_strlen( clgame.cdtracks[i] )) maxTrack++;
Con_Printf( "%u tracks\n", maxTrack );
if( track )
{
if( paused ) Con_Printf( "Paused %s track %u\n", looped ? "looping" : "playing", track );
else Con_Printf( "Currently %s track %u\n", looped ? "looping" : "playing", track );
}
Con_Printf( "Volume is %f\n", Cvar_VariableValue( "MP3Volume" ));
return;
}
else Con_Printf( "%s: unknown command %s\n", Cmd_Argv( 0 ), command );
}
/*
==================
CL_ScreenshotGetName
==================
*/
qboolean CL_ScreenshotGetName( int lastnum, char *filename )
{
int a, b, c, d;
if( lastnum < 0 || lastnum > 9999 )
{
MsgDev( D_ERROR, "unable to write screenshot\n" );
return false;
}
a = lastnum / 1000;
lastnum -= a * 1000;
b = lastnum / 100;
lastnum -= b * 100;
c = lastnum / 10;
lastnum -= c * 10;
d = lastnum;
Q_sprintf( filename, "scrshots/%s_shot%i%i%i%i.bmp", clgame.mapname, a, b, c, d );
return true;
}
/*
==================
CL_SnapshotGetName
==================
*/
qboolean CL_SnapshotGetName( int lastnum, char *filename )
{
int a, b, c, d;
if( lastnum < 0 || lastnum > 9999 )
{
MsgDev( D_ERROR, "unable to write snapshot\n" );
FS_AllowDirectPaths( false );
return false;
}
a = lastnum / 1000;
lastnum -= a * 1000;
b = lastnum / 100;
lastnum -= b * 100;
c = lastnum / 10;
lastnum -= c * 10;
d = lastnum;
Q_sprintf( filename, "../%s_%i%i%i%i.bmp", clgame.mapname, a, b, c, d );
return true;
}
/*
==============================================================================
SCREEN SHOTS
==============================================================================
*/
/*
==================
CL_ScreenShot_f
normal screenshot
==================
*/
void CL_ScreenShot_f( void )
{
int i;
string checkname;
if( CL_IsDevOverviewMode() == 1 )
{
// special case for write overview image and script file
Q_snprintf( cls.shotname, sizeof( cls.shotname ), "overviews/%s.bmp", clgame.mapname );
cls.scrshot_action = scrshot_mapshot; // build new frame for mapshot
}
else
{
// scan for a free filename
for( i = 0; i < 9999; i++ )
{
if( !CL_ScreenshotGetName( i, checkname ))
return; // no namespace
if( !FS_FileExists( checkname, false ))
break;
}
Q_strncpy( cls.shotname, checkname, sizeof( cls.shotname ));
cls.scrshot_action = scrshot_normal; // build new frame for screenshot
}
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
}
/*
==================
CL_SnapShot_f
save screenshots into root dir
==================
*/
void CL_SnapShot_f( void )
{
int i;
string checkname;
if( CL_IsDevOverviewMode() == 1 )
{
// special case for write overview image and script file
Q_snprintf( cls.shotname, sizeof( cls.shotname ), "overviews/%s.bmp", clgame.mapname );
cls.scrshot_action = scrshot_mapshot; // build new frame for mapshot
}
else
{
FS_AllowDirectPaths( true );
// scan for a free filename
for( i = 0; i < 9999; i++ )
{
if( !CL_SnapshotGetName( i, checkname ))
return; // no namespace
if( !FS_FileExists( checkname, false ))
break;
}
FS_AllowDirectPaths( false );
Q_strncpy( cls.shotname, checkname, sizeof( cls.shotname ));
cls.scrshot_action = scrshot_snapshot; // build new frame for screenshot
}
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
}
/*
==================
CL_EnvShot_f
cubemap view
==================
*/
void CL_EnvShot_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "envshot <shotname>\n" );
return;
}
Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_envshot; // build new frame for envshot
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
}
/*
==================
CL_SkyShot_f
skybox view
==================
*/
void CL_SkyShot_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "skyshot <shotname>\n" );
return;
}
Q_sprintf( cls.shotname, "gfx/env/%s", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_skyshot; // build new frame for skyshot
cls.envshot_vieworg = NULL; // no custom view
cls.envshot_viewsize = 0;
}
/*
==================
CL_LevelShot_f
splash logo while map is loading
==================
*/
void CL_LevelShot_f( void )
{
size_t ft1, ft2;
string filename;
if( cls.scrshot_request != scrshot_plaque ) return;
cls.scrshot_request = scrshot_inactive;
// check for exist
if( cls.demoplayback && ( cls.demonum != -1 ))
{
Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", cls.demoname, glState.wideScreen ? "16x9" : "4x3" );
Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", cls.demoname );
// make sure what levelshot is newer than demo
ft1 = FS_FileTime( filename, false );
ft2 = FS_FileTime( cls.shotname, true );
}
else
{
Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" );
// make sure what levelshot is newer than bsp
ft1 = FS_FileTime( cl.worldmodel->name, false );
ft2 = FS_FileTime( cls.shotname, true );
}
// missing levelshot or level never than levelshot
if( ft2 == -1 || ft1 > ft2 )
cls.scrshot_action = scrshot_plaque; // build new frame for levelshot
else cls.scrshot_action = scrshot_inactive; // disable - not needs
}
/*
==================
CL_SaveShot_f
mini-pic in loadgame menu
==================
*/
void CL_SaveShot_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "saveshot <savename>\n" );
return;
}
Q_sprintf( cls.shotname, "%s%s.bmp", DEFAULT_SAVE_DIRECTORY, Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_savegame; // build new frame for saveshot
}
/*
==================
CL_DemoShot_f
mini-pic in playdemo menu
==================
*/
void CL_DemoShot_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "demoshot <demoname>\n" );
return;
}
Q_sprintf( cls.shotname, "demos/%s.bmp", Cmd_Argv( 1 ));
cls.scrshot_action = scrshot_demoshot; // build new frame for demoshot
}
/*
==============
CL_DeleteDemo_f
==============
*/
void CL_DeleteDemo_f( void )
{
if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "killdemo <name>\n" );
return;
}
if( cls.demorecording && !Q_stricmp( cls.demoname, Cmd_Argv( 1 )))
{
Con_Printf( "Can't delete %s - recording\n", Cmd_Argv( 1 ));
return;
}
// delete save and saveshot
FS_Delete( va( "demos/%s.dem", Cmd_Argv( 1 )));
FS_Delete( va( "demos/%s.bmp", Cmd_Argv( 1 )));
}
/*
=================
CL_SetSky_f
Set a specified skybox (only for local clients)
=================
*/
void CL_SetSky_f( void )
{
if( Cmd_Argc() < 2 )
{
Con_Printf( S_USAGE "skyname <skybox>\n" );
return;
}
R_SetupSky( Cmd_Argv( 1 ));
}
/*
================
SCR_TimeRefresh_f
timerefresh [noflip]
================
*/
void SCR_TimeRefresh_f( void )
{
int i;
double start, stop;
double time;
if( cls.state != ca_active )
return;
start = Sys_DoubleTime();
// run without page flipping like GoldSrc
if( Cmd_Argc() == 1 )
{
pglDrawBuffer( GL_FRONT );
for( i = 0; i < 128; i++ )
{
RI.viewangles[1] = i / 128.0 * 360.0f;
R_RenderScene();
}
pglFinish();
R_EndFrame();
}
else
{
for( i = 0; i < 128; i++ )
{
R_BeginFrame( true );
RI.viewangles[1] = i / 128.0 * 360.0f;
R_RenderScene();
R_EndFrame();
}
}
stop = Sys_DoubleTime ();
time = (stop - start);
Con_Printf( "%f seconds (%f fps)\n", time, 128 / time );
}
/*
=============
SCR_Viewpos_f
viewpos (level-designer helper)
=============
*/
void SCR_Viewpos_f( void )
{
Con_Printf( "org ( %g %g %g )\n", RI.vieworg[0], RI.vieworg[1], RI.vieworg[2] );
Con_Printf( "ang ( %g %g %g )\n", RI.viewangles[0], RI.viewangles[1], RI.viewangles[2] );
}

143
engine/client/cl_custom.c Normal file
View File

@ -0,0 +1,143 @@
/*
cl_custom.c - downloading custom resources
Copyright (C) 2018 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 "net_encode.h"
qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
{
char filepath[MAX_QPATH];
switch( pResource->type )
{
case t_sound:
case t_model:
// built-in resources not needs to be downloaded
if( pResource->szFileName[0] == '*' )
return true;
break;
}
// resource was missed on server
if( pResource->nDownloadSize == -1 )
{
ClearBits( pResource->ucFlags, RES_FATALIFMISSING );
return true;
}
if( pResource->type == t_sound )
Q_strncpy( filepath, va( "%s%s", DEFAULT_SOUNDPATH, pResource->szFileName ), sizeof( filepath ));
else Q_strncpy( filepath, pResource->szFileName, sizeof( filepath ));
if( !COM_IsSafeFileToDownload( filepath ))
{
MsgDev( D_REPORT, "refusing to download %s\n", filepath );
return true;
}
if( !cl_allow_download.value )
{
MsgDev( D_REPORT, "Download refused, cl_allow_download is 0\n" );
return true;
}
if( cls.state == ca_active && !cl_download_ingame.value )
{
MsgDev( D_REPORT, "In-game download refused...\n" );
return true;
}
// don't request downloads from local client it's silly
if( Host_IsLocalClient() || FS_FileExists( filepath, false ))
return true;
if( cls.demoplayback )
{
MsgDev( D_WARN, "file %s missing during demo playback.\n", filepath );
return true;
}
MSG_BeginClientCmd( msg, clc_stringcmd );
MSG_WriteString( msg, va( "dlfile %s", filepath ));
host.downloadcount++;
return false;
}
void CL_AddToResourceList( resource_t *pResource, resource_t *pList )
{
if( pResource->pPrev != NULL || pResource->pNext != NULL )
{
MsgDev( D_ERROR, "Resource already linked\n" );
return;
}
if( pList->pPrev == NULL || pList->pNext == NULL )
Host_Error( "Resource list corrupted.\n" );
pResource->pPrev = pList->pPrev;
pResource->pNext = pList;
pList->pPrev->pNext = pResource;
pList->pPrev = pResource;
}
void CL_RemoveFromResourceList( resource_t *pResource )
{
if( pResource->pPrev == NULL || pResource->pNext == NULL )
Host_Error( "mislinked resource in CL_RemoveFromResourceList\n" );
if ( pResource->pNext == pResource || pResource->pPrev == pResource )
Host_Error( "attempt to free last entry in list.\n" );
pResource->pPrev->pNext = pResource->pNext;
pResource->pNext->pPrev = pResource->pPrev;
pResource->pPrev = NULL;
pResource->pNext = NULL;
}
void CL_MoveToOnHandList( resource_t *pResource )
{
if( !pResource )
{
MsgDev( D_REPORT, "Null resource passed to CL_MoveToOnHandList\n" );
return;
}
CL_RemoveFromResourceList( pResource );
CL_AddToResourceList( pResource, &cl.resourcesonhand );
}
void CL_ClearResourceList( resource_t *pList )
{
resource_t *p, *n;
for( p = pList->pNext; p != pList && p; p = n )
{
n = p->pNext;
CL_RemoveFromResourceList( p );
Mem_Free( p );
}
pList->pPrev = pList;
pList->pNext = pList;
}
void CL_ClearResourceLists( void )
{
CL_ClearResourceList( &cl.resourcesneeded );
CL_ClearResourceList( &cl.resourcesonhand );
}

1464
engine/client/cl_demo.c Normal file

File diff suppressed because it is too large Load Diff

505
engine/client/cl_events.c Normal file
View File

@ -0,0 +1,505 @@
/*
cl_events.c - client-side event system implementation
Copyright (C) 2011 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 "event_flags.h"
#include "net_encode.h"
#include "con_nprint.h"
/*
===============
CL_ResetEvent
===============
*/
void CL_ResetEvent( event_info_t *ei )
{
ei->index = 0;
memset( &ei->args, 0, sizeof( ei->args ));
ei->fire_time = 0.0;
ei->flags = 0;
}
/*
=============
CL_CalcPlayerVelocity
compute velocity for a given client
=============
*/
void CL_CalcPlayerVelocity( int idx, vec3_t velocity )
{
clientdata_t *pcd;
vec3_t delta;
double dt;
VectorClear( velocity );
if( idx <= 0 || idx > cl.maxclients )
return;
if( idx == cl.playernum + 1 )
{
pcd = &cl.frames[cl.parsecountmod].clientdata;
VectorCopy( pcd->velocity, velocity );
}
else
{
dt = clgame.entities[idx].curstate.animtime - clgame.entities[idx].prevstate.animtime;
if( dt != 0.0 )
{
VectorSubtract( clgame.entities[idx].curstate.velocity, clgame.entities[idx].prevstate.velocity, delta );
VectorScale( delta, 1.0 / dt, velocity );
}
else
{
VectorCopy( clgame.entities[idx].curstate.velocity, velocity );
}
}
}
/*
=============
CL_DescribeEvent
=============
*/
void CL_DescribeEvent( int slot, int flags, const char *eventname )
{
int idx = (slot & 31);
con_nprint_t info;
if( !eventname || !cl_showevents->value )
return;
// mark reliable as green and unreliable as red
if( FBitSet( flags, FEV_RELIABLE ))
VectorSet( info.color, 0.0f, 1.0f, 0.0f );
else VectorSet( info.color, 1.0f, 0.0f, 0.0f );
info.time_to_live = 0.5f;
info.index = idx;
Con_NXPrintf( &info, "%i %f %s", slot, cl.time, eventname );
}
/*
=============
CL_SetEventIndex
=============
*/
void CL_SetEventIndex( const char *szEvName, int ev_index )
{
cl_user_event_t *ev;
int i;
if( !szEvName || !*szEvName )
return; // ignore blank names
// search event by name to link with
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !Q_stricmp( ev->name, szEvName ))
{
ev->index = ev_index;
return;
}
}
}
/*
=============
CL_EventIndex
=============
*/
word CL_EventIndex( const char *name )
{
int i;
if( !COM_CheckString( name ))
return 0;
for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ )
{
if( !Q_stricmp( cl.event_precache[i], name ))
return i;
}
return 0;
}
/*
=============
CL_RegisterEvent
=============
*/
void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
{
cl_user_event_t *ev;
if( lastnum == MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" );
return;
}
// clear existing or allocate new one
if( !clgame.events[lastnum] )
clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( cl_user_event_t ));
else memset( clgame.events[lastnum], 0, sizeof( cl_user_event_t ));
ev = clgame.events[lastnum];
// NOTE: ev->index will be set later
Q_strncpy( ev->name, szEvName, MAX_QPATH );
ev->func = func;
}
/*
=============
CL_FireEvent
=============
*/
qboolean CL_FireEvent( event_info_t *ei, int slot )
{
cl_user_event_t *ev;
const char *name;
int i, idx;
if( !ei || !ei->index )
return false;
// get the func pointer
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev )
{
idx = bound( 1, ei->index, ( MAX_EVENTS - 1 ));
MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
break;
}
if( ev->index == ei->index )
{
if( ev->func )
{
CL_DescribeEvent( slot, ei->flags, cl.event_precache[ei->index] );
ev->func( &ei->args );
return true;
}
name = cl.event_precache[ei->index];
MsgDev( D_ERROR, "CL_FireEvent: %s not hooked\n", name );
break;
}
}
return false;
}
/*
=============
CL_FireEvents
called right before draw frame
=============
*/
void CL_FireEvents( void )
{
event_state_t *es;
event_info_t *ei;
int i;
es = &cl.events;
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index == 0 )
continue;
// delayed event!
if( ei->fire_time && ( ei->fire_time > cl.time ))
continue;
CL_FireEvent( ei, i );
// zero out the remaining fields
CL_ResetEvent( ei );
}
}
/*
=============
CL_FindEvent
find first empty event
=============
*/
event_info_t *CL_FindEmptyEvent( void )
{
int i;
event_state_t *es;
event_info_t *ei;
es = &cl.events;
// look for first slot where index is != 0
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
continue;
return ei;
}
// no slots available
return NULL;
}
/*
=============
CL_FindEvent
replace only unreliable events
=============
*/
event_info_t *CL_FindUnreliableEvent( void )
{
event_state_t *es;
event_info_t *ei;
int i;
es = &cl.events;
for ( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != 0 )
{
// it's reliable, so skip it
if( FBitSet( ei->flags, FEV_RELIABLE ))
continue;
}
return ei;
}
// this should never happen
return NULL;
}
/*
=============
CL_QueueEvent
=============
*/
void CL_QueueEvent( int flags, int index, float delay, event_args_t *args )
{
event_info_t *ei;
// find a normal slot
ei = CL_FindEmptyEvent();
if( !ei )
{
if( FBitSet( flags, FEV_RELIABLE ))
{
ei = CL_FindUnreliableEvent();
}
if( !ei ) return;
}
ei->index = index;
ei->packet_index = 0;
ei->fire_time = delay ? (cl.time + delay) : 0.0f;
ei->flags = flags;
ei->args = *args;
}
/*
=============
CL_ParseReliableEvent
=============
*/
void CL_ParseReliableEvent( sizebuf_t *msg )
{
int event_index;
event_args_t nullargs, args;
float delay = 0.0f;
memset( &nullargs, 0, sizeof( nullargs ));
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
if( MSG_ReadOneBit( msg ))
delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f);
// reliable events not use delta-compression just null-compression
MSG_ReadDeltaEvent( msg, &nullargs, &args );
if( args.entindex > 0 && args.entindex <= cl.maxclients )
args.angles[PITCH] *= -3.0f;
CL_QueueEvent( FEV_RELIABLE|FEV_SERVER, event_index, delay, &args );
}
/*
=============
CL_ParseEvent
=============
*/
void CL_ParseEvent( sizebuf_t *msg )
{
int event_index;
int i, num_events;
int packet_index;
event_args_t nullargs, args;
entity_state_t *state;
float delay;
memset( &nullargs, 0, sizeof( nullargs ));
memset( &args, 0, sizeof( args ));
num_events = MSG_ReadUBitLong( msg, 5 );
// parse events queue
for( i = 0 ; i < num_events; i++ )
{
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
if( MSG_ReadOneBit( msg ))
packet_index = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
else packet_index = -1;
if( MSG_ReadOneBit( msg ))
{
MSG_ReadDeltaEvent( msg, &nullargs, &args );
}
if( MSG_ReadOneBit( msg ))
delay = (float)MSG_ReadWord( msg ) * (1.0f / 100.0f);
else delay = 0.0f;
if( packet_index != -1 )
{
frame_t *frame = &cl.frames[cl.parsecountmod];
if( packet_index < frame->num_entities )
{
state = &cls.packet_entities[(frame->first_entity+packet_index)%cls.num_client_entities];
args.entindex = state->number;
if( VectorIsNull( args.origin ))
VectorCopy( state->origin, args.origin );
if( VectorIsNull( args.angles ))
VectorCopy( state->angles, args.angles );
COM_NormalizeAngles( args.angles );
if( state->number > 0 && state->number <= cl.maxclients )
{
args.angles[PITCH] *= -3.0f;
CL_CalcPlayerVelocity( state->number, args.velocity );
args.ducking = ( state->usehull == 1 );
}
}
else
{
if( args.entindex != 0 )
{
if( args.entindex > 0 && args.entindex <= cl.maxclients )
args.angles[PITCH] /= -3.0f;
}
else
{
MsgDev( D_WARN, "CL_ParseEvent: Received non-packet entity index 0 for event\n" );
}
}
// Place event on queue
CL_QueueEvent( FEV_SERVER, event_index, delay, &args );
}
}
}
/*
=============
CL_PlaybackEvent
=============
*/
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{
event_args_t args;
if( flags & FEV_SERVER )
{
MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" );
return;
}
// first check event for out of bounds
if( eventindex < 1 || eventindex > MAX_EVENTS )
{
MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
return;
}
// check event for precached
if( !CL_EventIndex( cl.event_precache[eventindex] ))
{
MsgDev( D_ERROR, "CL_PlaybackEvent: event %i was not precached\n", eventindex );
return;
}
flags |= FEV_CLIENT; // it's a client event
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL);
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
memset( &args, 0, sizeof( args ));
VectorCopy( origin, args.origin );
VectorCopy( angles, args.angles );
VectorCopy( cl.simvel, args.velocity );
args.entindex = cl.playernum + 1;
args.ducking = ( cl.local.usehull == 1 );
args.fparam1 = fparam1;
args.fparam2 = fparam2;
args.iparam1 = iparam1;
args.iparam2 = iparam2;
args.bparam1 = bparam1;
args.bparam2 = bparam2;
CL_QueueEvent( flags, eventindex, delay, &args );
}

1326
engine/client/cl_frame.c Normal file

File diff suppressed because it is too large Load Diff

3900
engine/client/cl_game.c Normal file

File diff suppressed because it is too large Load Diff

1064
engine/client/cl_gameui.c Normal file

File diff suppressed because it is too large Load Diff

2834
engine/client/cl_main.c Normal file

File diff suppressed because it is too large Load Diff

683
engine/client/cl_netgraph.c Normal file
View File

@ -0,0 +1,683 @@
/*
cl_netgraph.c - Draw Net statistics (borrowed from Xash3D SDL code)
Copyright (C) 2016 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 "gl_local.h"
#define NET_TIMINGS 1024
#define NET_TIMINGS_MASK (NET_TIMINGS - 1)
#define LATENCY_AVG_FRAC 0.5
#define FRAMERATE_AVG_FRAC 0.5
#define PACKETLOSS_AVG_FRAC 0.5
#define PACKETCHOKE_AVG_FRAC 0.5
#define NETGRAPH_LERP_HEIGHT 24
#define NETGRAPH_NET_COLORS 5
#define NUM_LATENCY_SAMPLES 8
convar_t *net_graph;
convar_t *net_graphpos;
convar_t *net_graphwidth;
convar_t *net_graphheight;
convar_t *net_graphsolid;
convar_t *net_scale;
static struct packet_latency_t
{
int latency;
int choked;
} netstat_packet_latency[NET_TIMINGS];
static struct cmdinfo_t
{
float cmd_lerp;
int size;
qboolean sent;
} netstat_cmdinfo[NET_TIMINGS];
static byte netcolors[NETGRAPH_NET_COLORS+NETGRAPH_LERP_HEIGHT][4] =
{
{ 255, 0, 0, 255 },
{ 0, 0, 255, 255 },
{ 240, 127, 63, 255 },
{ 255, 255, 0, 255 },
{ 63, 255, 63, 150 }
// other will be generated through NetGraph_InitColors()
};
static byte sendcolor[4] = { 88, 29, 130, 255 };
static byte holdcolor[4] = { 255, 0, 0, 200 };
static byte extrap_base_color[4] = { 255, 255, 255, 255 };
static netbandwidthgraph_t netstat_graph[NET_TIMINGS];
static float packet_loss;
static float packet_choke;
static float framerate = 0.0;
static int maxmsgbytes = 0;
/*
==========
NetGraph_DrawRect
NetGraph_FillRGBA shortcut
==========
*/
static void NetGraph_DrawRect( wrect_t *rect, byte colors[4] )
{
pglColor4ubv( colors ); // color for this quad
pglVertex2f( rect->left, rect->top );
pglVertex2f( rect->left + rect->right, rect->top );
pglVertex2f( rect->left + rect->right, rect->top + rect->bottom );
pglVertex2f( rect->left, rect->top + rect->bottom );
}
/*
==========
NetGraph_AtEdge
edge detect
==========
*/
qboolean NetGraph_AtEdge( int x, int width )
{
if( x > 3 )
{
if( x >= width - 4 )
return true;
return false;
}
return true;
}
/*
==========
NetGraph_InitColors
init netgraph colors
==========
*/
void NetGraph_InitColors( void )
{
byte mincolor[2][3];
byte maxcolor[2][3];
float dc[2][3];
int i, hfrac;
float f;
mincolor[0][0] = 63;
mincolor[0][1] = 0;
mincolor[0][2] = 100;
maxcolor[0][0] = 0;
maxcolor[0][1] = 63;
maxcolor[0][2] = 255;
mincolor[1][0] = 255;
mincolor[1][1] = 127;
mincolor[1][2] = 0;
maxcolor[1][0] = 250;
maxcolor[1][1] = 0;
maxcolor[1][2] = 0;
for( i = 0; i < 3; i++ )
{
dc[0][i] = (float)(maxcolor[0][i] - mincolor[0][i]);
dc[1][i] = (float)(maxcolor[1][i] - mincolor[1][i]);
}
hfrac = NETGRAPH_LERP_HEIGHT / 3;
for( i = 0; i < NETGRAPH_LERP_HEIGHT; i++ )
{
if( i < hfrac )
{
f = (float)i / (float)hfrac;
VectorMA( mincolor[0], f, dc[0], netcolors[NETGRAPH_NET_COLORS + i] );
}
else
{
f = (float)(i - hfrac) / (float)(NETGRAPH_LERP_HEIGHT - hfrac );
VectorMA( mincolor[1], f, dc[1], netcolors[NETGRAPH_NET_COLORS + i] );
}
}
}
/*
==========
NetGraph_GetFrameData
get frame data info, like chokes, packet losses, also update graph, packet and cmdinfo
==========
*/
void NetGraph_GetFrameData( float *latency, int *latency_count )
{
int i, choke_count = 0, loss_count = 0;
double newtime = Sys_DoubleTime();
static double nexttime = 0;
float loss, choke;
*latency_count = 0;
*latency = 0.0f;
if( newtime >= nexttime )
{
// soft fading of net peak usage
maxmsgbytes = Q_max( 0, maxmsgbytes - 50 );
nexttime = newtime + 0.05;
}
for( i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ )
{
frame_t *f = cl.frames + ( i & CL_UPDATE_MASK );
struct packet_latency_t *p = netstat_packet_latency + ( i & NET_TIMINGS_MASK );
netbandwidthgraph_t *g = netstat_graph + ( i & NET_TIMINGS_MASK );
p->choked = f->choked;
if( p->choked ) choke_count++;
if( !f->valid )
{
p->latency = 9998; // broken delta
}
else if( f->receivedtime == -1.0 )
{
p->latency = 9999; // dropped
loss_count++;
}
else if( f->receivedtime == -3.0 )
{
p->latency = 9997; // skipped
}
else
{
int frame_latency = Q_min( 1.0f, f->latency );
p->latency = (( frame_latency + 0.1 ) / 1.1 ) * ( net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2 );
if( i > cls.netchan.incoming_sequence - NUM_LATENCY_SAMPLES )
{
(*latency) += 1000.0f * f->latency;
(*latency_count)++;
}
}
memcpy( g, &f->graphdata, sizeof( netbandwidthgraph_t ));
if( g->msgbytes > maxmsgbytes )
maxmsgbytes = g->msgbytes;
}
if( maxmsgbytes > 1000 )
maxmsgbytes = 1000;
for( i = cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.outgoing_sequence; i++ )
{
netstat_cmdinfo[i & NET_TIMINGS_MASK].cmd_lerp = cl.commands[i & CL_UPDATE_MASK].frame_lerp;
netstat_cmdinfo[i & NET_TIMINGS_MASK].sent = cl.commands[i & CL_UPDATE_MASK].heldback ? false : true;
netstat_cmdinfo[i & NET_TIMINGS_MASK].size = cl.commands[i & CL_UPDATE_MASK].sendsize;
}
// packet loss
loss = 100.0 * (float)loss_count / CL_UPDATE_BACKUP;
packet_loss = PACKETLOSS_AVG_FRAC * packet_loss + ( 1.0 - PACKETLOSS_AVG_FRAC ) * loss;
// packet choke
choke = 100.0 * (float)choke_count / CL_UPDATE_BACKUP;
packet_choke = PACKETCHOKE_AVG_FRAC * packet_choke + ( 1.0 - PACKETCHOKE_AVG_FRAC ) * choke;
}
/*
===========
NetGraph_DrawTimes
===========
*/
void NetGraph_DrawTimes( wrect_t rect, int x, int w )
{
int i, j, extrap_point = NETGRAPH_LERP_HEIGHT / 3, a, h;
rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
wrect_t fill;
for( a = 0; a < w; a++ )
{
i = ( cls.netchan.outgoing_sequence - a ) & NET_TIMINGS_MASK;
h = ( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT;
fill.left = x + w - a - 1;
fill.right = fill.bottom = 1;
fill.top = rect.top + rect.bottom - 4;
if( h >= extrap_point )
{
int start = 0;
h -= extrap_point;
fill.top -= extrap_point;
if( !net_graphsolid->value )
{
fill.top -= (h - 1);
start = (h - 1);
}
for( j = start; j < h; j++ )
{
NetGraph_DrawRect( &fill, netcolors[NETGRAPH_NET_COLORS + j + extrap_point] );
fill.top--;
}
}
else
{
int oldh = h;
fill.top -= h;
h = extrap_point - h;
if( !net_graphsolid->value )
h = 1;
for( j = 0; j < h; j++ )
{
NetGraph_DrawRect( &fill, netcolors[NETGRAPH_NET_COLORS + j + oldh] );
fill.top--;
}
}
fill.top = rect.top + rect.bottom - 4 - extrap_point;
if( NetGraph_AtEdge( a, w ))
NetGraph_DrawRect( &fill, extrap_base_color );
fill.top = rect.top + rect.bottom - 4;
if( netstat_cmdinfo[i].sent )
NetGraph_DrawRect( &fill, sendcolor );
else NetGraph_DrawRect( &fill, holdcolor );
}
}
//left = x
//right = width
//top = y
//bottom = height
/*
===========
NetGraph_DrawHatches
===========
*/
void NetGraph_DrawHatches( int x, int y )
{
int ystep = (int)( 10.0f / net_scale->value );
byte colorminor[4] = { 0, 63, 63, 200 };
byte color[4] = { 0, 200, 0, 255 };
wrect_t hatch = { x, 4, y, 1 };
int starty;
ystep = Q_max( ystep, 1 );
for( starty = hatch.top; hatch.top > 0 && ((starty - hatch.top) * net_scale->value < (maxmsgbytes + 50)); hatch.top -= ystep )
{
if(!((int)((starty - hatch.top) * net_scale->value ) % 50 ))
{
NetGraph_DrawRect( &hatch, color );
}
else if( ystep > 5 )
{
NetGraph_DrawRect( &hatch, colorminor );
}
}
}
/*
===========
NetGraph_DrawTextFields
===========
*/
void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int count, float avg, int packet_loss, int packet_choke )
{
static int lastout;
rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
int ptx = Q_max( x + w - NETGRAPH_LERP_HEIGHT - 1, 1 );
int pty = Q_max( rect.top + rect.bottom - NETGRAPH_LERP_HEIGHT - 3, 1 );
int out, i = ( cls.netchan.outgoing_sequence - 1 ) & NET_TIMINGS_MASK;
int j = cls.netchan.incoming_sequence & NET_TIMINGS_MASK;
int last_y = y - net_graphheight->value;
if( count > 0 )
{
avg = avg / (float)( count - ( host.frametime * FRAMERATE_AVG_FRAC ));
if( cl_updaterate->value > 0.0f )
avg -= 1000.0f / cl_updaterate->value;
// can't be below zero
avg = Q_max( 0.0, avg );
}
else avg = 0.0;
// move rolling average
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0 - FRAMERATE_AVG_FRAC ) * framerate;
Con_SetFont( 0 );
if( framerate > 0.0f )
{
y -= net_graphheight->value;
Con_DrawString( x, y, va( "%.1f fps" , 1.0f / framerate ), colors );
if( avg > 1.0f )
Con_DrawString( x + 75, y, va( "%i ms" , (int)avg ), colors );
y += 15;
out = netstat_cmdinfo[i].size;
if( !out ) out = lastout;
else lastout = out;
Con_DrawString( x, y, va( "in : %i %.2f k/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors );
y += 15;
Con_DrawString( x, y, va( "out: %i %.2f k/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
y += 15;
if( net_graph->value > 2 )
{
int loss = (int)(( packet_loss + PACKETLOSS_AVG_FRAC ) - 0.01 );
int choke = (int)(( packet_choke + PACKETCHOKE_AVG_FRAC ) - 0.01 );
Con_DrawString( x, y, va( "loss: %i choke: %i", loss, choke ), colors );
}
}
if( net_graph->value < 3 )
Con_DrawString( ptx, pty, va( "%i/s", (int)cl_cmdrate->value ), colors );
Con_DrawString( ptx, last_y, va( "%i/s" , (int)cl_updaterate->value ), colors );
Con_RestoreFont();
}
/*
===========
NetGraph_DrawDataSegment
===========
*/
int NetGraph_DrawDataSegment( wrect_t *fill, int bytes, byte r, byte g, byte b, byte a )
{
float h = bytes / net_scale->value;
byte colors[4] = { r, g, b, a };
fill->top -= (int)h;
if( net_graphsolid->value )
fill->bottom = (int)h;
else fill->bottom = 1;
if( fill->top > 1 )
{
NetGraph_DrawRect( fill, colors );
return 1;
}
return 0;
}
/*
===========
NetGraph_ColorForHeight
color based on packet latency
===========
*/
void NetGraph_ColorForHeight( struct packet_latency_t *packet, byte color[4], int *ping )
{
switch( packet->latency )
{
case 9999:
memcpy( color, netcolors[0], sizeof( byte ) * 4 ); // dropped
*ping = 0;
break;
case 9998:
memcpy( color, netcolors[1], sizeof( byte ) * 4 ); // invalid
*ping = 0;
break;
case 9997:
memcpy( color, netcolors[2], sizeof( byte ) * 4 ); // skipped
*ping = 0;
break;
default:
*ping = 1;
if( packet->choked )
{
memcpy( color, netcolors[3], sizeof( byte ) * 4 );
}
else
{
memcpy( color, netcolors[4], sizeof( byte ) * 4 );
}
}
}
/*
===========
NetGraph_DrawDataUsage
===========
*/
void NetGraph_DrawDataUsage( int x, int y, int w )
{
int a, i, h, lastvalidh = 0, ping;
int pingheight = net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2;
wrect_t fill = { 0 };
byte color[4];
for( a = 0; a < w; a++ )
{
i = (cls.netchan.incoming_sequence - a) & NET_TIMINGS_MASK;
h = netstat_packet_latency[i].latency;
NetGraph_ColorForHeight( &netstat_packet_latency[i], color, &ping );
if( !ping ) h = lastvalidh;
else lastvalidh = h;
if( h > pingheight )
h = pingheight;
fill.left = x + w - a - 1;
fill.top = y - h;
fill.right = 1;
fill.bottom = ping ? 1: h;
if( !ping )
{
if( fill.bottom > 3 )
{
fill.bottom = 2;
NetGraph_DrawRect( &fill, color );
fill.top += fill.bottom - 2;
NetGraph_DrawRect( &fill, color );
}
else
{
NetGraph_DrawRect( &fill, color );
}
}
else
{
NetGraph_DrawRect( &fill, color );
}
fill.top = y;
fill.bottom = 1;
color[0] = 0;
color[1] = 255;
color[2] = 0;
color[3] = 160;
if( NetGraph_AtEdge( a, w ))
NetGraph_DrawRect( &fill, color );
if( net_graph->value < 2 )
continue;
color[0] = color[1] = color[2] = color[3] = 255;
fill.top = y - net_graphheight->value - 1;
fill.bottom = 1;
if( NetGraph_AtEdge( a, w ))
NetGraph_DrawRect( &fill, color );
fill.top -= 1;
if( netstat_packet_latency[i].latency > 9995 )
continue; // skip invalid
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].client, 255, 0, 0, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].players, 255, 255, 0, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].entities, 255, 0, 255, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].tentities, 0, 0, 255, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].sound, 0, 255, 0, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].event, 0, 255, 255, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].usr, 200, 200, 200, 128 ))
continue;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].voicebytes, 255, 255, 255, 255 ))
continue;
fill.top = y - net_graphheight->value - 1;
fill.bottom = 1;
fill.top -= 2;
if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].msgbytes, 240, 240, 240, 128 ))
continue;
}
if( net_graph->value >= 2 )
NetGraph_DrawHatches( x, y - net_graphheight->value - 1 );
}
/*
===========
NetGraph_GetScreenPos
===========
*/
void NetGraph_GetScreenPos( wrect_t *rect, int *w, int *x, int *y )
{
rect->left = rect->top = 0;
rect->right = glState.width;
rect->bottom = glState.height;
*w = Q_min( NET_TIMINGS, net_graphwidth->value );
if( rect->right < *w + 10 )
*w = rect->right - 10;
// detect x and y position
switch( (int)net_graphpos->value )
{
case 1: // right sided
*x = rect->left + rect->right - 5 - *w;
break;
case 2: // center
*x = rect->left + ( rect->right - 10 - *w ) / 2;
break;
default: // left sided
*x = rect->left + 5;
break;
}
*y = rect->bottom + rect->top - NETGRAPH_LERP_HEIGHT - 5;
}
/*
===========
SCR_DrawNetGraph
===========
*/
void SCR_DrawNetGraph( void )
{
wrect_t rect;
float avg_ping;
int ping_count;
int w, x, y;
if( !host.allow_console )
return;
if( cls.state != ca_active )
return;
if( !net_graph->value )
return;
if( net_scale->value <= 0 )
Cvar_SetValue( "net_scale", 0.1f );
NetGraph_GetScreenPos( &rect, &w, &x, &y );
NetGraph_GetFrameData( &avg_ping, &ping_count );
NetGraph_DrawTextFields( x, y, w, rect, ping_count, avg_ping, packet_loss, packet_choke );
if( net_graph->value < 3 )
{
pglEnable( GL_BLEND );
pglDisable( GL_TEXTURE_2D );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE );
pglBegin( GL_QUADS ); // draw all the fills as a long solid sequence of quads for speedup reasons
// NOTE: fill colors without texture at this point
NetGraph_DrawDataUsage( x, y, w );
NetGraph_DrawTimes( rect, x, w );
pglEnd();
pglColor4ub( 255, 255, 255, 255 );
pglEnable( GL_TEXTURE_2D );
pglDisable( GL_BLEND );
}
}
void CL_InitNetgraph( void )
{
net_graph = Cvar_Get( "net_graph", "0", FCVAR_ARCHIVE, "draw network usage graph" );
net_graphpos = Cvar_Get( "net_graphpos", "1", FCVAR_ARCHIVE, "network usage graph position" );
net_scale = Cvar_Get( "net_scale", "5", FCVAR_ARCHIVE, "network usage graph scale level" );
net_graphwidth = Cvar_Get( "net_graphwidth", "192", FCVAR_ARCHIVE, "network usage graph width" );
net_graphheight = Cvar_Get( "net_graphheight", "64", FCVAR_ARCHIVE, "network usage graph height" );
net_graphsolid = Cvar_Get( "net_graphsolid", "1", FCVAR_ARCHIVE, "fill segments in network usage graph" );
packet_loss = packet_choke = 0.0;
NetGraph_InitColors();
}

2499
engine/client/cl_parse.c Normal file

File diff suppressed because it is too large Load Diff

1410
engine/client/cl_pmove.c Normal file

File diff suppressed because it is too large Load Diff

433
engine/client/cl_remap.c Normal file
View File

@ -0,0 +1,433 @@
/*
gl_remap.c - remap model textures
Copyright (C) 2011 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 "gl_local.h"
#include "studio.h"
/*
====================
CL_GetRemapInfoForEntity
Returns remapinfo slot for specified entity
====================
*/
remap_info_t *CL_GetRemapInfoForEntity( cl_entity_t *e )
{
if( !e ) return NULL;
if( e == &clgame.viewent )
return clgame.remap_info[clgame.maxEntities];
return clgame.remap_info[e->curstate.number];
}
/*
====================
CL_CmpStudioTextures
return true if equal
====================
*/
qboolean CL_CmpStudioTextures( int numtexs, mstudiotexture_t *p1, mstudiotexture_t *p2 )
{
int i;
if( !p1 || !p2 ) return false;
for( i = 0; i < numtexs; i++, p1++, p2++ )
{
if( p1->flags & STUDIO_NF_COLORMAP )
continue; // colormaps always has different indexes
if( p1->index != p2->index )
return false;
}
return true;
}
/*
====================
CL_CreateRawTextureFromPixels
Convert texture_t struct into mstudiotexture_t prototype
====================
*/
byte *CL_CreateRawTextureFromPixels( texture_t *tx, size_t *size, int topcolor, int bottomcolor )
{
static mstudiotexture_t pin;
byte *pal;
Assert( size != NULL );
*size = sizeof( pin ) + (tx->width * tx->height) + 768;
// fill header
if( !pin.name[0] ) Q_strncpy( pin.name, "#raw_remap_image.mdl", sizeof( pin.name ));
pin.flags = STUDIO_NF_COLORMAP; // just in case :-)
pin.index = (int)(tx + 1); // pointer to pixels
pin.width = tx->width;
pin.height = tx->height;
// update palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
Image_PaletteHueReplace( pal, topcolor, tx->anim_min, tx->anim_max, 3 );
Image_PaletteHueReplace( pal, bottomcolor, tx->anim_max + 1, tx->anim_total, 3 );
return (byte *)&pin;
}
/*
====================
CL_DuplicateTexture
Dupliacte texture with remap pixels
====================
*/
void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
texture_t *tx = NULL;
char texname[128];
int i, size, index;
byte paletteBackup[768];
byte *raw, *pal;
// save off the real texture index
index = ptexture->index;
glt = R_GetTexture( index );
Q_snprintf( texname, sizeof( texname ), "#%i_%s", RI.currententity->curstate.number, glt->name + 1 );
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
Assert( tx != NULL );
// backup original palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
memcpy( paletteBackup, pal, 768 );
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR, NULL ); // do copy
// restore original palette
memcpy( pal, paletteBackup, 768 );
}
/*
====================
CL_UpdateStudioTexture
Update texture top and bottom colors
====================
*/
void CL_UpdateStudioTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
gltexture_t *glt;
rgbdata_t *pic;
texture_t *tx = NULL;
char texname[128], name[128], mdlname[128];
int i, size, index;
byte paletteBackup[768];
byte *raw, *pal;
// save off the real texture index
glt = R_GetTexture( ptexture->index );
// build name of original texture
Q_strncpy( mdlname, RI.currentmodel->name, sizeof( mdlname ));
COM_FileBase( ptexture->name, name );
COM_StripExtension( mdlname );
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
index = GL_FindTexture( texname );
if( !index ) return; // couldn't find texture
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
Assert( tx != NULL );
// backup original palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
memcpy( paletteBackup, pal, 768 );
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
pic = FS_LoadImage( glt->name, raw, size );
if( !pic )
{
MsgDev( D_ERROR, "Couldn't update texture %s\n", glt->name );
return;
}
index = GL_LoadTextureInternal( glt->name, pic, 0, true );
FS_FreeImage( pic );
// restore original palette
memcpy( pal, paletteBackup, 768 );
Assert( index == ptexture->index );
}
/*
====================
CL_UpdateAliasTexture
Update texture top and bottom colors
====================
*/
void CL_UpdateAliasTexture( unsigned short *texture, int skinnum, int topcolor, int bottomcolor )
{
char texname[MAX_QPATH];
rgbdata_t skin, *pic;
texture_t *tx;
if( !texture || !RI.currentmodel->textures )
return; // no remapinfo in model
tx = RI.currentmodel->textures[skinnum];
if( !tx ) return; // missing texture ?
if( *texture == 0 )
{
Q_snprintf( texname, sizeof( texname ), "%s:remap%i", RI.currentmodel->name, skinnum );
skin.width = tx->width;
skin.height = tx->height;
skin.depth = skin.numMips = 1;
skin.size = tx->width * tx->height;
skin.type = PF_INDEXED_24;
skin.flags = IMAGE_HAS_COLOR|IMAGE_QUAKEPAL;
skin.encode = DXT_ENCODE_DEFAULT;
skin.buffer = (byte *)(tx + 1);
skin.palette = skin.buffer + skin.size;
pic = FS_CopyImage( &skin ); // because GL_LoadTextureInternal will freed a rgbdata_t at end
*texture = GL_LoadTextureInternal( texname, pic, TF_KEEP_SOURCE, false );
}
// and now we can remap with internal routines
GL_ProcessTexture( *texture, -1.0f, topcolor, bottomcolor );
}
/*
====================
CL_AllocRemapInfo
Allocate new remap info per entity
and make copy of remap textures
====================
*/
void CL_AllocRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
studiohdr_t *phdr;
aliashdr_t *ahdr;
mstudiotexture_t *src, *dst;
int i, size;
if( !RI.currententity ) return;
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
if( !RI.currentmodel || ( RI.currentmodel->type != mod_alias && RI.currentmodel->type != mod_studio ))
{
// entity has changed model by another type, release remap info
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
return; // missed or hide model, ignore it
}
// model doesn't contains remap textures
if( RI.currentmodel->numtextures <= 0 )
{
// entity has changed model with no remap textures
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
return;
}
if( RI.currentmodel->type == mod_studio )
{
phdr = (studiohdr_t *)Mod_StudioExtradata( RI.currentmodel );
if( !phdr ) return; // bad model?
src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
dst = (clgame.remap_info[i] ? clgame.remap_info[i]->ptexture : NULL);
// NOTE: we must copy all the structures 'mstudiotexture_t' for easy access when model is rendering
if( !CL_CmpStudioTextures( phdr->numtextures, src, dst ) || clgame.remap_info[i]->model != RI.currentmodel )
{
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
size = sizeof( remap_info_t ) + ( sizeof( mstudiotexture_t ) * phdr->numtextures );
info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, size );
info->ptexture = (mstudiotexture_t *)(info + 1); // textures are immediately comes after remap_info
}
else
{
// studiomodel is valid, nothing to change
return;
}
info->numtextures = phdr->numtextures;
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
dst = info->ptexture;
// copy unchanged first
memcpy( dst, src, sizeof( mstudiotexture_t ) * phdr->numtextures );
// make local copies for remap textures
for( i = 0; i < info->numtextures; i++ )
{
if( dst[i].flags & STUDIO_NF_COLORMAP )
CL_DuplicateTexture( &dst[i], topcolor, bottomcolor );
}
}
else if( RI.currentmodel->type == mod_alias )
{
ahdr = (aliashdr_t *)Mod_AliasExtradata( RI.currentmodel );
if( !ahdr ) return; // bad model?
// NOTE: we must copy all the structures 'mstudiotexture_t' for easy access when model is rendering
if( !clgame.remap_info[i] || clgame.remap_info[i]->model != RI.currentmodel )
{
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
info = clgame.remap_info[i] = Mem_Alloc( clgame.mempool, sizeof( remap_info_t ));
}
else
{
// aliasmodel is valid, nothing to change
return;
}
info->numtextures = RI.currentmodel->numtextures;
// alias remapping is easy
CL_UpdateRemapInfo( topcolor, bottomcolor );
}
else
{
// only alias & studio models are supposed for remapping
return;
}
info->model = RI.currentmodel;
}
/*
====================
CL_UpdateRemapInfo
Update all remaps per entity
====================
*/
void CL_UpdateRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
int i;
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
info = clgame.remap_info[i];
if( !info ) return; // no remap info
if( info->topcolor == topcolor && info->bottomcolor == bottomcolor )
return; // values is valid
for( i = 0; i < info->numtextures; i++ )
{
if( info->ptexture != NULL )
{
if( FBitSet( info->ptexture[i].flags, STUDIO_NF_COLORMAP ))
CL_UpdateStudioTexture( &info->ptexture[i], topcolor, bottomcolor );
}
else CL_UpdateAliasTexture( &info->textures[i], i, topcolor, bottomcolor );
}
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
}
/*
====================
CL_FreeRemapInfo
Release remap info per entity
====================
*/
void CL_FreeRemapInfo( remap_info_t *info )
{
int i;
Assert( info != NULL );
// release all colormap texture copies
for( i = 0; i < info->numtextures; i++ )
{
if( info->ptexture != NULL )
{
if( FBitSet( info->ptexture[i].flags, STUDIO_NF_COLORMAP ))
GL_FreeTexture( info->ptexture[i].index );
}
if( info->textures[i] != 0 )
GL_FreeTexture( info->textures[i] );
}
Mem_Free( info ); // release struct
}
/*
====================
CL_ClearAllRemaps
Release all remap infos
====================
*/
void CL_ClearAllRemaps( void )
{
int i;
if( clgame.remap_info )
{
for( i = 0; i < clgame.maxRemapInfos; i++ )
{
if( clgame.remap_info[i] )
CL_FreeRemapInfo( clgame.remap_info[i] );
}
Mem_Free( clgame.remap_info );
}
clgame.remap_info = NULL;
}

757
engine/client/cl_scrn.c Normal file
View File

@ -0,0 +1,757 @@
/*
cl_scrn.c - refresh screen
Copyright (C) 2007 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 "gl_local.h"
#include "vgui_draw.h"
#include "qfont.h"
#include "input.h"
convar_t *scr_centertime;
convar_t *scr_loading;
convar_t *scr_download;
convar_t *scr_viewsize;
convar_t *cl_testlights;
convar_t *cl_allow_levelshots;
convar_t *cl_levelshot_name;
convar_t *cl_envshot_size;
convar_t *v_dark;
typedef struct
{
int x1, y1, x2, y2;
} dirty_t;
static dirty_t scr_dirty, scr_old_dirty[2];
static qboolean scr_init = false;
/*
==============
SCR_DrawFPS
==============
*/
void SCR_DrawFPS( int height )
{
float calc;
rgba_t color;
double newtime;
static double nexttime = 0, lasttime = 0;
static double framerate = 0;
static int framecount = 0;
static int minfps = 9999;
static int maxfps = 0;
char fpsstring[64];
int offset;
if( cls.state != ca_active || !cl_showfps->value || cl.background )
return;
switch( cls.scrshot_action )
{
case scrshot_normal:
case scrshot_snapshot:
case scrshot_inactive:
break;
default: return;
}
newtime = Sys_DoubleTime();
if( newtime >= nexttime )
{
framerate = framecount / (newtime - lasttime);
lasttime = newtime;
nexttime = Q_max( nexttime + 1.0, lasttime - 1.0 );
framecount = 0;
}
calc = framerate;
framecount++;
if( calc < 1.0f )
{
Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i spf", (int)(1.0f / calc + 0.5f));
MakeRGBA( color, 255, 0, 0, 255 );
}
else
{
int curfps = (int)(calc + 0.5f);
if( curfps < minfps ) minfps = curfps;
if( curfps > maxfps ) maxfps = curfps;
if( cl_showfps->value == 2 )
Q_snprintf( fpsstring, sizeof( fpsstring ), "fps: ^1%4i min, ^3%4i cur, ^2%4i max", minfps, curfps, maxfps );
else Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i fps", curfps );
MakeRGBA( color, 255, 255, 255, 255 );
}
Con_DrawStringLen( fpsstring, &offset, NULL );
Con_DrawString( glState.width - offset - 4, height, fpsstring, color );
}
/*
==============
SCR_NetSpeeds
same as r_speeds but for network channel
==============
*/
void SCR_NetSpeeds( void )
{
static char msg[MAX_SYSPATH];
int x, y, height;
char *p, *start, *end;
float time = cl.mtime[0];
static int min_svfps = 100;
static int max_svfps = 0;
int cur_svfps = 0;
static int min_clfps = 100;
static int max_clfps = 0;
int cur_clfps = 0;
rgba_t color;
if( !host.allow_console )
return;
if( !net_speeds->value || cls.demoplayback || cls.state != ca_active )
return;
// prevent to get too big values at max
if( cl_serverframetime() > 0.0001f )
{
cur_svfps = Q_rint( 1.0f / cl_serverframetime( ));
if( cur_svfps < min_svfps ) min_svfps = cur_svfps;
if( cur_svfps > max_svfps ) max_svfps = cur_svfps;
}
// prevent to get too big values at max
if( cl_clientframetime() > 0.0001f )
{
cur_clfps = Q_rint( 1.0f / cl_clientframetime( ));
if( cur_clfps < min_clfps ) min_clfps = cur_clfps;
if( cur_clfps > max_clfps ) max_clfps = cur_clfps;
}
Q_snprintf( msg, sizeof( msg ), "sv fps: ^1%4i min, ^3%4i cur, ^2%4i max\ncl fps: ^1%4i min, ^3%4i cur, ^2%4i max\nGame Time: %02d:%02d\nTotal received from server: %s\nTotal sent to server: %s\n",
min_svfps, cur_svfps, max_svfps, min_clfps, cur_clfps, max_clfps, (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_received ), Q_memprint( cls.netchan.total_sended ));
x = glState.width - 320;
y = 384;
Con_DrawStringLen( NULL, NULL, &height );
MakeRGBA( color, 255, 255, 255, 255 );
p = start = msg;
do
{
end = Q_strchr( p, '\n' );
if( end ) msg[end-start] = '\0';
Con_DrawString( x, y, p, color );
y += height;
if( end ) p = end + 1;
else break;
} while( 1 );
}
/*
================
SCR_RSpeeds
================
*/
void SCR_RSpeeds( void )
{
char msg[MAX_SYSPATH];
if( !host.allow_console )
return;
if( R_SpeedsMessage( msg, sizeof( msg )))
{
int x, y, height;
char *p, *start, *end;
rgba_t color;
x = glState.width - 340;
y = 64;
Con_DrawStringLen( NULL, NULL, &height );
MakeRGBA( color, 255, 255, 255, 255 );
p = start = msg;
do
{
end = Q_strchr( p, '\n' );
if( end ) msg[end-start] = '\0';
Con_DrawString( x, y, p, color );
y += height;
if( end ) p = end + 1;
else break;
} while( 1 );
}
}
/*
================
SCR_MakeLevelShot
creates levelshot at next frame
================
*/
void SCR_MakeLevelShot( void )
{
if( cls.scrshot_request != scrshot_plaque )
return;
// make levelshot at nextframe()
Cbuf_AddText( "levelshot\n" );
}
/*
================
SCR_MakeScreenShot
create a requested screenshot type
================
*/
void SCR_MakeScreenShot( void )
{
qboolean iRet = false;
int viewsize;
if( cls.envshot_viewsize > 0 )
viewsize = cls.envshot_viewsize;
else viewsize = cl_envshot_size->value;
switch( cls.scrshot_action )
{
case scrshot_normal:
iRet = VID_ScreenShot( cls.shotname, VID_SCREENSHOT );
break;
case scrshot_snapshot:
iRet = VID_ScreenShot( cls.shotname, VID_SNAPSHOT );
break;
case scrshot_plaque:
iRet = VID_ScreenShot( cls.shotname, VID_LEVELSHOT );
break;
case scrshot_savegame:
case scrshot_demoshot:
iRet = VID_ScreenShot( cls.shotname, VID_MINISHOT );
break;
case scrshot_envshot:
iRet = VID_CubemapShot( cls.shotname, viewsize, cls.envshot_vieworg, false );
break;
case scrshot_skyshot:
iRet = VID_CubemapShot( cls.shotname, viewsize, cls.envshot_vieworg, true );
break;
case scrshot_mapshot:
iRet = VID_ScreenShot( cls.shotname, VID_MAPSHOT );
break;
case scrshot_inactive:
return;
}
// report
if( iRet )
{
// snapshots don't writes message about image
if( cls.scrshot_action != scrshot_snapshot )
MsgDev( D_REPORT, "Write %s\n", cls.shotname );
}
else MsgDev( D_ERROR, "Unable to write %s\n", cls.shotname );
cls.envshot_vieworg = NULL;
cls.scrshot_action = scrshot_inactive;
cls.envshot_disable_vis = false;
cls.envshot_viewsize = 0;
cls.shotname[0] = '\0';
}
/*
================
SCR_DrawPlaque
================
*/
void SCR_DrawPlaque( void )
{
if(( cl_allow_levelshots->value && !cls.changelevel ) || cl.background )
{
int levelshot = GL_LoadTexture( cl_levelshot_name->string, NULL, 0, TF_IMAGE, NULL );
GL_SetRenderMode( kRenderNormal );
R_DrawStretchPic( 0, 0, glState.width, glState.height, 0, 0, 1, 1, levelshot );
if( !cl.background ) CL_DrawHUD( CL_LOADING );
}
}
/*
================
SCR_BeginLoadingPlaque
================
*/
void SCR_BeginLoadingPlaque( qboolean is_background )
{
S_StopAllSounds( true );
cl.audio_prepped = false; // don't play ambients
if( CL_IsInMenu( ) && !cls.changedemo && !is_background )
{
UI_SetActiveMenu( false );
if( cls.state == ca_disconnected )
SCR_UpdateScreen();
}
if( cls.state == ca_disconnected || cls.disable_screen )
return; // already set
if( cls.key_dest == key_console )
return;
if( is_background ) IN_MouseSavePos( );
cls.draw_changelevel = !is_background;
SCR_UpdateScreen();
cls.disable_screen = host.realtime;
cls.disable_servercount = cl.servercount;
cl.background = is_background; // set right state before svc_serverdata is came
// SNDDMA_LockSound();
}
/*
================
SCR_EndLoadingPlaque
================
*/
void SCR_EndLoadingPlaque( void )
{
cls.disable_screen = 0.0f;
Con_ClearNotify();
// SNDDMA_UnlockSound();
}
/*
=================
SCR_AddDirtyPoint
=================
*/
void SCR_AddDirtyPoint( int x, int y )
{
if( x < scr_dirty.x1 ) scr_dirty.x1 = x;
if( x > scr_dirty.x2 ) scr_dirty.x2 = x;
if( y < scr_dirty.y1 ) scr_dirty.y1 = y;
if( y > scr_dirty.y2 ) scr_dirty.y2 = y;
}
/*
================
SCR_DirtyScreen
================
*/
void SCR_DirtyScreen( void )
{
SCR_AddDirtyPoint( 0, 0 );
SCR_AddDirtyPoint( glState.width - 1, glState.height - 1 );
}
/*
================
SCR_TileClear
================
*/
void SCR_TileClear( void )
{
int i, top, bottom, left, right;
dirty_t clear;
if( scr_viewsize->value >= 120 )
return; // full screen rendering
// erase rect will be the union of the past three frames
// so tripple buffering works properly
clear = scr_dirty;
for( i = 0; i < 2; i++ )
{
if( scr_old_dirty[i].x1 < clear.x1 )
clear.x1 = scr_old_dirty[i].x1;
if( scr_old_dirty[i].x2 > clear.x2 )
clear.x2 = scr_old_dirty[i].x2;
if( scr_old_dirty[i].y1 < clear.y1 )
clear.y1 = scr_old_dirty[i].y1;
if( scr_old_dirty[i].y2 > clear.y2 )
clear.y2 = scr_old_dirty[i].y2;
}
scr_old_dirty[1] = scr_old_dirty[0];
scr_old_dirty[0] = scr_dirty;
scr_dirty.x1 = 9999;
scr_dirty.x2 = -9999;
scr_dirty.y1 = 9999;
scr_dirty.y2 = -9999;
if( clear.y2 <= clear.y1 )
return; // nothing disturbed
top = RI.viewport[1];
bottom = top + RI.viewport[3] - 1;
left = RI.viewport[0];
right = left + RI.viewport[2] - 1;
if( clear.y1 < top )
{
// clear above view screen
i = clear.y2 < top-1 ? clear.y2 : top - 1;
R_DrawTileClear( clear.x1, clear.y1, clear.x2 - clear.x1 + 1, i - clear.y1 + 1 );
clear.y1 = top;
}
if( clear.y2 > bottom )
{
// clear below view screen
i = clear.y1 > bottom + 1 ? clear.y1 : bottom + 1;
R_DrawTileClear( clear.x1, i, clear.x2 - clear.x1 + 1, clear.y2 - i + 1 );
clear.y2 = bottom;
}
if( clear.x1 < left )
{
// clear left of view screen
i = clear.x2 < left - 1 ? clear.x2 : left - 1;
R_DrawTileClear( clear.x1, clear.y1, i - clear.x1 + 1, clear.y2 - clear.y1 + 1 );
clear.x1 = left;
}
if( clear.x2 > right )
{
// clear left of view screen
i = clear.x1 > right + 1 ? clear.x1 : right + 1;
R_DrawTileClear( i, clear.y1, clear.x2 - i + 1, clear.y2 - clear.y1 + 1 );
clear.x2 = right;
}
}
/*
==================
SCR_UpdateScreen
This is called every frame, and can also be called explicitly to flush
text to the screen.
==================
*/
void SCR_UpdateScreen( void )
{
if( !V_PreRender( )) return;
switch( cls.state )
{
case ca_disconnected:
Con_RunConsole ();
break;
case ca_connecting:
case ca_connected:
case ca_validate:
SCR_DrawPlaque();
break;
case ca_active:
Con_RunConsole ();
V_RenderView();
break;
case ca_cinematic:
SCR_DrawCinematic();
break;
default:
Host_Error( "SCR_UpdateScreen: bad cls.state\n" );
break;
}
V_PostRender();
}
qboolean SCR_LoadFixedWidthFont( const char *fontname )
{
int i, fontWidth;
if( cls.creditsFont.valid )
return true; // already loaded
if( !FS_FileExists( fontname, false ))
return false;
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE|TF_KEEP_SOURCE, NULL );
R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture );
cls.creditsFont.charHeight = clgame.scrInfo.iCharHeight = fontWidth / 16;
cls.creditsFont.type = FONT_FIXED;
cls.creditsFont.valid = true;
// build fixed rectangles
for( i = 0; i < 256; i++ )
{
cls.creditsFont.fontRc[i].left = (i * (fontWidth / 16)) % fontWidth;
cls.creditsFont.fontRc[i].right = cls.creditsFont.fontRc[i].left + fontWidth / 16;
cls.creditsFont.fontRc[i].top = (i / 16) * (fontWidth / 16);
cls.creditsFont.fontRc[i].bottom = cls.creditsFont.fontRc[i].top + fontWidth / 16;
cls.creditsFont.charWidths[i] = clgame.scrInfo.charWidths[i] = fontWidth / 16;
}
return true;
}
qboolean SCR_LoadVariableWidthFont( const char *fontname )
{
int i, fontWidth;
byte *buffer;
size_t length;
qfont_t *src;
if( cls.creditsFont.valid )
return true; // already loaded
if( !FS_FileExists( fontname, false ))
return false;
cls.creditsFont.hFontTexture = GL_LoadTexture( fontname, NULL, 0, TF_IMAGE, NULL );
R_GetTextureParms( &fontWidth, NULL, cls.creditsFont.hFontTexture );
// half-life font with variable chars witdh
buffer = FS_LoadFile( fontname, &length, false );
// setup creditsfont
if( buffer && length >= sizeof( qfont_t ))
{
src = (qfont_t *)buffer;
cls.creditsFont.charHeight = clgame.scrInfo.iCharHeight = src->rowheight;
cls.creditsFont.type = FONT_VARIABLE;
// build rectangles
for( i = 0; i < 256; i++ )
{
cls.creditsFont.fontRc[i].left = (word)src->fontinfo[i].startoffset % fontWidth;
cls.creditsFont.fontRc[i].right = cls.creditsFont.fontRc[i].left + src->fontinfo[i].charwidth;
cls.creditsFont.fontRc[i].top = (word)src->fontinfo[i].startoffset / fontWidth;
cls.creditsFont.fontRc[i].bottom = cls.creditsFont.fontRc[i].top + src->rowheight;
cls.creditsFont.charWidths[i] = clgame.scrInfo.charWidths[i] = src->fontinfo[i].charwidth;
}
cls.creditsFont.valid = true;
}
if( buffer ) Mem_Free( buffer );
return true;
}
/*
================
SCR_LoadCreditsFont
INTERNAL RESOURCE
================
*/
void SCR_LoadCreditsFont( void )
{
if( !SCR_LoadVariableWidthFont( "gfx.wad/creditsfont.fnt" ))
{
if( !SCR_LoadFixedWidthFont( "gfx/conchars" ))
MsgDev( D_ERROR, "failed to load HUD font\n" );
}
}
/*
================
SCR_InstallParticlePalette
INTERNAL RESOURCE
================
*/
void SCR_InstallParticlePalette( void )
{
rgbdata_t *pic;
int i;
// first check 'palette.lmp' then 'palette.pal'
pic = FS_LoadImage( "gfx/palette.lmp", NULL, 0 );
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 )
{
for( i = 0; i < 256; i++ )
{
clgame.palette[i].r = pic->palette[i*4+0];
clgame.palette[i].g = pic->palette[i*4+1];
clgame.palette[i].b = pic->palette[i*4+2];
}
FS_FreeImage( pic );
}
else
{
for( i = 0; i < 256; i++ )
{
clgame.palette[i].r = i;
clgame.palette[i].g = i;
clgame.palette[i].b = i;
}
MsgDev( D_WARN, "CL_InstallParticlePalette: failed. Force to grayscale\n" );
}
}
/*
================
SCR_RegisterTextures
INTERNAL RESOURCE
================
*/
void SCR_RegisterTextures( void )
{
// register gfx.wad images
if( FS_FileExists( "gfx/paused.lmp", false ))
cls.pauseIcon = GL_LoadTexture( "gfx/paused.lmp", NULL, 0, TF_IMAGE, NULL );
else if( FS_FileExists( "gfx/pause.lmp", false ))
cls.pauseIcon = GL_LoadTexture( "gfx/pause.lmp", NULL, 0, TF_IMAGE, NULL );
if( FS_FileExists( "gfx/lambda.lmp", false ))
{
if( cl_allow_levelshots->value )
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 );
}
else if( FS_FileExists( "gfx/loading.lmp", false ))
{
if( cl_allow_levelshots->value )
cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE|TF_LUMINANCE, NULL );
else cls.loadingBar = GL_LoadTexture( "gfx/loading.lmp", NULL, 0, TF_IMAGE, NULL );
}
cls.tileImage = GL_LoadTexture( "gfx/backtile.lmp", NULL, 0, TF_NOMIPMAP, NULL );
}
/*
=================
SCR_SizeUp_f
Keybinding command
=================
*/
void SCR_SizeUp_f( void )
{
Cvar_SetValue( "viewsize", Q_min( scr_viewsize->value + 10, 120 ));
}
/*
=================
SCR_SizeDown_f
Keybinding command
=================
*/
void SCR_SizeDown_f( void )
{
Cvar_SetValue( "viewsize", Q_max( scr_viewsize->value - 10, 30 ));
}
/*
==================
SCR_VidInit
==================
*/
void SCR_VidInit( void )
{
memset( &clgame.ds, 0, sizeof( clgame.ds )); // reset a draw state
memset( &gameui.ds, 0, sizeof( gameui.ds )); // reset a draw state
memset( &clgame.centerPrint, 0, sizeof( clgame.centerPrint ));
// update screen sizes for menu
gameui.globals->scrWidth = glState.width;
gameui.globals->scrHeight = glState.height;
VGui_Startup ();
CL_ClearSpriteTextures(); // now all hud sprites are invalid
// vid_state has changed
if( gameui.hInstance ) gameui.dllFuncs.pfnVidInit();
if( clgame.hInstance ) clgame.dllFuncs.pfnVidInit();
// restart console size
Con_VidInit ();
}
/*
==================
SCR_Init
==================
*/
void SCR_Init( void )
{
if( scr_init ) return;
MsgDev( D_NOTE, "SCR_Init()\n" );
scr_centertime = Cvar_Get( "scr_centertime", "2.5", 0, "centerprint hold time" );
cl_levelshot_name = Cvar_Get( "cl_levelshot_name", "*black", 0, "contains path to current levelshot" );
cl_allow_levelshots = Cvar_Get( "allow_levelshots", "0", FCVAR_ARCHIVE, "allow engine to use indivdual levelshots instead of 'loading' image" );
scr_loading = Cvar_Get( "scr_loading", "0", 0, "loading bar progress" );
scr_download = Cvar_Get( "scr_download", "-1", 0, "downloading bar progress" );
cl_testlights = Cvar_Get( "cl_testlights", "0", 0, "test dynamic lights" );
cl_envshot_size = Cvar_Get( "cl_envshot_size", "256", FCVAR_ARCHIVE, "envshot size of cube side" );
v_dark = Cvar_Get( "v_dark", "0", 0, "starts level from dark screen" );
scr_viewsize = Cvar_Get( "viewsize", "120", FCVAR_ARCHIVE, "screen size" );
// register our commands
Cmd_AddCommand( "timerefresh", SCR_TimeRefresh_f, "turn quickly and print rendering statistcs" );
Cmd_AddCommand( "skyname", CL_SetSky_f, "set new skybox by basename" );
Cmd_AddCommand( "viewpos", SCR_Viewpos_f, "prints current player origin" );
Cmd_AddCommand( "sizeup", SCR_SizeUp_f, "screen size up to 10 points" );
Cmd_AddCommand( "sizedown", SCR_SizeDown_f, "screen size down to 10 points" );
if( !UI_LoadProgs( ))
{
Con_Printf( S_ERROR "can't initialize gameui.dll\n" ); // there is non fatal for us
host.allow_console = true; // we need console, because menu is missing
}
SCR_LoadCreditsFont ();
SCR_InstallParticlePalette ();
SCR_RegisterTextures ();
SCR_InitCinematic();
CL_InitNetgraph();
SCR_VidInit();
if( host.allow_console && Sys_CheckParm( "-toconsole" ))
Cbuf_AddText( "toggleconsole\n" );
else UI_SetActiveMenu( true );
scr_init = true;
}
void SCR_Shutdown( void )
{
if( !scr_init ) return;
MsgDev( D_NOTE, "SCR_Shutdown()\n" );
Cmd_RemoveCommand( "timerefresh" );
Cmd_RemoveCommand( "skyname" );
Cmd_RemoveCommand( "viewpos" );
UI_SetActiveMenu( false );
UI_UnloadProgs();
scr_init = false;
}

3106
engine/client/cl_tent.c Normal file

File diff suppressed because it is too large Load Diff

120
engine/client/cl_tent.h Normal file
View File

@ -0,0 +1,120 @@
/*
cl_tent.h - efx api set
Copyright (C) 2010 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.
*/
#ifndef CL_TENT_H
#define CL_TENT_H
// EfxAPI
struct particle_s *R_AllocParticle( void (*callback)( struct particle_s*, float ));
void R_Explosion( vec3_t pos, int model, float scale, float framerate, int flags );
void R_ParticleExplosion( const vec3_t org );
void R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength );
void R_Implosion( const vec3_t end, float radius, int count, float life );
void R_Blood( const vec3_t org, const vec3_t dir, int pcolor, int speed );
void R_BloodStream( const vec3_t org, const vec3_t dir, int pcolor, int speed );
void R_BlobExplosion( const vec3_t org );
void R_EntityParticles( cl_entity_t *ent );
void R_FlickerParticles( const vec3_t org );
void R_RunParticleEffect( const vec3_t org, const vec3_t dir, int color, int count );
void R_ParticleBurst( const vec3_t org, int size, int color, float life );
void R_LavaSplash( const vec3_t org );
void R_TeleportSplash( const vec3_t org );
void R_RocketTrail( vec3_t start, vec3_t end, int type );
short R_LookupColor( byte r, byte g, byte b );
void R_GetPackedColor( short *packed, short color );
void R_TracerEffect( const vec3_t start, const vec3_t end );
void R_UserTracerParticle( float *org, float *vel, float life, int colorIndex, float length, byte deathcontext, void (*deathfunc)( struct particle_s* ));
struct particle_s *R_TracerParticles( float *org, float *vel, float life );
void R_ParticleLine( const vec3_t start, const vec3_t end, byte r, byte g, byte b, float life );
void R_ParticleBox( const vec3_t mins, const vec3_t maxs, byte r, byte g, byte b, float life );
void R_ShowLine( const vec3_t start, const vec3_t end );
void R_BulletImpactParticles( const vec3_t pos );
void R_SparkShower( const vec3_t org );
struct tempent_s *CL_TempEntAlloc( const vec3_t org, model_t *pmodel );
struct tempent_s *CL_TempEntAllocHigh( const vec3_t org, model_t *pmodel );
struct tempent_s *CL_TempEntAllocNoModel( const vec3_t org );
struct tempent_s *CL_TempEntAllocCustom( const vec3_t org, model_t *model, int high, void (*callback)( struct tempent_s*, float, float ));
void R_FizzEffect( cl_entity_t *pent, int modelIndex, int density );
void R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIndex, int count, float speed );
void R_BubbleTrail( const vec3_t start, const vec3_t end, float flWaterZ, int modelIndex, int count, float speed );
void R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life );
void R_KillAttachedTents( int client );
void R_RicochetSprite( const vec3_t pos, model_t *pmodel, float duration, float scale );
void R_RocketFlare( const vec3_t pos );
void R_MuzzleFlash( const vec3_t pos, int type );
void R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelIndex2, float size );
void R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float random, float life, int count, int modelIndex, char flags );
struct tempent_s *R_TempModel( const vec3_t pos, const vec3_t dir, const vec3_t angles, float life, int modelIndex, int soundtype );
struct tempent_s *R_TempSprite( vec3_t pos, const vec3_t dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags );
struct tempent_s *R_DefaultSprite( const vec3_t pos, int spriteIndex, float framerate );
void R_Sprite_Explode( struct tempent_s *pTemp, float scale, int flags );
void R_Sprite_Smoke( struct tempent_s *pTemp, float scale );
void R_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int speed, int iRand, int renderMode );
void R_Sprite_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int speed, int iRand );
void R_Sprite_Trail( int type, vec3_t vecStart, vec3_t vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed );
void R_FunnelSprite( const vec3_t pos, int spriteIndex, int flags );
void R_LargeFunnel( const vec3_t pos, int reverse );
void R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax );
void R_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, float speed, int velMin, int velMax );
void R_SparkStreaks( const vec3_t pos, int count, int velocityMin, int velocityMax );
void R_Projectile( const vec3_t origin, const vec3_t velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s*, struct pmtrace_s* ));
void R_TempSphereModel( const vec3_t pos, float speed, float life, int count, int modelIndex );
void R_MultiGunshot( const vec3_t org, const vec3_t dir, const vec3_t noise, int count, int decalCount, int *decalIndices );
void R_FireField( float *org, int radius, int modelIndex, int count, int flags, float life );
void R_PlayerSprites( int client, int modelIndex, int count, int size );
void R_Sprite_WallPuff( struct tempent_s *pTemp, float scale );
void R_DebugParticle( const vec3_t pos, byte r, byte g, byte b );
void R_RicochetSound( const vec3_t pos );
struct dlight_s *CL_AllocDlight( int key );
struct dlight_s *CL_AllocElight( int key );
void CL_UpdateFlashlight( cl_entity_t *pEnt );
void CL_AddEntityEffects( cl_entity_t *ent );
void CL_AddModelEffects( cl_entity_t *ent );
void CL_DecalShoot( int textureIndex, int entityIndex, int modelIndex, float *pos, int flags );
void CL_DecalRemoveAll( int textureIndex );
int CL_DecalIndexFromName( const char *name );
int CL_DecalIndex( int id );
// Beams
struct beam_s *R_BeamLightning( vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed );
struct beam_s *R_BeamEnts( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct beam_s *R_BeamPoints( vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct beam_s *R_BeamCirclePoints( int type, vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct beam_s *R_BeamEntPoint( int startEnt, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct beam_s *R_BeamRing( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct beam_s *R_BeamFollow( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness );
void R_BeamKill( int deadEntity );
// TriAPI
void TriBegin( int mode );
void TriTexCoord2f( float u, float v );
void TriVertex3fv( const float *v );
void TriVertex3f( float x, float y, float z );
int TriBoxInPVS( float *mins, float *maxs );
void TriColor4f( float r, float g, float b, float a );
int TriSpriteTexture( model_t *pSpriteModel, int frame );
void TriColor4fRendermode( float r, float g, float b, float a, int rendermode );
int TriWorldToScreen( float *world, float *screen );
void TriColor4ub( byte r, byte g, byte b, byte a );
void TriBrightness( float brightness );
void TriRenderMode( int mode );
void TriCullFace( int mode );
void TriEnd( void );
extern model_t *cl_sprite_dot;
extern model_t *cl_sprite_shell;
#endif//CL_TENT_H

306
engine/client/cl_video.c Normal file
View File

@ -0,0 +1,306 @@
/*
cl_video.c - avi video player
Copyright (C) 2009 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 "gl_local.h"
/*
=================================================================
AVI PLAYING
=================================================================
*/
static long xres, yres;
static float video_duration;
static float cin_time;
static int cin_frame;
static wavdata_t cin_audio;
static movie_state_t *cin_state;
/*
==================
SCR_NextMovie
Called when a demo or cinematic finishes
If the "nextmovie" cvar is set, that command will be issued
==================
*/
qboolean SCR_NextMovie( void )
{
string str;
if( cls.movienum == -1 )
{
S_StopAllSounds( true );
SCR_StopCinematic();
return false; // don't play movies
}
if( !cls.movies[cls.movienum][0] || cls.movienum == MAX_MOVIES )
{
S_StopAllSounds( true );
SCR_StopCinematic();
cls.movienum = -1;
return false;
}
Q_snprintf( str, MAX_STRING, "movie %s full\n", cls.movies[cls.movienum] );
Cbuf_InsertText( str );
cls.movienum++;
return true;
}
void SCR_CreateStartupVids( void )
{
file_t *f;
f = FS_Open( DEFAULT_VIDEOLIST_PATH, "w", false );
if( !f ) return;
// make standard video playlist: sierra, valve
FS_Print( f, "media/sierra.avi\n" );
FS_Print( f, "media/valve.avi\n" );
FS_Close( f );
}
void SCR_CheckStartupVids( void )
{
int c = 0;
char *afile, *pfile;
string token;
if( Sys_CheckParm( "-nointro" ) || host_developer.value || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
{
// don't run movies where we in developer-mode
cls.movienum = -1;
return;
}
if( !FS_FileExists( DEFAULT_VIDEOLIST_PATH, false ))
SCR_CreateStartupVids();
afile = FS_LoadFile( DEFAULT_VIDEOLIST_PATH, NULL, false );
if( !afile ) return; // something bad happens
pfile = afile;
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
{
Q_strncpy( cls.movies[c], token, sizeof( cls.movies[0] ));
if( ++c > MAX_MOVIES - 1 )
{
Con_Printf( S_WARN "too many movies (%d) specified in %s\n", MAX_MOVIES, DEFAULT_VIDEOLIST_PATH );
break;
}
}
Mem_Free( afile );
// run cinematic
cls.movienum = 0;
SCR_NextMovie ();
Cbuf_Execute();
}
/*
==================
SCR_RunCinematic
==================
*/
void SCR_RunCinematic( void )
{
if( cls.state != ca_cinematic )
return;
if( !AVI_IsActive( cin_state ))
{
SCR_NextMovie( );
return;
}
if( UI_IsVisible( ))
{
// these can happens when user set +menu_ option to cmdline
AVI_CloseVideo( cin_state );
cls.state = ca_disconnected;
Key_SetKeyDest( key_menu );
S_StopStreaming();
cls.movienum = -1;
cin_time = 0.0f;
cls.signon = 0;
return;
}
// advances cinematic time (ignores maxfps and host_framerate settings)
cin_time += host.realframetime;
// stop the video after it finishes
if( cin_time > video_duration + 0.1f )
{
SCR_NextMovie( );
return;
}
// read the next frame
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
}
/*
==================
SCR_DrawCinematic
Returns true if a cinematic is active, meaning the view rendering
should be skipped
==================
*/
qboolean SCR_DrawCinematic( void )
{
static int last_frame = -1;
qboolean redraw = false;
byte *frame = NULL;
if( !glw_state.initialized || cin_time <= 0.0f )
return false;
if( cin_frame != last_frame )
{
frame = AVI_GetVideoFrame( cin_state, cin_frame );
last_frame = cin_frame;
redraw = true;
}
R_DrawStretchRaw( 0, 0, glState.width, glState.height, xres, yres, frame, redraw );
return true;
}
/*
==================
SCR_PlayCinematic
==================
*/
qboolean SCR_PlayCinematic( const char *arg )
{
string path;
const char *fullpath;
fullpath = FS_GetDiskPath( arg, false );
if( FS_FileExists( arg, false ) && !fullpath )
{
MsgDev( D_ERROR, "Couldn't load %s from packfile. Please extract it\n", path );
return false;
}
AVI_OpenVideo( cin_state, fullpath, true, false );
if( !AVI_IsActive( cin_state ))
{
AVI_CloseVideo( cin_state );
return false;
}
if( !( AVI_GetVideoInfo( cin_state, &xres, &yres, &video_duration ))) // couldn't open this at all.
{
AVI_CloseVideo( cin_state );
return false;
}
if( AVI_GetAudioInfo( cin_state, &cin_audio ))
{
// begin streaming
S_StopAllSounds( true );
S_StartStreaming();
}
UI_SetActiveMenu( false );
cls.state = ca_cinematic;
cin_time = 0.0f;
cls.signon = 0;
return true;
}
long SCR_GetAudioChunk( char *rawdata, long length )
{
int r;
r = AVI_GetAudioChunk( cin_state, rawdata, cin_audio.loopStart, length );
cin_audio.loopStart += r; // advance play position
return r;
}
wavdata_t *SCR_GetMovieInfo( void )
{
if( AVI_IsActive( cin_state ))
return &cin_audio;
return NULL;
}
/*
==================
SCR_StopCinematic
==================
*/
void SCR_StopCinematic( void )
{
if( cls.state != ca_cinematic )
return;
AVI_CloseVideo( cin_state );
S_StopStreaming();
cin_time = 0.0f;
cls.state = ca_disconnected;
cls.signon = 0;
UI_SetActiveMenu( true );
}
/*
==================
SCR_InitCinematic
==================
*/
void SCR_InitCinematic( void )
{
AVI_Initailize ();
cin_state = AVI_GetState( CIN_MAIN );
}
/*
==================
SCR_FreeCinematic
==================
*/
void SCR_FreeCinematic( void )
{
movie_state_t *cin_state;
// release videos
cin_state = AVI_GetState( CIN_LOGO );
AVI_CloseVideo( cin_state );
cin_state = AVI_GetState( CIN_MAIN );
AVI_CloseVideo( cin_state );
AVI_Shutdown();
}

396
engine/client/cl_view.c Normal file
View File

@ -0,0 +1,396 @@
/*
cl_view.c - player rendering positioning
Copyright (C) 2009 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 "const.h"
#include "entity_types.h"
#include "gl_local.h"
#include "vgui_draw.h"
/*
===============
V_CalcViewRect
calc frame rectangle (Quake1 style)
===============
*/
void V_CalcViewRect( void )
{
qboolean full = false;
int sb_lines;
float size;
// intermission is always full screen
if( cl.intermission ) size = 120.0f;
else size = scr_viewsize->value;
if( size >= 120.0f )
sb_lines = 0; // no status bar at all
else if( size >= 110.0f )
sb_lines = 24; // no inventory
else sb_lines = 48;
if( scr_viewsize->value >= 100.0 )
{
full = true;
size = 100.0f;
}
else size = scr_viewsize->value;
if( cl.intermission )
{
size = 100.0f;
sb_lines = 0;
full = true;
}
size /= 100.0;
clgame.viewport[2] = glState.width * size;
clgame.viewport[3] = glState.height * size;
if( clgame.viewport[3] > glState.height - sb_lines )
clgame.viewport[3] = glState.height - sb_lines;
if( clgame.viewport[3] > glState.height )
clgame.viewport[3] = glState.height;
clgame.viewport[0] = ( glState.width - clgame.viewport[2] ) / 2;
if( full ) clgame.viewport[1] = 0;
else clgame.viewport[1] = ( glState.height - sb_lines - clgame.viewport[3] ) / 2;
}
/*
===============
V_SetupViewModel
===============
*/
void V_SetupViewModel( void )
{
cl_entity_t *view = &clgame.viewent;
player_info_t *info = &cl.players[cl.playernum];
if( !cl.local.weaponstarttime )
cl.local.weaponstarttime = cl.time;
// setup the viewent variables
view->curstate.colormap = (info->topcolor & 0xFFFF)|((info->bottomcolor << 8) & 0xFFFF);
view->curstate.number = cl.playernum + 1;
view->index = cl.playernum + 1;
view->model = CL_ModelHandle( cl.local.viewmodel );
view->curstate.modelindex = cl.local.viewmodel;
view->curstate.sequence = cl.local.weaponsequence;
view->curstate.rendermode = kRenderNormal;
// alias models has another animation methods
if( view->model && view->model->type == mod_studio )
{
view->curstate.animtime = cl.local.weaponstarttime;
view->curstate.frame = 0.0f;
}
}
/*
===============
V_SetRefParams
===============
*/
void V_SetRefParams( ref_params_t *fd )
{
memset( fd, 0, sizeof( ref_params_t ));
// probably this is not needs
VectorCopy( RI.vieworg, fd->vieworg );
VectorCopy( RI.viewangles, fd->viewangles );
fd->frametime = host.frametime;
fd->time = cl.time;
fd->intermission = cl.intermission;
fd->paused = (cl.paused != 0);
fd->spectator = (cls.spectator != 0);
fd->onground = (cl.local.onground != -1);
fd->waterlevel = cl.local.waterlevel;
VectorCopy( cl.simvel, fd->simvel );
VectorCopy( cl.simorg, fd->simorg );
VectorCopy( cl.viewheight, fd->viewheight );
fd->idealpitch = cl.local.idealpitch;
VectorCopy( cl.viewangles, fd->cl_viewangles );
fd->health = cl.local.health;
VectorCopy( cl.crosshairangle, fd->crosshairangle );
fd->viewsize = scr_viewsize->value;
VectorCopy( cl.punchangle, fd->punchangle );
fd->maxclients = cl.maxclients;
fd->viewentity = cl.viewentity;
fd->playernum = cl.playernum;
fd->max_entities = clgame.maxEntities;
fd->demoplayback = cls.demoplayback;
fd->hardware = 1; // OpenGL
if( cl.first_frame )
{
cl.first_frame = false; // now can be unlocked
fd->smoothing = true; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
}
else fd->smoothing = cl.local.pushmsec; // enable smoothing in multiplayer by server request (AMX uses)
// get pointers to movement vars and user cmd
fd->movevars = &clgame.movevars;
fd->cmd = cl.cmd;
// setup viewport
fd->viewport[0] = clgame.viewport[0];
fd->viewport[1] = clgame.viewport[1];
fd->viewport[2] = clgame.viewport[2];
fd->viewport[3] = clgame.viewport[3];
fd->onlyClientDraw = 0; // reset clientdraw
fd->nextView = 0; // reset nextview
}
/*
===============
V_MergeOverviewRefdef
merge refdef with overview settings
===============
*/
void V_RefApplyOverview( ref_viewpass_t *rvp )
{
ref_overview_t *ov = &clgame.overView;
float aspect;
float size_x, size_y;
vec2_t mins, maxs;
if( !CL_IsDevOverviewMode( ))
return;
// NOTE: Xash3D may use 16:9 or 16:10 aspects
aspect = (float)glState.width / (float)glState.height;
size_x = fabs( 8192.0f / ov->flZoom );
size_y = fabs( 8192.0f / (ov->flZoom * aspect ));
// compute rectangle
ov->xLeft = -(size_x / 2);
ov->xRight = (size_x / 2);
ov->yTop = -(size_y / 2);
ov->yBottom = (size_y / 2);
if( CL_IsDevOverviewMode() == 1 )
{
Con_NPrintf( 0, " Overview: Zoom %.2f, Map Origin (%.2f, %.2f, %.2f), Z Min %.2f, Z Max %.2f, Rotated %i\n",
ov->flZoom, ov->origin[0], ov->origin[1], ov->origin[2], ov->zNear, ov->zFar, ov->rotated );
}
VectorCopy( ov->origin, rvp->vieworigin );
rvp->vieworigin[2] = ov->zFar + ov->zNear;
Vector2Copy( rvp->vieworigin, mins );
Vector2Copy( rvp->vieworigin, maxs );
mins[!ov->rotated] += ov->xLeft;
maxs[!ov->rotated] += ov->xRight;
mins[ov->rotated] += ov->yTop;
maxs[ov->rotated] += ov->yBottom;
rvp->viewangles[0] = 90.0f;
rvp->viewangles[1] = 90.0f;
rvp->viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
SetBits( rvp->flags, RF_DRAW_OVERVIEW );
Mod_SetOrthoBounds( mins, maxs );
}
/*
=============
V_GetRefParams
=============
*/
void V_GetRefParams( ref_params_t *fd, ref_viewpass_t *rvp )
{
// part1: deniable updates
VectorCopy( fd->simvel, cl.simvel );
VectorCopy( fd->simorg, cl.simorg );
VectorCopy( fd->punchangle, cl.punchangle );
VectorCopy( fd->viewheight, cl.viewheight );
// part2: really used updates
VectorCopy( fd->crosshairangle, cl.crosshairangle );
VectorCopy( fd->cl_viewangles, cl.viewangles );
// setup ref_viewpass
rvp->viewport[0] = fd->viewport[0];
rvp->viewport[1] = fd->viewport[1];
rvp->viewport[2] = fd->viewport[2];
rvp->viewport[3] = fd->viewport[3];
VectorCopy( fd->vieworg, rvp->vieworigin );
VectorCopy( fd->viewangles, rvp->viewangles );
rvp->viewentity = fd->viewentity;
// calc FOV
rvp->fov_x = bound( 10.0f, cl.local.scr_fov, 150.0f ); // this is a final fov value
// first we need to compute FOV and other things that needs for frustum properly work
rvp->fov_y = V_CalcFov( &rvp->fov_x, clgame.viewport[2], clgame.viewport[3] );
// adjust FOV for widescreen
if( glState.wideScreen && r_adjust_fov->value )
V_AdjustFov( &rvp->fov_x, &rvp->fov_y, clgame.viewport[2], clgame.viewport[3], false );
rvp->flags = 0;
if( fd->onlyClientDraw )
SetBits( rvp->flags, RF_ONLY_CLIENTDRAW );
SetBits( rvp->flags, RF_DRAW_WORLD );
}
/*
==================
V_PreRender
==================
*/
qboolean V_PreRender( void )
{
// too early
if( !glw_state.initialized )
return false;
if( host.status == HOST_NOFOCUS )
return false;
if( host.status == HOST_SLEEP )
return false;
// if the screen is disabled (loading plaque is up)
if( cls.disable_screen )
{
if(( host.realtime - cls.disable_screen ) > cl_timeout->value )
{
MsgDev( D_ERROR, "V_PreRender: loading plaque timed out\n" );
cls.disable_screen = 0.0f;
}
return false;
}
R_BeginFrame( !cl.paused );
return true;
}
//============================================================================
/*
==================
V_RenderView
==================
*/
void V_RenderView( void )
{
ref_params_t rp;
ref_viewpass_t rvp;
int viewnum = 0;
if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
return; // still loading
V_CalcViewRect (); // compute viewport rectangle
V_SetRefParams( &rp );
V_SetupViewModel ();
R_Set2DMode( false );
SCR_DirtyScreen();
GL_BackendStartFrame ();
do
{
clgame.dllFuncs.pfnCalcRefdef( &rp );
V_GetRefParams( &rp, &rvp );
V_RefApplyOverview( &rvp );
if( viewnum == 0 && FBitSet( rvp.flags, RF_ONLY_CLIENTDRAW ))
{
pglClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
pglClear( GL_COLOR_BUFFER_BIT );
}
R_RenderFrame( &rvp );
viewnum++;
} while( rp.nextView );
// draw debug triangles on a server
SV_DrawDebugTriangles ();
GL_BackendEndFrame ();
}
/*
==================
V_PostRender
==================
*/
void V_PostRender( void )
{
static double oldtime;
qboolean draw_2d = false;
R_AllowFog( false );
R_Set2DMode( true );
if( cls.state == ca_active && cls.signon == SIGNONS && cls.scrshot_action != scrshot_mapshot )
{
SCR_TileClear();
CL_DrawHUD( CL_ACTIVE );
VGui_Paint( true );
}
switch( cls.scrshot_action )
{
case scrshot_inactive:
case scrshot_normal:
case scrshot_snapshot:
draw_2d = true;
break;
}
if( draw_2d )
{
SCR_RSpeeds();
SCR_NetSpeeds();
SCR_DrawNetGraph();
SV_DrawOrthoTriangles();
CL_DrawDemoRecording();
CL_DrawHUD( CL_CHANGELEVEL );
R_ShowTextures();
Con_DrawConsole();
UI_UpdateMenu( host.realtime );
Con_DrawVersion();
Con_DrawDebug(); // must be last
S_ExtraUpdate();
}
SCR_MakeScreenShot();
R_AllowFog( true );
R_EndFrame();
}

1050
engine/client/client.h Normal file

File diff suppressed because it is too large Load Diff

1497
engine/client/gl_alias.c Normal file

File diff suppressed because it is too large Load Diff

721
engine/client/gl_backend.c Normal file
View File

@ -0,0 +1,721 @@
/*
gl_backend.c - rendering backend
Copyright (C) 2010 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 "gl_local.h"
#include "mathlib.h"
char r_speeds_msg[MAX_SYSPATH];
ref_speeds_t r_stats; // r_speeds counters
/*
===============
R_SpeedsMessage
===============
*/
qboolean R_SpeedsMessage( char *out, size_t size )
{
if( clgame.drawFuncs.R_SpeedsMessage != NULL )
{
if( clgame.drawFuncs.R_SpeedsMessage( out, size ))
return true;
// otherwise pass to default handler
}
if( r_speeds->value <= 0 ) return false;
if( !out || !size ) return false;
Q_strncpy( out, r_speeds_msg, size );
return true;
}
/*
==============
GL_BackendStartFrame
==============
*/
void GL_BackendStartFrame( void )
{
r_speeds_msg[0] = '\0';
}
/*
==============
GL_BackendEndFrame
==============
*/
void GL_BackendEndFrame( void )
{
if( r_speeds->value <= 0 || !RI.drawWorld )
return;
switch( (int)r_speeds->value )
{
case 1:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i wpoly, %3i apoly\n%3i epoly, %3i spoly",
r_stats.c_world_polys, r_stats.c_alias_polys, r_stats.c_studio_polys, r_stats.c_sprite_polys );
break;
case 2:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "visible leafs:\n%3i leafs\ncurrent leaf %3i",
r_stats.c_world_leafs, Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ) - cl.worldmodel->leafs );
break;
case 3:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i alias models drawn\n%3i studio models drawn\n%3i sprites drawn",
r_stats.c_alias_models_drawn, r_stats.c_studio_models_drawn, r_stats.c_sprite_models_drawn );
break;
case 4:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i static entities\n%3i normal entities\n%3i server entities",
r_numStatics, r_numEntities - r_numStatics, pfnNumberOfEntities( ));
break;
case 5:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i tempents\n%3i viewbeams\n%3i particles",
r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count );
break;
}
memset( &r_stats, 0, sizeof( r_stats ));
}
/*
=================
GL_LoadTexMatrix
=================
*/
void GL_LoadTexMatrix( const matrix4x4 m )
{
pglMatrixMode( GL_TEXTURE );
GL_LoadMatrix( m );
glState.texIdentityMatrix[glState.activeTMU] = false;
}
/*
=================
GL_LoadTexMatrixExt
=================
*/
void GL_LoadTexMatrixExt( const float *glmatrix )
{
Assert( glmatrix != NULL );
pglMatrixMode( GL_TEXTURE );
pglLoadMatrixf( glmatrix );
glState.texIdentityMatrix[glState.activeTMU] = false;
}
/*
=================
GL_LoadMatrix
=================
*/
void GL_LoadMatrix( const matrix4x4 source )
{
GLfloat dest[16];
Matrix4x4_ToArrayFloatGL( source, dest );
pglLoadMatrixf( dest );
}
/*
=================
GL_LoadIdentityTexMatrix
=================
*/
void GL_LoadIdentityTexMatrix( void )
{
if( glState.texIdentityMatrix[glState.activeTMU] )
return;
pglMatrixMode( GL_TEXTURE );
pglLoadIdentity();
glState.texIdentityMatrix[glState.activeTMU] = true;
}
/*
=================
GL_SelectTexture
=================
*/
void GL_SelectTexture( GLint tmu )
{
if( !GL_Support( GL_ARB_MULTITEXTURE ))
return;
// don't allow negative texture units
if( tmu < 0 ) return;
if( tmu >= GL_MaxTextureUnits( ))
{
MsgDev( D_ERROR, "GL_SelectTexture: bad tmu state %i\n", tmu );
return;
}
if( glState.activeTMU == tmu )
return;
glState.activeTMU = tmu;
if( pglActiveTextureARB )
{
pglActiveTextureARB( tmu + GL_TEXTURE0_ARB );
if( tmu < glConfig.max_texture_coords )
pglClientActiveTextureARB( tmu + GL_TEXTURE0_ARB );
}
}
/*
==============
GL_DisableAllTexGens
==============
*/
void GL_DisableAllTexGens( void )
{
GL_TexGen( GL_S, 0 );
GL_TexGen( GL_T, 0 );
GL_TexGen( GL_R, 0 );
GL_TexGen( GL_Q, 0 );
}
/*
==============
GL_CleanUpTextureUnits
==============
*/
void GL_CleanUpTextureUnits( int last )
{
int i;
for( i = glState.activeTMU; i > (last - 1); i-- )
{
// disable upper units
if( glState.currentTextureTargets[i] != GL_NONE )
{
pglDisable( glState.currentTextureTargets[i] );
glState.currentTextureTargets[i] = GL_NONE;
glState.currentTextures[i] = -1; // unbind texture
}
GL_SetTexCoordArrayMode( GL_NONE );
GL_LoadIdentityTexMatrix();
GL_DisableAllTexGens();
GL_SelectTexture( i - 1 );
}
}
/*
==============
GL_CleanupAllTextureUnits
==============
*/
void GL_CleanupAllTextureUnits( void )
{
// force to cleanup all the units
GL_SelectTexture( GL_MaxTextureUnits() - 1 );
GL_CleanUpTextureUnits( 0 );
}
/*
=================
GL_MultiTexCoord2f
=================
*/
void GL_MultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t )
{
if( !GL_Support( GL_ARB_MULTITEXTURE ))
return;
if( pglMultiTexCoord2f != NULL )
pglMultiTexCoord2f( texture + GL_TEXTURE0_ARB, s, t );
}
/*
=================
GL_TextureTarget
=================
*/
void GL_TextureTarget( uint target )
{
if( glState.activeTMU < 0 || glState.activeTMU >= GL_MaxTextureUnits( ))
{
MsgDev( D_ERROR, "GL_TextureTarget: bad tmu state %i\n", glState.activeTMU );
return;
}
if( glState.currentTextureTargets[glState.activeTMU] != target )
{
if( glState.currentTextureTargets[glState.activeTMU] != GL_NONE )
pglDisable( glState.currentTextureTargets[glState.activeTMU] );
glState.currentTextureTargets[glState.activeTMU] = target;
if( target != GL_NONE )
pglEnable( glState.currentTextureTargets[glState.activeTMU] );
}
}
/*
=================
GL_TexGen
=================
*/
void GL_TexGen( GLenum coord, GLenum mode )
{
int tmu = min( glConfig.max_texture_coords, glState.activeTMU );
int bit, gen;
switch( coord )
{
case GL_S:
bit = 1;
gen = GL_TEXTURE_GEN_S;
break;
case GL_T:
bit = 2;
gen = GL_TEXTURE_GEN_T;
break;
case GL_R:
bit = 4;
gen = GL_TEXTURE_GEN_R;
break;
case GL_Q:
bit = 8;
gen = GL_TEXTURE_GEN_Q;
break;
default: return;
}
if( mode )
{
if( !( glState.genSTEnabled[tmu] & bit ))
{
pglEnable( gen );
glState.genSTEnabled[tmu] |= bit;
}
pglTexGeni( coord, GL_TEXTURE_GEN_MODE, mode );
}
else
{
if( glState.genSTEnabled[tmu] & bit )
{
pglDisable( gen );
glState.genSTEnabled[tmu] &= ~bit;
}
}
}
/*
=================
GL_SetTexCoordArrayMode
=================
*/
void GL_SetTexCoordArrayMode( GLenum mode )
{
int tmu = min( glConfig.max_texture_coords, glState.activeTMU );
int bit, cmode = glState.texCoordArrayMode[tmu];
if( mode == GL_TEXTURE_COORD_ARRAY )
bit = 1;
else if( mode == GL_TEXTURE_CUBE_MAP_ARB )
bit = 2;
else bit = 0;
if( cmode != bit )
{
if( cmode == 1 ) pglDisableClientState( GL_TEXTURE_COORD_ARRAY );
else if( cmode == 2 ) pglDisable( GL_TEXTURE_CUBE_MAP_ARB );
if( bit == 1 ) pglEnableClientState( GL_TEXTURE_COORD_ARRAY );
else if( bit == 2 ) pglEnable( GL_TEXTURE_CUBE_MAP_ARB );
glState.texCoordArrayMode[tmu] = bit;
}
}
/*
=================
GL_Cull
=================
*/
void GL_Cull( GLenum cull )
{
if( !cull )
{
pglDisable( GL_CULL_FACE );
glState.faceCull = 0;
return;
}
pglEnable( GL_CULL_FACE );
pglCullFace( cull );
glState.faceCull = cull;
}
void GL_SetRenderMode( int mode )
{
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
switch( mode )
{
case kRenderNormal:
default:
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
break;
case kRenderTransColor:
case kRenderTransTexture:
pglEnable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
break;
case kRenderTransAlpha:
pglDisable( GL_BLEND );
pglEnable( GL_ALPHA_TEST );
break;
case kRenderGlow:
case kRenderTransAdd:
pglEnable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE );
break;
}
}
/*
==============================================================================
SCREEN SHOTS
==============================================================================
*/
// used for 'env' and 'sky' shots
typedef struct envmap_s
{
vec3_t angles;
int flags;
} envmap_t;
const envmap_t r_skyBoxInfo[6] =
{
{{ 0, 270, 180}, IMAGE_FLIP_X },
{{ 0, 90, 180}, IMAGE_FLIP_X },
{{ -90, 0, 180}, IMAGE_FLIP_X },
{{ 90, 0, 180}, IMAGE_FLIP_X },
{{ 0, 0, 180}, IMAGE_FLIP_X },
{{ 0, 180, 180}, IMAGE_FLIP_X },
};
const envmap_t r_envMapInfo[6] =
{
{{ 0, 0, 90}, 0 },
{{ 0, 180, -90}, 0 },
{{ 0, 90, 0}, 0 },
{{ 0, 270, 180}, 0 },
{{-90, 180, -90}, 0 },
{{ 90, 0, 90}, 0 }
};
/*
===============
VID_WriteOverviewScript
Create overview script file
===============
*/
void VID_WriteOverviewScript( void )
{
ref_overview_t *ov = &clgame.overView;
string filename;
file_t *f;
Q_snprintf( filename, sizeof( filename ), "overviews/%s.txt", clgame.mapname );
f = FS_Open( filename, "w", false );
if( !f ) return;
FS_Printf( f, "// overview description file for %s.bsp\n\n", clgame.mapname );
FS_Print( f, "global\n{\n" );
FS_Printf( f, "\tZOOM\t%.2f\n", ov->flZoom );
FS_Printf( f, "\tORIGIN\t%.2f\t%.2f\t%.2f\n", ov->origin[0], ov->origin[1], ov->origin[2] );
FS_Printf( f, "\tROTATED\t%i\n", ov->rotated ? 1 : 0 );
FS_Print( f, "}\n\nlayer\n{\n" );
FS_Printf( f, "\tIMAGE\t\"overviews/%s.bmp\"\n", clgame.mapname );
FS_Printf( f, "\tHEIGHT\t%.2f\n", ov->zFar ); // ???
FS_Print( f, "}\n" );
FS_Close( f );
}
qboolean VID_ScreenShot( const char *filename, int shot_type )
{
rgbdata_t *r_shot;
uint flags = IMAGE_FLIP_Y;
int width = 0, height = 0;
qboolean result;
r_shot = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
r_shot->width = (glState.width + 3) & ~3;
r_shot->height = (glState.height + 3) & ~3;
r_shot->flags = IMAGE_HAS_COLOR;
r_shot->type = PF_RGB_24;
r_shot->size = r_shot->width * r_shot->height * PFDesc[r_shot->type].bpp;
r_shot->palette = NULL;
r_shot->buffer = Mem_Alloc( r_temppool, r_shot->size );
// get screen frame
pglReadPixels( 0, 0, r_shot->width, r_shot->height, GL_RGB, GL_UNSIGNED_BYTE, r_shot->buffer );
switch( shot_type )
{
case VID_SCREENSHOT:
break;
case VID_SNAPSHOT:
FS_AllowDirectPaths( true );
break;
case VID_LEVELSHOT:
flags |= IMAGE_RESAMPLE;
if( glState.wideScreen )
{
height = 480;
width = 800;
}
else
{
height = 480;
width = 640;
}
break;
case VID_MINISHOT:
flags |= IMAGE_RESAMPLE;
height = 200;
width = 320;
break;
case VID_MAPSHOT:
VID_WriteOverviewScript(); // store overview script too
flags |= IMAGE_RESAMPLE|IMAGE_QUANTIZE; // GoldSrc request overviews in 8-bit format
height = 768;
width = 1024;
break;
}
Image_Process( &r_shot, width, height, flags, NULL );
// write image
result = FS_SaveImage( filename, r_shot );
host.write_to_clipboard = false; // disable write to clipboard
FS_AllowDirectPaths( false ); // always reset after store screenshot
FS_FreeImage( r_shot );
return result;
}
/*
=================
VID_CubemapShot
=================
*/
qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot )
{
rgbdata_t *r_shot, *r_side;
byte *temp = NULL;
byte *buffer = NULL;
string basename;
int i = 1, flags, result;
if( !RI.drawWorld || !cl.worldmodel )
return false;
// make sure the specified size is valid
while( i < size ) i<<=1;
if( i != size ) return false;
if( size > glState.width || size > glState.height )
return false;
// setup refdef
RI.params |= RP_ENVVIEW; // do not render non-bmodel entities
// alloc space
temp = Mem_Alloc( r_temppool, size * size * 3 );
buffer = Mem_Alloc( r_temppool, size * size * 3 * 6 );
r_shot = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
r_side = Mem_Alloc( r_temppool, sizeof( rgbdata_t ));
// use client vieworg
if( !vieworg ) vieworg = RI.vieworg;
for( i = 0; i < 6; i++ )
{
// go into 3d mode
R_Set2DMode( false );
if( skyshot )
{
R_DrawCubemapView( vieworg, r_skyBoxInfo[i].angles, size );
flags = r_skyBoxInfo[i].flags;
}
else
{
R_DrawCubemapView( vieworg, r_envMapInfo[i].angles, size );
flags = r_envMapInfo[i].flags;
}
pglReadPixels( 0, 0, size, size, GL_RGB, GL_UNSIGNED_BYTE, temp );
r_side->flags = IMAGE_HAS_COLOR;
r_side->width = r_side->height = size;
r_side->type = PF_RGB_24;
r_side->size = r_side->width * r_side->height * 3;
r_side->buffer = temp;
if( flags ) Image_Process( &r_side, 0, 0, flags, NULL );
memcpy( buffer + (size * size * 3 * i), r_side->buffer, size * size * 3 );
}
RI.params &= ~RP_ENVVIEW;
r_shot->flags = IMAGE_HAS_COLOR;
r_shot->flags |= (skyshot) ? IMAGE_SKYBOX : IMAGE_CUBEMAP;
r_shot->width = size;
r_shot->height = size;
r_shot->type = PF_RGB_24;
r_shot->size = r_shot->width * r_shot->height * 3 * 6;
r_shot->palette = NULL;
r_shot->buffer = buffer;
// make sure what we have right extension
Q_strncpy( basename, base, MAX_STRING );
COM_StripExtension( basename );
COM_DefaultExtension( basename, ".tga" );
// write image as 6 sides
result = FS_SaveImage( basename, r_shot );
FS_FreeImage( r_shot );
FS_FreeImage( r_side );
return result;
}
//=======================================================
/*
===============
R_ShowTextures
Draw all the images to the screen, on top of whatever
was there. This is used to test for texture thrashing.
===============
*/
void R_ShowTextures( void )
{
gltexture_t *image;
float x, y, w, h;
int total, start, end;
int i, j, k, base_w, base_h;
rgba_t color = { 192, 192, 192, 255 };
int charHeight, numTries = 0;
static qboolean showHelp = true;
string shortname;
if( !gl_showtextures->value )
return;
if( showHelp )
{
CL_CenterPrint( "use '<-' and '->' keys to change atlas page, ESC to quit", 0.25f );
showHelp = false;
}
GL_SetRenderMode( kRenderNormal );
pglClear( GL_COLOR_BUFFER_BIT );
pglFinish();
base_w = 8; // textures view by horizontal
base_h = 6; // textures view by vertical
rebuild_page:
total = base_w * base_h;
start = total * (gl_showtextures->value - 1);
end = total * gl_showtextures->value;
if( end > MAX_TEXTURES ) end = MAX_TEXTURES;
w = glState.width / base_w;
h = glState.height / base_h;
Con_DrawStringLen( NULL, NULL, &charHeight );
for( i = j = 0; i < MAX_TEXTURES; i++ )
{
image = R_GetTexture( i );
if( j == start ) break; // found start
if( pglIsTexture( image->texnum )) j++;
}
if( i == MAX_TEXTURES && gl_showtextures->value != 1 )
{
// bad case, rewind to one and try again
Cvar_SetValue( "r_showtextures", max( 1, gl_showtextures->value - 1 ));
if( ++numTries < 2 ) goto rebuild_page; // to prevent infinite loop
}
for( k = 0; i < MAX_TEXTURES; i++ )
{
if( j == end ) break; // page is full
image = R_GetTexture( i );
if( !pglIsTexture( image->texnum ))
continue;
x = k % base_w * w;
y = k / base_w * h;
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
GL_Bind( GL_TEXTURE0, i ); // NOTE: don't use image->texnum here, because skybox has a 'wrong' indexes
if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE ))
pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
pglBegin( GL_QUADS );
pglTexCoord2f( 0, 0 );
pglVertex2f( x, y );
if( image->target == GL_TEXTURE_RECTANGLE_EXT )
pglTexCoord2f( image->width, 0 );
else pglTexCoord2f( 1, 0 );
pglVertex2f( x + w, y );
if( image->target == GL_TEXTURE_RECTANGLE_EXT )
pglTexCoord2f( image->width, image->height );
else pglTexCoord2f( 1, 1 );
pglVertex2f( x + w, y + h );
if( image->target == GL_TEXTURE_RECTANGLE_EXT )
pglTexCoord2f( 0, image->height );
else pglTexCoord2f( 0, 1 );
pglVertex2f( x, y + h );
pglEnd();
if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE ))
pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
COM_FileBase( image->name, shortname );
if( Q_strlen( shortname ) > 18 )
{
// cutoff too long names, it looks ugly
shortname[16] = '.';
shortname[17] = '.';
shortname[18] = '\0';
}
Con_DrawString( x + 1, y + h - charHeight, shortname, color );
j++, k++;
}
CL_DrawCenterPrint ();
pglFinish();
}

2032
engine/client/gl_beams.c Normal file

File diff suppressed because it is too large Load Diff

151
engine/client/gl_cull.c Normal file
View File

@ -0,0 +1,151 @@
/*
gl_cull.c - render culling routines
Copyright (C) 2010 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 "gl_local.h"
#include "entity_types.h"
/*
=============================================================
FRUSTUM AND PVS CULLING
=============================================================
*/
/*
=================
R_CullBox
Returns true if the box is completely outside the frustum
=================
*/
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs )
{
return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 );
}
/*
=================
R_CullSphere
Returns true if the sphere is completely outside the frustum
=================
*/
qboolean R_CullSphere( const vec3_t centre, const float radius )
{
return GL_FrustumCullSphere( &RI.frustum, centre, radius, 0 );
}
/*
=============
R_CullModel
=============
*/
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax )
{
if( e == &clgame.viewent )
{
if( CL_IsDevOverviewMode( ))
return 1;
if( RP_NORMALPASS() && !cl.local.thirdperson && cl.viewentity == ( cl.playernum + 1 ))
return 0;
return 1;
}
// local client can't view himself if camera or thirdperson is not active
if( RP_LOCALCLIENT( e ) && !cl.local.thirdperson && cl.viewentity == ( cl.playernum + 1 ))
return 1;
if( R_CullBox( absmin, absmax ))
return 1;
return 0;
}
/*
=================
R_CullSurface
cull invisible surfaces
=================
*/
int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags )
{
cl_entity_t *e = RI.currententity;
if( !surf || !surf->texinfo || !surf->texinfo->texture )
return CULL_OTHER;
if( r_nocull->value )
return CULL_VISIBLE;
// world surfaces can be culled by vis frame too
if( RI.currententity == clgame.entities && surf->visframe != tr.framecount )
return CULL_VISFRAME;
// only static ents can be culled by frustum
if( !R_StaticEntity( e )) frustum = NULL;
if( !VectorIsNull( surf->plane->normal ))
{
float dist;
// can use normal.z for world (optimisation)
if( RI.drawOrtho )
{
vec3_t orthonormal;
if( e == clgame.entities ) orthonormal[2] = surf->plane->normal[2];
else Matrix4x4_VectorRotate( RI.objectMatrix, surf->plane->normal, orthonormal );
dist = orthonormal[2];
}
else dist = PlaneDiff( tr.modelorg, surf->plane );
if( glState.faceCull == GL_FRONT )
{
if( FBitSet( surf->flags, SURF_PLANEBACK ))
{
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
}
else if( glState.faceCull == GL_BACK )
{
if( FBitSet( surf->flags, SURF_PLANEBACK ))
{
if( dist <= BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return CULL_BACKSIDE; // wrong side
}
}
}
if( frustum && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags ))
return CULL_FRUSTUM;
return CULL_VISIBLE;
}

1293
engine/client/gl_decals.c Normal file

File diff suppressed because it is too large Load Diff

282
engine/client/gl_draw.c Normal file
View File

@ -0,0 +1,282 @@
/*
gl_draw.c - orthogonal drawing stuff
Copyright (C) 2010 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 "gl_local.h"
/*
=============
R_GetImageParms
=============
*/
void R_GetTextureParms( int *w, int *h, int texnum )
{
gltexture_t *glt;
glt = R_GetTexture( texnum );
if( w ) *w = glt->srcWidth;
if( h ) *h = glt->srcHeight;
}
/*
=============
R_GetSpriteParms
same as GetImageParms but used
for sprite models
=============
*/
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
{
mspriteframe_t *pFrame;
if( !pSprite || pSprite->type != mod_sprite ) return; // bad model ?
pFrame = R_GetSpriteFrame( pSprite, currentFrame, 0.0f );
if( frameWidth ) *frameWidth = pFrame->width;
if( frameHeight ) *frameHeight = pFrame->height;
if( numFrames ) *numFrames = pSprite->numframes;
}
int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
{
if( !m_pSpriteModel || m_pSpriteModel->type != mod_sprite || !m_pSpriteModel->cache.data )
return 0;
return R_GetSpriteFrame( m_pSpriteModel, frame, 0.0f )->gl_texturenum;
}
/*
=============
R_DrawStretchPic
=============
*/
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
{
GL_Bind( GL_TEXTURE0, texnum );
pglBegin( GL_QUADS );
pglTexCoord2f( s1, t1 );
pglVertex2f( x, y );
pglTexCoord2f( s2, t1 );
pglVertex2f( x + w, y );
pglTexCoord2f( s2, t2 );
pglVertex2f( x + w, y + h );
pglTexCoord2f( s1, t2 );
pglVertex2f( x, y + h );
pglEnd();
}
/*
=============
Draw_TileClear
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void R_DrawTileClear( int x, int y, int w, int h )
{
float tw, th;
gltexture_t *glt;
GL_SetRenderMode( kRenderNormal );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
GL_Bind( GL_TEXTURE0, cls.tileImage );
glt = R_GetTexture( cls.tileImage );
tw = glt->srcWidth;
th = glt->srcHeight;
pglBegin( GL_QUADS );
pglTexCoord2f( x / tw, y / th );
pglVertex2f( x, y );
pglTexCoord2f((x + w) / tw, y / th );
pglVertex2f( x + w, y );
pglTexCoord2f((x + w) / tw, (y + h) / th );
pglVertex2f( x + w, y + h );
pglTexCoord2f( x / tw, (y + h) / th );
pglVertex2f( x, y + h );
pglEnd ();
}
/*
=============
R_DrawStretchRaw
=============
*/
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
{
byte *raw = NULL;
gltexture_t *tex;
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{
int width = 1, height = 1;
// check the dimensions
width = NearestPOW( cols, true );
height = NearestPOW( rows, false );
if( cols != width || rows != height )
{
raw = GL_ResampleTexture( data, cols, rows, width, height, false );
cols = width;
rows = height;
}
}
else
{
raw = (byte *)data;
}
if( cols > glConfig.max_2d_texture_size )
Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", cols );
if( rows > glConfig.max_2d_texture_size )
Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", rows );
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
tex = R_GetTexture( tr.cinTexture );
GL_Bind( GL_TEXTURE0, tr.cinTexture );
if( cols == tex->width && rows == tex->height )
{
if( dirty )
{
pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw );
}
}
else
{
tex->width = cols;
tex->height = rows;
if( dirty )
{
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
}
}
pglBegin( GL_QUADS );
pglTexCoord2f( 0, 0 );
pglVertex2f( x, y );
pglTexCoord2f( 1, 0 );
pglVertex2f( x + w, y );
pglTexCoord2f( 1, 1 );
pglVertex2f( x + w, y + h );
pglTexCoord2f( 0, 1 );
pglVertex2f( x, y + h );
pglEnd();
}
/*
=============
R_UploadStretchRaw
=============
*/
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data )
{
byte *raw = NULL;
gltexture_t *tex;
if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{
// check the dimensions
width = NearestPOW( width, true );
height = NearestPOW( height, false );
}
else
{
width = bound( 128, width, glConfig.max_2d_texture_size );
height = bound( 128, height, glConfig.max_2d_texture_size );
}
if( cols != width || rows != height )
{
raw = GL_ResampleTexture( data, cols, rows, width, height, false );
cols = width;
rows = height;
}
else
{
raw = (byte *)data;
}
if( cols > glConfig.max_2d_texture_size )
Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", cols );
if( rows > glConfig.max_2d_texture_size )
Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", rows );
tex = R_GetTexture( texture );
GL_Bind( GL_KEEP_UNIT, texture );
tex->width = cols;
tex->height = rows;
pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
GL_ApplyTextureParams( tex );
}
/*
===============
R_Set2DMode
===============
*/
void R_Set2DMode( qboolean enable )
{
if( enable )
{
if( glState.in2DMode )
return;
// set 2D virtual screen size
pglViewport( 0, 0, glState.width, glState.height );
pglMatrixMode( GL_PROJECTION );
pglLoadIdentity();
pglOrtho( 0, glState.width, glState.height, 0, -99999, 99999 );
pglMatrixMode( GL_MODELVIEW );
pglLoadIdentity();
GL_Cull( GL_NONE );
pglDepthMask( GL_FALSE );
pglDisable( GL_DEPTH_TEST );
pglEnable( GL_ALPHA_TEST );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glState.in2DMode = true;
RI.currententity = NULL;
RI.currentmodel = NULL;
}
else
{
pglDepthMask( GL_TRUE );
pglEnable( GL_DEPTH_TEST );
glState.in2DMode = false;
pglMatrixMode( GL_PROJECTION );
GL_LoadMatrix( RI.projectionMatrix );
pglMatrixMode( GL_MODELVIEW );
GL_LoadMatrix( RI.worldviewMatrix );
GL_Cull( GL_FRONT );
}
}

1302
engine/client/gl_export.h Normal file

File diff suppressed because it is too large Load Diff

355
engine/client/gl_frustum.c Normal file
View File

@ -0,0 +1,355 @@
/*
gl_frustum.cpp - frustum test implementation
Copyright (C) 2016 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 "gl_local.h"
#include "mathlib.h"
void GL_FrustumEnablePlane( gl_frustum_t *out, int side )
{
Assert( side >= 0 && side < FRUSTUM_PLANES );
// make sure what plane is ready
if( !VectorIsNull( out->planes[side].normal ))
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumDisablePlane( gl_frustum_t *out, int side )
{
Assert( side >= 0 && side < FRUSTUM_PLANES );
ClearBits( out->clipFlags, BIT( side ));
}
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
{
Assert( side >= 0 && side < FRUSTUM_PLANES );
out->planes[side].type = PlaneTypeForNormal( vecNormal );
out->planes[side].signbits = SignbitsForPlane( vecNormal );
VectorCopy( vecNormal, out->planes[side].normal );
out->planes[side].dist = flDist;
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumNormalizePlane( gl_frustum_t *out, int side )
{
float length;
Assert( side >= 0 && side < FRUSTUM_PLANES );
// normalize
length = VectorLength( out->planes[side].normal );
if( length )
{
float ilength = (1.0f / length);
out->planes[side].normal[0] *= ilength;
out->planes[side].normal[1] *= ilength;
out->planes[side].normal[2] *= ilength;
out->planes[side].dist *= ilength;
}
out->planes[side].type = PlaneTypeForNormal( out->planes[side].normal );
out->planes[side].signbits = SignbitsForPlane( out->planes[side].normal );
SetBits( out->clipFlags, BIT( side ));
}
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY )
{
float xs, xc;
vec3_t farpoint, nearpoint;
vec3_t normal, iforward;
// horizontal fov used for left and right planes
SinCos( DEG2RAD( flFovX ) * 0.5f, &xs, &xc );
// setup left plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, normal, DotProduct( RI.cullorigin, normal ));
// setup right plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vright, normal );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, normal, DotProduct( RI.cullorigin, normal ));
// vertical fov used for top and bottom planes
SinCos( DEG2RAD( flFovY ) * 0.5f, &xs, &xc );
VectorNegate( RI.cull_vforward, iforward );
// setup bottom plane
VectorMAM( xs, RI.cull_vforward, -xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, normal, DotProduct( RI.cullorigin, normal ));
// setup top plane
VectorMAM( xs, RI.cull_vforward, xc, RI.cull_vup, normal );
GL_FrustumSetPlane( out, FRUSTUM_TOP, normal, DotProduct( RI.cullorigin, normal ));
// setup far plane
VectorMA( RI.cullorigin, flZFar, RI.cull_vforward, farpoint );
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, DotProduct( iforward, farpoint ));
// no need to setup backplane for general view.
if( flZNear == 0.0f ) return;
// setup near plane
VectorMA( RI.cullorigin, flZNear, RI.cull_vforward, nearpoint );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, DotProduct( RI.cull_vforward, nearpoint ));
}
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar )
{
vec3_t iforward, iright, iup;
// setup the near and far planes
float orgOffset = DotProduct( RI.cullorigin, RI.cull_vforward );
VectorNegate( RI.cull_vforward, iforward );
// because quake ortho is inverted and far and near should be swaped
GL_FrustumSetPlane( out, FRUSTUM_FAR, iforward, -flZNear - orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_NEAR, RI.cull_vforward, flZFar + orgOffset );
// setup left and right planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vright );
VectorNegate( RI.cull_vright, iright );
GL_FrustumSetPlane( out, FRUSTUM_LEFT, RI.cull_vright, xLeft + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_RIGHT, iright, -xRight - orgOffset );
// setup top and buttom planes
orgOffset = DotProduct( RI.cullorigin, RI.cull_vup );
VectorNegate( RI.cull_vup, iup );
GL_FrustumSetPlane( out, FRUSTUM_TOP, RI.cull_vup, yTop + orgOffset );
GL_FrustumSetPlane( out, FRUSTUM_BOTTOM, iup, -yBottom - orgOffset );
}
void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius )
{
vec3_t normal;
int i;
for( i = 0; i < FRUSTUM_PLANES; i++ )
{
// setup normal for each direction
VectorClear( normal );
normal[((i >> 1) + 1) % 3] = (i & 1) ? 1.0f : -1.0f;
GL_FrustumSetPlane( out, i, normal, DotProduct( org, normal ) - radius );
}
}
void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection )
{
int i;
// left
out->planes[FRUSTUM_LEFT].normal[0] = projection[0][3] + projection[0][0];
out->planes[FRUSTUM_LEFT].normal[1] = projection[1][3] + projection[1][0];
out->planes[FRUSTUM_LEFT].normal[2] = projection[2][3] + projection[2][0];
out->planes[FRUSTUM_LEFT].dist = -(projection[3][3] + projection[3][0]);
// right
out->planes[FRUSTUM_RIGHT].normal[0] = projection[0][3] - projection[0][0];
out->planes[FRUSTUM_RIGHT].normal[1] = projection[1][3] - projection[1][0];
out->planes[FRUSTUM_RIGHT].normal[2] = projection[2][3] - projection[2][0];
out->planes[FRUSTUM_RIGHT].dist = -(projection[3][3] - projection[3][0]);
// bottom
out->planes[FRUSTUM_BOTTOM].normal[0] = projection[0][3] + projection[0][1];
out->planes[FRUSTUM_BOTTOM].normal[1] = projection[1][3] + projection[1][1];
out->planes[FRUSTUM_BOTTOM].normal[2] = projection[2][3] + projection[2][1];
out->planes[FRUSTUM_BOTTOM].dist = -(projection[3][3] + projection[3][1]);
// top
out->planes[FRUSTUM_TOP].normal[0] = projection[0][3] - projection[0][1];
out->planes[FRUSTUM_TOP].normal[1] = projection[1][3] - projection[1][1];
out->planes[FRUSTUM_TOP].normal[2] = projection[2][3] - projection[2][1];
out->planes[FRUSTUM_TOP].dist = -(projection[3][3] - projection[3][1]);
// near
out->planes[FRUSTUM_NEAR].normal[0] = projection[0][3] + projection[0][2];
out->planes[FRUSTUM_NEAR].normal[1] = projection[1][3] + projection[1][2];
out->planes[FRUSTUM_NEAR].normal[2] = projection[2][3] + projection[2][2];
out->planes[FRUSTUM_NEAR].dist = -(projection[3][3] + projection[3][2]);
// far
out->planes[FRUSTUM_FAR].normal[0] = projection[0][3] - projection[0][2];
out->planes[FRUSTUM_FAR].normal[1] = projection[1][3] - projection[1][2];
out->planes[FRUSTUM_FAR].normal[2] = projection[2][3] - projection[2][2];
out->planes[FRUSTUM_FAR].dist = -(projection[3][3] - projection[3][2]);
for( i = 0; i < FRUSTUM_PLANES; i++ )
{
GL_FrustumNormalizePlane( out, i );
}
}
void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t corners[8] )
{
memset( corners, 0, sizeof( corners ));
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[0] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_FAR], corners[1] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[2] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_FAR], corners[3] );
if( FBitSet( out->clipFlags, BIT( FRUSTUM_NEAR )))
{
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[4] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], &out->planes[FRUSTUM_NEAR], corners[5] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[6] );
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_BOTTOM], &out->planes[FRUSTUM_NEAR], corners[7] );
}
else
{
PlanesGetIntersectionPoint( &out->planes[FRUSTUM_LEFT], &out->planes[FRUSTUM_RIGHT], &out->planes[FRUSTUM_TOP], corners[4] );
VectorCopy( corners[4], corners[5] );
VectorCopy( corners[4], corners[6] );
VectorCopy( corners[4], corners[7] );
}
}
void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs )
{
vec3_t corners[8];
int i;
GL_FrustumComputeCorners( out, corners );
ClearBounds( mins, maxs );
for( i = 0; i < 8; i++ )
AddPointToBounds( corners[i], mins, maxs );
}
void GL_FrustumDrawDebug( gl_frustum_t *out )
{
vec3_t bbox[8];
int i;
GL_FrustumComputeCorners( out, bbox );
// g-cont. frustum must be yellow :-)
pglColor4f( 1.0f, 1.0f, 0.0f, 1.0f );
pglDisable( GL_TEXTURE_2D );
pglBegin( GL_LINES );
for( i = 0; i < 2; i += 1 )
{
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i+0] );
pglVertex3fv( bbox[i+4] );
pglVertex3fv( bbox[i+2] );
pglVertex3fv( bbox[i+6] );
pglVertex3fv( bbox[i*2+0] );
pglVertex3fv( bbox[i*2+1] );
pglVertex3fv( bbox[i*2+4] );
pglVertex3fv( bbox[i*2+5] );
}
pglEnd();
pglEnable( GL_TEXTURE_2D );
}
// cull methods
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull->value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
switch( p->signbits )
{
case 0:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 1:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 2:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 3:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * maxs[2] < p->dist )
return true;
break;
case 4:
if( p->normal[0] * maxs[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 5:
if( p->normal[0] * mins[0] + p->normal[1] * maxs[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 6:
if( p->normal[0] * maxs[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
case 7:
if( p->normal[0] * mins[0] + p->normal[1] * mins[1] + p->normal[2] * mins[2] < p->dist )
return true;
break;
default:
return false;
}
}
return false;
}
qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags )
{
int iClipFlags;
int i, bit;
if( r_nocull->value )
return false;
if( userClipFlags != 0 )
iClipFlags = userClipFlags;
else iClipFlags = out->clipFlags;
for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 )
{
const mplane_t *p = &out->planes[FRUSTUM_PLANES - i];
if( !FBitSet( iClipFlags, bit ))
continue;
if( DotProduct( center, p->normal ) - p->dist <= -radius )
return true;
}
return false;
}

View File

@ -0,0 +1,52 @@
/*
gl_frustum.cpp - frustum test implementation
Copyright (C) 2016 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.
*/
#ifndef GL_FRUSTUM_H
#define GL_FRUSTUM_H
// don't change this order
#define FRUSTUM_LEFT 0
#define FRUSTUM_RIGHT 1
#define FRUSTUM_BOTTOM 2
#define FRUSTUM_TOP 3
#define FRUSTUM_FAR 4
#define FRUSTUM_NEAR 5
#define FRUSTUM_PLANES 6
typedef struct gl_frustum_s
{
mplane_t planes[FRUSTUM_PLANES];
unsigned int clipFlags;
} gl_frustum_t;
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY );
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar );
void GL_FrustumInitBox( gl_frustum_t *out, const vec3_t org, float radius ); // used for pointlights
void GL_FrustumInitProjFromMatrix( gl_frustum_t *out, const matrix4x4 projection );
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist );
void GL_FrustumNormalizePlane( gl_frustum_t *out, int side );
void GL_FrustumComputeBounds( gl_frustum_t *out, vec3_t mins, vec3_t maxs );
void GL_FrustumComputeCorners( gl_frustum_t *out, vec3_t bbox[8] );
void GL_FrustumDrawDebug( gl_frustum_t *out );
// cull methods
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags );
qboolean GL_FrustumCullSphere( gl_frustum_t *out, const vec3_t centre, float radius, int userClipFlags );
// plane manipulating
void GL_FrustumEnablePlane( gl_frustum_t *out, int side );
void GL_FrustumDisablePlane( gl_frustum_t *out, int side );
#endif//GL_FRUSTUM_H

2775
engine/client/gl_image.c Normal file

File diff suppressed because it is too large Load Diff

677
engine/client/gl_local.h Normal file
View File

@ -0,0 +1,677 @@
/*
gl_local.h - renderer local declarations
Copyright (C) 2010 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.
*/
#ifndef GL_LOCAL_H
#define GL_LOCAL_H
#include "gl_export.h"
#include "cl_entity.h"
#include "render_api.h"
#include "protocol.h"
#include "dlight.h"
#include "gl_frustum.h"
extern byte *r_temppool;
#define BLOCK_SIZE tr.block_size // lightmap blocksize
#define BLOCK_SIZE_DEFAULT 128 // for keep backward compatibility
#define BLOCK_SIZE_MAX 1024
#define MAX_TEXTURES 4096
#define MAX_DETAIL_TEXTURES 256
#define MAX_LIGHTMAPS 256
#define SUBDIVIDE_SIZE 64
#define MAX_DECAL_SURFS 4096
#define MAX_DRAW_STACK 2 // normal view and menu view
#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
#define SHADE_LAMBERT 1.495f
// refparams
#define RP_NONE 0
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
#define RP_OLDVIEWLEAF BIT( 1 )
#define RP_CLIPPLANE BIT( 2 )
#define RP_NONVIEWERREF (RP_ENVVIEW)
#define R_ModelOpaque( rm ) ( rm == kRenderNormal )
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
#define RP_NORMALPASS() ( FBitSet( RI.params, RP_NONVIEWERREF ) == 0 )
#define TF_SKY (TF_SKYSIDE|TF_NOMIPMAP)
#define TF_FONT (TF_NOMIPMAP|TF_CLAMP)
#define TF_IMAGE (TF_NOMIPMAP|TF_CLAMP)
#define TF_DECAL (TF_CLAMP)
#define CULL_VISIBLE 0 // not culled
#define CULL_BACKSIDE 1 // backside of transparent wall
#define CULL_FRUSTUM 2 // culled by frustum
#define CULL_VISFRAME 3 // culled by PVS
#define CULL_OTHER 4 // culled by other reason
typedef struct gltexture_s
{
char name[256]; // game path, including extension (can be store image programs)
word srcWidth; // keep unscaled sizes
word srcHeight;
word width; // upload width\height
word height;
word depth; // texture depth or count of layers for 2D_ARRAY
byte numMips; // mipmap count
GLuint target; // glTarget
GLuint texnum; // gl texture binding
GLint format; // uploaded format
GLint encode; // using GLSL decoder
texFlags_t flags;
rgba_t fogParams; // some water textures
// contain info about underwater fog
rgbdata_t *original; // keep original image
// debug info
size_t size; // upload size for debug targets
// detail textures stuff
float xscale;
float yscale;
int servercount;
uint hashValue;
struct gltexture_s *nextHash;
} gltexture_t;
typedef struct
{
int params; // rendering parameters
qboolean drawWorld; // ignore world for drawing PlayerModel
qboolean isSkyVisible; // sky is visible
qboolean onlyClientDraw; // disabled by client request
qboolean drawOrtho; // draw world as orthogonal projection
float fov_x, fov_y; // current view fov
cl_entity_t *currententity;
model_t *currentmodel;
cl_entity_t *currentbeam; // same as above but for beams
int viewport[4];
gl_frustum_t frustum;
mleaf_t *viewleaf;
mleaf_t *oldviewleaf;
vec3_t pvsorigin;
vec3_t vieworg; // locked vieworigin
vec3_t viewangles;
vec3_t vforward;
vec3_t vright;
vec3_t vup;
vec3_t cullorigin;
vec3_t cull_vforward;
vec3_t cull_vright;
vec3_t cull_vup;
float farClip;
qboolean fogCustom;
qboolean fogEnabled;
qboolean fogSkybox;
vec4_t fogColor;
float fogDensity;
float fogStart;
float fogEnd;
int cached_contents; // in water
int cached_waterlevel; // was in water
float skyMins[2][6];
float skyMaxs[2][6];
matrix4x4 objectMatrix; // currententity matrix
matrix4x4 worldviewMatrix; // modelview for world
matrix4x4 modelviewMatrix; // worldviewMatrix * objectMatrix
matrix4x4 projectionMatrix;
matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix
byte visbytes[(MAX_MAP_LEAFS+7)/8];// actual PVS for current frame
float viewplanedist;
mplane_t clipPlane;
} ref_instance_t;
typedef struct
{
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET];
uint num_solid_entities;
uint num_trans_entities;
uint num_beam_entities;
} draw_list_t;
typedef struct
{
int cinTexture; // cinematic texture
int skyTexture; // default sky texture
int whiteTexture;
int grayTexture;
int blackTexture;
int particleTexture;
int defaultTexture; // use for bad textures
int solidskyTexture; // quake1 solid-sky layer
int alphaskyTexture; // quake1 alpha-sky layer
int lightmapTextures[MAX_LIGHTMAPS];
int dlightTexture; // custom dlight texture
int dlightTexture2; // big dlight texture (for big lightmaps)
int attenuationTexture; // normal attenuation
int attenuationTexture2;// dark attenuation
int attenuationTexture3;// bright attenuation
int attenuationTexture3D;// 3D attenuation
int attenuationStubTexture;
int blankbumpTexture;
int blankdeluxeTexture;
int normalizeTexture;
int dlightCubeTexture; // dynamic cubemap
int vsdctCubeTexture; // Virtual Shadow Depth Cubemap Texture
int grayCubeTexture;
int whiteCubeTexture;
int skyboxTextures[6]; // skybox sides
int skytexturenum; // this not a gl_texturenum!
int skyboxbasenum; // start with 5800
// entity lists
draw_list_t draw_stack[MAX_DRAW_STACK];
int draw_stack_pos;
draw_list_t *draw_list;
msurface_t *draw_decals[MAX_DECAL_SURFS];
int num_draw_decals;
// OpenGL matrix states
qboolean modelviewIdentity;
int visframecount; // PVS frame
int dlightframecount; // dynamic light frame
int realframecount; // not including viewpasses
int framecount;
qboolean ignore_lightgamma;
qboolean fCustomRendering;
qboolean fResetVis;
qboolean fFlipViewModel;
byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS
int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
int block_size; // lightmap blocksize
double frametime; // special frametime for multipass rendering (will set to 0 on a nextview)
float blend; // global blend value
// cull info
vec3_t modelorg; // relative to viewpoint
} ref_globals_t;
typedef struct
{
uint c_world_polys;
uint c_studio_polys;
uint c_sprite_polys;
uint c_alias_polys;
uint c_world_leafs;
uint c_view_beams_count;
uint c_active_tents_count;
uint c_alias_models_drawn;
uint c_studio_models_drawn;
uint c_sprite_models_drawn;
uint c_particle_count;
uint c_client_ents; // entities that moved to client
} ref_speeds_t;
extern ref_speeds_t r_stats;
extern ref_instance_t RI;
extern ref_globals_t tr;
extern float gldepthmin, gldepthmax;
extern mleaf_t *r_viewleaf, *r_oldviewleaf;
extern mleaf_t *r_viewleaf2, *r_oldviewleaf2;
extern dlight_t cl_dlights[MAX_DLIGHTS];
extern dlight_t cl_elights[MAX_ELIGHTS];
#define r_numEntities (tr.draw_list->num_solid_entities + tr.draw_list->num_trans_entities)
#define r_numStatics (r_stats.c_client_ents)
extern struct beam_s *cl_active_beams;
extern struct beam_s *cl_free_beams;
extern struct particle_s *cl_free_particles;
//
// gl_backend.c
//
void GL_BackendStartFrame( void );
void GL_BackendEndFrame( void );
void GL_CleanUpTextureUnits( int last );
void GL_Bind( GLint tmu, GLenum texnum );
void GL_MultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t );
void GL_SetTexCoordArrayMode( GLenum mode );
void GL_LoadTexMatrix( const matrix4x4 m );
void GL_LoadTexMatrixExt( const float *glmatrix );
void GL_LoadMatrix( const matrix4x4 source );
void GL_TexGen( GLenum coord, GLenum mode );
void GL_SelectTexture( GLint texture );
void GL_CleanupAllTextureUnits( void );
void GL_LoadIdentityTexMatrix( void );
void GL_DisableAllTexGens( void );
void GL_SetRenderMode( int mode );
void GL_TextureTarget( uint target );
void GL_Cull( GLenum cull );
void R_ShowTextures( void );
//
// gl_cull.c
//
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
qboolean R_CullSphere( const vec3_t centre, const float radius );
int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags );
//
// gl_decals.c
//
void DrawSurfaceDecals( msurface_t *fa, qboolean single, qboolean reverse );
float *R_DecalSetupVerts( decal_t *pDecal, msurface_t *surf, int texture, int *outCount );
void DrawSingleDecal( decal_t *pDecal, msurface_t *fa );
void R_EntityRemoveDecals( model_t *mod );
void DrawDecalsBatch( void );
void R_ClearDecals( void );
//
// gl_draw.c
//
void R_Set2DMode( qboolean enable );
void R_DrawTileClear( int x, int y, int w, int h );
void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data );
//
// gl_image.c
//
void R_SetTextureParameters( void );
gltexture_t *R_GetTexture( GLenum texnum );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, imgfilter_t *filter );
int GL_LoadTextureArray( const char **names, int flags, imgfilter_t *filter );
int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap );
int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
void GL_ApplyTextureParams( gltexture_t *tex );
void R_FreeImage( gltexture_t *image );
int GL_FindTexture( const char *name );
void GL_FreeTexture( GLenum texnum );
void GL_FreeImage( const char *name );
const char *GL_Target( GLenum target );
void R_TextureList_f( void );
void R_InitImages( void );
void R_ShutdownImages( void );
//
// gl_refrag.c
//
void R_StoreEfrags( efrag_t **ppefrag, int framecount );
//
// gl_rlight.c
//
void R_PushDlights( void );
void R_AnimateLight( void );
void R_GetLightSpot( vec3_t lightspot );
void R_MarkLights( dlight_t *light, int bit, mnode_t *node );
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, qboolean useAmbient, float radius );
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot );
int R_CountSurfaceDlights( msurface_t *surf );
colorVec R_LightPoint( const vec3_t p0 );
int R_CountDlights( void );
//
// gl_rmain.c
//
void R_ClearScene( void );
void R_LoadIdentity( void );
void R_RenderScene( void );
void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size );
void R_SetupRefParams( const struct ref_viewpass_s *rvp );
void R_TranslateForEntity( cl_entity_t *e );
void R_RotateForEntity( cl_entity_t *e );
void R_SetupGL( qboolean set_gl_state );
qboolean R_InitRenderAPI( void );
void R_AllowFog( int allowed );
void R_SetupFrustum( void );
void R_FindViewLeaf( void );
void R_PushScene( void );
void R_PopScene( void );
void R_DrawFog( void );
//
// gl_rmath.c
//
float V_CalcFov( float *fov_x, float width, float height );
void V_AdjustFov( float *fov_x, float *fov_y, float width, float height, qboolean lock_x );
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] );
void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] );
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 );
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z );
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z );
void Matrix4x4_ConcatScale( matrix4x4 out, float x );
void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z );
void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z );
void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z );
void Matrix4x4_CreateScale( matrix4x4 out, float x );
void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z );
void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar);
void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar);
void Matrix4x4_CreateModelview( matrix4x4 out );
//
// gl_rmisc.
//
void R_ParseTexFilters( const char *filename );
imgfilter_t *R_FindTexFilter( const char *texname );
//
// gl_rsurf.c
//
void R_MarkLeaves( void );
void R_DrawWorld( void );
void R_DrawWaterSurfaces( void );
void R_DrawBrushModel( cl_entity_t *e );
void GL_SubdivideSurface( msurface_t *fa );
void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa );
void DrawGLPoly( glpoly_t *p, float xScale, float yScale );
texture_t *R_TextureAnimation( msurface_t *s );
void GL_SetupFogColorForSurfaces( void );
void R_DrawAlphaTextureChains( void );
void GL_RebuildLightmaps( void );
void GL_InitRandomTable( void );
void GL_BuildLightmaps( void );
void GL_ResetFogColor( void );
//
// gl_sprite.c
//
void R_SpriteInit( void );
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags );
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw );
void R_DrawSpriteModel( cl_entity_t *e );
//
// gl_studio.c
//
void R_StudioInit( void );
void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded );
void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles );
float CL_GetSequenceDuration( cl_entity_t *ent, int sequence );
struct mstudiotex_s *R_StudioGetTexture( cl_entity_t *e );
float CL_GetStudioEstimatedFrame( cl_entity_t *ent );
int R_GetEntityRenderMode( cl_entity_t *ent );
void R_DrawStudioModel( cl_entity_t *e );
player_info_t *pfnPlayerInfo( int index );
//
// gl_alias.c
//
void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded );
void R_DrawAliasModel( cl_entity_t *e );
void R_AliasInit( void );
//
// gl_warp.c
//
void R_InitSkyClouds( struct mip_s *mt, struct texture_s *tx, qboolean custom_palette );
void R_AddSkyBoxSurface( msurface_t *fa );
void R_ClearSkyBox( void );
void R_DrawSkyBox( void );
void R_DrawClouds( void );
void EmitWaterPolys( msurface_t *warp, qboolean reverse );
//
// gl_vidnt.c
//
#define GL_CheckForErrors() GL_CheckForErrors_( __FILE__, __LINE__ )
void GL_CheckForErrors_( const char *filename, const int fileline );
const char *VID_GetModeString( int vid_mode );
void *GL_GetProcAddress( const char *name );
void GL_UpdateSwapInterval( void );
qboolean GL_DeleteContext( void );
qboolean GL_Support( int r_ext );
void VID_CheckChanges( void );
int GL_MaxTextureUnits( void );
qboolean R_Init( void );
void R_Shutdown( void );
//
// renderer exports
//
qboolean R_Init( void );
void R_Shutdown( void );
void VID_CheckChanges( void );
int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, imgfilter_t *filter );
void GL_FreeImage( const char *name );
qboolean VID_ScreenShot( const char *filename, int shot_type );
qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot );
void R_BeginFrame( qboolean clearScene );
void R_RenderFrame( const struct ref_viewpass_s *vp );
void R_EndFrame( void );
void R_ClearScene( void );
void R_GetTextureParms( int *w, int *h, int texnum );
void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int curFrame, const struct model_s *pSprite );
void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty );
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
qboolean R_SpeedsMessage( char *out, size_t size );
void R_SetupSky( const char *skyboxname );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
qboolean R_WorldToScreen( const vec3_t point, vec3_t screen );
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );
void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size, qboolean *loaded );
void Mod_UnloadSpriteModel( struct model_s *mod );
void Mod_UnloadStudioModel( struct model_s *mod );
void Mod_UnloadBrushModel( struct model_s *mod );
void Mod_UnloadAliasModel( struct model_s *mod );
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, float scale );
void R_RemoveEfrags( struct cl_entity_s *ent );
void R_AddEfrags( struct cl_entity_s *ent );
void R_DecalRemoveAll( int texture );
byte *Mod_GetCurrentVis( void );
void Mod_SetOrthoBounds( float *mins, float *maxs );
void R_NewMap( void );
/*
=======================================================================
GL STATE MACHINE
=======================================================================
*/
enum
{
GL_OPENGL_110 = 0, // base
GL_WGL_EXTENSIONS,
GL_WGL_SWAPCONTROL,
GL_WGL_PROCADDRESS,
GL_ARB_MULTITEXTURE,
GL_TEXTURE_CUBEMAP_EXT,
GL_ANISOTROPY_EXT,
GL_TEXTURE_LOD_BIAS,
GL_TEXTURE_COMPRESSION_EXT,
GL_SHADER_GLSL100_EXT,
GL_TEXTURE_2D_RECT_EXT,
GL_TEXTURE_ARRAY_EXT,
GL_TEXTURE_3D_EXT,
GL_CLAMPTOEDGE_EXT,
GL_ARB_TEXTURE_NPOT_EXT,
GL_CLAMP_TEXBORDER_EXT,
GL_ARB_TEXTURE_FLOAT_EXT,
GL_ARB_DEPTH_FLOAT_EXT,
GL_ARB_SEAMLESS_CUBEMAP,
GL_EXT_GPU_SHADER4, // shaders only
GL_ARB_TEXTURE_RG,
GL_DEPTH_TEXTURE,
GL_DEBUG_OUTPUT,
GL_EXTCOUNT, // must be last
};
enum
{
GL_KEEP_UNIT = -1,
GL_TEXTURE0 = 0,
GL_TEXTURE1, // used in some cases
MAX_TEXTURE_UNITS = 32 // can't acess to all over units without GLSL or cg
};
typedef enum
{
GLHW_GENERIC, // where everthing works the way it should
GLHW_RADEON, // where you don't have proper GLSL support
GLHW_NVIDIA, // Geforce 8/9 class DX10 hardware
GLHW_INTEL // Intel Mobile Graphics
} glHWType_t;
typedef struct
{
const char *renderer_string; // ptrs to OpenGL32.dll, use with caution
const char *vendor_string;
const char *version_string;
glHWType_t hardware_type;
// list of supported extensions
const char *extensions_string;
const char *wgl_extensions_string;
byte extension[GL_EXTCOUNT];
int max_texture_units;
int max_texture_coords;
int max_teximage_units;
GLint max_2d_texture_size;
GLint max_2d_rectangle_size;
GLint max_2d_texture_layers;
GLint max_3d_texture_size;
GLint max_cubemap_size;
GLfloat max_texture_anisotropy;
GLfloat max_texture_lod_bias;
GLint max_vertex_uniforms;
GLint max_vertex_attribs;
int color_bits;
int alpha_bits;
int depth_bits;
int stencil_bits;
gl_context_type_t context;
gles_wrapper_t wrapper;
qboolean softwareGammaUpdate;
int prev_mode;
} glconfig_t;
typedef struct
{
int width, height;
qboolean fullScreen;
qboolean wideScreen;
int activeTMU;
GLint currentTextures[MAX_TEXTURE_UNITS];
GLuint currentTextureTargets[MAX_TEXTURE_UNITS];
GLboolean texIdentityMatrix[MAX_TEXTURE_UNITS];
GLint genSTEnabled[MAX_TEXTURE_UNITS]; // 0 - disabled, OR 1 - S, OR 2 - T, OR 4 - R
GLint texCoordArrayMode[MAX_TEXTURE_UNITS]; // 0 - disabled, 1 - enabled, 2 - cubemap
int faceCull;
qboolean stencilEnabled;
qboolean in2DMode;
} glstate_t;
typedef struct
{
HDC hDC; // handle to device context
HGLRC hGLRC; // handle to GL rendering context
int desktopBitsPixel;
int desktopWidth;
int desktopHeight;
qboolean initialized; // OpenGL subsystem started
qboolean extended; // extended context allows to GL_Debug
} glwstate_t;
extern glconfig_t glConfig;
extern glstate_t glState;
extern glwstate_t glw_state;
//
// renderer cvars
//
extern convar_t *gl_texture_anisotropy;
extern convar_t *gl_extensions;
extern convar_t *gl_check_errors;
extern convar_t *gl_texture_lodbias;
extern convar_t *gl_texture_nearest;
extern convar_t *gl_lightmap_nearest;
extern convar_t *gl_keeptjunctions;
extern convar_t *gl_detailscale;
extern convar_t *gl_wireframe;
extern convar_t *gl_polyoffset;
extern convar_t *gl_finish;
extern convar_t *gl_nosort;
extern convar_t *gl_clear;
extern convar_t *gl_test; // cvar to testify new effects
extern convar_t *r_speeds;
extern convar_t *r_fullbright;
extern convar_t *r_norefresh;
extern convar_t *r_lighting_extended;
extern convar_t *r_lighting_modulate;
extern convar_t *r_lighting_ambient;
extern convar_t *r_studio_lambert;
extern convar_t *r_detailtextures;
extern convar_t *r_drawentities;
extern convar_t *r_adjust_fov;
extern convar_t *r_decals;
extern convar_t *r_novis;
extern convar_t *r_nocull;
extern convar_t *r_lockpvs;
extern convar_t *r_lockfrustum;
extern convar_t *r_traceglow;
extern convar_t *r_dynamic;
extern convar_t *r_lightmap;
extern convar_t *vid_displayfrequency;
extern convar_t *vid_fullscreen;
extern convar_t *vid_brightness;
extern convar_t *vid_gamma;
extern convar_t *vid_mode;
#endif//GL_LOCAL_H

205
engine/client/gl_refrag.c Normal file
View File

@ -0,0 +1,205 @@
/*
gl_refrag.c - store entity fragments
Copyright (C) 2010 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 "gl_local.h"
#include "mod_local.h"
#include "entity_types.h"
#include "studio.h"
/*
===============================================================================
ENTITY FRAGMENT FUNCTIONS
===============================================================================
*/
static efrag_t **lastlink;
static mnode_t *r_pefragtopnode;
static vec3_t r_emins, r_emaxs;
static cl_entity_t *r_addent;
/*
================
R_RemoveEfrags
Call when removing an object from the world or moving it to another position
================
*/
void R_RemoveEfrags( cl_entity_t *ent )
{
efrag_t *ef, *old, *walk, **prev;
ef = ent->efrag;
while( ef )
{
prev = &ef->leaf->efrags;
while( 1 )
{
walk = *prev;
if( !walk ) break;
if( walk == ef )
{
// remove this fragment
*prev = ef->leafnext;
break;
}
else prev = &walk->leafnext;
}
old = ef;
ef = ef->entnext;
// put it on the free list
old->entnext = clgame.free_efrags;
clgame.free_efrags = old;
}
ent->efrag = NULL;
}
/*
===================
R_SplitEntityOnNode
===================
*/
static void R_SplitEntityOnNode( mnode_t *node )
{
efrag_t *ef;
mplane_t *splitplane;
mleaf_t *leaf;
int sides;
if( node->contents == CONTENTS_SOLID )
return;
// add an efrag if the node is a leaf
if( node->contents < 0 )
{
if( !r_pefragtopnode )
r_pefragtopnode = node;
leaf = (mleaf_t *)node;
// grab an efrag off the free list
ef = clgame.free_efrags;
if( !ef )
{
MsgDev( D_ERROR, "too many efrags!\n" );
return; // no free fragments...
}
clgame.free_efrags = clgame.free_efrags->entnext;
ef->entity = r_addent;
// add the entity link
*lastlink = ef;
lastlink = &ef->entnext;
ef->entnext = NULL;
// set the leaf links
ef->leaf = leaf;
ef->leafnext = leaf->efrags;
leaf->efrags = ef;
return;
}
// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE( r_emins, r_emaxs, splitplane );
if( sides == 3 )
{
// split on this plane
// if this is the first splitter of this bmodel, remember it
if( !r_pefragtopnode ) r_pefragtopnode = node;
}
// recurse down the contacted sides
if( sides & 1 ) R_SplitEntityOnNode( node->children[0] );
if( sides & 2 ) R_SplitEntityOnNode( node->children[1] );
}
/*
===========
R_AddEfrags
===========
*/
void R_AddEfrags( cl_entity_t *ent )
{
int i;
if( !ent->model )
return;
r_addent = ent;
lastlink = &ent->efrag;
r_pefragtopnode = NULL;
for( i = 0; i < 3; i++ )
{
r_emins[i] = ent->origin[i] + ent->model->mins[i];
r_emaxs[i] = ent->origin[i] + ent->model->maxs[i];
}
R_SplitEntityOnNode( cl.worldmodel->nodes );
ent->topnode = r_pefragtopnode;
}
/*
================
R_StoreEfrags
================
*/
void R_StoreEfrags( efrag_t **ppefrag, int framecount )
{
cl_entity_t *pent;
model_t *clmodel;
efrag_t *pefrag;
while(( pefrag = *ppefrag ) != NULL )
{
pent = pefrag->entity;
clmodel = pent->model;
switch( clmodel->type )
{
case mod_alias:
case mod_brush:
case mod_studio:
case mod_sprite:
pent = pefrag->entity;
if( pent->visframe != framecount )
{
if( CL_AddVisibleEntity( pent, ET_FRAGMENTED ))
{
// mark that we've recorded this entity for this frame
pent->visframe = framecount;
}
}
ppefrag = &pefrag->leafnext;
break;
default:
Host_Error( "R_StoreEfrags: bad entity type %d\n", clmodel->type );
break;
}
}
}

430
engine/client/gl_rlight.c Normal file
View File

@ -0,0 +1,430 @@
/*
gl_rlight.c - dynamic and static lights
Copyright (C) 2010 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 "gl_local.h"
#include "pm_local.h"
#include "studio.h"
/*
=============================================================================
DYNAMIC LIGHTS
=============================================================================
*/
/*
==================
CL_RunLightStyles
==================
*/
void CL_RunLightStyles( void )
{
int i, k, flight, clight;
float l, lerpfrac, backlerp;
float frametime = (cl.time - cl.oldtime);
float scale;
lightstyle_t *ls;
if( !cl.worldmodel ) return;
scale = r_lighting_modulate->value;
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
for( i = 0, ls = cl.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
{
if( r_fullbright->value || !cl.worldmodel->lightdata )
{
tr.lightstylevalue[i] = 256 * 256;
continue;
}
if( !cl.paused && frametime <= 0.1f )
ls->time += frametime; // evaluate local time
flight = (int)Q_floor( ls->time * 10 );
clight = (int)Q_ceil( ls->time * 10 );
lerpfrac = ( ls->time * 10 ) - flight;
backlerp = 1.0f - lerpfrac;
if( !ls->length )
{
tr.lightstylevalue[i] = 256 * scale;
continue;
}
else if( ls->length == 1 )
{
// single length style so don't bother interpolating
tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
continue;
}
else if( !ls->interp || !cl_lightstyle_lerping->value )
{
tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
continue;
}
// interpolate animating light
// frame just gone
k = ls->map[flight % ls->length];
l = (float)( k * 22.0f ) * backlerp;
// upcoming frame
k = ls->map[clight % ls->length];
l += (float)( k * 22.0f ) * lerpfrac;
tr.lightstylevalue[i] = (int)l * scale;
}
}
/*
=============
R_MarkLights
=============
*/
void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
{
float dist;
msurface_t *surf;
int i;
if( node->contents < 0 )
return;
dist = PlaneDiff( light->origin, node->plane );
if( dist > light->radius )
{
R_MarkLights( light, bit, node->children[0] );
return;
}
if( dist < -light->radius )
{
R_MarkLights( light, bit, node->children[1] );
return;
}
// mark the polygons
surf = RI.currentmodel->surfaces + node->firstsurface;
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius ))
continue; // no intersection
if( surf->dlightframe != tr.dlightframecount )
{
surf->dlightbits = 0;
surf->dlightframe = tr.dlightframecount;
}
surf->dlightbits |= bit;
}
R_MarkLights( light, bit, node->children[0] );
R_MarkLights( light, bit, node->children[1] );
}
/*
=============
R_PushDlights
=============
*/
void R_PushDlights( void )
{
dlight_t *l;
int i;
tr.dlightframecount = tr.framecount;
l = cl_dlights;
RI.currententity = clgame.entities;
RI.currentmodel = RI.currententity->model;
for( i = 0; i < MAX_DLIGHTS; i++, l++ )
{
if( l->die < cl.time || !l->radius )
continue;
if( GL_FrustumCullSphere( &RI.frustum, l->origin, l->radius, 15 ))
continue;
R_MarkLights( l, 1<<i, RI.currentmodel->nodes );
}
}
/*
=============
R_CountDlights
=============
*/
int R_CountDlights( void )
{
dlight_t *l;
int i, numDlights = 0;
for( i = 0, l = cl_dlights; i < MAX_DLIGHTS; i++, l++ )
{
if( l->die < cl.time || !l->radius )
continue;
numDlights++;
}
return numDlights;
}
/*
=============
R_CountSurfaceDlights
=============
*/
int R_CountSurfaceDlights( msurface_t *surf )
{
int i, numDlights = 0;
for( i = 0; i < MAX_DLIGHTS; i++ )
{
if(!( surf->dlightbits & BIT( i )))
continue; // not lit by this light
numDlights++;
}
return numDlights;
}
/*
=======================================================================
AMBIENT LIGHTING
=======================================================================
*/
static float g_trace_fraction;
static vec3_t g_trace_lightspot;
/*
=================
R_RecursiveLightPoint
=================
*/
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end, qboolean debug )
{
float front, back, frac, midf;
int i, map, side, size;
float ds, dt, s, t;
int sample_size;
mextrasurf_t *info;
msurface_t *surf;
mtexinfo_t *tex;
color24 *lm;
vec3_t mid;
// didn't hit anything
if( !node || node->contents < 0 )
{
cv->r = cv->g = cv->b = cv->a = 0;
return false;
}
// calculate mid point
front = PlaneDiff( start, node->plane );
back = PlaneDiff( end, node->plane );
side = front < 0;
if(( back < 0 ) == side )
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end, debug );
frac = front / ( front - back );
VectorLerp( start, frac, end, mid );
midf = p1f + ( p2f - p1f ) * frac;
// co down front side
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid, debug ))
return true; // hit something
if(( back < 0 ) == side )
{
cv->r = cv->g = cv->b = cv->a = 0;
return false; // didn't hit anything
}
// check for impact on this node
surf = model->surfaces + node->firstsurface;
VectorCopy( mid, g_trace_lightspot );
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
int smax, tmax;
tex = surf->texinfo;
info = surf->info;
if( FBitSet( surf->flags, SURF_DRAWTILED ))
continue; // no lightmaps
s = DotProduct( mid, info->lmvecs[0] ) + info->lmvecs[0][3];
t = DotProduct( mid, info->lmvecs[1] ) + info->lmvecs[1][3];
if( s < info->lightmapmins[0] || t < info->lightmapmins[1] )
continue;
ds = s - info->lightmapmins[0];
dt = t - info->lightmapmins[1];
if ( ds > info->lightextents[0] || dt > info->lightextents[1] )
continue;
cv->r = cv->g = cv->b = cv->a = 0;
if( !surf->samples )
return true;
sample_size = Mod_SampleSizeForFace( surf );
smax = (info->lightextents[0] / sample_size) + 1;
tmax = (info->lightextents[1] / sample_size) + 1;
ds /= sample_size;
dt /= sample_size;
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
g_trace_fraction = midf;
size = smax * tmax;
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
uint scale = tr.lightstylevalue[surf->styles[map]];
if( tr.ignore_lightgamma )
{
cv->r += lm->r * scale;
cv->g += lm->g * scale;
cv->b += lm->b * scale;
}
else
{
cv->r += LightToTexGamma( lm->r ) * scale;
cv->g += LightToTexGamma( lm->g ) * scale;
cv->b += LightToTexGamma( lm->b ) * scale;
}
lm += size; // skip to next lightmap
}
return true;
}
// go down back side
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end, debug );
}
int R_LightTraceFilter( physent_t *pe )
{
if( !pe || pe->solid != SOLID_BSP || pe->info == 0 )
return 1;
return 0;
}
/*
=================
R_LightVec
check bspmodels to get light from
=================
*/
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
{
float last_fraction;
int i, maxEnts = 1;
colorVec light, cv;
if( cl.worldmodel && cl.worldmodel->lightdata )
{
light.r = light.g = light.b = light.a = 0;
last_fraction = 1.0f;
// get light from bmodels too
if( r_lighting_extended->value )
maxEnts = clgame.pmove->numphysent;
// check all the bsp-models
for( i = 0; i < maxEnts; i++ )
{
physent_t *pe = &clgame.pmove->physents[i];
vec3_t offset, start_l, end_l;
mnode_t *pnodes;
matrix4x4 matrix;
if( !pe->model || pe->model->type != mod_brush )
continue; // skip non-bsp models
pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode];
VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset );
VectorAdd( offset, pe->origin, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
// rotate start and end into the models frame of reference
if( !VectorIsNull( pe->angles ))
{
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
Matrix4x4_VectorITransform( matrix, start, start_l );
Matrix4x4_VectorITransform( matrix, end, end_l );
}
VectorClear( g_trace_lightspot );
g_trace_fraction = 1.0f;
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l, lspot != NULL ))
continue; // didn't hit anything
if( g_trace_fraction < last_fraction )
{
if( lspot ) VectorCopy( g_trace_lightspot, lspot );
light.r = Q_min(( cv.r >> 7 ), 255 );
light.g = Q_min(( cv.g >> 7 ), 255 );
light.b = Q_min(( cv.b >> 7 ), 255 );
last_fraction = g_trace_fraction;
}
}
}
else
{
light.r = light.g = light.b = 255;
light.a = 0;
}
return light;
}
/*
=================
R_LightPoint
light from floor
=================
*/
colorVec R_LightPoint( const vec3_t p0 )
{
vec3_t p1;
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f );
return R_LightVec( p0, p1, NULL );
}

1541
engine/client/gl_rmain.c Normal file

File diff suppressed because it is too large Load Diff

320
engine/client/gl_rmath.c Normal file
View File

@ -0,0 +1,320 @@
/*
gl_rmath.c - renderer mathlib
Copyright (C) 2010 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 "gl_local.h"
#include "mathlib.h"
#include "client.h"
/*
====================
V_CalcFov
====================
*/
float V_CalcFov( float *fov_x, float width, float height )
{
float x, half_fov_y;
if( *fov_x < 1.0f || *fov_x > 170.0f )
{
if( !cls.demoplayback )
MsgDev( D_ERROR, "V_CalcFov: bad fov %g!\n", *fov_x );
*fov_x = 90.0f;
}
x = width / tan( DEG2RAD( *fov_x ) * 0.5f );
half_fov_y = atan( height / x );
return RAD2DEG( half_fov_y ) * 2;
}
/*
====================
V_AdjustFov
====================
*/
void V_AdjustFov( float *fov_x, float *fov_y, float width, float height, qboolean lock_x )
{
float x, y;
if( width * 3 == 4 * height || width * 4 == height * 5 )
{
// 4:3 or 5:4 ratio
return;
}
if( lock_x )
{
*fov_y = 2 * atan((width * 3) / (height * 4) * tan( *fov_y * M_PI / 360.0 * 0.5 )) * 360 / M_PI;
return;
}
y = V_CalcFov( fov_x, 640, 480 );
x = *fov_x;
*fov_x = V_CalcFov( &y, height, width );
if( *fov_x < x ) *fov_x = x;
else *fov_y = y;
}
/*
========================================================================
Matrix4x4 operations (private to renderer)
========================================================================
*/
void Matrix4x4_Concat( matrix4x4 out, const matrix4x4 in1, const matrix4x4 in2 )
{
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0] + in1[0][3] * in2[3][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1] + in1[0][3] * in2[3][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2] + in1[0][3] * in2[3][2];
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3] * in2[3][3];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0] + in1[1][3] * in2[3][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1] + in1[1][3] * in2[3][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2] + in1[1][3] * in2[3][2];
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3] * in2[3][3];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0] + in1[2][3] * in2[3][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1] + in1[2][3] * in2[3][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2] + in1[2][3] * in2[3][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3] * in2[3][3];
out[3][0] = in1[3][0] * in2[0][0] + in1[3][1] * in2[1][0] + in1[3][2] * in2[2][0] + in1[3][3] * in2[3][0];
out[3][1] = in1[3][0] * in2[0][1] + in1[3][1] * in2[1][1] + in1[3][2] * in2[2][1] + in1[3][3] * in2[3][1];
out[3][2] = in1[3][0] * in2[0][2] + in1[3][1] * in2[1][2] + in1[3][2] * in2[2][2] + in1[3][3] * in2[3][2];
out[3][3] = in1[3][0] * in2[0][3] + in1[3][1] * in2[1][3] + in1[3][2] * in2[2][3] + in1[3][3] * in2[3][3];
}
/*
================
Matrix4x4_CreateProjection
NOTE: produce quake style world orientation
================
*/
void Matrix4x4_CreateProjection( matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar )
{
out[0][0] = ( 2.0f * zNear ) / ( xMax - xMin );
out[1][1] = ( 2.0f * zNear ) / ( yMax - yMin );
out[2][2] = -( zFar + zNear ) / ( zFar - zNear );
out[3][3] = out[0][1] = out[1][0] = out[3][0] = out[0][3] = out[3][1] = out[1][3] = 0.0f;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[0][2] = ( xMax + xMin ) / ( xMax - xMin );
out[1][2] = ( yMax + yMin ) / ( yMax - yMin );
out[3][2] = -1.0f;
out[2][3] = -( 2.0f * zFar * zNear ) / ( zFar - zNear );
}
void Matrix4x4_CreateOrtho( matrix4x4 out, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar )
{
out[0][0] = 2.0f / (xRight - xLeft);
out[1][1] = 2.0f / (yTop - yBottom);
out[2][2] = -2.0f / (zFar - zNear);
out[3][3] = 1.0f;
out[0][1] = out[0][2] = out[1][0] = out[1][2] = out[3][0] = out[3][1] = out[3][2] = 0.0f;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[0][3] = -(xRight + xLeft) / (xRight - xLeft);
out[1][3] = -(yTop + yBottom) / (yTop - yBottom);
out[2][3] = -(zFar + zNear) / (zFar - zNear);
}
/*
================
Matrix4x4_CreateModelview
NOTE: produce quake style world orientation
================
*/
void Matrix4x4_CreateModelview( matrix4x4 out )
{
out[0][0] = out[1][1] = out[2][2] = 0.0f;
out[3][0] = out[0][3] = 0.0f;
out[3][1] = out[1][3] = 0.0f;
out[3][2] = out[2][3] = 0.0f;
out[3][3] = 1.0f;
out[1][0] = out[0][2] = out[2][1] = 0.0f;
out[2][0] = out[0][1] = -1.0f;
out[1][2] = 1.0f;
}
void Matrix4x4_ToArrayFloatGL( const matrix4x4 in, float out[16] )
{
out[ 0] = in[0][0];
out[ 1] = in[1][0];
out[ 2] = in[2][0];
out[ 3] = in[3][0];
out[ 4] = in[0][1];
out[ 5] = in[1][1];
out[ 6] = in[2][1];
out[ 7] = in[3][1];
out[ 8] = in[0][2];
out[ 9] = in[1][2];
out[10] = in[2][2];
out[11] = in[3][2];
out[12] = in[0][3];
out[13] = in[1][3];
out[14] = in[2][3];
out[15] = in[3][3];
}
void Matrix4x4_FromArrayFloatGL( matrix4x4 out, const float in[16] )
{
out[0][0] = in[0];
out[1][0] = in[1];
out[2][0] = in[2];
out[3][0] = in[3];
out[0][1] = in[4];
out[1][1] = in[5];
out[2][1] = in[6];
out[3][1] = in[7];
out[0][2] = in[8];
out[1][2] = in[9];
out[2][2] = in[10];
out[3][2] = in[11];
out[0][3] = in[12];
out[1][3] = in[13];
out[2][3] = in[14];
out[3][3] = in[15];
}
void Matrix4x4_CreateTranslate( matrix4x4 out, float x, float y, float z )
{
out[0][0] = 1.0f;
out[0][1] = 0.0f;
out[0][2] = 0.0f;
out[0][3] = x;
out[1][0] = 0.0f;
out[1][1] = 1.0f;
out[1][2] = 0.0f;
out[1][3] = y;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = 1.0f;
out[2][3] = z;
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
void Matrix4x4_CreateRotate( matrix4x4 out, float angle, float x, float y, float z )
{
float len, c, s;
len = x * x + y * y + z * z;
if( len != 0.0f ) len = 1.0f / sqrt( len );
x *= len;
y *= len;
z *= len;
angle *= (-M_PI / 180.0f);
SinCos( angle, &s, &c );
out[0][0]=x * x + c * (1 - x * x);
out[0][1]=x * y * (1 - c) + z * s;
out[0][2]=z * x * (1 - c) - y * s;
out[0][3]=0.0f;
out[1][0]=x * y * (1 - c) - z * s;
out[1][1]=y * y + c * (1 - y * y);
out[1][2]=y * z * (1 - c) + x * s;
out[1][3]=0.0f;
out[2][0]=z * x * (1 - c) + y * s;
out[2][1]=y * z * (1 - c) - x * s;
out[2][2]=z * z + c * (1 - z * z);
out[2][3]=0.0f;
out[3][0]=0.0f;
out[3][1]=0.0f;
out[3][2]=0.0f;
out[3][3]=1.0f;
}
void Matrix4x4_CreateScale( matrix4x4 out, float x )
{
out[0][0] = x;
out[0][1] = 0.0f;
out[0][2] = 0.0f;
out[0][3] = 0.0f;
out[1][0] = 0.0f;
out[1][1] = x;
out[1][2] = 0.0f;
out[1][3] = 0.0f;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = x;
out[2][3] = 0.0f;
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z )
{
out[0][0] = x;
out[0][1] = 0.0f;
out[0][2] = 0.0f;
out[0][3] = 0.0f;
out[1][0] = 0.0f;
out[1][1] = y;
out[1][2] = 0.0f;
out[1][3] = 0.0f;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = z;
out[2][3] = 0.0f;
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
void Matrix4x4_ConcatTranslate( matrix4x4 out, float x, float y, float z )
{
matrix4x4 base, temp;
Matrix4x4_Copy( base, out );
Matrix4x4_CreateTranslate( temp, x, y, z );
Matrix4x4_Concat( out, base, temp );
}
void Matrix4x4_ConcatRotate( matrix4x4 out, float angle, float x, float y, float z )
{
matrix4x4 base, temp;
Matrix4x4_Copy( base, out );
Matrix4x4_CreateRotate( temp, angle, x, y, z );
Matrix4x4_Concat( out, base, temp );
}
void Matrix4x4_ConcatScale( matrix4x4 out, float x )
{
matrix4x4 base, temp;
Matrix4x4_Copy( base, out );
Matrix4x4_CreateScale( temp, x );
Matrix4x4_Concat( out, base, temp );
}
void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z )
{
matrix4x4 base, temp;
Matrix4x4_Copy( base, out );
Matrix4x4_CreateScale3( temp, x, y, z );
Matrix4x4_Concat( out, base, temp );
}

514
engine/client/gl_rmisc.c Normal file
View File

@ -0,0 +1,514 @@
/*
gl_rmisc.c - renderer misceallaneous
Copyright (C) 2010 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 "gl_local.h"
#include "mod_local.h"
#include "shake.h"
typedef struct
{
const char *texname;
const char *detail;
const char material;
int lMin;
int lMax;
} dmaterial_t;
typedef struct
{
char texname[64]; // shortname
imgfilter_t filter;
} dfilter_t;
dfilter_t *tex_filters[MAX_TEXTURES];
int num_texfilters;
// default rules for apply detail textures.
// maybe move this to external script?
static const dmaterial_t detail_table[] =
{
{ "crt", "dt_conc", 'C', 0, 0 }, // concrete
{ "rock", "dt_rock1", 'C', 0, 0 },
{ "conc", "dt_conc", 'C', 0, 0 },
{ "brick", "dt_brick", 'C', 0, 0 },
{ "wall", "dt_brick", 'C', 0, 0 },
{ "city", "dt_conc", 'C', 0, 0 },
{ "crete", "dt_conc", 'C', 0, 0 },
{ "generic", "dt_brick", 'C', 0, 0 },
{ "floor", "dt_conc", 'C', 0, 0 },
{ "metal", "dt_metal%i", 'M', 1, 2 }, // metal
{ "mtl", "dt_metal%i", 'M', 1, 2 },
{ "pipe", "dt_metal%i", 'M', 1, 2 },
{ "elev", "dt_metal%i", 'M', 1, 2 },
{ "sign", "dt_metal%i", 'M', 1, 2 },
{ "barrel", "dt_metal%i", 'M', 1, 2 },
{ "bath", "dt_ssteel1", 'M', 1, 2 },
{ "tech", "dt_ssteel1", 'M', 1, 2 },
{ "refbridge", "dt_metal%i", 'M', 1, 2 },
{ "panel", "dt_ssteel1", 'M', 0, 0 },
{ "brass", "dt_ssteel1", 'M', 0, 0 },
{ "rune", "dt_metal%i", 'M', 1, 2 },
{ "car", "dt_metal%i", 'M', 1, 2 },
{ "circuit", "dt_metal%i", 'M', 1, 2 },
{ "steel", "dt_ssteel1", 'M', 0, 0 },
{ "dirt", "dt_ground%i", 'D', 1, 5 }, // dirt
{ "drt", "dt_ground%i", 'D', 1, 5 },
{ "out", "dt_ground%i", 'D', 1, 5 },
{ "grass", "dt_grass1", 'D', 0, 0 },
{ "mud", "dt_carpet1", 'D', 0, 0 },
{ "vent", "dt_ssteel1", 'V', 1, 4 }, // vent
{ "duct", "dt_ssteel1", 'V', 1, 4 },
{ "tile", "dt_smooth%i", 'T', 1, 2 },
{ "labflr", "dt_smooth%i", 'T', 1, 2 },
{ "bath", "dt_smooth%i", 'T', 1, 2 },
{ "grate", "dt_stone%i", 'G', 1, 4 }, // vent
{ "stone", "dt_stone%i", 'G', 1, 4 },
{ "grt", "dt_stone%i", 'G', 1, 4 },
{ "wiz", "dt_wood%i", 'W', 1, 3 },
{ "wood", "dt_wood%i", 'W', 1, 3 },
{ "wizwood", "dt_wood%i", 'W', 1, 3 },
{ "wd", "dt_wood%i", 'W', 1, 3 },
{ "table", "dt_wood%i", 'W', 1, 3 },
{ "board", "dt_wood%i", 'W', 1, 3 },
{ "chair", "dt_wood%i", 'W', 1, 3 },
{ "brd", "dt_wood%i", 'W', 1, 3 },
{ "carp", "dt_carpet1", 'W', 1, 3 },
{ "book", "dt_wood%i", 'W', 1, 3 },
{ "box", "dt_wood%i", 'W', 1, 3 },
{ "cab", "dt_wood%i", 'W', 1, 3 },
{ "couch", "dt_wood%i", 'W', 1, 3 },
{ "crate", "dt_wood%i", 'W', 1, 3 },
{ "poster", "dt_plaster%i", 'W', 1, 2 },
{ "sheet", "dt_plaster%i", 'W', 1, 2 },
{ "stucco", "dt_plaster%i", 'W', 1, 2 },
{ "comp", "dt_smooth1", 'P', 0, 0 },
{ "cmp", "dt_smooth1", 'P', 0, 0 },
{ "elec", "dt_smooth1", 'P', 0, 0 },
{ "vend", "dt_smooth1", 'P', 0, 0 },
{ "monitor", "dt_smooth1", 'P', 0, 0 },
{ "phone", "dt_smooth1", 'P', 0, 0 },
{ "glass", "dt_ssteel1", 'Y', 0, 0 },
{ "window", "dt_ssteel1", 'Y', 0, 0 },
{ "flesh", "dt_rough1", 'F', 0, 0 },
{ "meat", "dt_rough1", 'F', 0, 0 },
{ "fls", "dt_rough1", 'F', 0, 0 },
{ "ground", "dt_ground%i", 'D', 1, 5 },
{ "gnd", "dt_ground%i", 'D', 1, 5 },
{ "snow", "dt_snow%i", 'O', 1, 2 }, // snow
{ "wswamp", "dt_smooth1", 'W', 0, 0 },
{ NULL, NULL, 0, 0, 0 }
};
static const char *R_DetailTextureForName( const char *name )
{
const dmaterial_t *table;
if( !name || !*name ) return NULL;
if( !Q_strnicmp( name, "sky", 3 ))
return NULL; // never details for sky
// never apply details for liquids
if( !Q_strnicmp( name + 1, "!lava", 5 ))
return NULL;
if( !Q_strnicmp( name + 1, "!slime", 6 ))
return NULL;
if( !Q_strnicmp( name, "!cur_90", 7 ))
return NULL;
if( !Q_strnicmp( name, "!cur_0", 6 ))
return NULL;
if( !Q_strnicmp( name, "!cur_270", 8 ))
return NULL;
if( !Q_strnicmp( name, "!cur_180", 8 ))
return NULL;
if( !Q_strnicmp( name, "!cur_up", 7 ))
return NULL;
if( !Q_strnicmp( name, "!cur_dwn", 8 ))
return NULL;
if( name[0] == '!' )
return NULL;
// never apply details to the special textures
if( !Q_strnicmp( name, "origin", 6 ))
return NULL;
if( !Q_strnicmp( name, "clip", 4 ))
return NULL;
if( !Q_strnicmp( name, "hint", 4 ))
return NULL;
if( !Q_strnicmp( name, "skip", 4 ))
return NULL;
if( !Q_strnicmp( name, "translucent", 11 ))
return NULL;
if( !Q_strnicmp( name, "3dsky", 5 )) // xash-mod support :-)
return NULL;
if( !Q_strnicmp( name, "scroll", 6 ))
return NULL;
if( name[0] == '@' )
return NULL;
// last check ...
if( !Q_strnicmp( name, "null", 4 ))
return NULL;
for( table = detail_table; table && table->texname; table++ )
{
if( Q_stristr( name, table->texname ))
{
if(( table->lMin + table->lMax ) > 0 )
return va( table->detail, COM_RandomLong( table->lMin, table->lMax ));
return table->detail;
}
}
return NULL;
}
void R_CreateDetailTexturesList( const char *filename )
{
file_t *detail_txt = NULL;
float xScale, yScale;
const char *detail_name;
texture_t *tex;
rgbdata_t *pic;
int i;
for( i = 0; i < cl.worldmodel->numtextures; i++ )
{
tex = cl.worldmodel->textures[i];
detail_name = R_DetailTextureForName( tex->name );
if( !detail_name ) continue;
// detailtexture detected
if( detail_name )
{
if( !detail_txt ) detail_txt = FS_Open( filename, "w", false );
if( !detail_txt )
{
MsgDev( D_ERROR, "Can't write %s\n", filename );
break;
}
pic = FS_LoadImage( va( "gfx/detail/%s", detail_name ), NULL, 0 );
if( pic )
{
xScale = (pic->width / (float)tex->width) * gl_detailscale->value;
yScale = (pic->height / (float)tex->height) * gl_detailscale->value;
FS_FreeImage( pic );
}
else xScale = yScale = 10.0f;
// store detailtexture description
FS_Printf( detail_txt, "%s detail/%s %.2f %.2f\n", tex->name, detail_name, xScale, yScale );
}
}
if( detail_txt ) FS_Close( detail_txt );
}
void R_ParseDetailTextures( const char *filename )
{
char *afile, *pfile;
string token, texname;
string detail_texname;
string detail_path;
float xScale, yScale;
texture_t *tex;
int i;
if( r_detailtextures->value >= 2 && !FS_FileExists( filename, false ))
{
// use built-in generator for detail textures
R_CreateDetailTexturesList( filename );
}
afile = FS_LoadFile( filename, NULL, false );
if( !afile ) return;
pfile = afile;
// format: 'texturename' 'detailtexture' 'xScale' 'yScale'
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
{
texname[0] = '\0';
detail_texname[0] = '\0';
// read texname
if( token[0] == '{' )
{
// NOTE: COM_ParseFile handled some symbols seperately
// this code will be fix it
pfile = COM_ParseFile( pfile, token );
Q_strncat( texname, "{", sizeof( texname ));
Q_strncat( texname, token, sizeof( texname ));
}
else Q_strncpy( texname, token, sizeof( texname ));
// read detailtexture name
pfile = COM_ParseFile( pfile, token );
Q_strncat( detail_texname, token, sizeof( detail_texname ));
// trying the scales or '{'
pfile = COM_ParseFile( pfile, token );
// read second part of detailtexture name
if( token[0] == '{' )
{
Q_strncat( detail_texname, token, sizeof( detail_texname ));
pfile = COM_ParseFile( pfile, token ); // read scales
Q_strncat( detail_texname, token, sizeof( detail_texname ));
pfile = COM_ParseFile( pfile, token ); // parse scales
}
Q_snprintf( detail_path, sizeof( detail_path ), "gfx/%s", detail_texname );
// read scales
xScale = Q_atof( token );
pfile = COM_ParseFile( pfile, token );
yScale = Q_atof( token );
if( xScale <= 0.0f || yScale <= 0.0f )
continue;
// search for existing texture and uploading detail texture
for( i = 0; i < cl.worldmodel->numtextures; i++ )
{
tex = cl.worldmodel->textures[i];
if( Q_stricmp( tex->name, texname ))
continue;
tex->dt_texturenum = GL_LoadTexture( detail_path, NULL, 0, TF_FORCE_COLOR, NULL );
// texture is loaded
if( tex->dt_texturenum )
{
gltexture_t *glt;
glt = R_GetTexture( tex->gl_texturenum );
glt->xscale = xScale;
glt->yscale = yScale;
}
break;
}
}
Mem_Free( afile );
}
void R_ParseTexFilters( const char *filename )
{
char *afile, *pfile;
string token, texname;
dfilter_t *tf;
int i;
afile = FS_LoadFile( filename, NULL, false );
if( !afile ) return;
pfile = afile;
// format: 'texturename' 'filtername' 'factor' 'bias' 'blendmode' 'grayscale'
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
{
imgfilter_t filter;
memset( &filter, 0, sizeof( filter ));
Q_strncpy( texname, token, sizeof( texname ));
// parse filter
pfile = COM_ParseFile( pfile, token );
if( !Q_stricmp( token, "blur" ))
filter.filter = BLUR_FILTER;
else if( !Q_stricmp( token, "blur2" ))
filter.filter = BLUR_FILTER2;
else if( !Q_stricmp( token, "edge" ))
filter.filter = EDGE_FILTER;
else if( !Q_stricmp( token, "emboss" ))
filter.filter = EMBOSS_FILTER;
// reading factor
pfile = COM_ParseFile( pfile, token );
filter.factor = Q_atof( token );
// reading bias
pfile = COM_ParseFile( pfile, token );
filter.bias = Q_atof( token );
// reading blendFunc
pfile = COM_ParseFile( pfile, token );
if( !Q_stricmp( token, "modulate" ) || !Q_stricmp( token, "GL_MODULATE" ))
filter.blendFunc = GL_MODULATE;
else if( !Q_stricmp( token, "replace" ) || !Q_stricmp( token, "GL_REPLACE" ))
filter.blendFunc = GL_REPLACE;
else if( !Q_stricmp( token, "add" ) || !Q_stricmp( token, "GL_ADD" ))
filter.blendFunc = GL_ADD;
else if( !Q_stricmp( token, "decal" ) || !Q_stricmp( token, "GL_DECAL" ))
filter.blendFunc = GL_DECAL;
else if( !Q_stricmp( token, "blend" ) || !Q_stricmp( token, "GL_BLEND" ))
filter.blendFunc = GL_BLEND;
else if( !Q_stricmp( token, "add_signed" ) || !Q_stricmp( token, "GL_ADD_SIGNED" ))
filter.blendFunc = GL_ADD_SIGNED;
else MsgDev( D_WARN, "unknown blendFunc '%s' specified for texture '%s'\n", texname, token );
// reading flags
pfile = COM_ParseFile( pfile, token );
filter.flags = Q_atoi( token );
// make sure what factor is not zeroed
if( filter.factor == 0.0f )
{
MsgDev( D_WARN, "texfilter for texture %s has factor 0! Ignored\n", texname );
continue;
}
// check if already existed
for( i = 0; i < num_texfilters; i++ )
{
tf = tex_filters[i];
if( !Q_stricmp( tf->texname, texname ))
{
MsgDev( D_WARN, "texture %s has specified multiple filters! Ignored\n", texname );
break;
}
}
if( i != num_texfilters )
continue; // already specified
// allocate new texfilter
tf = Z_Malloc( sizeof( dfilter_t ));
tex_filters[num_texfilters++] = tf;
Q_strncpy( tf->texname, texname, sizeof( tf->texname ));
tf->filter = filter;
}
MsgDev( D_INFO, "%i texture filters parsed\n", num_texfilters );
Mem_Free( afile );
}
imgfilter_t *R_FindTexFilter( const char *texname )
{
dfilter_t *tf;
int i;
for( i = 0; i < num_texfilters; i++ )
{
tf = tex_filters[i];
if( !Q_stricmp( tf->texname, texname ))
return &tf->filter;
}
return NULL;
}
/*
=======================
R_ClearStaticEntities
e.g. by demo request
=======================
*/
void R_ClearStaticEntities( void )
{
int i;
if( host.type == HOST_DEDICATED )
return;
// clear out efrags in case the level hasn't been reloaded
for( i = 0; i < cl.worldmodel->numleafs; i++ )
cl.worldmodel->leafs[i+1].efrags = NULL;
clgame.numStatics = 0;
CL_ClearEfrags ();
}
void R_NewMap( void )
{
texture_t *tx;
int i;
R_ClearDecals(); // clear all level decals
// upload detailtextures
if( r_detailtextures->value )
{
string mapname, filepath;
Q_strncpy( mapname, cl.worldmodel->name, sizeof( mapname ));
COM_StripExtension( mapname );
Q_sprintf( filepath, "%s_detail.txt", mapname );
R_ParseDetailTextures( filepath );
}
if( v_dark->value )
{
screenfade_t *sf = &clgame.fade;
client_textmessage_t *title;
title = CL_TextMessageGet( "GAMETITLE" );
if( title )
{
// get settings from titles.txt
sf->fadeEnd = title->holdtime + title->fadeout;
sf->fadeReset = title->fadeout;
}
else sf->fadeEnd = sf->fadeReset = 5.0f;
sf->fadeFlags = FFADE_IN;
sf->fader = sf->fadeg = sf->fadeb = 0;
sf->fadealpha = 255;
sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset;
sf->fadeReset += cl.time;
sf->fadeEnd += sf->fadeReset;
Cvar_SetValue( "v_dark", 0.0f );
}
// clear out efrags in case the level hasn't been reloaded
for( i = 0; i < cl.worldmodel->numleafs; i++ )
cl.worldmodel->leafs[i+1].efrags = NULL;
tr.skytexturenum = -1;
pglDisable( GL_FOG );
// clearing texture chains
for( i = 0; i < cl.worldmodel->numtextures; i++ )
{
if( !cl.worldmodel->textures[i] )
continue;
tx = cl.worldmodel->textures[i];
if( !Q_strncmp( tx->name, "sky", 3 ) && tx->width == 256 && tx->height == 128 )
tr.skytexturenum = i;
tx->texturechain = NULL;
}
R_SetupSky( clgame.movevars.skyName );
GL_BuildLightmaps ();
}

1667
engine/client/gl_rpart.c Normal file

File diff suppressed because it is too large Load Diff

2190
engine/client/gl_rsurf.c Normal file

File diff suppressed because it is too large Load Diff

1091
engine/client/gl_sprite.c Normal file

File diff suppressed because it is too large Load Diff

3939
engine/client/gl_studio.c Normal file

File diff suppressed because it is too large Load Diff

1766
engine/client/gl_vidnt.c Normal file

File diff suppressed because it is too large Load Diff

815
engine/client/gl_warp.c Normal file
View File

@ -0,0 +1,815 @@
/*
gl_warp.c - sky and water polygons
Copyright (C) 2010 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 "gl_local.h"
#include "wadfile.h"
#define SKYCLOUDS_QUALITY 12
#define MAX_CLIP_VERTS 128 // skybox clip vertices
#define TURBSCALE ( 256.0f / ( M_PI2 ))
static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
static const vec3_t skyclip[6] =
{
{ 1, 1, 0 },
{ 1, -1, 0 },
{ 0, -1, 1 },
{ 0, 1, 1 },
{ 1, 0, 1 },
{ -1, 0, 1 }
};
// 1 = s, 2 = t, 3 = 2048
static const int st_to_vec[6][3] =
{
{ 3, -1, 2 },
{ -3, 1, 2 },
{ 1, 3, 2 },
{ -1, -3, 2 },
{ -2, -1, 3 }, // 0 degrees yaw, look straight up
{ 2, -1, -3 } // look straight down
};
// s = [0]/[2], t = [1]/[2]
static const int vec_to_st[6][3] =
{
{ -2, 3, 1 },
{ 2, 3, -1 },
{ 1, 3, 2 },
{ -1, 3, -2 },
{ -2, -1, 3 },
{ -2, 1, -3 }
};
// speed up sin calculations
float r_turbsin[] =
{
#include "warpsin.h"
};
#define SKYBOX_MISSED 0
#define SKYBOX_HLSTYLE 1
#define SKYBOX_Q1STYLE 2
static int CheckSkybox( const char *name )
{
const char *skybox_ext[3] = { "dds", "tga", "bmp" };
int i, j, num_checked_sides;
const char *sidename;
// search for skybox images
for( i = 0; i < 3; i++ )
{
num_checked_sides = 0;
for( j = 0; j < 6; j++ )
{
// build side name
sidename = va( "%s%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] );
if( FS_FileExists( sidename, false ))
num_checked_sides++;
}
if( num_checked_sides == 6 )
return SKYBOX_HLSTYLE; // image exists
for( j = 0; j < 6; j++ )
{
// build side name
sidename = va( "%s_%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] );
if( FS_FileExists( sidename, false ))
num_checked_sides++;
}
if( num_checked_sides == 6 )
return SKYBOX_Q1STYLE; // images exists
}
return SKYBOX_MISSED;
}
void DrawSkyPolygon( int nump, vec3_t vecs )
{
int i, j, axis;
float s, t, dv, *vp;
vec3_t v, av;
// decide which face it maps to
VectorClear( v );
for( i = 0, vp = vecs; i < nump; i++, vp += 3 )
VectorAdd( vp, v, v );
av[0] = fabs( v[0] );
av[1] = fabs( v[1] );
av[2] = fabs( v[2] );
if( av[0] > av[1] && av[0] > av[2] )
axis = (v[0] < 0) ? 1 : 0;
else if( av[1] > av[2] && av[1] > av[0] )
axis = (v[1] < 0) ? 3 : 2;
else axis = (v[2] < 0) ? 5 : 4;
// project new texture coords
for( i = 0; i < nump; i++, vecs += 3 )
{
j = vec_to_st[axis][2];
dv = (j > 0) ? vecs[j-1] : -vecs[-j-1];
if( dv == 0.0f ) continue;
j = vec_to_st[axis][0];
s = (j < 0) ? -vecs[-j-1] / dv : vecs[j-1] / dv;
j = vec_to_st[axis][1];
t = (j < 0) ? -vecs[-j-1] / dv : vecs[j-1] / dv;
if( s < RI.skyMins[0][axis] ) RI.skyMins[0][axis] = s;
if( t < RI.skyMins[1][axis] ) RI.skyMins[1][axis] = t;
if( s > RI.skyMaxs[0][axis] ) RI.skyMaxs[0][axis] = s;
if( t > RI.skyMaxs[1][axis] ) RI.skyMaxs[1][axis] = t;
}
}
/*
==============
ClipSkyPolygon
==============
*/
void ClipSkyPolygon( int nump, vec3_t vecs, int stage )
{
const float *norm;
float *v, d, e;
qboolean front, back;
float dists[MAX_CLIP_VERTS + 1];
int sides[MAX_CLIP_VERTS + 1];
vec3_t newv[2][MAX_CLIP_VERTS + 1];
int newc[2];
int i, j;
if( nump > MAX_CLIP_VERTS )
Host_Error( "ClipSkyPolygon: MAX_CLIP_VERTS\n" );
loc1:
if( stage == 6 )
{
// fully clipped, so draw it
DrawSkyPolygon( nump, vecs );
return;
}
front = back = false;
norm = skyclip[stage];
for( i = 0, v = vecs; i < nump; i++, v += 3 )
{
d = DotProduct( v, norm );
if( d > ON_EPSILON )
{
front = true;
sides[i] = SIDE_FRONT;
}
else if( d < -ON_EPSILON )
{
back = true;
sides[i] = SIDE_BACK;
}
else
{
sides[i] = SIDE_ON;
}
dists[i] = d;
}
if( !front || !back )
{
// not clipped
stage++;
goto loc1;
}
// clip it
sides[i] = sides[0];
dists[i] = dists[0];
VectorCopy( vecs, ( vecs + ( i * 3 )));
newc[0] = newc[1] = 0;
for( i = 0, v = vecs; i < nump; i++, v += 3 )
{
switch( sides[i] )
{
case SIDE_FRONT:
VectorCopy( v, newv[0][newc[0]] );
newc[0]++;
break;
case SIDE_BACK:
VectorCopy( v, newv[1][newc[1]] );
newc[1]++;
break;
case SIDE_ON:
VectorCopy( v, newv[0][newc[0]] );
newc[0]++;
VectorCopy( v, newv[1][newc[1]] );
newc[1]++;
break;
}
if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] )
continue;
d = dists[i] / ( dists[i] - dists[i+1] );
for( j = 0; j < 3; j++ )
{
e = v[j] + d * ( v[j+3] - v[j] );
newv[0][newc[0]][j] = e;
newv[1][newc[1]][j] = e;
}
newc[0]++;
newc[1]++;
}
// continue
ClipSkyPolygon( newc[0], newv[0][0], stage + 1 );
ClipSkyPolygon( newc[1], newv[1][0], stage + 1 );
}
void MakeSkyVec( float s, float t, int axis )
{
int j, k, farclip;
vec3_t v, b;
farclip = RI.farClip;
b[0] = s * (farclip >> 1);
b[1] = t * (farclip >> 1);
b[2] = (farclip >> 1);
for( j = 0; j < 3; j++ )
{
k = st_to_vec[axis][j];
v[j] = (k < 0) ? -b[-k-1] : b[k-1];
v[j] += RI.cullorigin[j];
}
// avoid bilerp seam
s = (s + 1.0f) * 0.5f;
t = (t + 1.0f) * 0.5f;
if( s < 1.0f / 512.0f )
s = 1.0f / 512.0f;
else if( s > 511.0f / 512.0f )
s = 511.0f / 512.0f;
if( t < 1.0f / 512.0f )
t = 1.0f / 512.0f;
else if( t > 511.0f / 512.0f )
t = 511.0f / 512.0f;
t = 1.0f - t;
pglTexCoord2f( s, t );
pglVertex3fv( v );
}
/*
==============
R_ClearSkyBox
==============
*/
void R_ClearSkyBox( void )
{
int i;
for( i = 0; i < 6; i++ )
{
RI.skyMins[0][i] = RI.skyMins[1][i] = 9999999.0f;
RI.skyMaxs[0][i] = RI.skyMaxs[1][i] = -9999999.0f;
}
}
/*
=================
R_AddSkyBoxSurface
=================
*/
void R_AddSkyBoxSurface( msurface_t *fa )
{
vec3_t verts[MAX_CLIP_VERTS];
glpoly_t *p;
float *v;
int i;
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && fa->polys && !FBitSet( world.flags, FWORLD_CUSTOM_SKYBOX ))
{
glpoly_t *p = fa->polys;
// draw the sky poly
pglBegin( GL_POLYGON );
for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
{
pglTexCoord2f( v[3], v[4] );
pglVertex3fv( v );
}
pglEnd ();
}
// calculate vertex values for sky box
for( p = fa->polys; p; p = p->next )
{
for( i = 0; i < p->numverts; i++ )
VectorSubtract( p->verts[i], RI.cullorigin, verts[i] );
ClipSkyPolygon( p->numverts, verts[0], 0 );
}
}
/*
==============
R_UnloadSkybox
Unload previous skybox
==============
*/
void R_UnloadSkybox( void )
{
int i;
// release old skybox
for( i = 0; i < 6; i++ )
{
if( !tr.skyboxTextures[i] ) continue;
GL_FreeTexture( tr.skyboxTextures[i] );
}
tr.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes)
memset( tr.skyboxTextures, 0, sizeof( tr.skyboxTextures ));
ClearBits( world.flags, FWORLD_CUSTOM_SKYBOX );
}
/*
==============
R_DrawSkybox
==============
*/
void R_DrawSkyBox( void )
{
int i;
RI.isSkyVisible = true;
// don't fogging skybox (this fix old Half-Life bug)
if( !RI.fogSkybox ) R_AllowFog( false );
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
for( i = 0; i < 6; i++ )
{
if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] )
continue;
if( tr.skyboxTextures[r_skyTexOrder[i]] )
GL_Bind( GL_TEXTURE0, tr.skyboxTextures[r_skyTexOrder[i]] );
else GL_Bind( GL_TEXTURE0, tr.skyTexture ); // stub
pglBegin( GL_QUADS );
MakeSkyVec( RI.skyMins[0][i], RI.skyMins[1][i], i );
MakeSkyVec( RI.skyMins[0][i], RI.skyMaxs[1][i], i );
MakeSkyVec( RI.skyMaxs[0][i], RI.skyMaxs[1][i], i );
MakeSkyVec( RI.skyMaxs[0][i], RI.skyMins[1][i], i );
pglEnd();
}
if( !RI.fogSkybox )
R_AllowFog( true );
R_LoadIdentity();
}
/*
===============
R_SetupSky
===============
*/
void R_SetupSky( const char *skyboxname )
{
char loadname[MAX_QPATH];
char sidename[MAX_QPATH];
int i, result;
if( !COM_CheckString( skyboxname ))
{
R_UnloadSkybox();
return; // clear old skybox
}
Q_snprintf( loadname, sizeof( loadname ), "gfx/env/%s", skyboxname );
COM_StripExtension( loadname );
// kill the underline suffix to find them manually later
if( loadname[Q_strlen( loadname ) - 1] == '_' )
loadname[Q_strlen( loadname ) - 1] = '\0';
result = CheckSkybox( loadname );
// to prevent infinite recursion if default skybox was missed
if( result == SKYBOX_MISSED && Q_stricmp( loadname, DEFAULT_SKYBOX_PATH ))
{
Con_Reportf( S_WARN "missed or incomplete skybox '%s'\n", skyboxname );
R_SetupSky( "desert" ); // force to default
return;
}
// release old skybox
R_UnloadSkybox();
Con_DPrintf( "SKY: " );
for( i = 0; i < 6; i++ )
{
if( result == SKYBOX_HLSTYLE )
Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
if( !tr.skyboxTextures[i] ) break;
Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " );
}
if( i == 6 )
{
SetBits( world.flags, FWORLD_CUSTOM_SKYBOX );
Con_DPrintf( "done\n" );
return; // loaded
}
Con_DPrintf( "^2failed\n" );
R_UnloadSkybox();
}
//==============================================================================
//
// RENDER CLOUDS
//
//==============================================================================
/*
==============
R_CloudVertex
==============
*/
void R_CloudVertex( float s, float t, int axis, vec3_t v )
{
int j, k, farclip;
vec3_t b;
farclip = RI.farClip;
b[0] = s * (farclip >> 1);
b[1] = t * (farclip >> 1);
b[2] = (farclip >> 1);
for( j = 0; j < 3; j++ )
{
k = st_to_vec[axis][j];
v[j] = (k < 0) ? -b[-k-1] : b[k-1];
v[j] += RI.cullorigin[j];
}
}
/*
=============
R_CloudTexCoord
=============
*/
void R_CloudTexCoord( vec3_t v, float speed, float *s, float *t )
{
float length, speedscale;
vec3_t dir;
speedscale = cl.time * speed;
speedscale -= (int)speedscale & ~127;
VectorSubtract( v, RI.vieworg, dir );
dir[2] *= 3.0f; // flatten the sphere
length = VectorLength( dir );
length = 6.0f * 63.0f / length;
*s = ( speedscale + dir[0] * length ) * (1.0f / 128.0f);
*t = ( speedscale + dir[1] * length ) * (1.0f / 128.0f);
}
/*
===============
R_CloudDrawPoly
===============
*/
void R_CloudDrawPoly( glpoly_t *p )
{
float s, t;
float *v;
int i;
GL_SetRenderMode( kRenderNormal );
GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
pglBegin( GL_QUADS );
for( i = 0, v = p->verts[0]; i < 4; i++, v += VERTEXSIZE )
{
R_CloudTexCoord( v, 8.0f, &s, &t );
pglTexCoord2f( s, t );
pglVertex3fv( v );
}
pglEnd();
GL_SetRenderMode( kRenderTransTexture );
GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
pglBegin( GL_QUADS );
for( i = 0, v = p->verts[0]; i < 4; i++, v += VERTEXSIZE )
{
R_CloudTexCoord( v, 16.0f, &s, &t );
pglTexCoord2f( s, t );
pglVertex3fv( v );
}
pglEnd();
pglDisable( GL_BLEND );
}
/*
==============
R_CloudRenderSide
==============
*/
void R_CloudRenderSide( int axis )
{
vec3_t verts[4];
float di, qi, dj, qj;
vec3_t vup, vright;
vec3_t temp, temp2;
glpoly_t p[1];
int i, j;
R_CloudVertex( -1.0f, -1.0f, axis, verts[0] );
R_CloudVertex( -1.0f, 1.0f, axis, verts[1] );
R_CloudVertex( 1.0f, 1.0f, axis, verts[2] );
R_CloudVertex( 1.0f, -1.0f, axis, verts[3] );
VectorSubtract( verts[2], verts[3], vup );
VectorSubtract( verts[2], verts[1], vright );
p->numverts = 4;
di = SKYCLOUDS_QUALITY;
qi = 1.0 / di;
dj = (axis < 4) ? di * 2 : di; //subdivide vertically more than horizontally on skybox sides
qj = 1.0 / dj;
for( i = 0; i < di; i++ )
{
for( j = 0; j < dj; j++ )
{
if( i * qi < RI.skyMins[0][axis] / 2 + 0.5f - qi
|| i * qi > RI.skyMaxs[0][axis] / 2 + 0.5f
|| j * qj < RI.skyMins[1][axis] / 2 + 0.5f - qj
|| j * qj > RI.skyMaxs[1][axis] / 2 + 0.5f )
continue;
VectorScale( vright, qi * i, temp );
VectorScale( vup, qj * j, temp2 );
VectorAdd( temp, temp2, temp );
VectorAdd( verts[0], temp, p->verts[0] );
VectorScale( vup, qj, temp );
VectorAdd( p->verts[0], temp, p->verts[1] );
VectorScale( vright, qi, temp );
VectorAdd( p->verts[1], temp, p->verts[2] );
VectorAdd( p->verts[0], temp, p->verts[3] );
R_CloudDrawPoly( p );
}
}
}
/*
==============
R_DrawClouds
Quake-style clouds
==============
*/
void R_DrawClouds( void )
{
int i;
RI.isSkyVisible = true;
if( RI.fogEnabled )
pglFogf( GL_FOG_DENSITY, RI.fogDensity * 0.25f );
pglDepthFunc( GL_GEQUAL );
pglDepthMask( GL_FALSE );
for( i = 0; i < 6; i++ )
{
if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] )
continue;
R_CloudRenderSide( i );
}
pglDepthFunc( GL_LEQUAL );
pglDepthMask( GL_TRUE );
if( RI.fogEnabled )
pglFogf( GL_FOG_DENSITY, RI.fogDensity );
}
/*
=============
R_InitSkyClouds
A sky texture is 256*128, with the right side being a masked overlay
==============
*/
void R_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette )
{
rgbdata_t r_temp, *r_sky;
uint *trans, *rgba;
uint transpix;
int r, g, b;
int i, j, p;
char texname[32];
if( !glw_state.initialized )
return;
Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", tx->name );
if( mt->offsets[0] > 0 )
{
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
if( custom_palette ) size += sizeof( short ) + 768;
r_sky = FS_LoadImage( texname, (byte *)mt, size );
}
else
{
// okay, loading it from wad
r_sky = FS_LoadImage( texname, NULL, 0 );
}
// make sure what sky image is valid
if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 || r_sky->height == 0 )
{
MsgDev( D_ERROR, "R_InitSky: unable to load sky texture %s\n", tx->name );
if( r_sky ) FS_FreeImage( r_sky );
return;
}
// make an average value for the back to avoid
// a fringe on the top level
trans = Mem_Alloc( r_temppool, r_sky->height * r_sky->height * sizeof( *trans ));
r = g = b = 0;
for( i = 0; i < r_sky->width >> 1; i++ )
{
for( j = 0; j < r_sky->height; j++ )
{
p = r_sky->buffer[i * r_sky->width + j + r_sky->height];
rgba = (uint *)r_sky->palette + p;
trans[(i * r_sky->height) + j] = *rgba;
r += ((byte *)rgba)[0];
g += ((byte *)rgba)[1];
b += ((byte *)rgba)[2];
}
}
((byte *)&transpix)[0] = r / ( r_sky->height * r_sky->height );
((byte *)&transpix)[1] = g / ( r_sky->height * r_sky->height );
((byte *)&transpix)[2] = b / ( r_sky->height * r_sky->height );
((byte *)&transpix)[3] = 0;
// build a temporary image
r_temp = *r_sky;
r_temp.width = r_sky->width >> 1;
r_temp.height = r_sky->height;
r_temp.type = PF_RGBA_32;
r_temp.flags = IMAGE_HAS_COLOR;
r_temp.size = r_temp.width * r_temp.height * 4;
r_temp.buffer = (byte *)trans;
r_temp.palette = NULL;
// load it in
tr.solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP, false );
for( i = 0; i < r_sky->width >> 1; i++ )
{
for( j = 0; j < r_sky->height; j++ )
{
p = r_sky->buffer[i * r_sky->width + j];
if( p == 0 )
{
trans[(i * r_sky->height) + j] = transpix;
}
else
{
rgba = (uint *)r_sky->palette + p;
trans[(i * r_sky->height) + j] = *rgba;
}
}
}
r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
// load it in
tr.alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP, false );
// clean up
FS_FreeImage( r_sky );
Mem_Free( trans );
}
/*
=============
EmitWaterPolys
Does a water warp on the pre-fragmented glpoly_t chain
=============
*/
void EmitWaterPolys( msurface_t *warp, qboolean reverse )
{
float *v, nv, waveHeight;
float s, t, os, ot;
glpoly_t *p;
int i;
if( !warp->polys ) return;
// set the current waveheight
if( warp->polys->verts[0][2] >= RI.vieworg[2] )
waveHeight = -RI.currententity->curstate.scale;
else waveHeight = RI.currententity->curstate.scale;
// reset fog color for nonlightmapped water
GL_ResetFogColor();
if( FBitSet( warp->flags, SURF_DRAWTURB_QUADS ))
pglBegin( GL_QUADS );
for( p = warp->polys; p; p = p->next )
{
if( reverse )
v = p->verts[0] + ( p->numverts - 1 ) * VERTEXSIZE;
else v = p->verts[0];
if( !FBitSet( warp->flags, SURF_DRAWTURB_QUADS ))
pglBegin( GL_POLYGON );
for( i = 0; i < p->numverts; i++ )
{
if( waveHeight )
{
nv = r_turbsin[(int)(cl.time * 160.0f + v[1] + v[0]) & 255] + 8.0f;
nv = (r_turbsin[(int)(v[0] * 5.0f + cl.time * 171.0f - v[1]) & 255] + 8.0f ) * 0.8f + nv;
nv = nv * waveHeight + v[2];
}
else nv = v[2];
os = v[3];
ot = v[4];
s = os + r_turbsin[(int)((ot * 0.125f + cl.time) * TURBSCALE) & 255];
s *= ( 1.0f / SUBDIVIDE_SIZE );
t = ot + r_turbsin[(int)((os * 0.125f + cl.time) * TURBSCALE) & 255];
t *= ( 1.0f / SUBDIVIDE_SIZE );
pglTexCoord2f( s, t );
pglVertex3f( v[0], v[1], nv );
if( reverse )
v -= VERTEXSIZE;
else v += VERTEXSIZE;
}
if( !FBitSet( warp->flags, SURF_DRAWTURB_QUADS ))
pglEnd();
}
if( FBitSet( warp->flags, SURF_DRAWTURB_QUADS ))
pglEnd();
GL_SetupFogColorForSurfaces();
}

483
engine/client/s_backend.c Normal file
View File

@ -0,0 +1,483 @@
/*
s_backend.c - sound hardware output
Copyright (C) 2009 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 "sound.h"
#include <dsound.h>
#define iDirectSoundCreate( a, b, c ) pDirectSoundCreate( a, b, c )
static HRESULT ( _stdcall *pDirectSoundCreate)(GUID* lpGUID, LPDIRECTSOUND* lpDS, IUnknown* pUnkOuter );
static dllfunc_t dsound_funcs[] =
{
{ "DirectSoundCreate", (void **) &pDirectSoundCreate },
{ NULL, NULL }
};
dll_info_t dsound_dll = { "dsound.dll", dsound_funcs, false };
#define SAMPLE_16BIT_SHIFT 1
#define SECONDARY_BUFFER_SIZE 0x10000
typedef enum
{
SIS_SUCCESS,
SIS_FAILURE,
SIS_NOTAVAIL
} si_state_t;
static qboolean snd_firsttime = true;
static qboolean primary_format_set;
static HWND snd_hwnd;
/*
=======================================================================
Global variables. Must be visible to window-procedure function
so it can unlock and free the data block after it has been played.
=======================================================================
*/
static DWORD locksize;
static HPSTR lpData, lpData2;
static DWORD gSndBufSize;
static MMTIME mmstarttime;
static LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
static LPDIRECTSOUND pDS;
qboolean SNDDMA_InitDirect( void *hInst );
void SNDDMA_FreeSound( void );
static const char *DSoundError( int error )
{
switch( error )
{
case DSERR_BUFFERLOST:
return "buffer is lost";
case DSERR_INVALIDCALL:
return "invalid call";
case DSERR_INVALIDPARAM:
return "invalid param";
case DSERR_PRIOLEVELNEEDED:
return "invalid priority level";
}
return "unknown error";
}
/*
==================
DS_CreateBuffers
==================
*/
static qboolean DS_CreateBuffers( void *hInst )
{
WAVEFORMATEX pformat, format;
DSBCAPS dsbcaps;
DSBUFFERDESC dsbuf;
memset( &format, 0, sizeof( format ));
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2;
format.wBitsPerSample = 16;
format.nSamplesPerSec = SOUND_DMA_SPEED;
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
format.cbSize = 0;
if( pDS->lpVtbl->SetCooperativeLevel( pDS, hInst, DSSCL_EXCLUSIVE ) != DS_OK )
{
Con_DPrintf( S_ERROR "DirectSound: failed to set EXCLUSIVE coop level\n" );
SNDDMA_FreeSound();
return false;
}
// get access to the primary buffer, if possible, so we can set the sound hardware format
memset( &dsbuf, 0, sizeof( dsbuf ));
dsbuf.dwSize = sizeof( DSBUFFERDESC );
dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbuf.dwBufferBytes = 0;
dsbuf.lpwfxFormat = NULL;
memset( &dsbcaps, 0, sizeof( dsbcaps ));
dsbcaps.dwSize = sizeof( dsbcaps );
primary_format_set = false;
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSPBuf, NULL ) == DS_OK )
{
pformat = format;
if( pDSPBuf->lpVtbl->SetFormat( pDSPBuf, &pformat ) != DS_OK )
{
if( snd_firsttime )
Con_DPrintf( S_ERROR "DirectSound: failed to set primary sound format\n" );
}
else
{
primary_format_set = true;
}
}
// create the secondary buffer we'll actually work with
memset( &dsbuf, 0, sizeof( dsbuf ));
dsbuf.dwSize = sizeof( DSBUFFERDESC );
dsbuf.dwFlags = (DSBCAPS_CTRLFREQUENCY|DSBCAPS_LOCSOFTWARE);
dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
dsbuf.lpwfxFormat = &format;
memset( &dsbcaps, 0, sizeof( dsbcaps ));
dsbcaps.dwSize = sizeof( dsbcaps );
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) != DS_OK )
{
// couldn't get hardware, fallback to software.
dsbuf.dwFlags = (DSBCAPS_LOCSOFTWARE|DSBCAPS_GETCURRENTPOSITION2);
if( pDS->lpVtbl->CreateSoundBuffer( pDS, &dsbuf, &pDSBuf, NULL ) != DS_OK )
{
Con_DPrintf( S_ERROR "DirectSound: failed to create secondary buffer\n" );
SNDDMA_FreeSound ();
return false;
}
}
if( pDSBuf->lpVtbl->GetCaps( pDSBuf, &dsbcaps ) != DS_OK )
{
Con_DPrintf( S_ERROR "DirectSound: failed to get capabilities\n" );
SNDDMA_FreeSound ();
return false;
}
// make sure mixer is active
if( pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING ) != DS_OK )
{
Con_DPrintf( S_ERROR "DirectSound: failed to create circular buffer\n" );
SNDDMA_FreeSound ();
return false;
}
// we don't want anyone to access the buffer directly w/o locking it first
lpData = NULL;
dma.samplepos = 0;
snd_hwnd = (HWND)hInst;
gSndBufSize = dsbcaps.dwBufferBytes;
dma.samples = gSndBufSize / 2;
dma.buffer = (byte *)lpData;
SNDDMA_BeginPainting();
if( dma.buffer ) memset( dma.buffer, 0, dma.samples * 2 );
SNDDMA_Submit();
return true;
}
/*
==================
DS_DestroyBuffers
==================
*/
static void DS_DestroyBuffers( void )
{
if( pDS ) pDS->lpVtbl->SetCooperativeLevel( pDS, snd_hwnd, DSSCL_NORMAL );
if( pDSBuf )
{
pDSBuf->lpVtbl->Stop( pDSBuf );
pDSBuf->lpVtbl->Release( pDSBuf );
}
// only release primary buffer if it's not also the mixing buffer we just released
if( pDSPBuf && ( pDSBuf != pDSPBuf ))
pDSPBuf->lpVtbl->Release( pDSPBuf );
dma.buffer = NULL;
pDSPBuf = NULL;
pDSBuf = NULL;
}
/*
==================
SNDDMA_LockSound
==================
*/
void SNDDMA_LockSound( void )
{
if( pDSBuf != NULL )
pDSBuf->lpVtbl->Stop( pDSBuf );
}
/*
==================
SNDDMA_LockSound
==================
*/
void SNDDMA_UnlockSound( void )
{
if( pDSBuf != NULL )
pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING );
}
/*
==================
SNDDMA_FreeSound
==================
*/
void SNDDMA_FreeSound( void )
{
if( pDS )
{
DS_DestroyBuffers();
pDS->lpVtbl->Release( pDS );
Sys_FreeLibrary( &dsound_dll );
}
lpData = NULL;
pDSPBuf = NULL;
pDSBuf = NULL;
pDS = NULL;
}
/*
==================
SNDDMA_InitDirect
Direct-Sound support
==================
*/
si_state_t SNDDMA_InitDirect( void *hInst )
{
DSCAPS dscaps;
HRESULT hresult;
if( !dsound_dll.link )
{
if( !Sys_LoadLibrary( &dsound_dll ))
return SIS_FAILURE;
}
if(( hresult = iDirectSoundCreate( NULL, &pDS, NULL )) != DS_OK )
{
if( hresult != DSERR_ALLOCATED )
return SIS_FAILURE;
Con_DPrintf( S_ERROR "DirectSound: hardware already in use\n" );
return SIS_NOTAVAIL;
}
dscaps.dwSize = sizeof( dscaps );
if( pDS->lpVtbl->GetCaps( pDS, &dscaps ) != DS_OK )
Con_DPrintf( S_ERROR "DirectSound: failed to get capabilities\n" );
if( FBitSet( dscaps.dwFlags, DSCAPS_EMULDRIVER ))
{
Con_DPrintf( S_ERROR "DirectSound: driver not installed\n" );
SNDDMA_FreeSound();
return SIS_FAILURE;
}
if( !DS_CreateBuffers( hInst ))
return SIS_FAILURE;
return SIS_SUCCESS;
}
/*
==================
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
==================
*/
int SNDDMA_Init( void *hInst )
{
// already initialized
if( dma.initialized ) return true;
memset( &dma, 0, sizeof( dma ));
// init DirectSound
if( SNDDMA_InitDirect( hInst ) != SIS_SUCCESS )
return false;
if( snd_firsttime )
Con_Printf( "Audio: DirectSound\n" );
dma.initialized = true;
snd_firsttime = false;
return true;
}
/*
==============
SNDDMA_GetDMAPos
return the current sample position (in mono samples read)
inside the recirculating dma buffer, so the mixing code will know
how many sample are required to fill it up.
===============
*/
int SNDDMA_GetDMAPos( void )
{
int s;
MMTIME mmtime;
DWORD dwWrite;
if( !dma.initialized )
return 0;
mmtime.wType = TIME_SAMPLES;
pDSBuf->lpVtbl->GetCurrentPosition( pDSBuf, &mmtime.u.sample, &dwWrite );
s = mmtime.u.sample - mmstarttime.u.sample;
s >>= SAMPLE_16BIT_SHIFT;
s &= (dma.samples - 1);
return s;
}
/*
==============
SNDDMA_GetSoundtime
update global soundtime
===============
*/
int SNDDMA_GetSoundtime( void )
{
static int buffers, oldsamplepos;
int samplepos, fullsamples;
fullsamples = dma.samples / 2;
// it is possible to miscount buffers
// if it has wrapped twice between
// calls to S_Update. Oh well.
samplepos = SNDDMA_GetDMAPos();
if( samplepos < oldsamplepos )
{
buffers++; // buffer wrapped
if( paintedtime > 0x40000000 )
{
// time to chop things off to avoid 32 bit limits
buffers = 0;
paintedtime = fullsamples;
S_StopAllSounds( true );
}
}
oldsamplepos = samplepos;
return (buffers * fullsamples + samplepos / 2);
}
/*
==============
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
===============
*/
void SNDDMA_BeginPainting( void )
{
int reps;
DWORD dwSize2;
DWORD *pbuf, *pbuf2;
HRESULT hr;
DWORD dwStatus;
if( !pDSBuf ) return;
// if the buffer was lost or stopped, restore it and/or restart it
if( pDSBuf->lpVtbl->GetStatus( pDSBuf, &dwStatus ) != DS_OK )
Con_DPrintf( S_ERROR "BeginPainting: couldn't get sound buffer status\n" );
if( dwStatus & DSBSTATUS_BUFFERLOST )
pDSBuf->lpVtbl->Restore( pDSBuf );
if( !FBitSet( dwStatus, DSBSTATUS_PLAYING ))
pDSBuf->lpVtbl->Play( pDSBuf, 0, 0, DSBPLAY_LOOPING );
// lock the dsound buffer
dma.buffer = NULL;
reps = 0;
while(( hr = pDSBuf->lpVtbl->Lock( pDSBuf, 0, gSndBufSize, &pbuf, &locksize, &pbuf2, &dwSize2, 0 )) != DS_OK )
{
if( hr != DSERR_BUFFERLOST )
{
Con_DPrintf( S_ERROR "BeginPainting: %s\n", DSoundError( hr ));
S_Shutdown ();
return;
}
else pDSBuf->lpVtbl->Restore( pDSBuf );
if( ++reps > 2 ) return;
}
dma.buffer = (byte *)pbuf;
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
===============
*/
void SNDDMA_Submit( void )
{
if( !dma.buffer ) return;
// unlock the dsound buffer
if( pDSBuf ) pDSBuf->lpVtbl->Unlock( pDSBuf, dma.buffer, locksize, NULL, 0 );
}
/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown( void )
{
if( !dma.initialized ) return;
dma.initialized = false;
SNDDMA_FreeSound();
}
/*
===========
S_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void S_Activate( qboolean active, void *hInst )
{
if( !dma.initialized ) return;
snd_hwnd = (HWND)hInst;
if( !pDS || !snd_hwnd )
return;
if( active )
DS_CreateBuffers( snd_hwnd );
else DS_DestroyBuffers();
}

905
engine/client/s_dsp.c Normal file
View File

@ -0,0 +1,905 @@
/*
s_dsp.c - digital signal processing algorithms for audio FX
Copyright (C) 2009 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 "sound.h"
#define MAX_DELAY 0.4f
#define MAX_ROOM_TYPES ARRAYSIZE( rgsxpre )
#define MONODLY 0
#define MAX_MONO_DELAY 0.4f
#define REVERBPOS 1
#define MAX_REVERB_DELAY 0.1f
#define STEREODLY 3
#define MAX_STEREO_DELAY 0.1f
#define REVERB_XFADE 32
#define MAXDLY (STEREODLY + 1)
#define MAXLP 10
#define MAXPRESETS ARRAYSIZE( rgsxpre )
typedef struct sx_preset_s
{
float room_lp; // lowpass
float room_mod; // modulation
// reverb
float room_size;
float room_refl;
float room_rvblp;
// delay
float room_delay;
float room_feedback;
float room_dlylp;
float room_left;
} sx_preset_t;
typedef struct dly_s
{
size_t cdelaysamplesmax; // delay line array size
// delay line pointers
size_t idelayinput;
size_t idelayoutput;
// crossfade
size_t idelayoutputxf; // output pointer
int xfade; // value
int delaysamples; // delay setting
int delayfeedback; // feedback setting
// lowpass
int lp; // is lowpass enabled
int lp0, lp1, lp2; // lowpass buffer
// modulation
int mod;
int modcur;
// delay line
int *lpdelayline;
} dly_t;
const sx_preset_t rgsxpre[] =
{
// -------reverb-------- -------delay--------
// lp mod size refl rvblp delay feedback dlylp left
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0 }, // 0 off
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.065, 0.1, 0.0, 0.01 }, // 1 generic
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.02, 0.75, 0.0, 0.01 }, // 2 metalic
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.03, 0.78, 0.0, 0.02 }, // 3
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.77, 0.0, 0.03 }, // 4
{ 0.0, 0.0, 0.05, 0.85, 1.0, 0.008, 0.96, 2.0, 0.01 }, // 5 tunnel
{ 0.0, 0.0, 0.05, 0.88, 1.0, 0.01, 0.98, 2.0, 0.02 }, // 6
{ 0.0, 0.0, 0.05, 0.92, 1.0, 0.015, 0.995, 2.0, 0.04 }, // 7
{ 0.0, 0.0, 0.05, 0.84, 1.0, 0.0, 0.0, 2.0, 0.012 }, // 8 chamber
{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.0, 0.0, 2.0, 0.008 }, // 9
{ 0.0, 0.0, 0.05, 0.95, 1.0, 0.0, 0.0, 2.0, 0.004 }, // 10
{ 0.0, 0.0, 0.05, 0.7, 0.0, 0.0, 0.0, 2.0, 0.012 }, // 11 brite
{ 0.0, 0.0, 0.055, 0.78, 0.0, 0.0, 0.0, 2.0, 0.008 }, // 12
{ 0.0, 0.0, 0.05, 0.86, 0.0, 0.0, 0.0, 2.0, 0.002 }, // 13
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.01 }, // 14 water
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.85, 2.0, 0.02 }, // 15
{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.2, 0.6, 2.0, 0.05 }, // 16
{ 0.0, 0.0, 0.05, 0.8, 1.0, 0.0, 0.48, 2.0, 0.016 }, // 17 concrete
{ 0.0, 0.0, 0.06, 0.9, 1.0, 0.0, 0.52, 2.0, 0.01 }, // 18
{ 0.0, 0.0, 0.07, 0.94, 1.0, 0.3, 0.6, 2.0, 0.008 }, // 19
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.3, 0.42, 2.0, 0.0 }, // 20 outside
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.35, 0.48, 2.0, 0.0 }, // 21
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.38, 0.6, 2.0, 0.0 }, // 22
{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.2, 0.28, 0.0, 0.0 }, // 23 cavern
{ 0.0, 0.0, 0.07, 0.9, 1.0, 0.3, 0.4, 0.0, 0.0 }, // 24
{ 0.0, 0.0, 0.09, 0.9, 1.0, 0.35, 0.5, 0.0, 0.0 }, // 25
{ 0.0, 1.0, 0.01, 0.9, 0.0, 0.0, 0.0, 2.0, 0.05 }, // 26 weirdo
{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.009, 0.999, 2.0, 0.04 }, // 27
{ 0.0, 0.0, 0.001, 0.999, 0.0, 0.2, 0.8, 2.0, 0.05 } // 28
};
// cvars
convar_t *dsp_off; // disable dsp
convar_t *roomwater_type; // water room_type
convar_t *room_type; // current room type
convar_t *hisound; // DSP quality
// underwater/special fx modulations
convar_t *sxmod_mod;
convar_t *sxmod_lowpass;
// stereo delay(no feedback)
convar_t *sxste_delay; // straight left delay
// mono reverb
convar_t *sxrvb_lp; // lowpass
convar_t *sxrvb_feedback; // reverb decay. Higher -- longer
convar_t *sxrvb_size; // room size. Higher -- larger
// mono delay
convar_t *sxdly_lp; // lowpass
convar_t *sxdly_feedback; // cycles
convar_t *sxdly_delay; // current delay in seconds
convar_t *dsp_room; // for compability
int idsp_dma_speed;
int idsp_room;
int room_typeprev;
// routines
int sxamodl, sxamodr; // amplitude modulation values
int sxamodlt, sxamodrt; // modulation targets
int sxmod1cur, sxmod2cur;
int sxmod1, sxmod2;
int sxhires;
portable_samplepair_t *paintto = NULL;
dly_t rgsxdly[MAXDLY]; // stereo is last
int rgsxlp[MAXLP];
void SX_Profiling_f( void );
/*
============
SX_ReloadRoomFX
============
*/
void SX_ReloadRoomFX( void )
{
if( !dsp_room ) return; // not initialized
SetBits( sxste_delay->flags, FCVAR_CHANGED );
SetBits( sxrvb_feedback->flags, FCVAR_CHANGED );
SetBits( sxdly_delay->flags, FCVAR_CHANGED );
SetBits( room_type->flags, FCVAR_CHANGED );
}
/*
============
SX_Init()
Starts sound crackling system
============
*/
void SX_Init( void )
{
memset( rgsxdly, 0, sizeof( rgsxdly ));
memset( rgsxlp, 0, sizeof( rgsxlp ));
sxamodr = sxamodl = sxamodrt = sxamodlt = 255;
idsp_dma_speed = SOUND_11k;
hisound = Cvar_Get( "room_hires", "2", FCVAR_ARCHIVE, "dsp quality. 1 for 22k, 2 for 44k(recommended) and 3 for 96k" );
sxhires = 2;
sxmod1cur = sxmod1 = 350 * ( idsp_dma_speed / SOUND_11k );
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
dsp_off = Cvar_Get( "dsp_off", "0", 0, "disable DSP processing" );
roomwater_type = Cvar_Get( "waterroom_type", "14", 0, "water room type" );
room_type = Cvar_Get( "room_type", "0", 0, "current room type preset" );
sxmod_lowpass = Cvar_Get( "room_lp", "0", 0, "for water fx, lowpass for entire room" );
sxmod_mod = Cvar_Get( "room_mod", "0", 0, "stereo amptitude modulation for room" );
sxrvb_size = Cvar_Get( "room_size", "0", 0, "reverb: initial reflection size" );
sxrvb_feedback = Cvar_Get( "room_refl", "0", 0, "reverb: decay time" );
sxrvb_lp = Cvar_Get( "room_rvblp", "1", 0, "reverb: low pass filtering level" );
sxdly_delay = Cvar_Get( "room_delay", "0.8", 0, "mono delay: delay time" );
sxdly_feedback = Cvar_Get( "room_feedback", "0.2", 0, "mono delay: decay time" );
sxdly_lp = Cvar_Get( "room_dlylp", "1", 0, "mono delay: low pass filtering level" );
sxste_delay = Cvar_Get( "room_left", "0", 0, "left channel delay time" );
Cmd_AddCommand( "dsp_profile", SX_Profiling_f, "dsp stress-test, first argument is room_type" );
// for compability
dsp_room = room_type;
SX_ReloadRoomFX();
}
/*
===========
DLY_Free
Free memory allocated for DSP
===========
*/
void DLY_Free( int idelay )
{
Assert( idelay >= 0 && idelay < MAXDLY );
if( rgsxdly[idelay].lpdelayline )
{
Z_Free( rgsxdly[idelay].lpdelayline );
rgsxdly[idelay].lpdelayline = NULL;
}
}
/*
==========
SX_Shutdown
Stop DSP processor
==========
*/
void SX_Free( void )
{
int i;
for( i = 0; i <= 3; i++ )
DLY_Free( i );
Cmd_RemoveCommand( "dsp_profile" );
}
/*
===========
DLY_Init
Initialize dly
===========
*/
int DLY_Init( int idelay, float delay )
{
dly_t *cur;
// DLY_Init called anytime with constants. So valid it in debug builds only.
Assert( idelay >= 0 && idelay < MAXDLY );
Assert( delay > 0.0f && delay <= MAX_DELAY );
DLY_Free( idelay ); // free dly if it's allocated
cur = &rgsxdly[idelay];
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
cur->lpdelayline = (int *)Z_Malloc( cur->cdelaysamplesmax * sizeof( int ));
cur->xfade = 0;
// init modulation
cur->mod = cur->modcur = 0;
// init lowpass
cur->lp = 1;
cur->lp0 = cur->lp1 = cur->lp2 = 0;
cur->idelayinput = 0;
cur->idelayoutput = cur->cdelaysamplesmax - cur->delaysamples; // NOTE: delaysamples must be set!!!
return 1;
}
/*
============
DLY_MovePointer
Checks overflow and moves pointer
============
*/
_inline void DLY_MovePointer( dly_t *dly )
{
if( ++dly->idelayinput >= dly->cdelaysamplesmax )
dly->idelayinput = 0;
if( ++dly->idelayoutput >= dly->cdelaysamplesmax )
dly->idelayoutput = 0;
}
/*
=============
DLY_CheckNewStereoDelayVal
Update stereo processor settings if we are in new room
=============
*/
void DLY_CheckNewStereoDelayVal( void )
{
dly_t *const dly = &rgsxdly[STEREODLY];
float delay = sxste_delay->value;
if( !FBitSet( sxste_delay->flags, FCVAR_CHANGED ))
return;
if( delay == 0 )
{
DLY_Free( STEREODLY );
}
else
{
int samples;
delay = Q_min( delay, MAX_STEREO_DELAY );
samples = (int)(delay * idsp_dma_speed) << sxhires;
// re-init dly
if( !dly->lpdelayline )
{
dly->delaysamples = samples;
DLY_Init( STEREODLY, MAX_STEREO_DELAY );
}
if( dly->delaysamples != samples )
{
dly->xfade = 128;
dly->idelayoutputxf = dly->idelayinput - samples;
if( dly->idelayoutputxf < 0 )
dly->idelayoutputxf += dly->cdelaysamplesmax;
}
dly->modcur = dly->mod = 0;
if( dly->delaysamples == 0 )
DLY_Free( STEREODLY );
}
ClearBits( sxste_delay->flags, FCVAR_CHANGED );
}
/*
=============
DLY_DoStereoDelay
Do stereo processing
=============
*/
void DLY_DoStereoDelay( int count )
{
int delay, samplexf;
dly_t *const dly = &rgsxdly[STEREODLY];
portable_samplepair_t *paint = paintto;
if( !dly->lpdelayline )
return; // inactive
for( ; count; count--, paint++ )
{
if( dly->mod && --dly->modcur < 0 )
dly->modcur = dly->mod;
delay = dly->lpdelayline[dly->idelayoutput];
// process only if crossfading, active left value or delayline
if( delay || paint->left || dly->xfade )
{
// set up new crossfade, if not crossfading, not modulating, but going to
if( !dly->xfade && !dly->modcur && dly->mod )
{
dly->idelayoutputxf = dly->idelayoutput + ((COM_RandomLong( 0, 255 ) * dly->delaysamples ) >> 9 );
dly->xfade = 128;
}
dly->idelayoutputxf %= dly->cdelaysamplesmax;
// modify delay, if crossfading
if( dly->xfade )
{
samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7;
delay = samplexf + ((delay * dly->xfade) >> 7);
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf = 0;
if( --dly->xfade == 0 )
dly->idelayoutput = dly->idelayoutputxf;
}
// save left value to delay line
dly->lpdelayline[dly->idelayinput] = CLIP( paint->left );
// paint new delay value
paint->left = delay;
}
else
{
// clear delay line
dly->lpdelayline[dly->idelayinput] = 0;
}
DLY_MovePointer( dly );
}
}
/*
=============
DLY_CheckNewDelayVal
Update delay processor settings if we are in new room
=============
*/
void DLY_CheckNewDelayVal( void )
{
float delay = sxdly_delay->value;
dly_t *const dly = &rgsxdly[MONODLY];
if( FBitSet( sxdly_delay->flags, FCVAR_CHANGED ))
{
if( delay == 0 )
{
DLY_Free( MONODLY );
}
else
{
delay = min( delay, MAX_MONO_DELAY );
dly->delaysamples = (int)(delay * idsp_dma_speed) << sxhires;
// init dly
if( !dly->lpdelayline )
DLY_Init( MONODLY, MAX_MONO_DELAY );
if( dly->lpdelayline )
{
memset( dly->lpdelayline, 0, dly->cdelaysamplesmax * sizeof( int ) );
dly->lp0 = dly->lp1 = dly->lp2 = 0;
}
dly->idelayinput = 0;
dly->idelayoutput = dly->cdelaysamplesmax - dly->delaysamples;
if( !dly->delaysamples )
DLY_Free( MONODLY );
}
}
ClearBits( sxdly_delay->flags, FCVAR_CHANGED );
dly->lp = sxdly_lp->value;
dly->delayfeedback = 255 * sxdly_feedback->value;
}
/*
=============
DLY_DoDelay
Do delay processing
=============
*/
void DLY_DoDelay( int count )
{
dly_t *const dly = &rgsxdly[MONODLY];
portable_samplepair_t *paint = paintto;
int delay;
if( !dly->lpdelayline || !count )
return; // inactive
for( ; count; count--, paint++ )
{
delay = dly->lpdelayline[dly->idelayoutput];
// don't process if delay line and left/right samples are zero
if( delay || paint->left || paint->right )
{
// calculate delayed value from average
int val = (( paint->left + paint->right ) >> 1 ) + (( dly->delayfeedback * delay ) >> 8);
val = CLIP( val );
if( dly->lp ) // lowpass
{
dly->lp0 = dly->lp1;
dly->lp1 = val;
val = ( dly->lp0 + dly->lp1 + (val << 1) ) >> 2;
}
dly->lpdelayline[dly->idelayinput] = val;
val >>= 2;
paint->left = CLIP( paint->left + val );
paint->right = CLIP( paint->right + val );
}
else
{
dly->lpdelayline[dly->idelayinput] = 0;
dly->lp0 = dly->lp1 = 0;
}
DLY_MovePointer( dly );
}
}
/*
===========
RVB_SetUpDly
Set up dly for reverb
===========
*/
void RVB_SetUpDly( int pos, float delay, int kmod )
{
int samples;
delay = Q_min( delay, MAX_REVERB_DELAY );
samples = (int)(delay * idsp_dma_speed) << sxhires;
if( !rgsxdly[pos].lpdelayline )
{
rgsxdly[pos].delaysamples = samples;
DLY_Init( pos, MAX_REVERB_DELAY );
}
rgsxdly[pos].modcur = rgsxdly[pos].mod = (int)(kmod * idsp_dma_speed / SOUND_11k) << sxhires;
// set up crossfade, if delay has changed
if( rgsxdly[pos].delaysamples != samples )
{
rgsxdly[pos].idelayoutputxf = rgsxdly[pos].idelayinput - samples;
if( rgsxdly[pos].idelayoutputxf < 0 )
rgsxdly[pos].idelayoutputxf += rgsxdly[pos].cdelaysamplesmax;
rgsxdly[pos].xfade = 32;
}
if( !rgsxdly[pos].delaysamples )
DLY_Free( pos );
}
/*
===========
RVB_CheckNewReverbVal
Update reverb settings if we are in new room
===========
*/
void RVB_CheckNewReverbVal( void )
{
dly_t *const dly1 = &rgsxdly[REVERBPOS];
dly_t *const dly2 = &rgsxdly[REVERBPOS + 1];
float delay = sxrvb_size->value;
if( FBitSet( sxrvb_size->flags, FCVAR_CHANGED ))
{
if( delay == 0.0f )
{
DLY_Free( REVERBPOS );
DLY_Free( REVERBPOS + 1 );
}
else
{
RVB_SetUpDly( REVERBPOS, sxrvb_size->value, 500 );
RVB_SetUpDly( REVERBPOS+1, sxrvb_size->value * 0.71f, 700 );
}
}
ClearBits( sxrvb_size->flags, FCVAR_CHANGED );
dly1->lp = dly2->lp = sxrvb_lp->value;
dly1->delayfeedback = dly2->delayfeedback = (int)(255 * sxrvb_feedback->value);
}
/*
===========
RVB_DoReverbForOneDly
Do reverberation for one dly
===========
*/
int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair )
{
int delay;
int samplexf;
int val, valt;
int voutm = 0;
if( --dly->modcur < 0 )
dly->modcur = dly->mod;
delay = dly->lpdelayline[dly->idelayoutput];
if( dly->xfade || delay || samplepair->left || samplepair->right )
{
// modulate delay rate
if( !dly->mod )
{
dly->idelayoutputxf = dly->idelayoutput + ((COM_RandomLong( 0, 255 ) * delay) >> 9 );
if( dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf -= dly->cdelaysamplesmax;
dly->xfade = REVERB_XFADE;
}
if( dly->xfade )
{
samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE;
delay = ((delay * dly->xfade) / REVERB_XFADE) + samplexf;
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
dly->idelayoutputxf = 0;
if( --dly->xfade == 0 )
dly->idelayoutput = dly->idelayoutputxf;
}
if( delay )
{
val = vlr + ( ( dly->delayfeedback * delay ) >> 8 );
val = CLIP( val );
}
else
val = vlr;
if( dly->lp )
{
valt = (dly->lp0 + val) >> 1;
dly->lp0 = val;
}
else
valt = val;
voutm = dly->lpdelayline[dly->idelayinput] = valt;
}
else
{
voutm = dly->lpdelayline[dly->idelayinput] = 0;
dly->lp0 = 0;
}
DLY_MovePointer( dly );
return voutm;
}
/*
===========
RVB_DoReverb
Do reverberation processing
===========
*/
void RVB_DoReverb( int count )
{
dly_t *const dly1 = &rgsxdly[REVERBPOS];
dly_t *const dly2 = &rgsxdly[REVERBPOS+1];
portable_samplepair_t *paint = paintto;
int vlr, voutm;
if( !dly1->lpdelayline )
return;
for( ; count; count--, paint++ )
{
vlr = ( paint->left + paint->right ) >> 1;
voutm = RVB_DoReverbForOneDly( dly1, vlr, paint );
voutm += RVB_DoReverbForOneDly( dly2, vlr, paint );
voutm = (11 * voutm) >> 6;
paint->left = CLIP( paint->left + voutm );
paint->right = CLIP( paint->right + voutm );
}
}
/*
===========
RVB_DoAMod
Do amplification modulation processing
===========
*/
void RVB_DoAMod( int count )
{
portable_samplepair_t *paint = paintto;
if( !sxmod_lowpass->value && !sxmod_mod->value )
return;
for( ; count; count--, paint++ )
{
portable_samplepair_t res = *paint;
if( sxmod_lowpass->value )
{
res.left = rgsxlp[0] + rgsxlp[1] + rgsxlp[2] + rgsxlp[3] + rgsxlp[4] + res.left;
res.right = rgsxlp[5] + rgsxlp[6] + rgsxlp[7] + rgsxlp[8] + rgsxlp[9] + res.right;
res.left >>= 2;
res.right >>= 2;
rgsxlp[0] = rgsxlp[1];
rgsxlp[1] = rgsxlp[2];
rgsxlp[2] = rgsxlp[3];
rgsxlp[3] = rgsxlp[4];
rgsxlp[4] = paint->left;
rgsxlp[5] = rgsxlp[6];
rgsxlp[6] = rgsxlp[7];
rgsxlp[7] = rgsxlp[8];
rgsxlp[8] = rgsxlp[9];
rgsxlp[9] = paint->right;
}
if( sxmod_mod->value )
{
if( --sxmod1cur < 0 )
sxmod1cur = sxmod1;
if( !sxmod1 )
sxamodlt = COM_RandomLong( 32, 255 );
if( --sxmod2cur < 0 )
sxmod2cur = sxmod2;
if( !sxmod2 )
sxamodrt = COM_RandomLong( 32, 255 );
res.left = (sxamodl * res.left) >> 8;
res.right = (sxamodr * res.right) >> 8;
if( sxamodl < sxamodlt )
sxamodl++;
else if( sxamodl > sxamodlt )
sxamodl--;
if( sxamodr < sxamodrt )
sxamodr++;
else if( sxamodr > sxamodrt )
sxamodr--;
}
paint->left = CLIP(res.left);
paint->right = CLIP(res.right);
}
}
/*
===========
DSP_Process
(xash dsp interface)
===========
*/
void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
{
if( dsp_off->value )
return;
// don't process DSP while in menu
if( cls.key_dest == key_menu || !sampleCount )
return;
// preset is already installed by CheckNewDspPresets
paintto = pbfront;
RVB_DoAMod( sampleCount );
RVB_DoReverb( sampleCount );
DLY_DoDelay( sampleCount );
DLY_DoStereoDelay( sampleCount );
}
/*
===========
DSP_ClearState
(xash dsp interface)
===========
*/
void DSP_ClearState( void )
{
Cvar_SetValue( "room_type", 0.0f );
SX_ReloadRoomFX();
}
/*
===========
CheckNewDspPresets
(xash dsp interface)
===========
*/
void CheckNewDspPresets( void )
{
if( dsp_off->value != 0.0f )
return;
if( s_listener.waterlevel > 2 )
idsp_room = roomwater_type->value;
else idsp_room = room_type->value;
if( FBitSet( hisound->flags, FCVAR_CHANGED ))
{
sxhires = hisound->value;
ClearBits( hisound->flags, FCVAR_CHANGED );
}
if( idsp_room == room_typeprev && idsp_room == 0 )
return;
if( idsp_room > MAX_ROOM_TYPES )
return;
if( idsp_room != room_typeprev )
{
const sx_preset_t *cur = rgsxpre + idsp_room;
Cvar_SetValue( "room_lp", cur->room_lp );
Cvar_SetValue( "room_mod", cur->room_mod );
Cvar_SetValue( "room_size", cur->room_size );
Cvar_SetValue( "room_refl", cur->room_refl );
Cvar_SetValue( "room_rvblp", cur->room_rvblp );
Cvar_SetValue( "room_delay", cur->room_delay );
Cvar_SetValue( "room_feedback", cur->room_feedback );
Cvar_SetValue( "room_dlylp", cur->room_dlylp );
Cvar_SetValue( "room_left", cur->room_left );
}
room_typeprev = idsp_room;
RVB_CheckNewReverbVal( );
DLY_CheckNewDelayVal( );
DLY_CheckNewStereoDelayVal();
}
/*
===========
DSP_GetGain
(xash dsp interface)
===========
*/
float DSP_GetGain( int idsp )
{
return 1.0f;
}
void SX_Profiling_f( void )
{
portable_samplepair_t testbuffer[512];
float oldroom = room_type->value;
double start, end;
int i, calls;
for( i = 0; i < 512; i++ )
{
testbuffer[i].left = COM_RandomLong( 0, 3000 );
testbuffer[i].right = COM_RandomLong( 0, 3000 );
}
if( Cmd_Argc() > 1 )
{
Cvar_SetValue( "room_type", Q_atof( Cmd_Argv( 1 )));
SX_ReloadRoomFX();
CheckNewDspPresets(); // we just need idsp_room immediately, for message below
}
Con_Printf( "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room );
start = Sys_DoubleTime();
for( calls = 10000; calls; calls-- )
{
DSP_Process( idsp_room, testbuffer, 512 );
}
end = Sys_DoubleTime();
Con_Printf( "----------\nTook %g seconds.\n", end - start );
if( Cmd_Argc() > 1 )
{
Cvar_SetValue( "room_type", oldroom );
SX_ReloadRoomFX();
CheckNewDspPresets();
}
}

395
engine/client/s_load.c Normal file
View File

@ -0,0 +1,395 @@
/*
s_load.c - sounds managment
Copyright (C) 2007 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 "sound.h"
// during registration it is possible to have more sounds
// than could actually be referenced during gameplay,
// because we don't want to free anything until we are
// sure we won't need it.
#define MAX_SFX 8192
#define MAX_SFX_HASH (MAX_SFX/4)
static int s_numSfx = 0;
static sfx_t s_knownSfx[MAX_SFX];
static sfx_t *s_sfxHashList[MAX_SFX_HASH];
static string s_sentenceImmediateName; // keep dummy sentence name
qboolean s_registering = false;
int s_registration_sequence = 0;
/*
=================
S_SoundList_f
=================
*/
void S_SoundList_f( void )
{
sfx_t *sfx;
wavdata_t *sc;
int i, totalSfx = 0;
int totalSize = 0;
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->servercount )
continue;
sc = sfx->cache;
if( sc )
{
totalSize += sc->size;
if( sc->loopStart >= 0 ) Con_Printf( "L" );
else Con_Printf( " " );
Con_Printf( " (%2db) %s : sound/%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
totalSfx++;
}
}
Con_Printf( "-------------------------------------------\n" );
Con_Printf( "%i total sounds\n", totalSfx );
Con_Printf( "%s total memory\n", Q_memprint( totalSize ));
Con_Printf( "\n" );
}
// return true if char 'c' is one of 1st 2 characters in pch
qboolean S_TestSoundChar( const char *pch, char c )
{
char *pcht = (char *)pch;
int i;
if( !pch || !*pch )
return false;
// check first 2 characters
for( i = 0; i < 2; i++ )
{
if( *pcht == c )
return true;
pcht++;
}
return false;
}
// return pointer to first valid character in file name
char *S_SkipSoundChar( const char *pch )
{
char *pcht = (char *)pch;
// check first character
if( *pcht == '!' )
pcht++;
return pcht;
}
/*
=================
S_CreateDefaultSound
=================
*/
static wavdata_t *S_CreateDefaultSound( void )
{
wavdata_t *sc;
sc = Mem_Alloc( sndpool, sizeof( wavdata_t ));
sc->width = 2;
sc->channels = 1;
sc->loopStart = -1;
sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels;
sc->buffer = Mem_Alloc( sndpool, sc->size );
return sc;
}
/*
=================
S_LoadSound
=================
*/
wavdata_t *S_LoadSound( sfx_t *sfx )
{
wavdata_t *sc = NULL;
if( !sfx ) return NULL;
if( sfx->cache ) return sfx->cache; // see if still in memory
if( Q_stricmp( sfx->name, "*default" ))
{
// load it from disk
if( sfx->name[0] == '*' )
sc = FS_LoadSound( sfx->name + 1, NULL, 0 );
else sc = FS_LoadSound( sfx->name, NULL, 0 );
}
if( !sc ) sc = S_CreateDefaultSound();
if( sc->rate < SOUND_11k ) // some bad sounds
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
sfx->cache = sc;
return sfx->cache;
}
// =======================================================================
// Load a sound
// =======================================================================
/*
==================
S_FindName
==================
*/
sfx_t *S_FindName( const char *pname, int *pfInCache )
{
sfx_t *sfx;
uint i, hash;
string name;
if( !COM_CheckString( pname ) || !dma.initialized )
return NULL;
if( Q_strlen( pname ) >= MAX_STRING )
{
MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", pname );
return NULL;
}
Q_strncpy( name, pname, sizeof( name ));
COM_FixSlashes( name );
// see if already loaded
hash = COM_HashKey( name, MAX_SFX_HASH );
for( sfx = s_sfxHashList[hash]; sfx; sfx = sfx->hashNext )
{
if( !Q_strcmp( sfx->name, name ))
{
if( pfInCache )
{
// indicate whether or not sound is currently in the cache.
*pfInCache = ( sfx->cache != NULL ) ? true : false;
}
// prolonge registration
sfx->servercount = s_registration_sequence;
return sfx;
}
}
// find a free sfx slot spot
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++)
if( !sfx->name[0] ) break; // free spot
if( i == s_numSfx )
{
if( s_numSfx == MAX_SFX )
{
MsgDev( D_ERROR, "S_FindName: MAX_SFX limit exceeded\n" );
return NULL;
}
s_numSfx++;
}
sfx = &s_knownSfx[i];
memset( sfx, 0, sizeof( *sfx ));
if( pfInCache ) *pfInCache = false;
Q_strncpy( sfx->name, name, MAX_STRING );
sfx->servercount = s_registration_sequence;
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
// link it in
sfx->hashNext = s_sfxHashList[sfx->hashValue];
s_sfxHashList[sfx->hashValue] = sfx;
return sfx;
}
/*
==================
S_FreeSound
==================
*/
void S_FreeSound( sfx_t *sfx )
{
sfx_t *hashSfx;
sfx_t **prev;
if( !sfx || !sfx->name[0] ) return;
// de-link it from the hash tree
prev = &s_sfxHashList[sfx->hashValue];
while( 1 )
{
hashSfx = *prev;
if( !hashSfx )
break;
if( hashSfx == sfx )
{
*prev = hashSfx->hashNext;
break;
}
prev = &hashSfx->hashNext;
}
if( sfx->cache ) FS_FreeSound( sfx->cache );
memset( sfx, 0, sizeof( *sfx ));
}
/*
=====================
S_BeginRegistration
=====================
*/
void S_BeginRegistration( void )
{
int i;
s_registration_sequence++;
s_registering = true;
// create unused 0-entry
S_RegisterSound( "*default" );
snd_ambient = false;
// check for automatic ambient sounds
for( i = 0; i < NUM_AMBIENTS; i++ )
{
if( !GI->ambientsound[i][0] )
continue; // empty slot
if( !ambient_sfx[i] )
MsgDev( D_NOTE, "Loading ambient[%i]: ^2%s^7\n", i, GI->ambientsound[i] );
ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] );
if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients
}
}
/*
=====================
S_EndRegistration
=====================
*/
void S_EndRegistration( void )
{
sfx_t *sfx;
int i;
if( !s_registering || !dma.initialized )
return;
// free any sounds not from this registration sequence
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->name[0] ) continue;
if( sfx->servercount != s_registration_sequence )
S_FreeSound( sfx ); // don't need this sound
}
// load everything in
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{
if( !sfx->name[0] ) continue;
S_LoadSound( sfx );
}
s_registering = false;
}
/*
==================
S_RegisterSound
==================
*/
sound_t S_RegisterSound( const char *name )
{
sfx_t *sfx;
if( !COM_CheckString( name ) || !dma.initialized )
return -1;
if( S_TestSoundChar( name, '!' ))
{
Q_strncpy( s_sentenceImmediateName, name, sizeof( s_sentenceImmediateName ));
return SENTENCE_INDEX;
}
// some stupid mappers used leading '/' or '\' in path to models or sounds
if( name[0] == '/' || name[0] == '\\' ) name++;
if( name[0] == '/' || name[0] == '\\' ) name++;
sfx = S_FindName( name, NULL );
if( !sfx ) return -1;
sfx->servercount = s_registration_sequence;
if( !s_registering ) S_LoadSound( sfx );
return sfx - s_knownSfx;
}
sfx_t *S_GetSfxByHandle( sound_t handle )
{
if( handle == -1 || !dma.initialized )
return NULL;
if( handle == SENTENCE_INDEX )
{
// create new sfx
return S_FindName( s_sentenceImmediateName, NULL );
}
if( handle < 0 || handle >= s_numSfx )
{
MsgDev( D_ERROR, "S_GetSfxByHandle: handle %i out of range (%i)\n", handle, s_numSfx );
return NULL;
}
return &s_knownSfx[handle];
}
/*
=================
S_FreeSounds
=================
*/
void S_FreeSounds( void )
{
sfx_t *sfx;
int i;
if( !dma.initialized )
return;
// stop all sounds
S_StopAllSounds( true );
// free all sounds
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
S_FreeSound( sfx );
memset( s_knownSfx, 0, sizeof( s_knownSfx ));
memset( s_sfxHashList, 0, sizeof( s_sfxHashList ));
s_numSfx = 0;
}

2244
engine/client/s_main.c Normal file

File diff suppressed because it is too large Load Diff

1062
engine/client/s_mix.c Normal file

File diff suppressed because it is too large Load Diff

152
engine/client/s_mouth.c Normal file
View File

@ -0,0 +1,152 @@
/*
s_mouth.c - animate mouth
Copyright (C) 2010 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 "sound.h"
#include "client.h"
#include "const.h"
#define CAVGSAMPLES 10
void SND_InitMouth( int entnum, int entchannel )
{
if(( entchannel == CHAN_VOICE || entchannel == CHAN_STREAM ) && entnum > 0 )
{
cl_entity_t *clientEntity;
// init mouth movement vars
clientEntity = CL_GetEntityByIndex( entnum );
if( clientEntity )
{
clientEntity->mouth.mouthopen = 0;
clientEntity->mouth.sndcount = 0;
clientEntity->mouth.sndavg = 0;
}
}
}
void SND_CloseMouth( channel_t *ch )
{
if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM )
{
cl_entity_t *clientEntity;
clientEntity = CL_GetEntityByIndex( ch->entnum );
if( clientEntity )
{
// shut mouth
clientEntity->mouth.mouthopen = 0;
}
}
}
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count )
{
cl_entity_t *clientEntity;
char *pdata = NULL;
mouth_t *pMouth = NULL;
int scount, pos = 0;
int savg, data;
uint i;
clientEntity = CL_GetEntityByIndex( ch->entnum );
if( !clientEntity ) return;
pMouth = &clientEntity->mouth;
if( ch->isSentence )
{
if( ch->currentWord )
pos = ch->currentWord->sample;
}
else pos = ch->pMixer.sample;
count = S_GetOutputData( pSource, &pdata, pos, count, ch->use_loop );
if( pdata == NULL ) return;
i = 0;
scount = pMouth->sndcount;
savg = 0;
while( i < count && scount < CAVGSAMPLES )
{
data = pdata[i];
savg += abs( data );
i += 80 + ((byte)data & 0x1F);
scount++;
}
pMouth->sndavg += savg;
pMouth->sndcount = (byte)scount;
if( pMouth->sndcount >= CAVGSAMPLES )
{
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
pMouth->sndavg = 0;
pMouth->sndcount = 0;
}
}
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count )
{
cl_entity_t *clientEntity;
short *pdata = NULL;
mouth_t *pMouth = NULL;
int savg, data;
int scount, pos = 0;
uint i;
clientEntity = CL_GetEntityByIndex( ch->entnum );
if( !clientEntity ) return;
pMouth = &clientEntity->mouth;
if( ch->isSentence )
{
if( ch->currentWord )
pos = ch->currentWord->sample;
}
else pos = ch->pMixer.sample;
count = S_GetOutputData( pSource, &pdata, pos, count, ch->use_loop );
if( pdata == NULL ) return;
i = 0;
scount = pMouth->sndcount;
savg = 0;
while( i < count && scount < CAVGSAMPLES )
{
data = pdata[i];
data = (bound( -32767, data, 0x7ffe ) >> 8);
savg += abs( data );
i += 80 + ((byte)data & 0x1F);
scount++;
}
pMouth->sndavg += savg;
pMouth->sndcount = (byte)scount;
if( pMouth->sndcount >= CAVGSAMPLES )
{
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
pMouth->sndavg = 0;
pMouth->sndcount = 0;
}
}

343
engine/client/s_stream.c Normal file
View File

@ -0,0 +1,343 @@
/*
s_stream.c - sound streaming
Copyright (C) 2009 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 "sound.h"
#include "client.h"
static bg_track_t s_bgTrack;
static musicfade_t musicfade; // controlled by game dlls
/*
=================
S_PrintBackgroundTrackState
=================
*/
void S_PrintBackgroundTrackState( void )
{
Con_Printf( "BackgroundTrack: " );
if( s_bgTrack.current[0] && s_bgTrack.loopName[0] )
Con_Printf( "intro %s, loop %s\n", s_bgTrack.current, s_bgTrack.loopName );
else if( s_bgTrack.current[0] )
Con_Printf( "%s\n", s_bgTrack.current );
else if( s_bgTrack.loopName[0] )
Con_Printf( "%s [loop]\n", s_bgTrack.loopName );
else Con_Printf( "not playing\n" );
}
/*
=================
S_FadeMusicVolume
=================
*/
void S_FadeMusicVolume( float fadePercent )
{
musicfade.percent = bound( 0.0f, fadePercent, 100.0f );
}
/*
=================
S_GetMusicVolume
=================
*/
float S_GetMusicVolume( void )
{
float scale = 1.0f;
if( !s_listener.inmenu && musicfade.percent != 0 )
{
scale = bound( 0.0f, musicfade.percent / 100.0f, 1.0f );
scale = 1.0f - scale;
}
return s_musicvolume->value * scale;
}
/*
=================
S_StartBackgroundTrack
=================
*/
void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long position, qboolean fullpath )
{
S_StopBackgroundTrack();
if( !dma.initialized ) return;
// check for special symbols
if( introTrack && *introTrack == '*' )
introTrack = NULL;
if( mainTrack && *mainTrack == '*' )
mainTrack = NULL;
if(( !introTrack || !*introTrack ) && ( !mainTrack || !*mainTrack ))
return;
if( !introTrack ) introTrack = mainTrack;
if( !*introTrack ) return;
if( !mainTrack || !*mainTrack ) s_bgTrack.loopName[0] = '\0';
else Q_strncpy( s_bgTrack.loopName, mainTrack, sizeof( s_bgTrack.loopName ));
if( fullpath ) Msg( "MP3:Playing: %s\n", introTrack );
// open stream
s_bgTrack.stream = FS_OpenStream( va( "media/%s", introTrack ));
Q_strncpy( s_bgTrack.current, introTrack, sizeof( s_bgTrack.current ));
memset( &musicfade, 0, sizeof( musicfade )); // clear any soundfade
s_bgTrack.source = cls.key_dest;
if( position != 0 )
{
// restore message, update song position
FS_SetStreamPos( s_bgTrack.stream, position );
}
}
/*
=================
S_StopBackgroundTrack
=================
*/
void S_StopBackgroundTrack( void )
{
s_listener.stream_paused = false;
if( !dma.initialized ) return;
if( !s_bgTrack.stream ) return;
FS_FreeStream( s_bgTrack.stream );
memset( &s_bgTrack, 0, sizeof( bg_track_t ));
memset( &musicfade, 0, sizeof( musicfade ));
}
/*
=================
S_StreamSetPause
=================
*/
void S_StreamSetPause( int pause )
{
s_listener.stream_paused = pause;
}
/*
=================
S_StreamGetCurrentState
save\restore code
=================
*/
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position )
{
if( !s_bgTrack.stream )
return false; // not active
if( currentTrack )
{
if( s_bgTrack.current[0] )
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING );
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track
}
if( loopTrack )
{
if( s_bgTrack.loopName[0] )
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING );
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track
}
if( position )
*position = FS_GetStreamPos( s_bgTrack.stream );
return true;
}
/*
=================
S_StreamBackgroundTrack
=================
*/
void S_StreamBackgroundTrack( void )
{
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES];
int r, fileBytes;
rawchan_t *ch = NULL;
if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming )
return;
// don't bother playing anything if musicvolume is 0
if( !s_musicvolume->value || s_listener.paused || s_listener.stream_paused )
return;
if( !cl.background )
{
// pause music by source type
if( s_bgTrack.source == key_game && cls.key_dest == key_menu ) return;
if( s_bgTrack.source == key_menu && cls.key_dest != key_menu ) return;
}
else if( cls.key_dest == key_console )
return;
ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, true );
Assert( ch != NULL );
// see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size
fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw ))
{
fileBytes = sizeof( raw );
fileSamples = fileBytes / ( info->width * info->channels );
}
// read
r = FS_ReadStream( s_bgTrack.stream, fileBytes, raw );
if( r < fileBytes )
{
fileBytes = r;
fileSamples = r / ( info->width * info->channels );
}
if( r > 0 )
{
// add to raw buffer
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_BACKGROUNDTRACK );
}
else
{
// loop
if( s_bgTrack.loopName[0] )
{
FS_FreeStream( s_bgTrack.stream );
s_bgTrack.stream = FS_OpenStream( va( "media/%s", s_bgTrack.loopName ));
Q_strncpy( s_bgTrack.current, s_bgTrack.loopName, sizeof( s_bgTrack.current ));
if( !s_bgTrack.stream ) return;
}
else
{
S_StopBackgroundTrack();
return;
}
}
}
}
/*
=================
S_StartStreaming
=================
*/
void S_StartStreaming( void )
{
if( !dma.initialized ) return;
// begin streaming movie soundtrack
s_listener.streaming = true;
}
/*
=================
S_StopStreaming
=================
*/
void S_StopStreaming( void )
{
if( !dma.initialized ) return;
s_listener.streaming = false;
}
/*
=================
S_StreamSoundTrack
=================
*/
void S_StreamSoundTrack( void )
{
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES];
int r, fileBytes;
rawchan_t *ch = NULL;
if( !dma.initialized || !s_listener.streaming || s_listener.paused )
return;
ch = S_FindRawChannel( S_RAW_SOUND_SOUNDTRACK, true );
Assert( ch != NULL );
// see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = SCR_GetMovieInfo();
if( !info ) break; // bad soundtrack?
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size
fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw ))
{
fileBytes = sizeof( raw );
fileSamples = fileBytes / ( info->width * info->channels );
}
// read audio stream
r = SCR_GetAudioChunk( raw, fileBytes );
if( r < fileBytes )
{
fileBytes = r;
fileSamples = r / ( info->width * info->channels );
}
if( r > 0 )
{
// add to raw buffer
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_SOUNDTRACK );
}
else break; // no more samples for this frame
}
}

306
engine/client/s_utils.c Normal file
View File

@ -0,0 +1,306 @@
/*
s_utils.c - common sound functions
Copyright (C) 2009 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 "sound.h"
// hardcoded macros to test for zero crossing
#define ZERO_X_8( b ) (( b ) < 2 && ( b ) > -2 )
#define ZERO_X_16( b ) (( b ) < 512 && ( b ) > -512 )
//-----------------------------------------------------------------------------
// Purpose: Search backward for a zero crossing starting at sample
// Input : sample - starting point
// Output : position of zero crossing
//-----------------------------------------------------------------------------
int S_ZeroCrossingBefore( wavdata_t *pWaveData, int sample )
{
if( pWaveData == NULL )
return sample;
if( pWaveData->type == WF_PCMDATA )
{
int sampleSize;
sampleSize = pWaveData->width * pWaveData->channels;
// this can never be zero -- other functions divide by this.
// This should never happen, but avoid crashing
if( sampleSize <= 0 ) sampleSize = 1;
if( pWaveData->width == 1 )
{
char *pData = pWaveData->buffer + sample * sampleSize;
qboolean zero = false;
if( pWaveData->channels == 1 )
{
while( sample > 0 && !zero )
{
if( ZERO_X_8( *pData ))
{
zero = true;
}
else
{
sample--;
pData--;
}
}
}
else
{
while( sample > 0 && !zero )
{
if( ZERO_X_8( *pData ) && ZERO_X_8( pData[1] ))
{
zero = true;
}
else
{
sample--;
pData--;
}
}
}
}
else
{
short *pData = (short *)(pWaveData->buffer + sample * sampleSize);
qboolean zero = false;
if( pWaveData->channels == 1 )
{
while( sample > 0 && !zero )
{
if( ZERO_X_16(*pData ))
{
zero = true;
}
else
{
pData--;
sample--;
}
}
}
else
{
while( sample > 0 && !zero )
{
if( ZERO_X_16( *pData ) && ZERO_X_16( pData[1] ))
{
zero = true;
}
else
{
sample--;
pData--;
}
}
}
}
}
return sample;
}
//-----------------------------------------------------------------------------
// Purpose: Search forward for a zero crossing
// Input : sample - starting point
// Output : position of found zero crossing
//-----------------------------------------------------------------------------
int S_ZeroCrossingAfter( wavdata_t *pWaveData, int sample )
{
if( pWaveData == NULL )
return sample;
if( pWaveData->type == WF_PCMDATA )
{
int sampleSize;
sampleSize = pWaveData->width * pWaveData->channels;
// this can never be zero -- other functions divide by this.
// This should never happen, but avoid crashing
if( sampleSize <= 0 ) sampleSize = 1;
if( pWaveData->width == 1 ) // 8-bit
{
char *pData = pWaveData->buffer + sample * sampleSize;
qboolean zero = false;
if( pWaveData->channels == 1 )
{
while( sample < pWaveData->samples && !zero )
{
if( ZERO_X_8( *pData ))
{
zero = true;
}
else
{
sample++;
pData++;
}
}
}
else
{
while( sample < pWaveData->samples && !zero )
{
if( ZERO_X_8( *pData ) && ZERO_X_8( pData[1] ))
{
zero = true;
}
else
{
sample++;
pData++;
}
}
}
}
else
{
short *pData = (short *)(pWaveData->buffer + sample * sampleSize);
qboolean zero = false;
if( pWaveData->channels == 1 )
{
while( sample > 0 && !zero )
{
if( ZERO_X_16( *pData ))
{
zero = true;
}
else
{
pData++;
sample++;
}
}
}
else
{
while( sample > 0 && !zero )
{
if( ZERO_X_16( *pData ) && ZERO_X_16( pData[1] ))
{
zero = true;
}
else
{
sample++;
pData++;
}
}
}
}
}
return sample;
}
//-----------------------------------------------------------------------------
// Purpose: wrap the position wrt looping
// Input : samplePosition - absolute position
// Output : int - looped position
//-----------------------------------------------------------------------------
int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean use_loop )
{
// if the wave is looping and we're past the end of the sample
// convert to a position within the loop
// At the end of the loop, we return a short buffer, and subsequent call
// will loop back and get the rest of the buffer
if( pSource->loopStart >= 0 && samplePosition >= pSource->samples && use_loop )
{
// size of loop
int loopSize = pSource->samples - pSource->loopStart;
// subtract off starting bit of the wave
samplePosition -= pSource->loopStart;
if( loopSize )
{
// "real" position in memory (mod off extra loops)
samplePosition = pSource->loopStart + ( samplePosition % loopSize );
}
// ERROR? if no loopSize
}
return samplePosition;
}
int S_GetOutputData( wavdata_t *pSource, void **pData, int samplePosition, int sampleCount, qboolean use_loop )
{
int totalSampleCount;
int sampleSize;
// handle position looping
samplePosition = S_ConvertLoopedPosition( pSource, samplePosition, use_loop );
// how many samples are available (linearly not counting looping)
totalSampleCount = pSource->samples - samplePosition;
// may be asking for a sample out of range, clip at zero
if( totalSampleCount < 0 ) totalSampleCount = 0;
// clip max output samples to max available
if( sampleCount > totalSampleCount )
sampleCount = totalSampleCount;
sampleSize = pSource->width * pSource->channels;
// this can never be zero -- other functions divide by this.
// This should never happen, but avoid crashing
if( sampleSize <= 0 ) sampleSize = 1;
// byte offset in sample database
samplePosition *= sampleSize;
// if we are returning some samples, store the pointer
if( sampleCount )
{
*pData = pSource->buffer + samplePosition;
}
return sampleCount;
}
// move the current position to newPosition
void S_SetSampleStart( channel_t *pChan, wavdata_t *pSource, int newPosition )
{
if( pSource )
newPosition = S_ZeroCrossingAfter( pSource, newPosition );
pChan->pMixer.sample = newPosition;
}
// end playback at newEndPosition
void S_SetSampleEnd( channel_t *pChan, wavdata_t *pSource, int newEndPosition )
{
// forced end of zero means play the whole sample
if( !newEndPosition ) newEndPosition = 1;
if( pSource )
newEndPosition = S_ZeroCrossingBefore( pSource, newEndPosition );
// past current position? limit.
if( newEndPosition < pChan->pMixer.sample )
newEndPosition = pChan->pMixer.sample;
pChan->pMixer.forcedEndSample = newEndPosition;
}

681
engine/client/s_vox.c Normal file
View File

@ -0,0 +1,681 @@
/*
s_vox.c - npc sentences
Copyright (C) 2010 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 "sound.h"
#include "const.h"
sentence_t g_Sentences[MAX_SENTENCES];
static uint g_numSentences;
static char *rgpparseword[CVOXWORDMAX]; // array of pointers to parsed words
static char voxperiod[] = "_period"; // vocal pause
static char voxcomma[] = "_comma"; // vocal pause
static int IsNextWord( const char c )
{
if( c == '.' || c == ',' || c == ' ' || c == '(' )
return 1;
return 0;
}
static int IsSkipSpace( const char c )
{
if( c == ',' || c == '.' || c == ' ' )
return 1;
return 0;
}
static int IsWhiteSpace( const char space )
{
if( space == ' ' || space == '\t' || space == '\r' || space == '\n' )
return 1;
return 0;
}
static int IsCommandChar( const char c )
{
if( c == 'v' || c == 'p' || c == 's' || c == 'e' || c == 't' )
return 1;
return 0;
}
static int IsDelimitChar( const char c )
{
if( c == '(' || c == ')' )
return 1;
return 0;
}
static char *ScanForwardUntil( char *string, const char scan )
{
while( string[0] )
{
if( string[0] == scan )
return string;
string++;
}
return string;
}
// backwards scan psz for last '/'
// return substring in szpath null terminated
// if '/' not found, return 'vox/'
static char *VOX_GetDirectory( char *szpath, char *psz )
{
char c;
int cb = 0;
char *p = psz + Q_strlen( psz ) - 1;
// scan backwards until first '/' or start of string
c = *p;
while( p > psz && c != '/' )
{
c = *( --p );
cb++;
}
if( c != '/' )
{
// didn't find '/', return default directory
Q_strcpy( szpath, "vox/" );
return psz;
}
cb = Q_strlen( psz ) - cb;
memcpy( szpath, psz, cb );
szpath[cb] = 0;
return p + 1;
}
// scan g_Sentences, looking for pszin sentence name
// return pointer to sentence data if found, null if not
// CONSIDER: if we have a large number of sentences, should
// CONSIDER: sort strings in g_Sentences and do binary search.
char *VOX_LookupString( const char *pSentenceName, int *psentencenum )
{
int i;
if( Q_isdigit( pSentenceName ) && (i = Q_atoi( pSentenceName )) < g_numSentences )
{
if( psentencenum ) *psentencenum = i;
return (g_Sentences[i].pName + Q_strlen( g_Sentences[i].pName ) + 1 );
}
for( i = 0; i < g_numSentences; i++ )
{
if( !Q_stricmp( pSentenceName, g_Sentences[i].pName ))
{
if( psentencenum ) *psentencenum = i;
return (g_Sentences[i].pName + Q_strlen( g_Sentences[i].pName ) + 1 );
}
}
return NULL;
}
// parse a null terminated string of text into component words, with
// pointers to each word stored in rgpparseword
// note: this code actually alters the passed in string!
char **VOX_ParseString( char *psz )
{
int i, fdone = 0;
char c, *p = psz;
memset( rgpparseword, 0, sizeof( char* ) * CVOXWORDMAX );
if( !psz ) return NULL;
i = 0;
rgpparseword[i++] = psz;
while( !fdone && i < CVOXWORDMAX )
{
// scan up to next word
c = *p;
while( c && !IsNextWord( c ))
c = *(++p);
// if '(' then scan for matching ')'
if( c == '(' )
{
p = ScanForwardUntil( p, ')' );
c = *(++p);
if( !c ) fdone = 1;
}
if( fdone || !c )
{
fdone = 1;
}
else
{
// if . or , insert pause into rgpparseword,
// unless this is the last character
if(( c == '.' || c == ',' ) && *(p+1) != '\n' && *(p+1) != '\r' && *(p+1) != 0 )
{
if( c == '.' ) rgpparseword[i++] = voxperiod;
else rgpparseword[i++] = voxcomma;
if( i >= CVOXWORDMAX )
break;
}
// null terminate substring
*p++ = 0;
// skip whitespace
c = *p;
while( c && IsSkipSpace( c ))
c = *(++p);
if( !c ) fdone = 1;
else rgpparseword[i++] = p;
}
}
return rgpparseword;
}
float VOX_GetVolumeScale( channel_t *pchan )
{
if( pchan->currentWord )
{
if ( pchan->words[pchan->wordIndex].volume )
{
float volume = pchan->words[pchan->wordIndex].volume * 0.01f;
if( volume < 1.0f ) return volume;
}
}
return 1.0f;
}
void VOX_SetChanVol( channel_t *ch )
{
float scale;
if( !ch->currentWord )
return;
scale = VOX_GetVolumeScale( ch );
if( scale == 1.0f ) return;
ch->rightvol = (int)(ch->rightvol * scale);
ch->leftvol = (int)(ch->leftvol * scale);
}
float VOX_ModifyPitch( channel_t *ch, float pitch )
{
if( ch->currentWord )
{
if( ch->words[ch->wordIndex].pitch > 0 )
{
pitch += ( ch->words[ch->wordIndex].pitch - PITCH_NORM ) * 0.01f;
}
}
return pitch;
}
//===============================================================================
// Get any pitch, volume, start, end params into voxword
// and null out trailing format characters
// Format:
// someword(v100 p110 s10 e20)
//
// v is volume, 0% to n%
// p is pitch shift up 0% to n%
// s is start wave offset %
// e is end wave offset %
// t is timecompression %
//
// pass fFirst == 1 if this is the first string in sentence
// returns 1 if valid string, 0 if parameter block only.
//
// If a ( xxx ) parameter block does not directly follow a word,
// then that 'default' parameter block will be used as the default value
// for all following words. Default parameter values are reset
// by another 'default' parameter block. Default parameter values
// for a single word are overridden for that word if it has a parameter block.
//
//===============================================================================
int VOX_ParseWordParams( char *psz, voxword_t *pvoxword, int fFirst )
{
char *pszsave = psz;
char c, ct, sznum[8];
static voxword_t voxwordDefault;
int i;
// init to defaults if this is the first word in string.
if( fFirst )
{
voxwordDefault.pitch = -1;
voxwordDefault.volume = 100;
voxwordDefault.start = 0;
voxwordDefault.end = 100;
voxwordDefault.fKeepCached = 0;
voxwordDefault.timecompress = 0;
}
*pvoxword = voxwordDefault;
// look at next to last char to see if we have a
// valid format:
c = *( psz + Q_strlen( psz ) - 1 );
// no formatting, return
if( c != ')' ) return 1;
// scan forward to first '('
c = *psz;
while( !IsDelimitChar( c ))
c = *(++psz);
// bogus formatting
if( c == ')' ) return 0;
// null terminate
*psz = 0;
ct = *(++psz);
while( 1 )
{
// scan until we hit a character in the commandSet
while( ct && !IsCommandChar( ct ))
ct = *(++psz);
if( ct == ')' )
break;
memset( sznum, 0, sizeof( sznum ));
i = 0;
c = *(++psz);
if( !isdigit( c ))
break;
// read number
while( isdigit( c ) && i < sizeof( sznum ) - 1 )
{
sznum[i++] = c;
c = *(++psz);
}
// get value of number
i = Q_atoi( sznum );
switch( ct )
{
case 'v': pvoxword->volume = i; break;
case 'p': pvoxword->pitch = i; break;
case 's': pvoxword->start = i; break;
case 'e': pvoxword->end = i; break;
case 't': pvoxword->timecompress = i; break;
}
ct = c;
}
// if the string has zero length, this was an isolated
// parameter block. Set default voxword to these
// values
if( Q_strlen( pszsave ) == 0 )
{
voxwordDefault = *pvoxword;
return 0;
}
return 1;
}
void VOX_LoadWord( channel_t *pchan )
{
if( pchan->words[pchan->wordIndex].sfx )
{
wavdata_t *pSource = S_LoadSound( pchan->words[pchan->wordIndex].sfx );
if( pSource )
{
int start = pchan->words[pchan->wordIndex].start;
int end = pchan->words[pchan->wordIndex].end;
// apply mixer
pchan->currentWord = &pchan->pMixer;
pchan->currentWord->pData = pSource;
// don't allow overlapped ranges
if( end <= start ) end = 0;
if( start || end )
{
int sampleCount = pSource->samples;
if( start )
{
S_SetSampleStart( pchan, pSource, (int)(sampleCount * 0.01f * start));
}
if( end )
{
S_SetSampleEnd( pchan, pSource, (int)(sampleCount * 0.01f * end));
}
}
}
}
}
void VOX_FreeWord( channel_t *pchan )
{
pchan->currentWord = NULL; // sentence is finished
memset( &pchan->pMixer, 0, sizeof( pchan->pMixer ));
// release unused sounds
if( pchan->words[pchan->wordIndex].sfx )
{
// If this wave wasn't precached by the game code
if( !pchan->words[pchan->wordIndex].fKeepCached )
{
FS_FreeSound( pchan->words[pchan->wordIndex].sfx->cache );
pchan->words[pchan->wordIndex].sfx->cache = NULL;
pchan->words[pchan->wordIndex].sfx = NULL;
}
}
}
void VOX_LoadFirstWord( channel_t *pchan, voxword_t *pwords )
{
int i = 0;
// copy each pointer in the sfx temp array into the
// sentence array, and set the channel to point to the
// sentence array
while( pwords[i].sfx != NULL )
{
pchan->words[i] = pwords[i];
i++;
}
pchan->words[i].sfx = NULL;
pchan->wordIndex = 0;
VOX_LoadWord( pchan );
}
// return number of samples mixed
int VOX_MixDataToDevice( channel_t *pchan, int sampleCount, int outputRate, int outputOffset )
{
// save this to compute total output
int startingOffset = outputOffset;
if( !pchan->currentWord )
return 0;
while( sampleCount > 0 && pchan->currentWord )
{
int timeCompress = pchan->words[pchan->wordIndex].timecompress;
int outputCount = S_MixDataToDevice( pchan, sampleCount, outputRate, outputOffset, timeCompress );
outputOffset += outputCount;
sampleCount -= outputCount;
// if we finished load a next word
if( pchan->currentWord->finished )
{
VOX_FreeWord( pchan );
pchan->wordIndex++;
VOX_LoadWord( pchan );
if( pchan->currentWord )
{
pchan->sfx = pchan->words[pchan->wordIndex].sfx;
}
}
}
return outputOffset - startingOffset;
}
// link all sounds in sentence, start playing first word.
void VOX_LoadSound( channel_t *pchan, const char *pszin )
{
char buffer[512];
int i, cword;
char pathbuffer[64];
char szpath[32];
voxword_t rgvoxword[CVOXWORDMAX];
char *psz;
if( !pszin || !*pszin )
return;
memset( rgvoxword, 0, sizeof( voxword_t ) * CVOXWORDMAX );
memset( buffer, 0, sizeof( buffer ));
// lookup actual string in g_Sentences,
// set pointer to string data
psz = VOX_LookupString( pszin, NULL );
if( !psz )
{
Con_DPrintf( S_ERROR "VOX_LoadSound: no such sentence %s\n", pszin );
return;
}
// get directory from string, advance psz
psz = VOX_GetDirectory( szpath, psz );
if( Q_strlen( psz ) > sizeof( buffer ) - 1 )
{
MsgDev( D_ERROR, "VOX_LoadSound: sentence is too long %s\n", psz );
return;
}
// copy into buffer
Q_strcpy( buffer, psz );
psz = buffer;
// parse sentence (also inserts null terminators between words)
VOX_ParseString( psz );
// for each word in the sentence, construct the filename,
// lookup the sfx and save each pointer in a temp array
i = 0;
cword = 0;
while( rgpparseword[i] )
{
// Get any pitch, volume, start, end params into voxword
if( VOX_ParseWordParams( rgpparseword[i], &rgvoxword[cword], i == 0 ))
{
// this is a valid word (as opposed to a parameter block)
Q_strcpy( pathbuffer, szpath );
Q_strncat( pathbuffer, rgpparseword[i], sizeof( pathbuffer ));
Q_strncat( pathbuffer, ".wav", sizeof( pathbuffer ));
// find name, if already in cache, mark voxword
// so we don't discard when word is done playing
rgvoxword[cword].sfx = S_FindName( pathbuffer, &( rgvoxword[cword].fKeepCached ));
cword++;
}
i++;
}
VOX_LoadFirstWord( pchan, rgvoxword );
pchan->isSentence = true;
pchan->sfx = rgvoxword[0].sfx;
}
//-----------------------------------------------------------------------------
// Purpose: Take a NULL terminated sentence, and parse any commands contained in
// {}. The string is rewritten in place with those commands removed.
//
// Input : *pSentenceData - sentence data to be modified in place
// sentenceIndex - global sentence table index for any data that is
// parsed out
//-----------------------------------------------------------------------------
void VOX_ParseLineCommands( char *pSentenceData, int sentenceIndex )
{
char tempBuffer[512];
char *pNext, *pStart;
int length, tempBufferPos = 0;
if( !pSentenceData )
return;
pStart = pSentenceData;
while( *pSentenceData )
{
pNext = ScanForwardUntil( pSentenceData, '{' );
// find length of "good" portion of the string (not a {} command)
length = pNext - pSentenceData;
if( tempBufferPos + length > sizeof( tempBuffer ))
{
MsgDev( D_ERROR, "sentence too long!\n" );
return;
}
// Copy good string to temp buffer
memcpy( tempBuffer + tempBufferPos, pSentenceData, length );
// move the copy position
tempBufferPos += length;
pSentenceData = pNext;
// skip ahead of the opening brace
if( *pSentenceData ) pSentenceData++;
// skip whitespace
while( *pSentenceData && *pSentenceData <= 32 )
pSentenceData++;
// simple comparison of string commands:
switch( Q_tolower( *pSentenceData ))
{
case 'l':
// all commands starting with the letter 'l' here
if( !Q_strnicmp( pSentenceData, "len", 3 ))
{
g_Sentences[sentenceIndex].length = Q_atof( pSentenceData + 3 );
}
break;
case 0:
default:
break;
}
pSentenceData = ScanForwardUntil( pSentenceData, '}' );
// skip the closing brace
if( *pSentenceData ) pSentenceData++;
// skip trailing whitespace
while( *pSentenceData && *pSentenceData <= 32 )
pSentenceData++;
}
if( tempBufferPos < sizeof( tempBuffer ))
{
// terminate cleaned up copy
tempBuffer[tempBufferPos] = 0;
// copy it over the original data
Q_strcpy( pStart, tempBuffer );
}
}
// Load sentence file into memory, insert null terminators to
// delimit sentence name/sentence pairs. Keep pointer to each
// sentence name so we can search later.
void VOX_ReadSentenceFile( const char *psentenceFileName )
{
char c, *pch, *pFileData;
char *pchlast, *pSentenceData;
int fileSize;
// load file
pFileData = (char *)FS_LoadFile( psentenceFileName, &fileSize, false );
if( !pFileData ) return; // this game just doesn't used vox sound system
pch = pFileData;
pchlast = pch + fileSize;
while( pch < pchlast )
{
// only process this pass on sentences
pSentenceData = NULL;
// skip newline, cr, tab, space
c = *pch;
while( pch < pchlast && IsWhiteSpace( c ))
c = *(++pch);
// skip entire line if first char is /
if( *pch != '/' )
{
sentence_t *pSentence = &g_Sentences[g_numSentences++];
pSentence->pName = pch;
pSentence->length = 0;
// scan forward to first space, insert null terminator
// after sentence name
c = *pch;
while( pch < pchlast && c != ' ' )
c = *(++pch);
if( pch < pchlast )
*pch++ = 0;
// a sentence may have some line commands, make an extra pass
pSentenceData = pch;
}
// scan forward to end of sentence or eof
while( pch < pchlast && pch[0] != '\n' && pch[0] != '\r' )
pch++;
// insert null terminator
if( pch < pchlast ) *pch++ = 0;
// If we have some sentence data, parse out any line commands
if( pSentenceData && pSentenceData < pchlast )
{
int index = g_numSentences - 1;
// the current sentence has an index of count-1
VOX_ParseLineCommands( pSentenceData, index );
}
}
}
void VOX_Init( void )
{
memset( g_Sentences, 0, sizeof( g_Sentences ));
g_numSentences = 0;
VOX_ReadSentenceFile( DEFAULT_SOUNDPATH "sentences.txt" );
}
void VOX_Shutdown( void )
{
g_numSentences = 0;
}

359
engine/client/sound.h Normal file
View File

@ -0,0 +1,359 @@
/*
sound.h - sndlib main header
Copyright (C) 2009 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.
*/
#ifndef SOUND_H
#define SOUND_H
extern byte *sndpool;
#include "mathlib.h"
// sound engine rate defines
#define SOUND_DMA_SPEED 44100 // hardware playback rate
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_16k 16000 // 16khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_32k 32000 // 32khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
#define SND_TRACE_UPDATE_MAX 2 // max of N channels may be checked for obscured source per frame
#define SND_RADIUS_MAX 240.0f // max sound source radius
#define SND_RADIUS_MIN 24.0f // min sound source radius
#define SND_OBSCURED_LOSS_DB -2.70f // dB loss due to obscured sound source
// calculate gain based on atmospheric attenuation.
// as gain excedes threshold, round off (compress) towards 1.0 using spline
#define SND_GAIN_COMP_EXP_MAX 2.5f // Increasing SND_GAIN_COMP_EXP_MAX fits compression curve
// more closely to original gain curve as it approaches 1.0.
#define SND_GAIN_FADE_TIME 0.25f // xfade seconds between obscuring gain changes
#define SND_GAIN_COMP_EXP_MIN 0.8f
#define SND_GAIN_COMP_THRESH 0.5f // gain value above which gain curve is rounded to approach 1.0
#define SND_DB_MAX 140.0f // max db of any sound source
#define SND_DB_MED 90.0f // db at which compression curve changes
#define SND_DB_MIN 60.0f // min db of any sound source
#define SND_GAIN_PLAYER_WEAPON_DB 2.0f // increase player weapon gain by N dB
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE (1 << FIX_BITS)
#define FIX_MASK ((1 << FIX_BITS)-1)
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
#define FIX(a) (((int)(a)) << FIX_BITS)
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
#define SNDLVL_TO_DIST_MULT( sndlvl ) \
( sndlvl ? ((pow( 10, s_refdb->value / 20 ) / pow( 10, (float)sndlvl / 20 )) / s_refdist->value ) : 0 )
#define DIST_MULT_TO_SNDLVL( dist_mult ) \
(int)( dist_mult ? ( 20 * log10( pow( 10, s_refdb->value / 20 ) / (dist_mult * s_refdist->value ))) : 0 )
// NOTE: clipped sound at 32760 to avoid overload
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define SWAP( a, b, t ) {(t) = (a); (a) = (b); (b) = (t);}
#define AVG( a, b ) (((a) + (b)) >> 1 )
#define AVG4( a, b, c, d ) (((a) + (b) + (c) + (d)) >> 2 )
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
#define PAINTBUFFER (g_curpaintbuffer)
#define CPAINTBUFFERS 3
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
typedef struct
{
int left;
int right;
} portable_samplepair_t;
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
extern portable_samplepair_t paintbuffer[];
extern portable_samplepair_t roombuffer[];
extern portable_samplepair_t temppaintbuffer[];
extern portable_samplepair_t *g_curpaintbuffer;
extern paintbuffer_t paintbuffers[];
// structure used for fading in and out client sound volume.
typedef struct
{
float initial_percent;
float percent; // how far to adjust client's volume down by.
float starttime; // GetHostTime() when we started adjusting volume
float fadeouttime; // # of seconds to get to faded out state
float holdtime; // # of seconds to hold
float fadeintime; // # of seconds to restore
} soundfade_t;
typedef struct
{
float percent;
} musicfade_t;
typedef struct
{
int samples; // mono samples in buffer
int samplepos; // in mono samples
byte *buffer;
qboolean initialized; // sound engine is active
} dma_t;
#include "vox.h"
typedef struct
{
double sample;
wavdata_t *pData;
double forcedEndSample;
qboolean finished;
} mixer_t;
typedef struct rawchan_s
{
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
float radius; // radius of this sound effect
volatile uint s_rawend;
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
} rawchan_t;
typedef struct channel_s
{
char name[16]; // keept sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
qboolean isSentence; // bit who indicated sentence
int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds
qboolean staticsound; // use origin instead of fetching entnum's origin
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
// sound culling
qboolean bfirstpass; // true if this is first time sound is spatialized
float ob_gain; // gain drop if sound source obscured from listener
float ob_gain_target; // target gain while crossfading between ob_gain & ob_gain_target
float ob_gain_inc; // crossfade increment
qboolean bTraced; // true if channel was already checked this frame for obscuring
float radius; // radius of this sound effect
vec3_t absmin, absmax; // filled in CL_GetEntitySpatialization
int movetype; // to determine point entities
// sentence mixer
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX];
} channel_t;
typedef struct
{
vec3_t origin; // simorg + view_ofs
vec3_t velocity;
vec3_t forward;
vec3_t right;
vec3_t up;
int entnum;
int waterlevel;
float frametime; // used for sound fade
qboolean active;
qboolean inmenu; // listener in-menu ?
qboolean paused;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
byte pasbytes[(MAX_MAP_LEAFS+7)/8];// actual PHS for current frame
} listener_t;
typedef struct
{
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
} bg_track_t;
/*
====================================================================
SYSTEM SPECIFIC FUNCTIONS
====================================================================
*/
// initializes cycling through a DMA buffer and returns information on it
qboolean SNDDMA_Init( void *hInst );
int SNDDMA_GetSoundtime( void );
void SNDDMA_Shutdown( void );
void SNDDMA_BeginPainting( void );
void SNDDMA_Submit( void );
void SNDDMA_LockSound( void );
void SNDDMA_UnlockSound( void );
//====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 16
#define MAX_RAW_SAMPLES 8192
extern sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern convar_t *s_volume;
extern convar_t *s_musicvolume;
extern convar_t *s_show;
extern convar_t *s_mixahead;
extern convar_t *s_lerping;
extern convar_t *dsp_off;
extern convar_t *s_test; // cvar to testify new effects
void S_InitScaletable( void );
wavdata_t *S_LoadSound( sfx_t *sfx );
float S_GetMasterVolume( void );
float S_GetMusicVolume( void );
//
// s_main.c
//
void S_FreeChannel( channel_t *ch );
//
// s_mix.c
//
int S_MixDataToDevice( channel_t *pChannel, int sampleCount, int outputRate, int outputOffset, int timeCompress );
void MIX_ClearAllPaintBuffers( int SampleCount, qboolean clearFilters );
void MIX_InitAllPaintbuffers( void );
void MIX_FreeAllPaintbuffers( void );
void MIX_PaintChannels( int endtime );
// s_load.c
qboolean S_TestSoundChar( const char *pch, char c );
char *S_SkipSoundChar( const char *pch );
sfx_t *S_FindName( const char *name, int *pfInCache );
sound_t S_RegisterSound( const char *name );
void S_FreeSound( sfx_t *sfx );
// s_dsp.c
void SX_Init( void );
void SX_Free( void );
void CheckNewDspPresets( void );
void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount );
float DSP_GetGain( int idsp );
void DSP_ClearState( void );
qboolean S_Init( void );
void S_Shutdown( void );
void S_Activate( qboolean active, void *hInst );
void S_SoundList_f( void );
void S_SoundInfo_f( void );
channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean *ignore );
channel_t *SND_PickStaticChannel( const vec3_t pos, sfx_t *sfx );
int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
sfx_t *S_GetSfxByHandle( sound_t handle );
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
void S_StopSound( int entnum, int channel, const char *soundname );
uint S_GetRawSamplesLength( int entnum );
void S_ClearRawChannel( int entnum );
void S_StopAllSounds( qboolean ambient );
void S_FreeSounds( void );
//
// s_mouth.c
//
void SND_InitMouth( int entnum, int entchannel );
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count );
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count );
void SND_CloseMouth( channel_t *ch );
//
// s_stream.c
//
void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
void S_PrintBackgroundTrackState( void );
void S_FadeMusicVolume( float fadePercent );
//
// s_utils.c
//
int S_ZeroCrossingAfter( wavdata_t *pWaveData, int sample );
int S_ZeroCrossingBefore( wavdata_t *pWaveData, int sample );
int S_GetOutputData( wavdata_t *pSource, void **pData, int samplePosition, int sampleCount, qboolean use_loop );
void S_SetSampleStart( channel_t *pChan, wavdata_t *pSource, int newPosition );
void S_SetSampleEnd( channel_t *pChan, wavdata_t *pSource, int newEndPosition );
//
// s_vox.c
//
void VOX_Init( void );
void VOX_Shutdown( void );
void VOX_SetChanVol( channel_t *ch );
void VOX_LoadSound( channel_t *pchan, const char *psz );
float VOX_ModifyPitch( channel_t *ch, float pitch );
int VOX_MixDataToDevice( channel_t *pChannel, int sampleCount, int outputRate, int outputOffset );
#endif//SOUND_H

View File

@ -0,0 +1,110 @@
/*
vgui_clip.cpp - clip in 2D space
Copyright (C) 2011 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 "vgui_draw.h"
#include "wrect.h"
//-----------------------------------------------------------------------------
// For simulated scissor tests...
//-----------------------------------------------------------------------------
static wrect_t g_ScissorRect;
static qboolean g_bScissor = false;
//-----------------------------------------------------------------------------
// Enable/disable scissoring...
//-----------------------------------------------------------------------------
void EnableScissor( qboolean enable )
{
g_bScissor = enable;
}
void SetScissorRect( int left, int top, int right, int bottom )
{
// Check for a valid rectangle...
Assert( left <= right );
Assert( top <= bottom );
g_ScissorRect.left = left;
g_ScissorRect.top = top;
g_ScissorRect.right = right;
g_ScissorRect.bottom = bottom;
}
//-----------------------------------------------------------------------------
// Purpose: Used for clipping, produces an interpolated texture coordinate
//-----------------------------------------------------------------------------
inline float InterpTCoord( float val, float mins, float maxs, float tMin, float tMax )
{
float flPercent;
if( mins != maxs )
flPercent = (float)(val - mins) / (maxs - mins);
else flPercent = 0.5f;
return tMin + (tMax - tMin) * flPercent;
}
//-----------------------------------------------------------------------------
// Purpose: Does a scissor clip of the input rectangle.
// Returns false if it is completely clipped off.
//-----------------------------------------------------------------------------
qboolean ClipRect( const vpoint_t &inUL, const vpoint_t &inLR, vpoint_t *pOutUL, vpoint_t *pOutLR )
{
if( g_bScissor )
{
// pick whichever left side is larger
if( g_ScissorRect.left > inUL.point[0] )
pOutUL->point[0] = g_ScissorRect.left;
else
pOutUL->point[0] = inUL.point[0];
// pick whichever right side is smaller
if( g_ScissorRect.right <= inLR.point[0] )
pOutLR->point[0] = g_ScissorRect.right;
else
pOutLR->point[0] = inLR.point[0];
// pick whichever top side is larger
if( g_ScissorRect.top > inUL.point[1] )
pOutUL->point[1] = g_ScissorRect.top;
else
pOutUL->point[1] = inUL.point[1];
// pick whichever bottom side is smaller
if( g_ScissorRect.bottom <= inLR.point[1] )
pOutLR->point[1] = g_ScissorRect.bottom;
else
pOutLR->point[1] = inLR.point[1];
// Check for non-intersecting
if(( pOutUL->point[0] > pOutLR->point[0] ) || ( pOutUL->point[1] > pOutLR->point[1] ))
{
return false;
}
pOutUL->coord[0] = InterpTCoord(pOutUL->point[0], inUL.point[0], inLR.point[0], inUL.coord[0], inLR.coord[0] );
pOutLR->coord[0] = InterpTCoord(pOutLR->point[0], inUL.point[0], inLR.point[0], inUL.coord[0], inLR.coord[0] );
pOutUL->coord[1] = InterpTCoord(pOutUL->point[1], inUL.point[1], inLR.point[1], inUL.coord[1], inLR.coord[1] );
pOutLR->coord[1] = InterpTCoord(pOutLR->point[1], inUL.point[1], inLR.point[1], inUL.coord[1], inLR.coord[1] );
}
else
{
*pOutUL = inUL;
*pOutLR = inLR;
}
return true;
}

View File

@ -0,0 +1,218 @@
/*
vgui_draw.c - vgui draw methods
Copyright (C) 2011 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 "gl_local.h"
#include "vgui_draw.h"
convar_t *vgui_colorstrings;
int g_textures[VGUI_MAX_TEXTURES];
int g_textureId = 0;
/*
================
VGUI_DrawInit
Startup VGUI backend
================
*/
void VGUI_DrawInit( void )
{
memset( g_textures, 0, sizeof( g_textures ));
g_textureId = 0;
vgui_colorstrings = Cvar_Get( "vgui_colorstrings", "0", FCVAR_ARCHIVE, "allow colorstrings in VGUI texts" );
}
/*
================
VGUI_DrawShutdown
Release all the textures
================
*/
void VGUI_DrawShutdown( void )
{
int i;
for( i = 1; i < g_textureId; i++ )
{
GL_FreeImage( va( "*vgui%i", i ));
}
}
/*
================
VGUI_GenerateTexture
generate unique texture number
================
*/
int VGUI_GenerateTexture( void )
{
if( ++g_textureId >= VGUI_MAX_TEXTURES )
Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
return g_textureId;
}
/*
================
VGUI_UploadTexture
Upload texture into video memory
================
*/
void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
{
rgbdata_t r_image;
char texName[32];
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
{
MsgDev( D_ERROR, "VGUI_UploadTexture: bad texture %i. Ignored\n", id );
return;
}
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
memset( &r_image, 0, sizeof( r_image ));
r_image.width = width;
r_image.height = height;
r_image.type = PF_RGBA_32;
r_image.size = r_image.width * r_image.height * 4;
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
r_image.buffer = (byte *)buffer;
g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE, false );
}
/*
================
VGUI_SetupDrawingRect
setup transparency etc
================
*/
void VGUI_SetupDrawingRect( int *pColor )
{
pglEnable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglColor4ub( pColor[0], pColor[1], pColor[2], 255 - pColor[3] );
}
/*
================
VGUI_SetupDrawingImage
setup transparency etc
================
*/
void VGUI_SetupDrawingImage( int *pColor )
{
pglEnable( GL_BLEND );
pglEnable( GL_ALPHA_TEST );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglColor4ub( pColor[0], pColor[1], pColor[2], 255 - pColor[3] );
}
/*
================
VGUI_BindTexture
bind VGUI texture through private index
================
*/
void VGUI_BindTexture( int id )
{
if( id > 0 && id < VGUI_MAX_TEXTURES && g_textures[id] )
{
GL_Bind( GL_TEXTURE0, g_textures[id] );
}
else
{
// NOTE: same as bogus index 2700 in GoldSrc
GL_Bind( GL_TEXTURE0, g_textures[1] );
}
}
/*
================
VGUI_EnableTexture
disable texturemode for fill rectangle
================
*/
void VGUI_EnableTexture( qboolean enable )
{
if( enable ) pglEnable( GL_TEXTURE_2D );
else pglDisable( GL_TEXTURE_2D );
}
/*
================
VGUI_DrawQuad
generic method to fill rectangle
================
*/
void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
{
pglBegin( GL_QUADS );
pglTexCoord2f( ul->coord[0], ul->coord[1] );
pglVertex2f( ul->point[0], ul->point[1] );
pglTexCoord2f( lr->coord[0], ul->coord[1] );
pglVertex2f( lr->point[0], ul->point[1] );
pglTexCoord2f( lr->coord[0], lr->coord[1] );
pglVertex2f( lr->point[0], lr->point[1] );
pglTexCoord2f( ul->coord[0], lr->coord[1] );
pglVertex2f( ul->point[0], lr->point[1] );
pglEnd();
}
/*
================
VGUI_DrawBuffer
render the quads array
================
*/
void VGUI_DrawBuffer( const vpoint_t *buffer, int numVerts )
{
if( numVerts <= 0 ) return;
pglEnable( GL_BLEND );
pglEnable( GL_ALPHA_TEST );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglEnableClientState( GL_VERTEX_ARRAY );
pglEnableClientState( GL_TEXTURE_COORD_ARRAY );
pglEnableClientState( GL_COLOR_ARRAY );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vpoint_t ), &buffer->coord[0] );
pglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( vpoint_t ), &buffer->color[0] );
pglVertexPointer( 2, GL_FLOAT, sizeof( vpoint_t ), &buffer->point[0] );
pglDrawArrays( GL_QUADS, 0, numVerts );
pglDisableClientState( GL_VERTEX_ARRAY );
pglDisableClientState( GL_TEXTURE_COORD_ARRAY );
pglDisableClientState( GL_COLOR_ARRAY );
}

View File

@ -0,0 +1,77 @@
/*
vgui_draw.h - vgui draw methods
Copyright (C) 2011 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.
*/
#ifndef VGUI_DRAW_H
#define VGUI_DRAW_H
#ifdef __cplusplus
extern "C" {
#endif
#define VGUI_MAX_TEXTURES 2048 // a half of total textures count
extern rgba_t g_color_table[8]; // for colored strings support
extern convar_t *vgui_colorstrings;
// VGUI generic vertex
typedef struct
{
vec2_t point;
vec2_t coord;
byte color[4];
} vpoint_t;
//
// vgui_backend.c
//
void VGUI_DrawInit( void );
void VGUI_DrawShutdown( void );
void VGUI_SetupDrawingRect( int *pColor );
void VGUI_SetupDrawingImage( int *pColor );
void VGUI_BindTexture( int id );
void VGUI_EnableTexture( qboolean enable );
void VGUI_UploadTexture( int id, const char *buffer, int width, int height );
LONG VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
void VGUI_DrawBuffer( const vpoint_t *buffer, int numVerts );
int VGUI_GenerateTexture( void );
void *VGui_GetPanel( void );
#ifdef __cplusplus
void EnableScissor( qboolean enable );
void SetScissorRect( int left, int top, int right, int bottom );
qboolean ClipRect( const vpoint_t &inUL, const vpoint_t &inLR, vpoint_t *pOutUL, vpoint_t *pOutLR );
#endif
//
// gl_vidnt.c
//
qboolean R_DescribeVIDMode( int width, int height );
//
// vgui_int.c
//
void VGui_Startup( void );
void VGui_Shutdown( void );
void *VGui_GetPanel( void );
void VGui_Paint( int paintAll );
void VGui_RunFrame( void );
void VGui_ViewportPaintBackground( int extents[4] );
#ifdef __cplusplus
}
#endif
#endif//VGUI_DRAW_H

View File

@ -0,0 +1,290 @@
/*
vgui_input.cpp - handle kb & mouse
Copyright (C) 2011 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.
*/
#define OEMRESOURCE // for OCR_* cursor junk
#include "common.h"
#include "client.h"
#include "vgui_draw.h"
#include "vgui_main.h"
#include "input.h"
static KeyCode s_pVirtualKeyTrans[256];
static HICON s_pDefaultCursor[20];
static HICON s_hCurrentCursor = NULL;
void VGUI_InitCursors( void )
{
// load up all default cursors
s_pDefaultCursor[Cursor::dc_none] = NULL;
s_pDefaultCursor[Cursor::dc_arrow] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_NORMAL );
s_pDefaultCursor[Cursor::dc_ibeam] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_IBEAM );
s_pDefaultCursor[Cursor::dc_hourglass]= (HICON)LoadCursor( NULL, (LPCTSTR)OCR_WAIT );
s_pDefaultCursor[Cursor::dc_crosshair]= (HICON)LoadCursor( NULL, (LPCTSTR)OCR_CROSS );
s_pDefaultCursor[Cursor::dc_up] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_UP );
s_pDefaultCursor[Cursor::dc_sizenwse] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_SIZENWSE );
s_pDefaultCursor[Cursor::dc_sizenesw] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_SIZENESW );
s_pDefaultCursor[Cursor::dc_sizewe] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_SIZEWE );
s_pDefaultCursor[Cursor::dc_sizens] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_SIZENS );
s_pDefaultCursor[Cursor::dc_sizeall] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_SIZEALL );
s_pDefaultCursor[Cursor::dc_no] = (HICON)LoadCursor( NULL, (LPCTSTR)OCR_NO );
s_pDefaultCursor[Cursor::dc_hand] = (HICON)LoadCursor( NULL, (LPCTSTR)32649 );
s_hCurrentCursor = s_pDefaultCursor[Cursor::dc_arrow];
host.mouse_visible = true;
}
void VGUI_CursorSelect( Cursor *cursor )
{
Assert( cursor != NULL );
host.mouse_visible = true;
switch( cursor->getDefaultCursor( ))
{
case Cursor::dc_user:
case Cursor::dc_none:
host.mouse_visible = false;
break;
case Cursor::dc_arrow:
case Cursor::dc_ibeam:
case Cursor::dc_hourglass:
case Cursor::dc_crosshair:
case Cursor::dc_up:
case Cursor::dc_sizenwse:
case Cursor::dc_sizenesw:
case Cursor::dc_sizewe:
case Cursor::dc_sizens:
case Cursor::dc_sizeall:
case Cursor::dc_no:
case Cursor::dc_hand:
s_hCurrentCursor = s_pDefaultCursor[cursor->getDefaultCursor()];
break;
default:
host.mouse_visible = false;
Assert( 0 );
break;
}
VGUI_ActivateCurrentCursor();
}
void VGUI_ActivateCurrentCursor( void )
{
if( cls.key_dest != key_game || cl.paused )
return;
if( host.mouse_visible )
{
while( ShowCursor( true ) < 0 );
SetCursor( s_hCurrentCursor );
}
else
{
while( ShowCursor( false ) >= 0 );
SetCursor( NULL );
}
}
void VGUI_InitKeyTranslationTable( void )
{
static bool bInitted = false;
if( bInitted ) return;
bInitted = true;
// set virtual key translation table
memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ));
s_pVirtualKeyTrans['0'] = KEY_0;
s_pVirtualKeyTrans['1'] = KEY_1;
s_pVirtualKeyTrans['2'] = KEY_2;
s_pVirtualKeyTrans['3'] = KEY_3;
s_pVirtualKeyTrans['4'] = KEY_4;
s_pVirtualKeyTrans['5'] = KEY_5;
s_pVirtualKeyTrans['6'] = KEY_6;
s_pVirtualKeyTrans['7'] = KEY_7;
s_pVirtualKeyTrans['8'] = KEY_8;
s_pVirtualKeyTrans['9'] = KEY_9;
s_pVirtualKeyTrans['A'] = s_pVirtualKeyTrans['a'] = KEY_A;
s_pVirtualKeyTrans['B'] = s_pVirtualKeyTrans['b'] = KEY_B;
s_pVirtualKeyTrans['C'] = s_pVirtualKeyTrans['c'] = KEY_C;
s_pVirtualKeyTrans['D'] = s_pVirtualKeyTrans['d'] = KEY_D;
s_pVirtualKeyTrans['E'] = s_pVirtualKeyTrans['e'] = KEY_E;
s_pVirtualKeyTrans['F'] = s_pVirtualKeyTrans['f'] = KEY_F;
s_pVirtualKeyTrans['G'] = s_pVirtualKeyTrans['g'] = KEY_G;
s_pVirtualKeyTrans['H'] = s_pVirtualKeyTrans['h'] = KEY_H;
s_pVirtualKeyTrans['I'] = s_pVirtualKeyTrans['i'] = KEY_I;
s_pVirtualKeyTrans['J'] = s_pVirtualKeyTrans['j'] = KEY_J;
s_pVirtualKeyTrans['K'] = s_pVirtualKeyTrans['k'] = KEY_K;
s_pVirtualKeyTrans['L'] = s_pVirtualKeyTrans['l'] = KEY_L;
s_pVirtualKeyTrans['M'] = s_pVirtualKeyTrans['m'] = KEY_M;
s_pVirtualKeyTrans['N'] = s_pVirtualKeyTrans['n'] = KEY_N;
s_pVirtualKeyTrans['O'] = s_pVirtualKeyTrans['o'] = KEY_O;
s_pVirtualKeyTrans['P'] = s_pVirtualKeyTrans['p'] = KEY_P;
s_pVirtualKeyTrans['Q'] = s_pVirtualKeyTrans['q'] = KEY_Q;
s_pVirtualKeyTrans['R'] = s_pVirtualKeyTrans['r'] = KEY_R;
s_pVirtualKeyTrans['S'] = s_pVirtualKeyTrans['s'] = KEY_S;
s_pVirtualKeyTrans['T'] = s_pVirtualKeyTrans['t'] = KEY_T;
s_pVirtualKeyTrans['U'] = s_pVirtualKeyTrans['u'] = KEY_U;
s_pVirtualKeyTrans['V'] = s_pVirtualKeyTrans['v'] = KEY_V;
s_pVirtualKeyTrans['W'] = s_pVirtualKeyTrans['w'] = KEY_W;
s_pVirtualKeyTrans['X'] = s_pVirtualKeyTrans['x'] = KEY_X;
s_pVirtualKeyTrans['Y'] = s_pVirtualKeyTrans['y'] = KEY_Y;
s_pVirtualKeyTrans['Z'] = s_pVirtualKeyTrans['z'] = KEY_Z;
s_pVirtualKeyTrans[VK_NUMPAD0] = KEY_PAD_0;
s_pVirtualKeyTrans[VK_NUMPAD1] = KEY_PAD_1;
s_pVirtualKeyTrans[VK_NUMPAD2] = KEY_PAD_2;
s_pVirtualKeyTrans[VK_NUMPAD3] = KEY_PAD_3;
s_pVirtualKeyTrans[VK_NUMPAD4] = KEY_PAD_4;
s_pVirtualKeyTrans[VK_NUMPAD5] = KEY_PAD_5;
s_pVirtualKeyTrans[VK_NUMPAD6] = KEY_PAD_6;
s_pVirtualKeyTrans[VK_NUMPAD7] = KEY_PAD_7;
s_pVirtualKeyTrans[VK_NUMPAD8] = KEY_PAD_8;
s_pVirtualKeyTrans[VK_NUMPAD9] = KEY_PAD_9;
s_pVirtualKeyTrans[VK_DIVIDE] = KEY_PAD_DIVIDE;
s_pVirtualKeyTrans[VK_MULTIPLY] = KEY_PAD_MULTIPLY;
s_pVirtualKeyTrans[VK_SUBTRACT] = KEY_PAD_MINUS;
s_pVirtualKeyTrans[VK_ADD] = KEY_PAD_PLUS;
s_pVirtualKeyTrans[VK_RETURN] = KEY_PAD_ENTER;
s_pVirtualKeyTrans[VK_DECIMAL] = KEY_PAD_DECIMAL;
s_pVirtualKeyTrans[0xdb] = KEY_LBRACKET;
s_pVirtualKeyTrans[0xdd] = KEY_RBRACKET;
s_pVirtualKeyTrans[0xba] = KEY_SEMICOLON;
s_pVirtualKeyTrans[0xde] = KEY_APOSTROPHE;
s_pVirtualKeyTrans[0xc0] = KEY_BACKQUOTE;
s_pVirtualKeyTrans[0xbc] = KEY_COMMA;
s_pVirtualKeyTrans[0xbe] = KEY_PERIOD;
s_pVirtualKeyTrans[0xbf] = KEY_SLASH;
s_pVirtualKeyTrans[0xdc] = KEY_BACKSLASH;
s_pVirtualKeyTrans[0xbd] = KEY_MINUS;
s_pVirtualKeyTrans[0xbb] = KEY_EQUAL;
s_pVirtualKeyTrans[VK_RETURN] = KEY_ENTER;
s_pVirtualKeyTrans[VK_SPACE] = KEY_SPACE;
s_pVirtualKeyTrans[VK_BACK] = KEY_BACKSPACE;
s_pVirtualKeyTrans[VK_TAB] = KEY_TAB;
s_pVirtualKeyTrans[VK_CAPITAL] = KEY_CAPSLOCK;
s_pVirtualKeyTrans[VK_NUMLOCK] = KEY_NUMLOCK;
s_pVirtualKeyTrans[VK_ESCAPE] = KEY_ESCAPE;
s_pVirtualKeyTrans[VK_SCROLL] = KEY_SCROLLLOCK;
s_pVirtualKeyTrans[VK_INSERT] = KEY_INSERT;
s_pVirtualKeyTrans[VK_DELETE] = KEY_DELETE;
s_pVirtualKeyTrans[VK_HOME] = KEY_HOME;
s_pVirtualKeyTrans[VK_END] = KEY_END;
s_pVirtualKeyTrans[VK_PRIOR] = KEY_PAGEUP;
s_pVirtualKeyTrans[VK_NEXT] = KEY_PAGEDOWN;
s_pVirtualKeyTrans[VK_PAUSE] = KEY_BREAK;
s_pVirtualKeyTrans[VK_SHIFT] = KEY_RSHIFT;
s_pVirtualKeyTrans[VK_SHIFT] = KEY_LSHIFT; // SHIFT -> left SHIFT
s_pVirtualKeyTrans[VK_MENU] = KEY_RALT;
s_pVirtualKeyTrans[VK_MENU] = KEY_LALT; // ALT -> left ALT
s_pVirtualKeyTrans[VK_CONTROL] = KEY_RCONTROL;
s_pVirtualKeyTrans[VK_CONTROL] = KEY_LCONTROL; // CTRL -> left CTRL
s_pVirtualKeyTrans[VK_LWIN] = KEY_LWIN;
s_pVirtualKeyTrans[VK_RWIN] = KEY_RWIN;
s_pVirtualKeyTrans[VK_APPS] = KEY_APP;
s_pVirtualKeyTrans[VK_UP] = KEY_UP;
s_pVirtualKeyTrans[VK_LEFT] = KEY_LEFT;
s_pVirtualKeyTrans[VK_DOWN] = KEY_DOWN;
s_pVirtualKeyTrans[VK_RIGHT] = KEY_RIGHT;
s_pVirtualKeyTrans[VK_F1] = KEY_F1;
s_pVirtualKeyTrans[VK_F2] = KEY_F2;
s_pVirtualKeyTrans[VK_F3] = KEY_F3;
s_pVirtualKeyTrans[VK_F4] = KEY_F4;
s_pVirtualKeyTrans[VK_F5] = KEY_F5;
s_pVirtualKeyTrans[VK_F6] = KEY_F6;
s_pVirtualKeyTrans[VK_F7] = KEY_F7;
s_pVirtualKeyTrans[VK_F8] = KEY_F8;
s_pVirtualKeyTrans[VK_F9] = KEY_F9;
s_pVirtualKeyTrans[VK_F10] = KEY_F10;
s_pVirtualKeyTrans[VK_F11] = KEY_F11;
s_pVirtualKeyTrans[VK_F12] = KEY_F12;
}
KeyCode VGUI_MapKey( int keyCode )
{
VGUI_InitKeyTranslationTable();
if( keyCode < 0 || keyCode >= ARRAYSIZE( s_pVirtualKeyTrans ))
{
Assert( 0 );
return (KeyCode)-1;
}
else
{
return s_pVirtualKeyTrans[keyCode];
}
}
LONG VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if( !engSurface )
return 0;
switch( uMsg )
{
case WM_SETCURSOR:
VGUI_ActivateCurrentCursor();
break;
case WM_MOUSEMOVE:
engApp->internalCursorMoved((short)LOWORD( lParam ), (short)HIWORD( lParam ), engSurface );
break;
case WM_LBUTTONDOWN:
engApp->internalMousePressed( MOUSE_LEFT, engSurface );
break;
case WM_RBUTTONDOWN:
engApp->internalMousePressed( MOUSE_RIGHT, engSurface );
break;
case WM_MBUTTONDOWN:
engApp->internalMousePressed( MOUSE_MIDDLE, engSurface );
break;
case WM_LBUTTONUP:
engApp->internalMouseReleased( MOUSE_LEFT, engSurface );
break;
case WM_RBUTTONUP:
engApp->internalMouseReleased( MOUSE_RIGHT, engSurface );
break;
case WM_MBUTTONUP:
engApp->internalMouseReleased( MOUSE_MIDDLE, engSurface );
break;
case WM_LBUTTONDBLCLK:
engApp->internalMouseDoublePressed( MOUSE_LEFT, engSurface );
break;
case WM_RBUTTONDBLCLK:
engApp->internalMouseDoublePressed( MOUSE_RIGHT, engSurface );
break;
case WM_MBUTTONDBLCLK:
engApp->internalMouseDoublePressed( MOUSE_MIDDLE, engSurface );
break;
case WM_MOUSEWHEEL:
engApp->internalMouseWheeled(((short)HIWORD( wParam )) / WHEEL_DELTA, engSurface );
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if( !FBitSet( lParam, BIT( 30 )))
engApp->internalKeyPressed( VGUI_MapKey( wParam ), engSurface );
engApp->internalKeyTyped( VGUI_MapKey( wParam ), engSurface );
break;
case WM_CHAR:
case WM_SYSCHAR:
// already handled in Key_Event
break;
case WM_KEYUP:
case WM_SYSKEYUP:
engApp->internalKeyReleased( VGUI_MapKey( wParam ), engSurface );
break;
}
return 1;
}

View File

@ -0,0 +1,129 @@
/*
vgui_int.cpp - vgui dll interaction
Copyright (C) 2011 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 "const.h"
#include "vgui_draw.h"
#include "vgui_main.h"
Panel *rootPanel = NULL;
CEngineSurface *engSurface = NULL;
CEngineApp staticApp, *engApp;
void CEngineApp :: setCursorPos( int x, int y )
{
POINT pt;
pt.x = x;
pt.y = y;
ClientToScreen( (HWND)host.hWnd, &pt );
::SetCursorPos( pt.x, pt.y );
}
void CEngineApp :: getCursorPos( int &x,int &y )
{
POINT pt;
// find mouse movement
::GetCursorPos( &pt );
ScreenToClient((HWND)host.hWnd, &pt );
x = pt.x;
y = pt.y;
}
void VGui_RunFrame( void )
{
if( GetModuleHandle( "fraps32.dll" ) || GetModuleHandle( "fraps64.dll" ))
host.force_draw_version = true;
else host.force_draw_version = false;
}
void VGui_SetRootPanelSize( void )
{
if( rootPanel != NULL )
rootPanel->setBounds( 0, 0, gameui.globals->scrWidth, gameui.globals->scrHeight );
}
void VGui_Startup( void )
{
if( engSurface ) return;
engApp = (CEngineApp *)App::getInstance();
engApp->reset();
engApp->setMinimumTickMillisInterval( 0 ); // paint every frame
rootPanel = new Panel( 0, 0, 320, 240 ); // size will be changed in VGui_SetRootPanelSize
rootPanel->setPaintBorderEnabled( false );
rootPanel->setPaintBackgroundEnabled( false );
rootPanel->setPaintEnabled( false );
rootPanel->setCursor( engApp->getScheme()->getCursor( Scheme::scu_none ));
engSurface = new CEngineSurface( rootPanel );
VGui_SetRootPanelSize ();
VGUI_DrawInit ();
}
void VGui_Shutdown( void )
{
delete rootPanel;
delete engSurface;
engSurface = NULL;
rootPanel = NULL;
}
void VGui_Paint( int paintAll )
{
int extents[4];
if( cls.state != ca_active || !rootPanel )
return;
VGui_SetRootPanelSize ();
rootPanel->repaint();
EnableScissor( true );
if( cls.key_dest == key_game )
{
App::getInstance()->externalTick();
}
if( paintAll )
{
// paint everything
rootPanel->paintTraverse();
}
else
{
rootPanel->getAbsExtents( extents[0], extents[1], extents[2], extents[3] );
VGui_ViewportPaintBackground( extents );
}
EnableScissor( false );
}
void VGui_ViewportPaintBackground( int extents[4] )
{
// Msg( "Vgui_ViewportPaintBackground( %i, %i, %i, %i )\n", extents[0], extents[1], extents[2], extents[3] );
}
void *VGui_GetPanel( void )
{
return (void *)rootPanel;
}

View File

@ -0,0 +1,117 @@
/*
vgui_main.h - vgui main header
Copyright (C) 2011 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.
*/
#ifndef VGUI_MAIN_H
#define VGUI_MAIN_H
#include<VGUI.h>
#include<VGUI_App.h>
#include<VGUI_Font.h>
#include<VGUI_Panel.h>
#include<VGUI_Cursor.h>
#include<VGUI_SurfaceBase.h>
#include<VGUI_InputSignal.h>
#include<VGUI_MouseCode.h>
#include<VGUI_KeyCode.h>
using namespace vgui;
struct PaintStack
{
Panel *m_pPanel;
int iTranslateX;
int iTranslateY;
int iScissorLeft;
int iScissorRight;
int iScissorTop;
int iScissorBottom;
};
class CEngineSurface : public SurfaceBase
{
private:
void InitVertex( vpoint_t &vertex, int x, int y, float u, float v );
public:
CEngineSurface( Panel *embeddedPanel );
~CEngineSurface();
public:
// not used in engine instance
virtual bool setFullscreenMode( int wide, int tall, int bpp ) { return false; }
virtual void setWindowedMode( void ) { }
virtual void setTitle( const char *title ) { }
virtual void createPopup( Panel* embeddedPanel ) { }
virtual bool isWithin( int x, int y ) { return true; }
void SetupPaintState( const PaintStack *paintState );
#ifdef NEW_VGUI_DLL
virtual void GetMousePos( int &x, int &y ) { }
#endif
virtual bool hasFocus( void ) { return true; }
protected:
virtual int createNewTextureID( void );
virtual void drawSetColor( int r, int g, int b, int a );
virtual void drawSetTextColor( int r, int g, int b, int a );
virtual void drawFilledRect( int x0, int y0, int x1, int y1 );
virtual void drawOutlinedRect( int x0,int y0,int x1,int y1 );
virtual void drawSetTextFont( Font *font );
virtual void drawSetTextPos( int x, int y );
virtual void drawPrintText( const char* text, int textLen );
virtual void drawSetTextureRGBA( int id, const char* rgba, int wide, int tall );
virtual void drawSetTexture( int id );
virtual void drawTexturedRect( int x0, int y0, int x1, int y1 );
virtual void drawPrintChar( int x, int y, int wide, int tall, float s0, float t0, float s1, float t1, int color[4] );
virtual void addCharToBuffer( const vpoint_t *ul, const vpoint_t *lr, int color[4] );
virtual void setCursor( Cursor* cursor );
virtual void pushMakeCurrent( Panel* panel, bool useInsets );
virtual void popMakeCurrent( Panel* panel );
// not used in engine instance
virtual bool createPlat( void ) { return false; }
virtual bool recreateContext( void ) { return false; }
virtual void enableMouseCapture( bool state ) { }
virtual void invalidate( Panel *panel ) { }
virtual void setAsTopMost( bool state ) { }
virtual void applyChanges( void ) { }
virtual void swapBuffers( void ) { }
virtual void flushBuffer( void );
protected:
int _drawTextPos[2];
int _drawColor[4];
int _drawTextColor[4];
int _translateX, _translateY;
int _currentTexture;
};
// initialize VGUI::App as external (part of engine)
class CEngineApp : public App
{
public:
virtual void main( int argc, char* argv[] ) { }
virtual void setCursorPos( int x, int y ); // we need to recompute abs position to window
virtual void getCursorPos( int &x,int &y );
protected:
virtual void platTick(void) { }
};
extern Panel *rootPanel;
extern CEngineSurface *engSurface;
extern CEngineApp *engApp;
//
// vgui_input.cpp
//
void VGUI_InitCursors( void );
void VGUI_CursorSelect( Cursor *cursor );
void VGUI_ActivateCurrentCursor( void );
#endif//VGUI_MAIN_H

View File

@ -0,0 +1,465 @@
/*
vgui_surf.cpp - main vgui layer
Copyright (C) 2011 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 "vgui_draw.h"
#include "vgui_main.h"
#define MAXVERTEXBUFFERS 1024
#define MAX_PAINT_STACK 8
#define FONT_SIZE 512
#define FONT_PAGES 8
static char staticRGBA[FONT_SIZE * FONT_SIZE * 4];
static vpoint_t g_VertexBuffer[MAXVERTEXBUFFERS];
static int g_iVertexBufferEntriesUsed = 0;
static int staticContextCount = 0;
struct FontInfo
{
int id;
int pageCount;
int pageForChar[256];
int bindIndex[FONT_PAGES];
float texCoord[256][FONT_PAGES];
int contextCount;
};
static Font* staticFont = NULL;
static FontInfo* staticFontInfo;
static Dar<FontInfo*> staticFontInfoDar;
static PaintStack paintStack[MAX_PAINT_STACK];
static staticPaintStackPos = 0;
CEngineSurface :: CEngineSurface( Panel *embeddedPanel ):SurfaceBase( embeddedPanel )
{
_drawTextColor[0] = _drawTextColor[1] = _drawTextColor[2] = _drawTextColor[3] = 255;
_drawColor[0] = _drawColor[1] = _drawColor[2] = _drawColor[3] = 255;
_drawTextPos[0] = _drawTextPos[1] = _currentTexture = 0;
staticFont = NULL;
staticFontInfo = NULL;
staticFontInfoDar.setCount( 0 );
staticPaintStackPos = 0;
staticContextCount++;
VGUI_InitCursors ();
}
CEngineSurface :: ~CEngineSurface( void )
{
VGUI_DrawShutdown ();
}
void CEngineSurface :: setCursor( Cursor *cursor )
{
_currentCursor = cursor;
VGUI_CursorSelect( cursor );
}
void CEngineSurface :: SetupPaintState( const PaintStack *paintState )
{
_translateX = paintState->iTranslateX;
_translateY = paintState->iTranslateY;
SetScissorRect( paintState->iScissorLeft, paintState->iScissorTop, paintState->iScissorRight, paintState->iScissorBottom );
}
void CEngineSurface :: InitVertex( vpoint_t &vertex, int x, int y, float u, float v )
{
vertex.point[0] = x + _translateX;
vertex.point[1] = y + _translateY;
vertex.coord[0] = u;
vertex.coord[1] = v;
}
int CEngineSurface :: createNewTextureID( void )
{
return VGUI_GenerateTexture();
}
void CEngineSurface :: drawSetColor( int r, int g, int b, int a )
{
_drawColor[0] = r;
_drawColor[1] = g;
_drawColor[2] = b;
_drawColor[3] = a;
}
void CEngineSurface :: drawSetTextColor( int r, int g, int b, int a )
{
_drawTextColor[0] = r;
_drawTextColor[1] = g;
_drawTextColor[2] = b;
_drawTextColor[3] = a;
}
void CEngineSurface :: drawFilledRect( int x0, int y0, int x1, int y1 )
{
vpoint_t rect[2];
vpoint_t clippedRect[2];
if( _drawColor[3] >= 255 ) return;
InitVertex( rect[0], x0, y0, 0, 0 );
InitVertex( rect[1], x1, y1, 0, 0 );
// fully clipped?
if( !ClipRect( rect[0], rect[1], &clippedRect[0], &clippedRect[1] ))
return;
VGUI_SetupDrawingRect( _drawColor );
VGUI_EnableTexture( false );
VGUI_DrawQuad( &clippedRect[0], &clippedRect[1] );
VGUI_EnableTexture( true );
}
void CEngineSurface :: drawOutlinedRect( int x0, int y0, int x1, int y1 )
{
if( _drawColor[3] >= 255 ) return;
drawFilledRect( x0, y0, x1, y0 + 1 ); // top
drawFilledRect( x0, y1 - 1, x1, y1 ); // bottom
drawFilledRect( x0, y0 + 1, x0 + 1, y1 - 1 ); // left
drawFilledRect( x1 - 1, y0 + 1, x1, y1 - 1 ); // right
}
void CEngineSurface :: drawSetTextFont( Font *font )
{
staticFont = font;
if( font )
{
bool buildFont = false;
staticFontInfo = NULL;
for( int i = 0; i < staticFontInfoDar.getCount(); i++ )
{
if( staticFontInfoDar[i]->id == font->getId( ))
{
staticFontInfo = staticFontInfoDar[i];
if( staticFontInfo->contextCount != staticContextCount )
buildFont = true;
}
}
if( !staticFontInfo || buildFont )
{
staticFontInfo = new FontInfo;
staticFontInfo->id = 0;
staticFontInfo->pageCount = 0;
staticFontInfo->bindIndex[0] = 0;
staticFontInfo->bindIndex[1] = 0;
staticFontInfo->bindIndex[2] = 0;
staticFontInfo->bindIndex[3] = 0;
memset( staticFontInfo->pageForChar, 0, sizeof( staticFontInfo->pageForChar ));
staticFontInfo->contextCount = -1;
staticFontInfo->id = staticFont->getId();
staticFontInfoDar.putElement( staticFontInfo );
staticFontInfo->contextCount = staticContextCount;
int currentPage = 0;
int x = 0, y = 0;
memset( staticRGBA, 0, sizeof( staticRGBA ));
for( int i = 0; i < 256; i++ )
{
int abcA, abcB, abcC;
staticFont->getCharABCwide( i, abcA, abcB, abcC );
int wide = abcB;
if( isspace( i )) continue;
int tall = staticFont->getTall();
if( x + wide + 1 > FONT_SIZE )
{
x = 0;
y += tall + 1;
}
if( y + tall + 1 > FONT_SIZE )
{
if( !staticFontInfo->bindIndex[currentPage] )
{
int bindIndex = createNewTextureID();
staticFontInfo->bindIndex[currentPage] = bindIndex;
}
drawSetTextureRGBA( staticFontInfo->bindIndex[currentPage], staticRGBA, FONT_SIZE, FONT_SIZE );
currentPage++;
if( currentPage == FONT_PAGES )
break;
memset( staticRGBA, 0, sizeof( staticRGBA ));
x = y = 0;
}
staticFont->getCharRGBA( i, x, y, FONT_SIZE, FONT_SIZE, (byte *)staticRGBA );
staticFontInfo->pageForChar[i] = currentPage;
staticFontInfo->texCoord[i][0] = (float)((double)x / (double)FONT_SIZE );
staticFontInfo->texCoord[i][1] = (float)((double)y / (double)FONT_SIZE );
staticFontInfo->texCoord[i][2] = (float)((double)(x + wide)/(double)FONT_SIZE );
staticFontInfo->texCoord[i][3] = (float)((double)(y + tall)/(double)FONT_SIZE );
x += wide + 1;
}
if( currentPage != FONT_PAGES )
{
if( !staticFontInfo->bindIndex[currentPage] )
{
int bindIndex = createNewTextureID();
staticFontInfo->bindIndex[currentPage] = bindIndex;
}
drawSetTextureRGBA( staticFontInfo->bindIndex[currentPage], staticRGBA, FONT_SIZE, FONT_SIZE );
}
staticFontInfo->pageCount = currentPage + 1;
}
}
}
void CEngineSurface :: drawSetTextPos( int x, int y )
{
_drawTextPos[0] = x;
_drawTextPos[1] = y;
}
void CEngineSurface :: addCharToBuffer( const vpoint_t *ul, const vpoint_t *lr, int color[4] )
{
if( g_iVertexBufferEntriesUsed >= MAXVERTEXBUFFERS )
flushBuffer();
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].coord[0] = ul->coord[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].coord[1] = ul->coord[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].point[0] = ul->point[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].point[1] = ul->point[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].color[0] = color[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].color[1] = color[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].color[2] = color[2];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 0].color[3] = 255 - color[3];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].coord[0] = lr->coord[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].coord[1] = ul->coord[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].point[0] = lr->point[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].point[1] = ul->point[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].color[0] = color[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].color[1] = color[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].color[2] = color[2];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 1].color[3] = 255 - color[3];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].coord[0] = lr->coord[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].coord[1] = lr->coord[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].point[0] = lr->point[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].point[1] = lr->point[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].color[0] = color[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].color[1] = color[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].color[2] = color[2];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 2].color[3] = 255 - color[3];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].coord[0] = ul->coord[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].coord[1] = lr->coord[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].point[0] = ul->point[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].point[1] = lr->point[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].color[0] = color[0];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].color[1] = color[1];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].color[2] = color[2];
g_VertexBuffer[g_iVertexBufferEntriesUsed + 3].color[3] = 255 - color[3];
g_iVertexBufferEntriesUsed += 4;
}
void CEngineSurface :: flushBuffer( void )
{
if( g_iVertexBufferEntriesUsed <= 0 )
return;
VGUI_DrawBuffer( g_VertexBuffer, g_iVertexBufferEntriesUsed );
g_iVertexBufferEntriesUsed = 0;
}
void CEngineSurface :: drawPrintChar( int x, int y, int wide, int tall, float s0, float t0, float s1, float t1, int color[4] )
{
vpoint_t ul, lr;
ul.point[0] = x;
ul.point[1] = y;
lr.point[0] = x + wide;
lr.point[1] = y + tall;
// gets at the texture coords for this character in its texture page
ul.coord[0] = s0;
ul.coord[1] = t0;
lr.coord[0] = s1;
lr.coord[1] = t1;
vpoint_t clippedRect[2];
if( !ClipRect( ul, lr, &clippedRect[0], &clippedRect[1] ))
return;
#if 1
// TESTTEST: needs to be more tested
addCharToBuffer( &clippedRect[0], &clippedRect[1], color );
#else
VGUI_SetupDrawingImage( color );
VGUI_DrawQuad( &clippedRect[0], &clippedRect[1] ); // draw the letter
#endif
}
void CEngineSurface :: drawPrintText( const char *text, int textLen )
{
static bool hasColor = 0;
static int numColor = 7;
if( !text || !staticFont || !staticFontInfo )
return;
int x = _drawTextPos[0] + _translateX;
int y = _drawTextPos[1] + _translateY;
int tall = staticFont->getTall();
int curTextColor[4];
// HACKHACK: allow color strings in VGUI
if( numColor != 7 && vgui_colorstrings->value )
{
for( int j = 0; j < 3; j++ ) // grab predefined color
curTextColor[j] = g_color_table[numColor][j];
}
else
{
for( int j = 0; j < 3; j++ ) // revert default color
curTextColor[j] = _drawTextColor[j];
}
curTextColor[3] = _drawTextColor[3]; // copy alpha
if( textLen == 1 && vgui_colorstrings->value )
{
if( *text == '^' )
{
hasColor = true;
return; // skip '^'
}
else if( hasColor && isdigit( *text ))
{
numColor = ColorIndex( *text );
hasColor = false; // handled
return; // skip colornum
}
else hasColor = false;
}
for( int i = 0; i < textLen; i++ )
{
int abcA, abcB, abcC;
int curCh = (byte)text[i];
staticFont->getCharABCwide( curCh, abcA, abcB, abcC );
float s0 = staticFontInfo->texCoord[curCh][0];
float t0 = staticFontInfo->texCoord[curCh][1];
float s1 = staticFontInfo->texCoord[curCh][2];
float t1 = staticFontInfo->texCoord[curCh][3];
int wide = abcB;
drawSetTexture( staticFontInfo->bindIndex[staticFontInfo->pageForChar[curCh]] );
drawPrintChar( x, y, wide, tall, s0, t0, s1, t1, curTextColor );
x += abcA + abcB + abcC;
}
_drawTextPos[0] += x;
}
void CEngineSurface :: drawSetTextureRGBA( int id, const char* rgba, int wide, int tall )
{
VGUI_UploadTexture( id, rgba, wide, tall );
_currentTexture = id;
}
void CEngineSurface :: drawSetTexture( int id )
{
if( _currentTexture != id )
{
_currentTexture = id;
flushBuffer();
}
VGUI_BindTexture( id );
}
void CEngineSurface :: drawTexturedRect( int x0, int y0, int x1, int y1 )
{
vpoint_t rect[2];
vpoint_t clippedRect[2];
InitVertex( rect[0], x0, y0, 0, 0 );
InitVertex( rect[1], x1, y1, 1, 1 );
// fully clipped?
if( !ClipRect( rect[0], rect[1], &clippedRect[0], &clippedRect[1] ))
return;
VGUI_SetupDrawingImage( _drawColor );
VGUI_DrawQuad( &clippedRect[0], &clippedRect[1] );
}
void CEngineSurface :: pushMakeCurrent( Panel* panel, bool useInsets )
{
int insets[4] = { 0, 0, 0, 0 };
int absExtents[4];
int clipRect[4];
if( useInsets )
panel->getInset( insets[0], insets[1], insets[2], insets[3] );
panel->getAbsExtents( absExtents[0], absExtents[1], absExtents[2], absExtents[3] );
panel->getClipRect( clipRect[0], clipRect[1], clipRect[2], clipRect[3] );
PaintStack *paintState = &paintStack[staticPaintStackPos];
ASSERT( staticPaintStackPos < MAX_PAINT_STACK );
paintState->m_pPanel = panel;
// determine corrected top left origin
paintState->iTranslateX = insets[0] + absExtents[0];
paintState->iTranslateY = insets[1] + absExtents[1];
// setup clipping rectangle for scissoring
paintState->iScissorLeft = clipRect[0];
paintState->iScissorTop = clipRect[1];
paintState->iScissorRight = clipRect[2];
paintState->iScissorBottom = clipRect[3];
SetupPaintState( paintState );
staticPaintStackPos++;
}
void CEngineSurface :: popMakeCurrent( Panel *panel )
{
flushBuffer();
int top = staticPaintStackPos - 1;
// more pops that pushes?
Assert( top >= 0 );
// didn't pop in reverse order of push?
Assert( paintStack[top].m_pPanel == panel );
staticPaintStackPos--;
if( top > 0 ) SetupPaintState( &paintStack[top-1] );
}

47
engine/client/vox.h Normal file
View File

@ -0,0 +1,47 @@
/*
vox.h - sentences vox private header
Copyright (C) 2010 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.
*/
#ifndef VOX_H
#define VOX_H
#define CVOXWORDMAX 64
#define CVOXZEROSCANMAX 255 // scan up to this many samples for next zero crossing
#define MAX_SENTENCES 2048
#define SENTENCE_INDEX -99999 // unique sentence index
typedef struct voxword_s
{
int volume; // increase percent, ie: 125 = 125% increase
int pitch; // pitch shift up percent
int start; // offset start of wave percent
int end; // offset end of wave percent
int cbtrim; // end of wave after being trimmed to 'end'
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
int samplefrac; // if pitch shifting, this is position into wav * 256
int timecompress; // % of wave to skip during playback (causes no pitch shift)
sfx_t *sfx; // name and cache pointer
} voxword_t;
typedef struct
{
char *pName;
float length;
} sentence_t;
void VOX_LoadWord( struct channel_s *pchan );
void VOX_FreeWord( struct channel_s *pchan );
#endif

712
engine/common/avikit.c Normal file
View File

@ -0,0 +1,712 @@
/*
avikit.c - playing AVI files (based on original AVIKit code)
Copyright (C) 2010 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 "gl_local.h"
#include <vfw.h> // video for windows
// msvfw32.dll exports
static HDRAWDIB (_stdcall *pDrawDibOpen)( void );
static BOOL (_stdcall *pDrawDibClose)( HDRAWDIB hdd );
static BOOL (_stdcall *pDrawDibDraw)( HDRAWDIB, HDC, int, int, int, int, LPBITMAPINFOHEADER, void*, int, int, int, int, uint );
static dllfunc_t msvfw_funcs[] =
{
{ "DrawDibOpen", (void **) &pDrawDibOpen },
{ "DrawDibDraw", (void **) &pDrawDibDraw },
{ "DrawDibClose", (void **) &pDrawDibClose },
{ NULL, NULL }
};
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, false };
// msacm32.dll exports
static MMRESULT (_stdcall *pacmStreamOpen)( LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD );
static MMRESULT (_stdcall *pacmStreamPrepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
static MMRESULT (_stdcall *pacmStreamUnprepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
static MMRESULT (_stdcall *pacmStreamConvert)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
static MMRESULT (_stdcall *pacmStreamSize)( HACMSTREAM, DWORD, LPDWORD, DWORD );
static MMRESULT (_stdcall *pacmStreamClose)( HACMSTREAM, DWORD );
static dllfunc_t msacm_funcs[] =
{
{ "acmStreamOpen", (void **) &pacmStreamOpen },
{ "acmStreamPrepareHeader", (void **) &pacmStreamPrepareHeader },
{ "acmStreamUnprepareHeader", (void **) &pacmStreamUnprepareHeader },
{ "acmStreamConvert", (void **) &pacmStreamConvert },
{ "acmStreamSize", (void **) &pacmStreamSize },
{ "acmStreamClose", (void **) &pacmStreamClose },
{ NULL, NULL }
};
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, false };
// avifil32.dll exports
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
static int (_stdcall *pAVIStreamRead)( PAVISTREAM pavi, LONG lStart, LONG lSamples, void *lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples );
static PGETFRAME (_stdcall *pAVIStreamGetFrameOpen)( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted );
static void* (_stdcall *pAVIStreamGetFrame)( PGETFRAME pg, LONG lPos );
static int (_stdcall *pAVIStreamGetFrameClose)( PGETFRAME pg );
static dword (_stdcall *pAVIStreamRelease)( PAVISTREAM pavi );
static int (_stdcall *pAVIFileOpen)( PAVIFILE *ppfile, LPCSTR szFile, UINT uMode, LPCLSID lpHandler );
static int (_stdcall *pAVIFileGetStream)( PAVIFILE pfile, PAVISTREAM *ppavi, DWORD fccType, LONG lParam );
static int (_stdcall *pAVIStreamReadFormat)( PAVISTREAM pavi, LONG lPos,LPVOID lpFormat, LONG *lpcbFormat );
static long (_stdcall *pAVIStreamStart)( PAVISTREAM pavi );
static dword (_stdcall *pAVIFileRelease)( PAVIFILE pfile );
static void (_stdcall *pAVIFileInit)( void );
static void (_stdcall *pAVIFileExit)( void );
static dllfunc_t avifile_funcs[] =
{
{ "AVIFileExit", (void **) &pAVIFileExit },
{ "AVIFileGetStream", (void **) &pAVIFileGetStream },
{ "AVIFileInit", (void **) &pAVIFileInit },
{ "AVIFileOpenA", (void **) &pAVIFileOpen },
{ "AVIFileRelease", (void **) &pAVIFileRelease },
{ "AVIStreamGetFrame", (void **) &pAVIStreamGetFrame },
{ "AVIStreamGetFrameClose", (void **) &pAVIStreamGetFrameClose },
{ "AVIStreamGetFrameOpen", (void **) &pAVIStreamGetFrameOpen },
{ "AVIStreamInfoA", (void **) &pAVIStreamInfo },
{ "AVIStreamRead", (void **) &pAVIStreamRead },
{ "AVIStreamReadFormat", (void **) &pAVIStreamReadFormat },
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
{ "AVIStreamStart", (void **) &pAVIStreamStart },
{ NULL, NULL }
};
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, false };
typedef struct movie_state_s
{
qboolean active;
qboolean quiet; // ignore error messages
PAVIFILE pfile; // avi file pointer
PAVISTREAM video_stream; // video stream pointer
PGETFRAME video_getframe; // pointer to getframe object for video stream
long video_frames; // total frames
long video_xres; // video stream resolution
long video_yres;
float video_fps; // video stream fps
PAVISTREAM audio_stream; // audio stream pointer
WAVEFORMAT *audio_header; // audio stream header
long audio_header_size; // WAVEFORMAT is returned for PCM data; WAVEFORMATEX for others
long audio_codec; // WAVE_FORMAT_PCM is oldstyle: anything else needs conversion
long audio_length; // in converted samples
long audio_bytes_per_sample; // guess.
// compressed audio specific data
dword cpa_blockalign; // block size to read
HACMSTREAM cpa_conversion_stream;
ACMSTREAMHEADER cpa_conversion_header;
byte *cpa_srcbuffer; // maintained buffer for raw data
byte *cpa_dstbuffer;
dword cpa_blocknum; // current block
dword cpa_blockpos; // read position in current block
dword cpa_blockoffset; // corresponding offset in bytes in the output stream
// for additional unpack Ms-RLE codecs etc
HDC hDC; // compatible DC
HDRAWDIB hDD; // DrawDib handler
HBITMAP hBitmap; // for DIB conversions
byte *pframe_data; // converted framedata
} movie_state_t;
static qboolean avi_initialized = false;
static movie_state_t avi[2];
// Converts a compressed audio stream into uncompressed PCM.
qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
{
WAVEFORMATEX dest_header, *sh, *dh;
AVISTREAMINFO stream_info;
dword dest_length;
short bits;
// WMA codecs, both versions - they simply don't work.
if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM does not support this audio codec.\n" );
return false;
}
// get audio stream info to work with
pAVIStreamInfo( Avi->audio_stream, &stream_info, sizeof( stream_info ));
if( Avi->audio_header_size < sizeof( WAVEFORMATEX ))
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM failed to open conversion stream.\n" );
return false;
}
sh = (WAVEFORMATEX *)Avi->audio_header;
bits = 16; // predict state
// how much of this is actually required?
dest_header.wFormatTag = WAVE_FORMAT_PCM; // yay
dest_header.wBitsPerSample = bits; // 16bit
dest_header.nChannels = sh->nChannels;
dest_header.nSamplesPerSec = sh->nSamplesPerSec; // take straight from the source stream
dest_header.nAvgBytesPerSec = (bits >> 3) * sh->nChannels * sh->nSamplesPerSec;
dest_header.nBlockAlign = (bits >> 3) * sh->nChannels;
dest_header.cbSize = 0; // no more data.
dh = &dest_header;
// open the stream
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
{
// try with 8 bit destination instead
bits = 8;
dest_header.wBitsPerSample = bits; // 8bit
dest_header.nAvgBytesPerSec = ( bits >> 3 ) * sh->nChannels * sh->nSamplesPerSec;
dest_header.nBlockAlign = ( bits >> 3 ) * sh->nChannels; // 1 sample at a time
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "ACM failed to open conversion stream.\n" );
return false;
}
}
Avi->cpa_blockalign = sh->nBlockAlign;
dest_length = 0;
// mp3 specific fix
if( sh->wFormatTag == 0x55 )
{
LPMPEGLAYER3WAVEFORMAT k;
k = (LPMPEGLAYER3WAVEFORMAT)sh;
Avi->cpa_blockalign = k->nBlockSize;
}
// get the size of the output buffer for streaming the compressed audio
if( pacmStreamSize( Avi->cpa_conversion_stream, Avi->cpa_blockalign, &dest_length, ACM_STREAMSIZEF_SOURCE ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "Couldn't get ACM conversion stream size.\n" );
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
return false;
}
Avi->cpa_srcbuffer = (byte *)Mem_Alloc( cls.mempool, Avi->cpa_blockalign );
Avi->cpa_dstbuffer = (byte *)Mem_Alloc( cls.mempool, dest_length ); // maintained buffer for raw data
// prep the headers!
Avi->cpa_conversion_header.cbStruct = sizeof( ACMSTREAMHEADER );
Avi->cpa_conversion_header.fdwStatus = 0;
Avi->cpa_conversion_header.dwUser = 0; // no user data
Avi->cpa_conversion_header.pbSrc = Avi->cpa_srcbuffer; // source buffer
Avi->cpa_conversion_header.cbSrcLength = Avi->cpa_blockalign; // source buffer size
Avi->cpa_conversion_header.cbSrcLengthUsed = 0;
Avi->cpa_conversion_header.dwSrcUser = 0; // no user data
Avi->cpa_conversion_header.pbDst = Avi->cpa_dstbuffer; // dest buffer
Avi->cpa_conversion_header.cbDstLength = dest_length; // dest buffer size
Avi->cpa_conversion_header.cbDstLengthUsed = 0;
Avi->cpa_conversion_header.dwDstUser = 0; // no user data
if( pacmStreamPrepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 ) != MMSYSERR_NOERROR )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "couldn't prep headers.\n" );
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
return false;
}
Avi->cpa_blocknum = 0; // start at 0.
Avi->cpa_blockpos = 0;
Avi->cpa_blockoffset = 0;
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
Avi->audio_bytes_per_sample = (bits >> 3 ) * Avi->audio_header->nChannels;
return true;
}
qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration )
{
if( !Avi->active )
return false;
if( xres != NULL )
*xres = Avi->video_xres;
if( yres != NULL )
*yres = Avi->video_yres;
if( duration != NULL )
*duration = (float)Avi->video_frames / Avi->video_fps;
return true;
}
// returns a unique frame identifier
long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
{
if( !Avi->active )
return 0;
return (time * Avi->video_fps);
}
// gets the raw frame data
byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
{
LPBITMAPINFOHEADER frame_info;
byte *frame_raw;
if( !Avi->active ) return NULL;
if( frame >= Avi->video_frames )
frame = Avi->video_frames - 1;
frame_info = (LPBITMAPINFOHEADER)pAVIStreamGetFrame( Avi->video_getframe, frame );
frame_raw = (byte *)frame_info + frame_info->biSize + frame_info->biClrUsed * sizeof( RGBQUAD );
pDrawDibDraw( Avi->hDD, Avi->hDC, 0, 0, Avi->video_xres, Avi->video_yres, frame_info, frame_raw, 0, 0, Avi->video_xres, Avi->video_yres, 0 );
return Avi->pframe_data;
}
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
{
if( !Avi->active || Avi->audio_stream == NULL || snd_info == NULL )
{
return false;
}
snd_info->rate = Avi->audio_header->nSamplesPerSec;
snd_info->channels = Avi->audio_header->nChannels;
if( Avi->audio_codec == WAVE_FORMAT_PCM ) // uncompressed audio!
snd_info->width = ( Avi->audio_bytes_per_sample > Avi->audio_header->nChannels ) ? 2 : 1;
else snd_info->width = 2; // assume compressed audio is always 16 bit
snd_info->size = snd_info->rate * snd_info->width * snd_info->channels;
snd_info->loopStart = 0; // using loopStart as streampos
return true;
}
// sync the current audio read to a specific offset
qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
{
int breaker;
if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
{
if( Avi->cpa_blockoffset - offset < 500000 )
return false; // don't bother if it's gonna catch up soon
Avi->cpa_blocknum = 0; // start at 0, eh.
Avi->cpa_blockpos = 0;
Avi->cpa_blockoffset = 0;
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
}
// now then: seek forwards to the required block
breaker = 30; // maximum zero blocks: anti-freeze protection
while( Avi->cpa_blockoffset + Avi->cpa_conversion_header.cbDstLengthUsed < offset )
{
Avi->cpa_blocknum++;
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
if( Avi->cpa_conversion_header.cbDstLengthUsed == 0 )
breaker--;
else breaker = 30;
if( breaker <= 0 )
return false;
Avi->cpa_blockpos = 0;
}
// seek to the right position inside the block
Avi->cpa_blockpos = offset - Avi->cpa_blockoffset;
return true;
}
// get a chunk of audio from the stream (in bytes)
long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length )
{
long result = 0;
int i;
// zero data past the end of the file
if( offset + length > Avi->audio_length )
{
if( offset <= Avi->audio_length )
{
long remaining_length = Avi->audio_length - offset;
AVI_GetAudioChunk( Avi, audiodata, offset, remaining_length );
for( i = remaining_length; i < length; i++ )
audiodata[i] = 0;
}
else
{
for( i = 0; i < length; i++ )
audiodata[i] = 0;
}
}
// uncompressed audio!
if( Avi->audio_codec == WAVE_FORMAT_PCM )
{
// very simple - read straight out
pAVIStreamRead( Avi->audio_stream, offset / Avi->audio_bytes_per_sample, length / Avi->audio_bytes_per_sample, audiodata, length, &result, NULL );
return result;
}
else
{
// compressed audio!
result = 0;
// seek to correct chunk and all that stuff
if( !AVI_SeekPosition( Avi, offset ))
return 0; // don't continue if we're waiting for the play pointer to catch up
while( length > 0 )
{
long blockread = Avi->cpa_conversion_header.cbDstLengthUsed - Avi->cpa_blockpos;
if( blockread <= 0 ) // read next
{
Avi->cpa_blocknum++;
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
Avi->cpa_blockpos = 0;
continue;
}
if( blockread > length )
blockread = length;
// copy the data
memcpy( audiodata + result, (void *)( Avi->cpa_dstbuffer + Avi->cpa_blockpos ), blockread );
Avi->cpa_blockpos += blockread;
result += blockread;
length -= blockread;
}
return result;
}
}
void AVI_CloseVideo( movie_state_t *Avi )
{
if( Avi->active )
{
pAVIStreamGetFrameClose( Avi->video_getframe );
if( Avi->audio_stream != NULL )
{
pAVIStreamRelease( Avi->audio_stream );
Mem_Free( Avi->audio_header );
if( Avi->audio_codec != WAVE_FORMAT_PCM )
{
pacmStreamUnprepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 );
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
Mem_Free( Avi->cpa_srcbuffer );
Mem_Free( Avi->cpa_dstbuffer );
}
}
pAVIStreamRelease( Avi->video_stream );
DeleteObject( Avi->hBitmap );
pDrawDibClose( Avi->hDD );
DeleteDC( Avi->hDC );
}
memset( Avi, 0, sizeof( movie_state_t ));
}
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
{
BITMAPINFOHEADER bmih;
AVISTREAMINFO stream_info;
long opened_streams = 0;
LONG hr;
// default state: non-working.
Avi->active = false;
Avi->quiet = quiet;
// can't load Video For Windows :-(
if( !avi_initialized ) return;
// load the AVI
hr = pAVIFileOpen( &Avi->pfile, filename, OF_SHARE_DENY_WRITE, 0L );
if( hr != 0 ) // error opening AVI:
{
switch( hr )
{
case AVIERR_BADFORMAT:
if( !Avi->quiet ) MsgDev( D_ERROR, "corrupt file or unknown format.\n" );
break;
case AVIERR_MEMORY:
if( !Avi->quiet ) MsgDev( D_ERROR, "insufficient memory to open file.\n" );
break;
case AVIERR_FILEREAD:
if( !Avi->quiet ) MsgDev( D_ERROR, "disk error reading file.\n" );
break;
case AVIERR_FILEOPEN:
if( !Avi->quiet ) MsgDev( D_ERROR, "disk error opening file.\n" );
break;
case REGDB_E_CLASSNOTREG:
default:
if( !Avi->quiet ) MsgDev( D_ERROR, "no handler found (or file not found).\n" );
break;
}
return;
}
Avi->video_stream = Avi->audio_stream = NULL;
// open the streams until a stream is not available.
while( 1 )
{
PAVISTREAM stream = NULL;
if( pAVIFileGetStream( Avi->pfile, &stream, 0L, opened_streams++ ) != AVIERR_OK )
break;
if( stream == NULL )
break;
pAVIStreamInfo( stream, &stream_info, sizeof( stream_info ));
if( stream_info.fccType == streamtypeVIDEO && Avi->video_stream == NULL )
{
Avi->video_stream = stream;
Avi->video_frames = stream_info.dwLength;
Avi->video_xres = stream_info.rcFrame.right - stream_info.rcFrame.left;
Avi->video_yres = stream_info.rcFrame.bottom - stream_info.rcFrame.top;
Avi->video_fps = (float)stream_info.dwRate / (float)stream_info.dwScale;
}
else if( stream_info.fccType == streamtypeAUDIO && Avi->audio_stream == NULL && load_audio )
{
long size;
Avi->audio_stream = stream;
// read the audio header
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), 0, &size );
Avi->audio_header = (WAVEFORMAT *)Mem_Alloc( cls.mempool, size );
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), Avi->audio_header, &size );
Avi->audio_header_size = size;
Avi->audio_codec = Avi->audio_header->wFormatTag;
// length of converted audio in samples
Avi->audio_length = (long)((float)stream_info.dwLength / Avi->audio_header->nAvgBytesPerSec );
Avi->audio_length *= Avi->audio_header->nSamplesPerSec;
if( Avi->audio_codec != WAVE_FORMAT_PCM )
{
if( !AVI_ACMConvertAudio( Avi ))
{
Mem_Free( Avi->audio_header );
Avi->audio_stream = NULL;
continue;
}
}
else Avi->audio_bytes_per_sample = Avi->audio_header->nBlockAlign;
Avi->audio_length *= Avi->audio_bytes_per_sample;
}
else
{
pAVIStreamRelease( stream );
}
}
// display error message-stream not found.
if( Avi->video_stream == NULL )
{
if( Avi->pfile ) // if file is open, close it
pAVIFileRelease( Avi->pfile );
if( !Avi->quiet ) MsgDev( D_ERROR, "couldn't find a valid video stream.\n" );
return;
}
pAVIFileRelease( Avi->pfile ); // release the file
Avi->video_getframe = pAVIStreamGetFrameOpen( Avi->video_stream, NULL ); // open the frame getter
if( Avi->video_getframe == NULL )
{
if( !Avi->quiet ) MsgDev( D_ERROR, "error attempting to read video frames.\n" );
return; // couldn't open frame getter.
}
bmih.biSize = sizeof( BITMAPINFOHEADER );
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biWidth = Avi->video_xres;
bmih.biHeight = -Avi->video_yres; // invert height to flip image upside down
Avi->hDC = CreateCompatibleDC( 0 );
Avi->hDD = pDrawDibOpen();
Avi->hBitmap = CreateDIBSection( Avi->hDC, (BITMAPINFO*)(&bmih), DIB_RGB_COLORS, (void**)(&Avi->pframe_data), NULL, 0 );
SelectObject( Avi->hDC, Avi->hBitmap );
Avi->active = true; // done
}
qboolean AVI_IsActive( movie_state_t *Avi )
{
if( Avi != NULL )
return Avi->active;
return false;
}
movie_state_t *AVI_GetState( int num )
{
return &avi[num];
}
/*
=============
AVIKit user interface
=============
*/
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
{
movie_state_t *Avi;
string path;
const char *fullpath;
// fast reject
if( !avi_initialized )
{
MsgDev( D_ERROR, "AVI_LoadVideo: movie support is disabled\n" );
return NULL;
}
// open cinematic
Q_snprintf( path, sizeof( path ), "media/%s", filename );
COM_DefaultExtension( path, ".avi" );
fullpath = FS_GetDiskPath( path, false );
if( FS_FileExists( path, false ) && !fullpath )
{
MsgDev( D_ERROR, "AVI_LoadVideo: Couldn't load %s from packfile. Please extract it\n", path );
return NULL;
}
Avi = Mem_Alloc( cls.mempool, sizeof( movie_state_t ));
AVI_OpenVideo( Avi, fullpath, load_audio, false );
if( !AVI_IsActive( Avi ))
{
AVI_FreeVideo( Avi ); // something bad happens
return NULL;
}
// all done
return Avi;
}
movie_state_t *AVI_LoadVideoNoSound( const char *filename )
{
return AVI_LoadVideo( filename, false );
}
void AVI_FreeVideo( movie_state_t *state )
{
if( !state ) return;
if( Mem_IsAllocatedExt( cls.mempool, state ))
{
AVI_CloseVideo( state );
Mem_Free( state );
}
}
qboolean AVI_Initailize( void )
{
if( Sys_CheckParm( "-noavi" ))
{
MsgDev( D_INFO, "AVI: Disabled\n" );
return false;
}
if( !Sys_LoadLibrary( &avifile_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
return false;
}
if( !Sys_LoadLibrary( &msvfw_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
Sys_FreeLibrary( &avifile_dll );
return false;
}
if( !Sys_LoadLibrary( &msacm_dll ))
{
MsgDev( D_ERROR, "AVI_Initailize: failed\n" );
Sys_FreeLibrary( &avifile_dll );
Sys_FreeLibrary( &msvfw_dll );
return false;
}
pAVIFileInit();
avi_initialized = true;
MsgDev( D_NOTE, "AVI_Initailize: done\n" );
return true;
}
void AVI_Shutdown( void )
{
if( !avi_initialized ) return;
pAVIFileExit();
Sys_FreeLibrary( &avifile_dll );
Sys_FreeLibrary( &msvfw_dll );
Sys_FreeLibrary( &msacm_dll );
avi_initialized = false;
}

53
engine/common/build.c Normal file
View File

@ -0,0 +1,53 @@
/*
build.c - returns a engine build number
Copyright (C) 2010 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"
static char *date = __DATE__ ;
static char *mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char mond[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// returns days since Feb 13 2007
int Q_buildnum( void )
{
// do not touch this! Only author of Xash3D can increase buildnumbers!
#if 1
int m = 0, d = 0, y = 0;
static int b = 0;
if( b != 0 ) return b;
for( m = 0; m < 11; m++ )
{
if( !Q_strnicmp( &date[0], mon[m], 3 ))
break;
d += mond[m];
}
d += Q_atoi( &date[4] ) - 1;
y = Q_atoi( &date[7] ) - 1900;
b = d + (int)((y - 1) * 365.25f );
if((( y % 4 ) == 0 ) && m > 1 )
{
b += 1;
}
b -= 38752; // Feb 13 2007
return b;
#else
return 3847;
#endif
}

Some files were not shown because too many files have changed in this diff Show More