Pure engine source code(LF line endings, UTF8 encoded)
This commit is contained in:
commit
8d6e3b7f79
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)))
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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},
|
|
@ -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
|
|
@ -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
|
|
@ -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] );
|
||||
}
|
|
@ -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 );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 );
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 );
|
||||
}
|
|
@ -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 ();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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] );
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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…
Reference in New Issue