Pure engine source code(LF line endings, UTF8 encoded)
This commit is contained in:
commit
8d6e3b7f79
197 changed files with 125800 additions and 0 deletions
60
common/beamdef.h
Normal file
60
common/beamdef.h
Normal 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
321
common/bspfile.h
Normal 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
105
common/cl_entity.h
Normal 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
497
common/com_model.h
Normal 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
25
common/con_nprint.h
Normal 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
779
common/const.h
Normal 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
45
common/cvardef.h
Normal 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
27
common/demo_api.h
Normal 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
31
common/dlight.h
Normal 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
188
common/entity_state.h
Normal 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
25
common/entity_types.h
Normal 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
56
common/event_api.h
Normal 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
47
common/event_args.h
Normal 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
45
common/event_flags.h
Normal 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
30
common/features.h
Normal 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
49
common/gameinfo.h
Normal 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
59
common/hltv.h
Normal 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
38
common/ivoicetweak.h
Normal 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
29
common/lightstyle.h
Normal 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
95
common/mathlib.h
Normal 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
97
common/net_api.h
Normal 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
37
common/netadr.h
Normal 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
53
common/particledef.h
Normal 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
41
common/pmtrace.h
Normal 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
38
common/qfont.h
Normal 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
195
common/r_efx.h
Normal 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
154
common/r_studioint.h
Normal 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
105
common/ref_params.h
Normal 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
266
common/render_api.h
Normal 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
29
common/screenfade.h
Normal 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
27
common/studio_event.h
Normal 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
62
common/triangleapi.h
Normal 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
39
common/usercmd.h
Normal 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
97
common/wadfile.h
Normal 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
50
common/weaponinfo.h
Normal 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
24
common/wrect.h
Normal 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
138
engine/alias.h
Normal 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
177
engine/anorms.h
Normal 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
67
engine/cdll_exp.h
Normal 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
259
engine/cdll_int.h
Normal 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
507
engine/client/cl_cmds.c
Normal 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
143
engine/client/cl_custom.c
Normal 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
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
505
engine/client/cl_events.c
Normal 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
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
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
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
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
683
engine/client/cl_netgraph.c
Normal 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
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
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
433
engine/client/cl_remap.c
Normal 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
757
engine/client/cl_scrn.c
Normal 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
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
120
engine/client/cl_tent.h
Normal 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
306
engine/client/cl_video.c
Normal 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
396
engine/client/cl_view.c
Normal 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
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
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
721
engine/client/gl_backend.c
Normal 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
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
151
engine/client/gl_cull.c
Normal 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
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
282
engine/client/gl_draw.c
Normal 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
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
355
engine/client/gl_frustum.c
Normal 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;
|
||||
}
|
52
engine/client/gl_frustum.h
Normal file
52
engine/client/gl_frustum.h
Normal 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
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
677
engine/client/gl_local.h
Normal 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
205
engine/client/gl_refrag.c
Normal 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
430
engine/client/gl_rlight.c
Normal 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
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
320
engine/client/gl_rmath.c
Normal 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
514
engine/client/gl_rmisc.c
Normal 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
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
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
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
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
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
815
engine/client/gl_warp.c
Normal 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
483
engine/client/s_backend.c
Normal 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
905
engine/client/s_dsp.c
Normal 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
395
engine/client/s_load.c
Normal 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
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
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
152
engine/client/s_mouth.c
Normal 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
343
engine/client/s_stream.c
Normal 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
306
engine/client/s_utils.c
Normal 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
681
engine/client/s_vox.c
Normal 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
359
engine/client/sound.h
Normal 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
|
110
engine/client/vgui/vgui_clip.cpp
Normal file
110
engine/client/vgui/vgui_clip.cpp
Normal 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;
|
||||
}
|
218
engine/client/vgui/vgui_draw.c
Normal file
218
engine/client/vgui/vgui_draw.c
Normal 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 );
|
||||
}
|
77
engine/client/vgui/vgui_draw.h
Normal file
77
engine/client/vgui/vgui_draw.h
Normal 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
|
290
engine/client/vgui/vgui_input.cpp
Normal file
290
engine/client/vgui/vgui_input.cpp
Normal 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;
|
||||
}
|
129
engine/client/vgui/vgui_int.cpp
Normal file
129
engine/client/vgui/vgui_int.cpp
Normal 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;
|
||||
}
|
117
engine/client/vgui/vgui_main.h
Normal file
117
engine/client/vgui/vgui_main.h
Normal 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
|
465
engine/client/vgui/vgui_surf.cpp
Normal file
465
engine/client/vgui/vgui_surf.cpp
Normal 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
47
engine/client/vox.h
Normal 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
712
engine/common/avikit.c
Normal 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
53
engine/common/build.c
Normal 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
Loading…
Add table
Reference in a new issue