Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git b/change.log a/change.log
- new file mode 100644
- index 0000000..1993d14
- --- /dev/null
- +++ a/change.log
- @@ -0,0 +1,797 @@
- +build 3597
- +
- +Engine: implemenantion of generic extension of BSP file format. Some extra lumps used by mods to get a new features like terrains, improved lighting etc
- +Engine: rewrite PVS system for variable PVS radius that can be used as FAT pvs or FAT phs without recalculating vis-array
- +Engine: starting to implement a new global feature that called HOST_FIXED_FRAMERATE to get client and server with constant fps (xash-based mods only)
- +Render: some unsed funcs from RenderAPI was replaced with usefully funcs. Backward compatibility stay keep on
- +Render: added few function in RenderAPI for SDLash3D by Albatross request
- +Render: get support for loading multi-layered textures (for potential landscape implemenantion)
- +Client: added two funcs into engine interface for custom interpolation on the client
- +Server: allow to write map lums on a server to store userdata (physic collision, ai nodegraph as example). Works with extended BSP format only
- +Server: physic interface was updated and expanded to get more control over player and entities simulation
- +Client: demo protocol was changed to 2 ( allow comment in demo header)
- +Client: demo playing is now using interpolation of client view angles
- +Client: fixup some issues on demo playback
- +Client: fix broken parametric entities (rockets in TFC as example) in multiplayer
- +Client: net graph implementation like in GoldSrc
- +Client: fixup ugly "un-duck" effect while after changing level (see for example transition from c0a0b to c0a0c)
- +Client: clean-up and rewrite predicting code to get more compatibility for original prediction
- +Client: handle colon separately for client version of COM_ParseFile (like in goldsrc)
- +Client: finalize NETAPI. Now it can handle servers list from a master server (and display on a built-in client browser of course)
- +GameUI: fixup color-strings that sended across network as server names or player names
- +Client: texturebrower and overview mode now is not affected to player moving in world
- +Client: accumulate pmove entities right after handling delta's not after world rendering
- +Client: change master server address and request to actual
- +Client: exclude dead bodies from solid objects in pmove processing
- +Engine: fixup wad parsing from "wad" string in worldspawn settings (broken in previous version)
- +Client: new style of displaying FPS counter
- +Network: remove compression routine (very low efficiency)
- +Client: fix muzzleflashes decoding from an studio animation event
- +Engine: fix crash\hanging while trying to play AVI-file when codec is not-installed
- +Client: change color handle for viewbeams (remove color normalization)
- +Render: rewrite waves on water surfaces, uses table sin, increase speed and look close GoldSrc
- +Render: completely rewrite texture loader, remove obsolete code, added support for multi-layered textures and float textures, fix errors
- +Render: now "gl_texturemode" is obsolete and removed. Use "gl_texture_nearest" cvar instead
- +Render: improved doble-cloud layering sky for Quake. reduce parallax distorsion
- +Render: completely rewrite OpenGL loader. Remove obsolete extensions, fixup some errors
- +Render: moved lightstyle animation from render frame loop to client frame loop (to prevent execute lightstyle animation on multipass viewing)
- +Client: fixup studio culling on models with non-default scaling (large models in SoHL)
- +Sound: change DSP code to get DSP effects like in original GoldSrc
- +Sound: rewite sound PHS code. Now it can be useful
- +Sound: first implenantion of raw-channels manager (in future this will be used for a custom video playing in xash-based mods and voice stream)
- +Sound: sentence sounds now can be freed after playing (and saves some memory)
- +Client: get VGUI backend to implement of lastest version of vgui.dll
- +Engine: sort commands and cvars in alpha-bethical order. Include scripting functions from SDLash3D
- +Console: now map list show an extension or type of various map and mapstats check level for transparent water support
- +Console: replace the console buffer with effectively circular buffer (up to 1mb messages)
- +FS: do complete revision of filesystem code, remove WAD2 support
- +ImageLib: fix crash in quantizer while image is completely black
- +Server: ignore sounds from pmove code when prediction is enabled
- +Server: change userinfo handling, fixup info send to all the clients
- +Server: fixup player animtion timings
- +Server: enable cl_msglevel to filter up unneeded messages
- +Server: restart server right if circular buffer pointer was exceeded 32-bit limit value
- +Server: fixup player think timings
- +
- +
- +build 3366
- +
- +Render: get support for custom DXT encoding (custom renderers only)
- +Render: remove image program stuff (just not used)
- +Engine: adding support for new wad filetypes (like DDS images) and wad imagetypes (normalmap, glossmap etc)
- +Render: implement tiling on the studiomodels
- +Client: do revision of predicting implementation, fix errors, more clean code
- +Client: implement prediction error to avoid ugly blinking view on moving platforms when predicting is enabled
- +Render: fixup the DDS loading code (invalid calc for mip-sizes)
- +Client: fixup parser of detailtextures when texturename contain symbol '{'
- +Render: added experimental hint for Nvidia drivers for force select Nvidia videocard when engine is running
- +Engine: rewrote condition to calculate level CRC (singleplayer or multiplayer)
- +Engine: added cvar r_wadtextures like in HL. First load textures from the wad, then from BSP
- +Server: fix bug with cl_updaterate variable (always get default values if not changed by user)
- +Server: recalc the ping time correctly
- +Server: fix bug with too long player name
- +GameUI: fix bug with 4-bit bmps buttons (image cutter)
- +
- +build 3224
- +
- +Client: make players solid for prediction code
- +Client: change out of band request to make compatibility with custom master-servers
- +Client: reject triggers and other like things for prediction code
- +Client: fix the potential crash in prediction code
- +Render: fix the potential crash in image loader
- +Client: fix thirdperson camera culling
- +Console: experimental fix for console problems with word-wrapping
- +Network: fix bug in BF_WriteBitAngle function (thx mittorn)
- +Network: rewrite clamping bounds for delta-variables (it was incorrectly)
- +Network: change address of master server (now master is working)
- +Server: some changes for client connection\disconnection to prevent possible errors or crash the server
- +
- +build 3153
- +
- +Render: RenderAPI update. New parm PARM_REBUILD_GAMMA to differentiate from map restart or change level when called from GL_BuildLightmaps
- +GameUI: increased slots for savedgames\multiplayer maps up to 900
- +
- +build 3145
- +
- +Engine: add support for studiomodels with fixed texcoords multiplier (a studiomodel format extension)
- +Engine: first experimental implementation of client movement predicting code (thx SovietCoder)
- +Engine: first experimental implementation of client movement interpolation code (thx SovietCoder)
- +Engine: some small bugfixes
- +
- +build 3030
- +
- +Client: remove demoheader.tmp while engine is shutting down
- +Render: allow .dds format for detail textures
- +Render: get support up to 16384 verts per submodel for studio models
- +Render: disable vertical sync while level is loading
- +ImageLib: allow support big textures up to 8192x8192
- +ImageLib: rewrited code for detecting alpha in DXT3, DXT5 formats
- +
- +build 3000
- +
- +Render: new render info parm PARM_TEX_GLFORMAT for getting a real format for a given texture
- +Server: added a engine memory allocations through internal mempool and function GetTextureData (a part of tracing alpha-textures)
- +Client: clamping client pmove time if fps is too high
- +Client: new fps counter-style that showing min and max values (cl_showfps 2 to enable)
- +Render: get support for DDS textures (DXT1, DXT3, DXT5 and ARGB is allowed)
- +Render: get support for floating depth-buffer texture (high prescision depth-buffer)
- +Render: added VSDCT internal texture
- +Render: add support for seamless cubemaps
- +Render: fullscreen resolution auto-detect on first launch
- +Render: added resolution 1600x900
- +Render: new command line option -gldebug (enable internal GL-driver debug info)
- +Engine: fix bug with CRC calculation on BSP31 format (thx [WPMG]PRoSToTeM@)
- +FS: additional check to prevent error "Mem_Free: not allocated or double freed (free at filesystem.c:1489)"
- +FS: fix FS_Eof function (thx [WPMG]PRoSToTeM@)
- +VGUI: handle ESC key while VGUI is shown
- +Engine: allows to load "deluxedata" from base folder even if a map placed in game folder (probably it was a stupid limitation)
- +Server: replace Host_Error "ED_Alloc: no free edicts" with Sys_Error to prevent possible troubles
- +
- +build 2900
- +
- +Console: add detection for Paranoia 2 maps (show message in console)
- +Engine: fix playing video when fps_max is 0 and framerate too high
- +Engine: add function TraceSurface into pmove, EventAPI and PhysicAPI interfaces
- +
- +build 2867
- +
- +Client: another extension for EventAPI: function EV_SoundForIndex to get soundpath from soundindex
- +Render: RenderAPI update. New flag TF_NOCOMPARE to disable comparing for depth-textures and PARM_CLIENT_ACTIVE (self-explanatory)
- +Server: PhysicAPI update. Add support for file searching.
- +Client: fix a little bug in CL_AddVisibleEntity
- +Client: check rectangles right for hud.txt
- +Client: fix demoplaying in background mode (changelevel etc)
- +Client: fix SOLID_CUSTOM support in client trace
- +Render: create debug context for powerful OpenGL debugging
- +Render: fix bug with kRenderWorldGlow
- +Sound: add two new cmds: spk and speak like in GoldSrc
- +GameUI: fix buttons bmp loader
- +
- +build 2664
- +
- +Engine: restore right ordering of arguments of SV_StudioSetupBones export
- +Render: a some cosmetic changes in RenderAPI
- +Client: make levelshots for background demos
- +Client: now cmd 'startdemos' invoke to play demos sequence like as background map
- +Client: increase demo auto-naming from 100 up to 10000
- +Client: fix bug with inverted PITCH of non-local playermodel
- +Client: added FireCustomDecal into EfxAPI (was missed)
- +GameUI: fix some crashes after end the background map (like call of trigger_endsection)
- +Client: eliminate muzzleflash copy from mirror reflection in normal view
- +Render: fix bug with max_texture_units clamping
- +Render: completely remove glScissor calls (just unused)
- +Render: update thirdperson code for mirrors
- +Render: rewrite viewport setup code
- +Render: fix software gamma adjustment bug while flashlight is enabled
- +Render: reset vid_displayfrequency if current value isn't support by user display. Throw warning message
- +Engine: allow new param in gameinfo.txt who called soundclip_dist <radius>. Default is 1000.
- +Sound: new cmd 'playvol' like in GoldSrc
- +Server: fix crash in 'Gunman Chronicles' at map end1.bsp
- +Engine: show more infos with cmd 'mapstats'
- +Network: fix bug with DT_TIMEWINDOW_8
- +Server: fix bug with triggers with 'liquid' textures
- +Server: fix some bugs in PVS calculation on server
- +GameUI: enable auto-refresh of actual multiplayer maps list
- +GameUI: update 3D playermodel preview for 16:9 screen aspect
- +
- +build 2636
- +
- +Engine: added internal loader for deluxemap data (.dlit file that produces VHLT)
- +Engine: msurfmesh_t was reorganized to complex vertex data instead of single arrays (VBO-ready)
- +Engine: decal_t now contain msurfmesh_t with all vertices and texcoords
- +Render: RenderAPI interface updated to version 35
- +Render: get support for float textures format (GL_ARB_texture_float is required)
- +Render: implementation of image program preprocessor, like in Doom3, syntax: AddNormals( texture1.tga, texture2.tga );
- +Render: get acess to internal tesselator through RenderAPI
- +Server: a little update for PhysicInterface: get support for custom decal save\restore
- +Client: separate levelshots for wide-screen and normal screen
- +Client: revert parametric rocket implementation (previous was lost between two backups)
- +Client: fix a potentially crash when calling function IsSpectateOnly
- +Client: now 'ESC' button while playing video invoke jump to next video in list (instead of completely stopping video)
- +Client: fix bug when demo ends up (Connection Problem)
- +Client: now compensate screenshot gamma is toggleable (cvar "gl_compensate_gamma_screenshots")
- +Render: optimize decal code, remove unused functions
- +Render: now all the lightmaps stored into 1024x1024 texture
- +Render: add cvar "gl_detailscale" for customize _detail.txt generation
- +Render: fix some errors with studiomodels lighting
- +Sound: increase maximum count of words in sentence up to 64 (from 29)
- +Engine: fix broken recursion in Cmd_CheckMapLis_R (potentially crash)
- +Client: passed keyup event through HUD_KeyEvent callback
- +Network: change delta params for skycolor_* variables (in some cases color value was incorrect received)
- +Network: fixed TIMEWINDOW_BIG mode
- +Engine: add engine build number into console log
- +
- +build 2463
- +
- +Engine: reorganize data in texture_t. Release one variable for mod-makers
- +Engine: change decal_t structure get compatibility with GoldSrc
- +Engine: expanded mextrasurf_t reserved fields up 32
- +Engine: update player_info_t (added customization_t like in SDK 2.3)
- +Engine: increase local_state_t->weapondata up 64 slots
- +Engine: update IVoiceTweak interface
- +Engine: new lightstyle system with local time and custom interpolation
- +Engine: fix bug with lightstyle save\restore (only first 64 symbols of pattern was saved)
- +Engine: update r_efx_api_t interface
- +Engine: update engine_studio_api_t, remove uncompatible function StudioGetTexture, added three new (thats came from CS:CZ)
- +Engine: added ref_overview to support custom overview implementation
- +Engine: render interface is outdated now. New render interface has version 30 (too much changed)
- +Engine: update triangleapi_t interface
- +Engine: update cl_dll interface (also added support for signle export that called 'F')
- +Engine: a lttle update for enginefuncs_t (server interface)
- +Client: fixed crash on shutdown when custom renderer uses AVI-files
- +Engine: applaying scale for decals on brushmodels or world geometry
- +Engine: update model_state_t thats keep info about studiomodels for studio decals. Include body and skin
- +Engine: get support for custom studiocache on static and tempents
- +Engine: write R_Srpite_WallPuff from pEfxAPI
- +Client: fix bug with beam sorting (solid beams was drawing in translucent pass)
- +Render: add special flag for decals thats indicated local space (any decal after first shoot)
- +Render: apply emboss filter on studiomodel textures
- +Render: rewrite client event system for studiomodels. Get more predictable results
- +Network: write existing decals and static entities into new demo
- +Network: protocol was changed to 48
- +ImageLib: fix old bug with save non-aligned 8-bit bmp files
- +Server: fix bug with reloading hl.dll when map was changed every time
- +Server: a client part of save-file is outdated. New version is 0.68
- +
- +build 2402
- +
- +Engine: added new feature flag for compensate stupid quake bug
- +Client: update the render interface, added usefully function GL_TextureTarget
- +Render: get support for GL_RECTANGLE textures
- +Client: fix playerangles in event receive (Paranoia bug with decals)
- +Render: fixed mipmap generation for normalmaps (TF_NORMALMAP)
- +Render: added two built-in textures: *blankbump and *whiteCube (self-explanatory names)
- +Engine: made better check for Half-Life alpha maps (version 29 with colored lighting)
- +
- +build 2271
- +
- +Client: fix message TE_GLOWSPRITE. The gaussgun in Xash Mod is properly worked now.
- +Client: restore studio check for missed models and ignore them instead of call the Sys_Error
- +Server: fix crash in Gunman Chronicles (scorcher issues)
- +
- +build 2223
- +
- +Engine: added option "nomodels" for liblist.gam (disallow user to choose playermodel)
- +Client: a new callback for render interface who called R_DrawCubemapView. This fixes cmd "envshot" for XashXT
- +Client: store screenshots into root of folder "scrshots" instead of "scrshots\mapname"
- +Client: engine using callback CL_CameraOffset now
- +Client: fix angles for cmd "envshot"
- +Render: rename a miss cvar "r_anisotropy" to real name "gl_anisotropy"
- +Render: now "r_speeds 4" displays an actual count of "real" static entities that was created by call of MAKE_STATIC function
- +Render: fix bug with blinking Quake Sky while autosave in progress
- +Render: keep actual hardware gamma for multiple instances of application
- +Engine: get support for Half-Life alpha maps (that has version 29)
- +Server: fix the client rejection mechanism
- +Server: using the pfnClientDisconnect callback
- +Server: some changes in physics code (for MOVETYPE_PUSH)
- +
- +build 2153
- +
- +Render: added cvar "gl_nosort" that disables sorting of translucent surfaces
- +
- +build 2148
- +
- +Engine: implement support of new BSP format that called BSP31
- +Engine: added new feature - big lightmaps 256x256 instead of 128x128. This is used for new BSP format 31
- +Render: new texture viewer implemented (navigate pages with arrow keys)
- +Engine: added cvar gl_keeptjunctions from Quake (removes a collinear points, economy some vertexes)
- +Sound: test thing: release sentence sounds after playing
- +Engine: rewrited code for anti (_-=ZhekA=-_) system
- +Console: don't moving cursor if autocomplete was failed on second or all next arguments
- +Engine: release all elements of client game cvar (was potential memory leak)
- +Engine: allow change game for dedicated servers
- +Server: added default case for Studio Blending Interface while server is not loaded (e.g. remote connection). Was here a potential crashpoint.
- +Engine: parse "wad" field from entity string and use wad ordering for loading textures that may have matched names but placed in different wads
- +Network: change protocol to 47. Old demos will stop working.
- +Network: rewrite delta-comparing code. In theory this may reduce a network traffic
- +Server: fix crash for fast switching between singleplayer and multiplayer
- +Server: optimize MOVETYPE_COMPOUND code
- +Server: added missed flag FL_FAKECLIENT for bots
- +
- +build 2112
- +
- +Engine: fix bug with ambient sounds that won't writes into demo
- +Client: allow plaque 'loading' between demos change
- +Client: make work fade flag FFADE_MODULATE
- +Render: fixed underwater fog recursive leaf search code (thx XaeroX)
- +Render: replace all 'random' calls in CL_RocketTrail code from RANDOM_LONG to rand() to get more compatibility with original quake particles
- +Render: adding default studiomodel bbox for right culling client static entities
- +Sound: add info about background track state into console command "s_info"
- +Sound: increase static channels count up to 128
- +Client: write background track state into demo
- +Engine: fix crash when typing 'cvarlist' into console
- +FS: allows lookup system files into root directory (e.g. vgui.dll etc)
- +Engine: added new command 'modellist" (prints list about all loaded models)
- +Engine: add terminator for entity string to be guranteed have valid end of the entity string
- +Engine: purge all fake bmodels from previous map when server is changed
- +Memory: increase check for filename debug length from 32 to 128 characters
- +Server: background track which will be specfied from worldpsawn settings now are looped
- +Engine: fix bug with recorded demos in Quake Remake after changelevel
- +GameUI: 'gamestartup.mp3' now are looped
- +Server: fix the SV_StudioSetupBones interface declaration error (thx maricool)
- +Render: change MAXSTUDIOTEXTURES limit from 128 to 256
- +Client: change passed argument for HUD_Frame callback from cl.time to host.frametime (thx XWider)
- +Client: remove screen align to prevent deform on resolution 1366x768
- +FS: do check what mod folder is really existed (this helps avoid to creating empty folder)
- +GameUI: replace checkbox "Allow Software" with "Vertical Sync" in menu "Video Modes"
- +
- +
- +build 2015
- +
- +Server: fix the sound problem with weapons
- +Render: added rendermode kRenderWorldGlow (6) like in HL2
- +Server: added new callback into PhysicsInterface that named SV_TriggerTouch
- +Client: kill a little jitter for monsters that standing on elevators
- +Client: fix very old bug (initially comes from Quake1) with efrags relinking on a static client entities
- +Sound: got rid of message "S_PickChannel: no free channels" when breakble objects were broken.
- +Engine: ignore to load HD-textures when dedicated server is running
- +Client: count of static entities increased up to 512
- +Render: fixed bug with wrong clamping on 3D textures
- +Render: added a new one internal texture - gray cubemap that named as "*grayCube" without quotes
- +Render: disable depth mask on studiomodels when render mode is "additive" (original HL rules)
- +Sound: added a new untested feature for cull sounds by PAS on the client. Cvar "s_phs".
- +Sound: add save\restore for all dynamic sounds in-game
- +Sound: add save\restore for background track
- +Engine: added two new cvars called "build" and "ver" for more info
- +Engine: get support for loading game dlls from packfile
- +Engine: get support for transparent conveyor belts. Texture name must starting from "{scroll"
- +Sound: fix bug in wav-streaming code
- +Server: add save\restore for client static entities (engine function MAKE_STATIC is now useful!)
- +Server: remove command "map_backgound" in dedicated server mode
- +Server: disable "Touch" function when playersonly-mode is active
- +GameUI: don't draw logo.avi from root folder with user mods
- +Client: added partially HD-textures support for sprites
- +Server: now custom message code check all the visible portals (Xash-mod feature)
- +Server: add quake-style for BSP hulls selection (cvar sv_quakehulls set to 1)
- +Engine: remove jpeg image support (just unneeded)
- +Server: remove ugly movement delay after map loaging in singleplayer
- +Render: check studio skins for negative values to prevent possible crashes
- +Console: fixup negative values for "scr_conspeed" variable
- +Render: fix interpolation bug for studiomodels on internal studio renderer
- +Physic: transform trace BBox into local space of bmodel
- +Engine: implement new system of engine features that can be enabled by Mod-Maker request
- +Engine: build BSP surface meshes for Mod-Makers. e.g. for build collision tree of VBO\VA custom rendering
- +Engine: allow support of large maps up to +\- 16384 units (need to edit delta.lst and enable feature in the engine)
- +Engine: rewrite MOVETYPE_TOSS, MOVETYPE_BOUNCE etc
- +Client: implement new draw type TRI_POINTS for TriAPI
- +Client: changed snapshot name from mapnameXXXX.bmp to mapname_XXXX.bmp (by Qwertyus request)
- +Client: write experimental code for interpolate bmodels movement (pev->animtime must not equal 0 for enable)
- +GameUI: allow scissor for enginefunc pfnDrawCharacter
- +Network: protocol changed. replace obsolete message svc_frame with message svc_restoresound
- +Client: remove pieces that stuck in the walls for TE_BREAKMODEL message
- +Render: fix mode r_lighting_extended 1 for prevent permanently black lighting in some cases
- +Render: global fog update. get the uniform color for all the underwater objects (thx n00b)
- +Render: fix issues with conveyor HD-textures (it can moves slower than physical conveyor speed)
- +Render: added support for HD-textures for normal sprite frames (non-HUD sprites)
- +Render: sorting meshes for studiomodel surfaces (draw "adiitive" surfaces at end of the list)
- +Render: release GL-context when engine is shutting down
- +Render: set gl_allow_static to zero as default
- +Sound: set s_cull to zero as default
- +Input: fix problems with call WC_SYSMENU instead of user-defined command when ALT is pressed
- +Console: add a new command that called "mapstats" and works like bspinfo.exe
- +Physic: added new meta-type SOLID_CUSTOM that could be traced in game dlls with physic API
- +Pmove: get to work PM_CheckStuck on a server-side
- +Server: added a new cvar that called a "sv_validate_changelevel" for skip any checks with changelevel problems
- +Server: make check for recursive changelevel (and ignore it)
- +Server: fix the problem with non-sended events when a player sight cross-line contents
- +Server: rewrite MOVETYPE_STEP and MOVETYPE_PUSHSTEP physics
- +Server: allow to MOVETYEP_PUSH blocking by dead bodies
- +Server: fix bug with MOVETYPE_FOLLOW
- +Server: added TriAPI through Server_PhysicsInterface for debug purposes
- +GameUI: replace broken letter 'ั' with 'ะต'
- +GameUI: don't draw logo.avi for mods without this file in gamedir
- +GameUI: fix buttons loader bug
- +GameUI: enable scissor for all ScrollList menus
- +GameUI: restore the menu buttons control from keyboard
- +Client: get walk animation support for 'wrong' player models that uses different skeleton
- +Server: ignore savegame during intermission (used for Quake remake)
- +Render: merge mirrors with same plane into one pass (perfomance option)
- +Render: fix errors in function GL_CleanupTextureUnits (it was cause problems in XashXT)
- +Render: allow decals on 'Solid" surfaces: grates, ladders etc (thx n00b)
- +Render: rewrite "r_lighting_extended 2" mode
- +Render: add optional texture sorting for models with Additive and Transparent textures (r_studio_sort_textures cvar)
- +Engine: makes AABB transform trace an option for switchable engine features
- +Engine: allow studiomodel textures up to 4096x4096 (for indexed images)
- +Server: merge PVS for looking for client through portal cameras
- +Server: fix bug with collect savegame info from basedir (e.g. valve)
- +
- +
- +build 1905
- +
- +Physic: fix trace bug when model is missing
- +Client: implement function TriScreenToWorld
- +Server: add local times for all the clients
- +Server: implement unlag system
- +Client: added ex_interp variable
- +GameUI: added support for playermodel images (preview thumbnails)
- +Engine: fix potentially crash in menu after calling Host_Error
- +Engine: fix crash on Cry Of Fear modification (memory corrupts)
- +Engine: first implementation of HLTV
- +Render: fix a little bug with engine mirrors
- +Sound: implement separate volume controls for background track and game sounds
- +Sound: fix wrong position for dynamic sounds in case parent entity never has updates on the client
- +Client: first implementation of extended engineinterface.
- +Server: fix bug with update movevars after the server initialization.
- +Input: cancel mouse movement while switches between menu\console and game
- +Render: added function R_EntityRemoveDecals into RendererInterface
- +Render: fixed bug with crash engine on custom resolutions while makes a screenshot (e.g. 1366x768)
- +
- +build 1850
- +
- +Physic: add check for liquid brushes that has only hull0
- +Render: draw decals without culling on the transparent surfaces
- +Engine: fix decal transition bug on global entities
- +Client: fix "r_drawentities 5" debug code in client.dll
- +Render: rewrited detail texture code for using detail scale for each diffuse texture instead of each detail texture
- +Render: custom render interface is changed to version 26
- +Engine: added custom studio decals serializtaion
- +Server: fixed check for russian letters in the commands "say" and "say_team"
- +Server: physics interface is changed to version 6
- +Client: allow console in multiplayer even while dev-mode is disabled
- +Engine: added new message SVC_STUDIODECAL that passed through engine and call function in extended rendered interface
- +Engine: hook PrintScreen and manually writing screenshot into clipboard
- +Render: fix decals drawing when rendermode is TransColor
- +Render: add support for cubemaps, 1D and 3D textures
- +Render: added some new internal textures that using by Xash-Mod 0.5
- +Render: fix reflection for Glow-Sprites and follow beams
- +Studio: fix poly-counter for studio models
- +Engine: add support for userconfig
- +Engine: allow letter 'ั' in console and chat-mode
- +Engine: fix REG_USER_MSG for messages that registering in-game
- +Server: clear savedir when new game is started
- +GameUI: loading maps.lst from basedir while mod doesn't contain multiplayer maps
- +Network: implemented QueryCvarValue and QueryCvarValue2
- +Physic: new pm-trace code, new server trace code, new studio hitbox trace code
- +Client: rewrite demo record and playback
- +Render: add support for STUDIO_NF_FULLBRIGHT
- +Physic: fix pmove trace bug
- +
- +build 1770
- +
- +Client: add command "on"-"off" for virtual CD-player
- +Client: add command "snapshot" that save screenshots into root folder
- +Client: add studiomodel missed flags like in Quake (EF_ROTATE, EF_ROCKET, EF_GIB etc)
- +Sound: clear LOOP flag for engine funcs PlaySoundByIndex and PlaySoundAtLocation
- +Render: fix r_wateralpha, move cvar to server and allow save-restore it
- +Render: fix old bug with surface->flags
- +Render: fix crash when studiomodel isn't loaded but trying to draw
- +Render: remove cvar gl_texturebits
- +Render: allow 16-bit color mode when decktop has same
- +Render: rename "vid_gamma" to "gamma", make backward compatibility with GoldSource config
- +Sound: get support for automatic ambient sounds like in Quake
- +Sound: add cvar "s_combine_channels" that trying to combine mutilpe channels with same sounds into one
- +Engine: add "secure" option support for both liblist.gam and gameinfo.txt
- +Engine: fix bug determine current directory
- +Server: fix bug when some sound messages can't be sended to client (e.g. not vised map)
- +Render: allow to load hi-res quake sky (two layers called as sky_solid and sky_alpha)
- +Physic: fix trace bug when bbox mins are 0 0 0 and bbox maxs are positive values (like quake boxes)
- +GameUI: add checkbox "allow materials" in menu Video Options.
- +Client: implement "viewsize" cvar
- +GameUI: add new function to inteface called as pfnProcessImage
- +Client: add support for default studiomodel flags like quake effects (light, smoke, blood etc)
- +Render: add engine mirrors (can be set on map with texture "decals.wad\reflect1")
- +Client: rewrite client font system to allow support for "hud_scale" feature
- +Client: re-enable client static entities (see engine function MAKE_STATIC for details)
- +Sound: clear "loop" flags for client engine functions PlaySoundByName and PlaySoundByIndex
- +Client: fix potentially crash in StudioRemap code
- +Client: finalize 'GlowShell' effect on StudioModels
- +Render: implement software gamma control that based on lightmap adjusting (gl_ignorehwgamma 1)
- +Render: restore projection and modelview matrices before call V_CalcRefdef to avoid errors on custom rendering (e.g. HLFX 0.5, Trinity Renderers)
- +Render: remove all stuff for 3dfx gamma control
- +Render: add missing function R_ScreenToWorld
- +Engine: add "icon" option support for both liblist.gam and gameinfo.txt
- +Render: get support for rotational skybox that can be saved and restored with current angle
- +Engine: fix bug with incorrect detecting Blue-Shift maps in some rare cases
- +Engine: add autocomplete for 'entpatch' command
- +Engine: fix Host_Error issues
- +Network: add IPX and IPX_BROADCAST for backward compatibility with GoldSrc
- +Engine: do revision for 'allow_studio_scale' cvar in trace code
- +GameUI: added support for Steam backgrounds
- +GameUI: hide input symbols for "password" field in "create server" menu page
- +Client: initial implementation of NetAPI
- +Render: clear decals code. Add transparent rendering for 'glass' decals
- +GameUI: added new argument for pfnPIC_Load.
- +GameUI: fix loading flipped Steam background images
- +Client: remove gravity for R_Implosion effect
- +Sound: add SND_MoveMouth16 for support 16-bit sounds lip-sync
- +Engine: fix potentially crash during parsing titles.txt when file is empty
- +Engine: increase MAX_VALUE field up to 2048 characters
- +Console: rename con_gamemaps to con_mapfilter
- +Sound: add check by PVS for dynamic entity channels
- +Sound: add sound culling by geometry (cvar 's_cull' for enable or disable)
- +Server: fix changelevel bug
- +Engine: fix sound pathes with backward slash
- +Engine: rewrite COM_LoadFile and LoadFileForMe for use malloc instead of engine Mem_Alloc
- +Server: check date for entitypatch to avoid loading too old pathes (when map is never than path)
- +Server: bug fixed in CreateNamedEntity (on create not existed entities).
- +Server: rewrite engine func pfnAlertMessage to avoid crash in AM:Rebrith
- +Server: align memory for edicts by 4 (this help to avoid crash in Poke646)
- +Render: bugfixed with rotational brush culling (perfomance)
- +Server: changelevel bug fixed (accumulate global entities)
- +Server: changelevel bug when entitypath on new level is too old (new level is never than him entitypath)
- +Server: physical inetrface for custom physic implementation is updated to version 5
- +Physic: fix bug with MOVETYPE_COMPOUND
- +Server: fix bug with force_retouch on start the level (to avoid crash in Todesangst2 on t2e1m10)
- +Render: fix rendering for FACE_UPRIGHT sprite types (doom-like sprite monsters)
- +Protocol: shifted up additional EF_ flags to avoid collisions with Trinity Renderers
- +Render: now hardware gamma-control is fixed
- +Client: implement new render interface for custom renderer implementation (current version is 12)
- +Client: added two new funcstions into event API (IndexForEvent and EventForIndex)
- +Client: added new function into IEngineStudio interface (StudioGetTexture) for custom rendering implementation
- +Client: passed server beam entity through client function HUD_AddEntity, make force to add menu entity (player setup)
- +Client: passed static client entities through client function HUD_AddEntity
- +Physic: add support for rotational water and triggers
- +
- +build 1662
- +
- +Client: implement StudioRemapColors function
- +Client: add simple shadows for stduiomodels (disabled like in GoldSrc)
- +Client: fix some Paranoia bugs when custom renderer is disabled
- +Client: implement overview tool (dev_overview)
- +Client: add debug commands linefile and pointfile
- +Client: get support for full-color external textures (tga format) - world, studiomodels and decals
- +Client: fixed some HLFX 0.6 bugs
- +Client: fixed follow studiomodels (like flags in CTF)
- +Server: add pfnGetApproxWavePlayLen
- +Sound: get support for mp3's with wav header
- +Server: fixed FIND_CLIENT_IN_PVS
- +Server: fixed PlaybackEvent, use camera PVS point when client see in
- +Render: enable lightmaps on a transparent surfaces like windows (r_lighting_extended 2)
- +Server: func_pushable can push players which standing on (sv_fix_pushstep)
- +Render: partially fix for underwater fog (temporary solution)
- +
- +build 1613
- +
- +Client: fix drawing beams for 'solid' mode
- +Image: fix BMP loader for 4-bit color bmp's
- +Client: fix lightlevel calculating for local client (remove 'ambient' base from final value)
- +GameUI: first implementation of custom strings and support 'strings.lst' parsing
- +GameUI: replace unneeded button 'credits' with button 'previews'
- +Render: fix sprite interpolation
- +Render: fix angled sprites offset
- +Render: implement detail textures like in Steam Half-Life (thx n00b)
- +Client: rework env_funnel effect
- +Engine: get full support for input, processing and drawing russian letters
- +Console: add console commands 'messagemode' and 'messagemode2'
- +Console: fix bug with autocomplete (enable sort for found cmds)
- +Client: added HUD_ChatInputPosition for CS 1.6
- +
- +build 1598
- +
- +Client: fix crosshair drawing
- +Sound: change libmad mp3 decoder on a mpg123
- +Client: fix gibs randomization for TE_BREAKMODEL
- +Engine: fix modelloader bug (engine crash after not found map)
- +Video: add resolution 1366x768
- +GameUI: fix skill select
- +Network: change 'svc_setangle' message, include rollangle
- +Render: fix chrome rendering on a studiomodels
- +Render: added video memory economy mode - cvar 'gl_luminance_textures'
- +GameDLL: first implementation of extended engineinterface. Metamod is supported now
- +
- +build 1557
- +
- +Sound: fixed wrong sound angles when client see in the camera
- +Render: fix crash on change gl_texturemode and gl_anisotropy.
- +Client: change relationsip for GetLocalPlayer. Now it's always valid.
- +Server: rewrite SV_Multicast for correct work with custom user cameras
- +Server: rewrite FIND_CLIENT_IN_PVS like in QW
- +
- +build 1540
- +
- +Fixed many-many small and large bugs before final release
- +
- +build 1529
- +
- +FS: add "fallback_dir" option
- +Server: fix func_pushable interaction with movers. Add new cvar "sv_allow_rotate_pushables"
- +Server: added support for 'SV_SaveGameComment' export
- +Server: fixed backup for quick.sav and autosave.save (quick01.sav and autosave01.sav)
- +Client: add commandline option "-nointro" to skip start movies
- +Pmove: add sv_clienttrace that shared across network
- +Render: implement "envshot" and "skyshot" commands for make cubemaps or skyboxes
- +Server: fix remote connection (rcon)
- +Render: add glare reduction option in menu
- +Server: fix FindEntityInSphere bug (satchel issues in multiplayer)
- +GameUI: added to scrollbar in srcoll lists (thx ADAMIX)
- +
- +build 1516
- +
- +Engine: fix Sys_Error blowout
- +GameUI: implement new credits effect in Half-Life (when game is end)
- +GameUI: use system cursor instead of emulated
- +
- +build 1515
- +
- +Engine: fix some bugs
- +
- +build 1507
- +
- +Console: implement Con_NPrintf and Con_NXPrintf
- +Render: adding better lighting for studiomodels (right lighting for long sequences e.g. forklift.mdl)
- +Network: clamp all integer values to prevent them out of range
- +Client: VGUI implementation
- +Render: fix decals loading
- +Server: fix NAN error on a crossbow launch
- +
- +build 1488
- +
- +Render: fix invisible sprites when game is paused
- +Render: implement new better sprites lighting
- +GameUI: HL-style buttons (old good menu form WON version)
- +Render: fix some rendering bugs
- +
- +build 1482
- +
- +Engine: fixed critical bug
- +Launch: remove all built-in tools
- +Engine: add underwater fog
- +Engine: add cvar to control studio model scaling (enable or disable)
- +Engine: fixed bug with mouse in multiplayer (not work in menu)
- +Engine: fixed lag on rpg laserspot
- +Engine: added weapon and movement prediction (may be bugly, use with caution)
- +GameUI: added pfnRandomLong and pfnRandomFloat built-ins (and keep compatibility with old versions)
- +Engine: added map_background (special command for loading background maps like in Source Engine)
- +GameUI: added support for chaptermapbackground.txt script-file (random choose background maps)
- +Render: fix some rendering bugs for mods with custom renderer (Paranoia, HLFX etc)
- +
- +build 1433
- +
- +Engine: rework hitbox trace
- +Engine: implement new check for blue-shift map format
- +Engine: fix PointContents for custom contents checking (spirit)
- +Engine: fix "angle" field on maps (typically for gearbox)
- +GameUI: implement 'mouse look' checkbox
- +
- +build 1430
- +
- +Engine: fix crash with invalid room_type set (more than 60)
- +Engine: fix stuck on elevators or tracktrains for clients
- +
- +build 1428
- +
- +Engine: fix trigger_camera serialization bug
- +Engine: many-many physics bugs fixed
- +Engine: reworking monster's movement and path finding
- +Engine: hlfx 0.6 is now working
- +FS: fix bug with game and base directory dectecting when they matches
- +FS: watch for changes in liblist.gam and update gameinfo.txt (feature)
- +Engine: fix some rendering bugs
- +GameUI: added 'suitvolume' control
- +GameUI: rewrite playeyrmodel drawing, so you can shows changes when hi\low resolution button is toggled
- +GameUI: remove choosing audio and video library (interface changed!)
- +Engine: fix train startup sound on new level
- +
- +build 1422
- +
- +Render: fix decals serialization bug
- +Engine: fix movie plaback bug (black screen)
- +Engine: fix crash on loading encrypted client.dll
- +GameUI: now recalc resolution when vid_mode is changed
- +Sound: fix musicvolume bug
- +Image: fix indexalpha palette bug
- +Physic: fix stuck on some items (weapons, ammo)
- +
- +build 1418
- +
- +Tools: move all tools into launch.dll
- +Sound: moving snd_dx.dll into engine.dll
- +Sound: implement CDAudio emulator with support mp3 tracks from original Half-Life
- +Sound: implement mp3 support
- +GameUI: GameUI.dll renamed to MainUI.dll to avoid conflict with original valve's GameUI.dll
- +Engine: support for StartupVids.txt
- +Engine: get full compatibility with hl.dll
- +FS: recode wad resource management (now support lumps from wads with same name)
- +Engine: trigger_camera is now correctly saved and restored
- +Render: add sorting for translucent surfaces
- +Render: make support for 'static' models (any opaque non-moving brushes engine automatically make as part of world)
- +Render: correct serialization for decals on bmodels
- +
- +build 1338
- +
- +Engine: fix a broken demos recording\playing
- +GameUI: get support for internal resources (built-in)
- +GameUI: make font.bmp, cursor.bmp and typing.bmp as part of GameUI.dll
- +GameUI: remove demo menus heads.
- +
- +build 1334
- +
- +Engine: prevent auto-repeat for most keys in-game
- +Engine: implement AVI movies support (instead of RoQ support)
- +Engine: enable logo.avi in main menu (see GameUI source for details)
- +
- +build 1313
- +
- +Launch: code revision, remove dead code, implement some missed functions
- +Sound: fix some errors and crash
- +Sound: implement music volume
- +Sound: reworking sound mixer
- +Sound: implement DSP
- +Engine: add support for five mouse extra-buttons
- +Engine: fix some physics bugs
- +SDK: add blue-shift game source to SDK (combined with main game source)
- +
- +build 1305
- +
- +Engine: implement bit-stream network buffer
- +Engine: implement custom delta-encoding with user defined script (delta.lst)
- +Engine: reworking client entity for get more compatibility with original HL client
- +Engine: make SDK compatible with HLSDK 2.3 on the server-side
- +Engine: fixup across transition time-bug
- +Engine: completely rewrite server trace
- +Engine: rewrite hitbox trace
- +Engine: rewrite SV_PointContents
- +Engine: implement a new movetype: compound for gluing two entities together (like movewith in spirit)
- +Engine: fix toss entities on conveyors
- +Engine: rewrite MOVETYPE_PUSH
- +Engine: rewrite monsters movement code
- +Engine: reworking client and game interfaces
- +Engine: fix camera bugs (no sounds when client see in the camera)
- +SDK: fix many-many small HL bugs in original sdk code
- +Engine: fix trigger retouching system
- +Engine: adjust beam visibility
- +
- +build 1271
- +
- +Engine: enable server.cfg, listenserver.cfg, mapcycle.txt etc
- +Engine: got to work mapcycle.txt
- +GameUI: implement redefine keys menu
- +Engine: added autocomplete for cmd 'exec'
- +Engine: added version info in menu
- +
- +build 1270
- +
- +SDK: Shared launcher code
- +Engine: Partially fix bmodel interpolation
- +Engine: use standard .cfg files instead of .rc files
- +
- +build 1269
- +
- +Render: cut invisible water polygons
- +Render: implement EF_NOWATERCSG for control func_water backface culling
- +Tools: fix wadlib and spritegen round bugs
- +FS: implement binary search for wadlumps
- +Engine: revert low-res timer
- +Network: fixup userinfo fields 'model' and 'name'
- +Sound: implement custom pause for various sources
- +Input: disable mouse events when level is loading
- +GameUI: adding some missed dialogs
- +Render: fix interpolation on flying monsters
- +Render: fix wrong sprite attachments
- +Render: fix invalid frustum culling for studiomodels ( e.g. barnacle.mdl )
- +Physic: fix trace for rotating bmodels
- +Engine: fixup physinfo save\restore bug
- +
- +build 1262
- +
- +Engine: add 'allow_levelshots' cvar (disabled by default) to switch between custom levelshots and normal 'loading' screen
- +Client: remove fmod.dll implementation
- +Engine: implement variable-sized fonts (console, menu hints)
- +Sound: added support for stereo wavs plays (menu sounds)
- +Render: enable custom game icons (game.ico in mod folder)
- +Engine: move menu code into new user dll called GameUI.dll (based on original q2e 0.40 menu code)
- +FS: implement simple converter liblist.gam to gameinfo.txt
- +
- +build 1254
- +
- +SoundLib: ogg loop points (LOOP_START comment)
- +Client: recalc fov y for more matched with original HL
- +Bshift: fix env_laser entity
- +Client: fix fadeout for break model pieces
- +Gfx: replace default.bmp font with fixed alpha-channel (thx LokiMb)
- +Render: fix invisible beams behind glass
- +Render: fix glow-sprites drawing through walls (see also r_cullflares cvar)
- +FS: implement filter wadlumps by wadname (e.g. gfx.wad/backtile)
- +Render: implement kRenderTransColor
- +Engine: completely moving particle code into the client.dll
- +Client: implement tracers for sparks, garg streaks and bullets
- +
- +build 1249
- +
- +ImageLib: added support for 4-bits and monochrome uncompressed BMPs.
- +ImageLib: fix data align for NPOT textures in menu (e.g. slider.bmp).
- +StdLib: skip empty symbols in numerical string for atoi and atof.
- +Render: implement LoadSprite for custom client sprites (e.g. hud)
- +Sound: fixed bug with background music looping
- +Fonts: implement Half-Life creditfonts
- +Client: move client.dll to valve folder
- \ No newline at end of file
- diff --git b/cl_dll/hud_servers.cpp a/cl_dll/hud_servers.cpp
- index 7a5a147..61f6454 100644
- --- b/cl_dll/hud_servers.cpp
- +++ a/cl_dll/hud_servers.cpp
- @@ -17,7 +17,7 @@
- static int context_id;
- // Default master server address in case we can't read any from woncomm.lst file
- -#define VALVE_MASTER_ADDRESS "half-life.east.won.net"
- +#define VALVE_MASTER_ADDRESS "ms.xash.su"
- #define PORT_MASTER 27010
- #define PORT_SERVER 27015
- @@ -902,7 +902,7 @@ void CHudServers::RequestList( void )
- NET_API->InitNetworking();
- // Kill off left overs if any
- - NET_API->CancelAllRequests();
- + CancelRequest();
- // Request Server List from master
- NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse );
- @@ -935,7 +935,7 @@ void CHudServers::RequestBroadcastList( int clearpending )
- if ( clearpending )
- {
- // Kill off left overs if any
- - NET_API->CancelAllRequests();
- + CancelRequest();
- }
- adr.type = NA_BROADCAST;
- diff --git b/common/bspfile.h a/common/bspfile.h
- index 51452cd..12b8d65 100644
- --- b/common/bspfile.h
- +++ a/common/bspfile.h
- @@ -31,7 +31,8 @@ BRUSH MODELS
- #define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit
- #define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH"
- -#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT
- +#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"
- @@ -103,11 +104,19 @@ BRUSH MODELS
- #define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3
- #define HEADER_LUMPS_31 17
- -#define LUMP_FACES_EXTRADATA 0 // extension of dface_t
- -#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t
- -#define LUMP_CUBEMAPS 2 // cubemap description
- -
- -#define EXTRA_LUMPS 8 // g-cont. just for future expansions
- +#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_LEAF_LIGHTING 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_UNUSED0 8 // one lump reserved for me
- +#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
- @@ -216,9 +225,18 @@ typedef struct
- {
- float vecs[2][4]; // texmatrix [s/t][xyz offset]
- int miptex;
- - int flags;
- + 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 dsurfedge_t; // map surfedges
- diff --git b/common/com_model.h a/common/com_model.h
- index 709f23d..24077e0 100644
- --- b/common/com_model.h
- +++ a/common/com_model.h
- @@ -84,10 +84,20 @@ typedef struct texture_s
- 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
- +
- + 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]
- - float mipadjust; // mipmap limits for very small surfaces
- + 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;
- @@ -168,7 +178,7 @@ typedef struct mleaf_s
- msurface_t **firstmarksurface;
- int nummarksurfaces;
- - byte *compressed_pas;
- + int cluster; // helper to acess to uncompressed visdata
- byte ambient_sound_level[NUM_AMBIENTS];
- } mleaf_t;
- diff --git b/common/const.h a/common/const.h
- index e80c8a4..192b263 100644
- --- b/common/const.h
- +++ a/common/const.h
- @@ -50,6 +50,7 @@
- #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_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
- diff --git b/common/cvardef.h a/common/cvardef.h
- index f822cc7..614c898 100644
- --- b/common/cvardef.h
- +++ a/common/cvardef.h
- @@ -25,6 +25,8 @@
- #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_GLCONFIG (1<<18) // write it into opengl.cfg
- +
- typedef struct cvar_s
- {
- char *name;
- diff --git b/common/entity_state.h a/common/entity_state.h
- index ef5448f..4d04e8f 100644
- --- b/common/entity_state.h
- +++ a/common/entity_state.h
- @@ -176,11 +176,13 @@ typedef struct clientdata_s
- #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[64];
- + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
- } local_state_t;
- #endif//ENTITY_STATE_H
- \ No newline at end of file
- diff --git b/common/features.h a/common/features.h
- index efc0bab..73f184e 100644
- --- b/common/features.h
- +++ a/common/features.h
- @@ -25,6 +25,6 @@ GNU General Public License for more details.
- #define ENGINE_COMPENSATE_QUAKE_BUG (1<<5) // compensate stupid quake bug (inverse pitch) for mods where this bug is fixed
- #define ENGINE_DISABLE_HDTEXTURES (1<<6) // disable support of HD-textures in case custom renderer have separate way to load them
- #define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
- -#define ENGINE_THREADED_MAIN_LOOP (1<<8) // simulate dedictated thread for main engine loop (prefomance)
- +#define ENGINE_FIXED_FRAMERATE (1<<8) // keep constant rate for client and server (but don't clamp renderer calls)
- #endif//FEATURES_H
- \ No newline at end of file
- diff --git b/common/render_api.h a/common/render_api.h
- index 8f2b364..6bc60f9 100644
- --- b/common/render_api.h
- +++ a/common/render_api.h
- @@ -44,11 +44,11 @@ GNU General Public License for more details.
- #define PARM_TEX_TARGET 8
- #define PARM_TEX_TEXNUM 9
- #define PARM_TEX_FLAGS 10
- -#define PARM_TEX_TYPE 11
- +#define PARM_TEX_DEPTH 11 // 3D texture depth or 2D array num layers
- #define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload
- #define PARM_TEX_GLFORMAT 13 // get a texture GL-format
- #define PARM_TEX_ENCODE 14 // custom encoding for DXT image
- -// reserved
- +#define PARM_TEX_MIPCOUNT 15 // count of mipmaps (0 - autogenerated, 1 - disabled of mipmapping)
- #define PARM_WORLD_VERSION 16 // return the version of bsp
- #define PARM_SKY_SPHERE 17 // sky is quake sphere ?
- #define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs
- @@ -65,6 +65,10 @@ GNU General Public License for more details.
- #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 //
- enum
- {
- @@ -79,25 +83,6 @@ enum
- typedef enum
- {
- - TEX_INVALID = 0, // free slot
- - TEX_SYSTEM, // generated by engine
- - TEX_NOMIP, // hud pics, menu etc
- - TEX_BRUSH, // a map texture
- - TEX_SPRITE, // sprite frames
- - TEX_STUDIO, // studio skins
- - TEX_LIGHTMAP, // lightmap textures
- - TEX_DECAL, // decals
- - TEX_VGUI, // vgui fonts or images
- - TEX_CUBEMAP, // cubemap textures (sky)
- - TEX_DETAIL, // detail textures
- - TEX_REMAP, // local copy of remap texture
- - TEX_SCREENCOPY, // keep screen copy e.g. for mirror
- - TEX_CUSTOM, // user created texture
- - TEX_DEPTHMAP // shadowmap texture
- -} texType_t;
- -
- -typedef enum
- -{
- TF_NEAREST = (1<<0), // disable texfilter
- TF_KEEP_RGBDATA = (1<<1), // some images keep source
- TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20
- @@ -106,7 +91,7 @@ typedef enum
- TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory
- TF_CUBEMAP = (1<<6), // it's cubemap texture
- TF_DEPTHMAP = (1<<7), // custom texture filter used
- - TF_INTENSITY = (1<<8), // monochrome intensity image
- +// reserved
- 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
- @@ -119,16 +104,29 @@ typedef enum
- 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_STATIC = (1<<21), // a marker for purge mechanism (not used by engine)
- +// reserved
- TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE
- - TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference)
- -
- - TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage
- - TF_FLOAT = (1<<26), // float textures
- +// reserved
- + TF_TEXTURE_2D_ARRAY = (1<<24), // this is 2D texture array (multi-layers)
- + 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_FLOATDATA = (1<<28), // incoming dataType has type GL_FLOAT
- + 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;
- +
- typedef struct beam_s BEAM;
- typedef struct particle_s particle_t;
- @@ -184,8 +182,8 @@ typedef struct render_api_s
- 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 );
- - void (*GL_SetTextureType)( unsigned int texnum, unsigned int type );
- - void (*GL_TextureCacheFrame)( unsigned int texnum );
- + 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)
- @@ -211,11 +209,11 @@ typedef struct render_api_s
- 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 );
- - void (*GL_Reserved3)( void );
- -
- +
- // Misc renderer functions
- void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags );
- void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder
- @@ -255,8 +253,10 @@ typedef struct render_interface_s
- qboolean (*R_SpeedsMessage)( char *out, size_t size );
- // replace with built-in R_DrawCubemapView for make skyshots or envshots
- qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size );
- - // alloc or destroy studiomodel custom data
- + // 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 );
- } render_interface_t;
- #endif//RENDER_API_H
- \ No newline at end of file
- diff --git b/common/wadfile.h a/common/wadfile.h
- index ae85648..a7e0231 100644
- --- b/common/wadfile.h
- +++ a/common/wadfile.h
- @@ -20,7 +20,7 @@
- ========================================================================
- .WAD archive format (WhereAllData - WAD)
- -List of compressed files, that can be identify only by TYPE_*
- +List of compressed files, that can be identify only by TYP_*
- <format>
- header: dwadinfo_t[dwadinfo_t]
- @@ -33,7 +33,7 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
- ========================================================================
- */
- -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W')
- +#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
- diff --git b/engine/cdll_exp.h a/engine/cdll_exp.h
- index bf43654..c059231 100644
- --- b/engine/cdll_exp.h
- +++ a/engine/cdll_exp.h
- @@ -64,6 +64,8 @@ typedef struct cldll_func_s
- // 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 );
- + void (*pfnUpdateEntityState)( cl_entity_t *ent, entity_state_t *newstate, int noInterp ); // custom interp
- + void (*pfnInterpolateEntity)( cl_entity_t *ent, float lerpFrac );
- } cldll_func_t;
- #endif//CDLL_EXP_H
- \ No newline at end of file
- diff --git b/engine/client/cl_cmds.c a/engine/client/cl_cmds.c
- index af77f70..74b9e06 100644
- --- b/engine/client/cl_cmds.c
- +++ a/engine/client/cl_cmds.c
- @@ -70,7 +70,8 @@ void CL_PlayCDTrack_f( void )
- if( Cmd_Argc() < 2 ) return;
- command = Cmd_Argv( 1 );
- - if( !enabled && Q_stricmp( command, "on" )) return; // CD-player is disabled
- + if( !enabled && Q_stricmp( command, "on" ))
- + return; // CD-player is disabled
- if( !Q_stricmp( command, "play" ))
- {
- @@ -135,15 +136,14 @@ void CL_PlayCDTrack_f( void )
- CL_ScreenshotGetName
- ==================
- */
- -void CL_ScreenshotGetName( int lastnum, char *filename )
- +qboolean CL_ScreenshotGetName( int lastnum, char *filename )
- {
- int a, b, c, d;
- if( lastnum < 0 || lastnum > 9999 )
- {
- - // bound
- - Q_sprintf( filename, "scrshots/%s/!error.bmp", clgame.mapname );
- - return;
- + MsgDev( D_ERROR, "unable to write screenshot\n" );
- + return false;
- }
- a = lastnum / 1000;
- @@ -155,6 +155,8 @@ void CL_ScreenshotGetName( int lastnum, char *filename )
- d = lastnum;
- Q_sprintf( filename, "scrshots/%s_shot%i%i%i%i.bmp", clgame.mapname, a, b, c, d );
- +
- + return true;
- }
- /*
- @@ -216,7 +218,9 @@ void CL_ScreenShot_f( void )
- // scan for a free filename
- for( i = 0; i < 9999; i++ )
- {
- - CL_ScreenshotGetName( i, checkname );
- + if( !CL_ScreenshotGetName( i, checkname ))
- + return; // no namespace
- +
- if( !FS_FileExists( checkname, false ))
- break;
- }
- diff --git b/engine/client/cl_demo.c a/engine/client/cl_demo.c
- index c2f8765..8aeee5c 100644
- --- b/engine/client/cl_demo.c
- +++ a/engine/client/cl_demo.c
- @@ -30,7 +30,7 @@ GNU General Public License for more details.
- #define DEMO_NORMAL 1 // this lump contains playback info of messages, etc., needed during playback.
- #define IDEMOHEADER (('M'<<24)+('E'<<16)+('D'<<8)+'I') // little-endian "IDEM"
- -#define DEMO_PROTOCOL 1
- +#define DEMO_PROTOCOL 2
- const char *demo_cmd[dem_lastcmd+1] =
- {
- @@ -49,6 +49,7 @@ typedef struct
- int dem_protocol; // should be DEMO_PROTOCOL
- int net_protocol; // should be PROTOCOL_VERSION
- char mapname[64]; // name of map
- + char comment[64]; // comment for demo
- char gamedir[64]; // name of game directory (FS_Gamedir())
- int directory_offset; // offset of Entry Directory.
- } demoheader_t;
- @@ -68,6 +69,13 @@ typedef struct
- int numentries; // number of tracks
- } demodirectory_t;
- +// add angles
- +typedef struct
- +{
- + float starttime;
- + vec3_t viewangles;
- +} demoangle_t;
- +
- // private demo states
- struct
- {
- @@ -77,7 +85,13 @@ struct
- int framecount;
- float starttime;
- float realstarttime;
- + float timestamp;
- + float lasttime;
- int entryIndex;
- +
- + // interpolation stuff
- + demoangle_t cmds[ANGLE_BACKUP];
- + int angle_position;
- } demo;
- /*
- @@ -261,11 +275,7 @@ void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg )
- swlen = MSG_GetNumBytesWritten( msg ) - start;
- if( swlen <= 0 ) return;
- - if( !startup )
- - {
- - cls.demotime += host.frametime;
- - demo.framecount++;
- - }
- + if( !startup ) demo.framecount++;
- // demo playback should read this as an incoming message.
- c = (cls.state != ca_active) ? dem_norewind : dem_read;
- @@ -313,9 +323,9 @@ Write demo header
- */
- void CL_WriteDemoHeader( const char *name )
- {
- - fs_offset_t copysize;
- - fs_offset_t savepos;
- - fs_offset_t curpos;
- + long copysize;
- + long savepos;
- + long curpos;
- MsgDev( D_INFO, "recording to %s.\n", name );
- cls.demofile = FS_Open( name, "wb", false );
- @@ -336,6 +346,7 @@ void CL_WriteDemoHeader( const char *name )
- demo.header.dem_protocol = DEMO_PROTOCOL;
- demo.header.net_protocol = PROTOCOL_VERSION;
- Q_strncpy( demo.header.mapname, clgame.mapname, sizeof( demo.header.mapname ));
- + Q_strncpy( demo.header.comment, clgame.maptitle, sizeof( demo.header.comment ));
- Q_strncpy( demo.header.gamedir, FS_Gamedir(), sizeof( demo.header.gamedir ));
- // write header
- @@ -420,9 +431,7 @@ void CL_StopRecord( void )
- FS_Write( cls.demofile, &demo.directory.numentries, sizeof( int ));
- for( i = 0; i < demo.directory.numentries; i++ )
- - {
- FS_Write( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t ));
- - }
- Mem_Free( demo.directory.entries );
- demo.directory.numentries = 0;
- @@ -438,7 +447,7 @@ void CL_StopRecord( void )
- gameui.globals->demoname[0] = '\0';
- Msg( "Completed demo\n" );
- - MsgDev( D_INFO, "Recording time %.2f\n", cls.demotime );
- + MsgDev( D_INFO, "Recording time: %02d:%02d", (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
- cls.demotime = 0.0;
- }
- @@ -449,16 +458,17 @@ CL_DrawDemoRecording
- */
- void CL_DrawDemoRecording( void )
- {
- - char string[64];
- - rgba_t color = { 255, 255, 255, 255 };
- - fs_offset_t pos;
- - int len;
- + char string[64];
- + rgba_t color = { 255, 255, 255, 255 };
- + long pos;
- + int len;
- if(!( host.developer && cls.demorecording ))
- return;
- pos = FS_Tell( cls.demofile );
- - Q_snprintf( string, sizeof( string ), "RECORDING %s: %ik", cls.demoname, pos / 1024 );
- + Q_snprintf( string, sizeof( string ), "^1RECORDING:^7 %s: %s time: %02d:%02d", cls.demoname,
- + Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
- Con_DrawStringLen( string, &len, NULL );
- Con_DrawString(( scr_width->integer - len) >> 1, scr_height->integer >> 2, string, color );
- @@ -511,8 +521,9 @@ void CL_ReadDemoUserCmd( qboolean discard )
- if( !discard )
- {
- - usercmd_t nullcmd;
- - sizebuf_t buf;
- + usercmd_t nullcmd;
- + sizebuf_t buf;
- + demoangle_t *a;
- memset( &nullcmd, 0, sizeof( nullcmd ));
- MSG_Init( &buf, "UserCmd", data, sizeof( data ));
- @@ -530,6 +541,20 @@ void CL_ReadDemoUserCmd( qboolean discard )
- MSG_ReadDeltaUsercmd( &buf, &nullcmd, cl.refdef.cmd );
- + // make sure what interp info contain angles from different frames
- + // or lerping will stop working
- + if( demo.lasttime != demo.timestamp )
- + {
- + // select entry into circular buffer
- + demo.angle_position = (demo.angle_position + 1) & ANGLE_MASK;
- + a = &demo.cmds[demo.angle_position];
- +
- + // record update
- + a->starttime = demo.timestamp;
- + VectorCopy( cl.refdef.cmd->viewangles, a->viewangles );
- + demo.lasttime = demo.timestamp;
- + }
- +
- // NOTE: we need to have the current outgoing sequence correct
- // so we can do prediction correctly during playback
- cls.netchan.outgoing_sequence = outgoing_sequence;
- @@ -674,7 +699,6 @@ reads demo data and write it to client
- */
- qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
- {
- - float f = 0.0f;
- long curpos = 0;
- float fElapsedTime = 0.0f;
- qboolean swallowmessages = true;
- @@ -690,8 +714,7 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
- }
- // HACKHACK: changedemo issues
- - if( !cls.netchan.remote_address.type )
- - cls.netchan.remote_address.type = NA_LOOPBACK;
- + if( !cls.netchan.remote_address.type ) cls.netchan.remote_address.type = NA_LOOPBACK;
- if(( !cl.background && ( cl.refdef.paused || cls.key_dest != key_game )) || cls.key_dest == key_console )
- {
- @@ -706,16 +729,14 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
- if( !cls.demofile ) break;
- curpos = FS_Tell( cls.demofile );
- - CL_ReadDemoCmdHeader( &cmd, &f );
- + CL_ReadDemoCmdHeader( &cmd, &demo.timestamp );
- fElapsedTime = CL_GetDemoPlaybackClock() - demo.starttime;
- - bSkipMessage = (f >= fElapsedTime) ? true : false;
- + bSkipMessage = ((demo.timestamp - cl_serverframetime()) >= fElapsedTime) ? true : false;
- + if( cls.changelevel ) demo.framecount = 1;
- - if( cls.changelevel )
- - demo.framecount = 1;
- -
- - // HACKHACK: changelevel issues
- - if( demo.framecount <= 10 && ( fElapsedTime - f ) > host.frametime )
- + // changelevel issues
- + if( demo.framecount <= 2 && ( fElapsedTime - demo.timestamp ) > host.frametime )
- demo.starttime = CL_GetDemoPlaybackClock();
- // not ready for a message yet, put it back on the file.
- @@ -778,6 +799,79 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
- return CL_ReadRawNetworkData( buffer, length );
- }
- +void CL_DemoFindInterpolatedViewAngles( float t, float *frac, demoangle_t **prev, demoangle_t **next )
- +{
- + int i, i0, i1, imod;
- + float at;
- +
- + imod = demo.angle_position - 1;
- + i0 = (imod + 1) & ANGLE_MASK;
- + i1 = (imod + 0) & ANGLE_MASK;
- +
- + if( demo.cmds[i0].starttime >= t )
- + {
- + for( i = 0; i < ANGLE_BACKUP - 2; i++ )
- + {
- + at = demo.cmds[imod & ANGLE_MASK].starttime;
- + if( at == 0.0f ) break;
- +
- + if( at < t )
- + {
- + i0 = (imod + 1) & ANGLE_MASK;
- + i1 = (imod + 0) & ANGLE_MASK;
- + break;
- + }
- + imod--;
- + }
- + }
- +
- + *next = &demo.cmds[i0];
- + *prev = &demo.cmds[i1];
- +
- + // avoid division by zero (probably this should never happens)
- + if((*prev)->starttime == (*next)->starttime )
- + {
- + *prev = *next;
- + *frac = 0.0f;
- + return;
- + }
- +
- + // time spans the two entries
- + *frac = ( t - (*prev)->starttime ) / ((*next)->starttime - (*prev)->starttime );
- + *frac = bound( 0.0f, *frac, 1.0f );
- +}
- +
- +/*
- +==============
- +CL_DemoInterpolateAngles
- +
- +We can predict or inpolate player movement with standed client code
- +but viewangles interpolate here
- +==============
- +*/
- +void CL_DemoInterpolateAngles( void )
- +{
- + float curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime;
- + demoangle_t *prev = NULL, *next = NULL;
- + float frac = 0.0f;
- +
- + if( curtime > demo.timestamp )
- + curtime = demo.timestamp; // don't run too far
- +
- + CL_DemoFindInterpolatedViewAngles( curtime, &frac, &prev, &next );
- +
- + if( prev && next )
- + {
- + vec4_t q, q1, q2;
- +
- + AngleQuaternion( next->viewangles, q1, false );
- + AngleQuaternion( prev->viewangles, q2, false );
- + QuaternionSlerp( q2, q1, frac, q );
- + QuaternionAngle( q, cl.refdef.cl_viewangles );
- + }
- + else VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
- +}
- +
- /*
- ==============
- CL_StopPlayback
- @@ -804,16 +898,21 @@ void CL_StopPlayback( void )
- cls.demoname[0] = '\0'; // clear demoname too
- gameui.globals->demoname[0] = '\0';
- - S_StopAllSounds();
- - S_StopBackgroundTrack();
- -
- - if( !cls.changedemo )
- + if( cls.changedemo )
- + {
- + S_StopAllSounds();
- + S_StopBackgroundTrack();
- + }
- + else
- {
- // let game known about demo state
- Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );
- cls.state = ca_disconnected;
- - cl.background = 0;
- + cls.connect_time = 0;
- cls.demonum = -1;
- +
- + // and finally clear the state
- + CL_ClearState ();
- }
- }
- @@ -876,7 +975,7 @@ qboolean CL_GetComment( const char *demoname, char *comment )
- // split comment to sections
- Q_strncpy( comment, demohdr.mapname, CS_SIZE );
- - Q_strncpy( comment + CS_SIZE, "<No Title>", CS_SIZE ); // TODO: write titles or somewhat
- + Q_strncpy( comment + CS_SIZE, demohdr.comment, CS_SIZE );
- Q_strncpy( comment + CS_SIZE * 2, va( "%g sec", playtime ), CS_TIME );
- // all done
- @@ -889,8 +988,7 @@ qboolean CL_GetComment( const char *demoname, char *comment )
- ==================
- CL_NextDemo
- -Called when a demo or cinematic finishes
- -If the "nextdemo" cvar is set, that command will be issued
- +Called when a demo finishes
- ==================
- */
- qboolean CL_NextDemo( void )
- @@ -1086,14 +1184,11 @@ void CL_PlayDemo_f( void )
- if( demo.header.net_protocol != PROTOCOL_VERSION || demo.header.dem_protocol != DEMO_PROTOCOL )
- {
- - MsgDev( D_ERROR, "demo protocol outdated\n"
- - "Demo file protocols Network(%i), Demo(%i)\n"
- - "Server protocol is at Network(%i), Demo(%i)\n",
- - demo.header.net_protocol,
- - demo.header.dem_protocol,
- - PROTOCOL_VERSION,
- - DEMO_PROTOCOL
- - );
- + if( demo.header.dem_protocol != DEMO_PROTOCOL )
- + MsgDev( D_ERROR, "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
- +
- + if( demo.header.net_protocol != PROTOCOL_VERSION )
- + MsgDev( D_ERROR, "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
- FS_Close( cls.demofile );
- cls.demofile = NULL;
- @@ -1129,7 +1224,7 @@ void CL_PlayDemo_f( void )
- CL_Disconnect();
- Host_ShutdownServer();
- - Con_Close();
- + Con_FastClose();
- UI_SetActiveMenu( false );
- }
- @@ -1154,9 +1249,12 @@ void CL_PlayDemo_f( void )
- Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableValue( "net_qport" ));
- + memset( demo.cmds, 0, sizeof( demo.cmds ));
- + demo.angle_position = 1;
- demo.framecount = 0;
- cls.lastoutgoingcommand = -1;
- cls.nextcmdtime = host.realtime;
- + cl.last_command_ack = -1;
- // g-cont. is this need?
- Q_strncpy( cls.servername, demoname, sizeof( cls.servername ));
- diff --git b/engine/client/cl_events.c a/engine/client/cl_events.c
- index 7b023c5..a6c9ee3 100644
- --- b/engine/client/cl_events.c
- +++ a/engine/client/cl_events.c
- @@ -142,7 +142,7 @@ qboolean CL_FireEvent( event_info_t *ei )
- if( !ev )
- {
- - idx = bound( 1, ei->index, MAX_EVENTS );
- + idx = bound( 1, ei->index, ( MAX_EVENTS - 1 ));
- MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
- break;
- }
- @@ -173,10 +173,9 @@ called right before draw frame
- */
- void CL_FireEvents( void )
- {
- - int i;
- event_state_t *es;
- event_info_t *ei;
- - qboolean success;
- + int i;
- es = &cl.events;
- @@ -191,7 +190,7 @@ void CL_FireEvents( void )
- if( ei->fire_time && ( ei->fire_time > cl.time ))
- continue;
- - success = CL_FireEvent( ei );
- + CL_FireEvent( ei );
- // zero out the remaining fields
- CL_ResetEvent( ei );
- @@ -395,8 +394,15 @@ void CL_ParseEvent( sizebuf_t *msg )
- args.angles[PITCH] = -state->angles[PITCH] * 3;
- args.angles[YAW] = state->angles[YAW];
- args.angles[ROLL] = 0; // no roll
- +
- + if( VectorIsNull( args.origin ))
- + VectorCopy( state->origin, args.origin );
- + if( VectorIsNull( args.velocity ))
- + VectorCopy( state->velocity, args.velocity );
- }
- - }
- +
- + COM_NormalizeAngles( args.angles );
- + }
- else if( state )
- {
- if( VectorIsNull( args.origin ))
- @@ -443,6 +449,13 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
- MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
- return;
- }
- +
- + if( flags & FEV_SERVER )
- + {
- + MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" );
- + return;
- + }
- +
- // check event for precached
- if( !CL_EventIndex( cl.event_precache[eventindex] ))
- {
- @@ -459,15 +472,27 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
- args.flags = 0;
- args.entindex = invokerIndex;
- -// TODO: restore checks when predicting will be done
- -// if( !angles || VectorIsNull( angles ))
- + if( !angles || VectorIsNull( angles ))
- VectorCopy( cl.refdef.cl_viewangles, args.angles );
- + else VectorCopy( angles, args.angles );
- -// if( !origin || VectorIsNull( origin ))
- - VectorCopy( cl.frame.client.origin, args.origin );
- + if( !origin || VectorIsNull( origin ))
- + {
- + if( CL_IsPredicted( )) VectorCopy( cl.predicted.origin, args.origin );
- + else VectorCopy( cl.frame.client.origin, args.origin );
- + }
- + else VectorCopy( origin, args.origin );
- - VectorCopy( cl.frame.client.velocity, args.velocity );
- - args.ducking = cl.frame.client.bInDuck;
- + if( CL_IsPredicted( ))
- + {
- + VectorCopy( cl.predicted.velocity, args.velocity );
- + args.ducking = (cl.predicted.usehull == 1);
- + }
- + else
- + {
- + VectorCopy( cl.frame.client.velocity, args.velocity );
- + args.ducking = cl.frame.client.bInDuck;
- + }
- args.fparam1 = fparam1;
- args.fparam2 = fparam2;
- diff --git b/engine/client/cl_frame.c a/engine/client/cl_frame.c
- index f1f1529..de18211 100644
- --- b/engine/client/cl_frame.c
- +++ a/engine/client/cl_frame.c
- @@ -38,7 +38,7 @@ qboolean CL_IsPredicted( void )
- if( !cl_predict->integer || !cl.frame.valid || cl.background )
- return false;
- - if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= ( CL_UPDATE_BACKUP - 1 ))
- + if( !cl.validsequence || ( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
- return false;
- return true;
- @@ -123,7 +123,7 @@ qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, float targettime, positi
- int CL_InterpolateModel( cl_entity_t *e )
- {
- - position_history_t *ph0, *ph1;
- + position_history_t *ph0 = NULL, *ph1 = NULL;
- vec3_t origin, angles, delta;
- float t, t1, t2, frac;
- int i;
- @@ -131,13 +131,20 @@ int CL_InterpolateModel( cl_entity_t *e )
- VectorCopy( e->curstate.origin, e->origin );
- VectorCopy( e->curstate.angles, e->angles );
- - if( e->model == NULL || cl.maxclients <= 1 )
- + if( cl.first_frame ) return 0;
- +
- + if( !e->model || ( e->model->name[0] == '*' && !cl_bmodelinterp->integer ) || RP_LOCALCLIENT( e ) || cl.maxclients <= 1 )
- + return 1;
- +
- + if( cl.predicted.moving && cl.predicted.onground == e->index )
- return 1;
- + if( e->curstate.starttime != 0.0f && e->curstate.impacttime != 0.0f )
- + return 1; // don't interpolate parametric entities
- +
- t = cl.time - cl_interp->value;
- - if( !CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL ))
- - return 0;
- + CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL );
- if( ph0 == NULL || ph1 == NULL )
- return 0;
- @@ -148,7 +155,7 @@ int CL_InterpolateModel( cl_entity_t *e )
- if( t - t2 < 0.0f )
- return 0;
- - if( t2 == 0.0f || VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin ))
- + if( t2 == 0.0f || ( VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin )))
- {
- VectorCopy( ph0->origin, e->origin );
- VectorCopy( ph0->angles, e->angles );
- @@ -193,6 +200,36 @@ int CL_InterpolateModel( cl_entity_t *e )
- return 1;
- }
- +void CL_InterpolateMovingEntity( cl_entity_t *ent )
- +{
- + float d, f = 0.0f;
- + int i;
- +
- + // don't do it if the goalstarttime hasn't updated in a while.
- + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
- + // was increased to 1.0 s., which is 2x the max lag we are accounting for.
- + if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
- + f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );
- +
- + f = f - 1.0f;
- +
- + ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f;
- + ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f;
- + ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f;
- +
- + for( i = 0; i < 3; i++ )
- + {
- + float ang1, ang2;
- +
- + ang1 = ent->angles[i];
- + ang2 = ent->latched.prevangles[i];
- + d = ang1 - ang2;
- + if( d > 180.0f ) d -= 360.0f;
- + else if( d < -180.0f ) d += 360.0f;
- + ent->angles[i] += d * f;
- + }
- +}
- +
- void CL_UpdateEntityFields( cl_entity_t *ent )
- {
- // parametric rockets code
- @@ -217,8 +254,12 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
- if( ent->player && RP_LOCALCLIENT( ent )) // stupid Half-Life bug
- ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f;
- - // make me lerp
- - if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
- + // make me lerp (multiplayer only. this code visually breaks XashXT parent system)
- + if( ent->index == cl.predicted.onground && cl.predicted.moving && ( cl.maxclients > 1 ))
- + {
- + CL_InterpolateMovingEntity( ent );
- + }
- + else if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
- {
- float d, f = 0.0f;
- int i;
- @@ -324,7 +365,7 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
- }
- }
- - // move code from StudioSetupTransform here
- + // moved code from StudioSetupTransform here
- if( host.features & ENGINE_COMPUTE_STUDIO_LERP )
- {
- ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
- @@ -513,7 +554,8 @@ void CL_WeaponAnim( int iAnim, int body )
- {
- cl_entity_t *view = &clgame.viewent;
- - view->curstate.modelindex = cl.frame.client.viewmodel;
- + cl.weaponstarttime = 0;
- + cl.weaponsequence = iAnim;
- // anim is changed. update latchedvars
- if( iAnim != view->curstate.sequence )
- @@ -538,6 +580,9 @@ void CL_WeaponAnim( int iAnim, int body )
- view->curstate.frame = 0.0f;
- view->curstate.body = body;
- + view->curstate.rendermode = kRenderNormal;
- + view->curstate.renderamt = 255;
- +
- #if 0 // g-cont. for GlowShell testing
- view->curstate.renderfx = kRenderFxGlowShell;
- view->curstate.rendercolor.r = 255;
- @@ -652,8 +697,16 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
- qboolean newent = (old) ? false : true;
- qboolean result = true;
- - ent = CL_EDICT_NUM( newnum );
- state = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities];
- +
- + if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
- + {
- + if( !unchanged )
- + MSG_ReadDeltaEntity( msg, old, state, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] );
- + return;
- + }
- +
- + ent = CL_EDICT_NUM( newnum );
- ent->index = newnum;
- if( newent ) old = &ent->baseline;
- @@ -663,7 +716,21 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
- if( !result )
- {
- - if( newent ) Host_Error( "Cl_DeltaEntity: tried to release new entity\n" );
- + if( newent )
- + {
- + MsgDev( D_WARN, "Cl_DeltaEntity: tried to release new entity\n" );
- +
- + // perform remove, entity was created and removed between packets
- + if( state->number == -1 )
- + {
- + MsgDev( D_NOTE, "Entity %i was removed from server\n", newnum );
- + ent->curstate.messagenum = 0;
- + ent->baseline.number = 0;
- + }
- + else MsgDev( D_NOTE, "Entity %i was removed from delta-message\n", newnum );
- +
- + return;
- + }
- CL_KillDeadBeams( ent ); // release dead beams
- #if 0
- @@ -703,14 +770,21 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
- ent->prevstate = ent->curstate;
- }
- - // NOTE: always check modelindex for new state not current
- - if( Mod_GetType( state->modelindex ) == mod_studio )
- + if( clgame.dllFuncs.pfnUpdateEntityState != NULL )
- {
- - CL_UpdateStudioVars( ent, state, newent );
- + clgame.dllFuncs.pfnUpdateEntityState( ent, state, newent );
- }
- - else if( Mod_GetType( state->modelindex ) == mod_brush )
- + else
- {
- - CL_UpdateBmodelVars( ent, state, newent );
- + // NOTE: always check modelindex for new state not current
- + if( Mod_GetType( state->modelindex ) == mod_studio )
- + {
- + CL_UpdateStudioVars( ent, state, newent );
- + }
- + else if( Mod_GetType( state->modelindex ) == mod_brush )
- + {
- + CL_UpdateBmodelVars( ent, state, newent );
- + }
- }
- // set right current state
- @@ -722,6 +796,8 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
- /*
- =================
- CL_FlushEntityPacket
- +
- +Read and ignore whole entity packet.
- =================
- */
- void CL_FlushEntityPacket( sizebuf_t *msg )
- @@ -729,7 +805,6 @@ void CL_FlushEntityPacket( sizebuf_t *msg )
- int newnum;
- entity_state_t from, to;
- - MsgDev( D_INFO, "FlushEntityPacket()\n" );
- memset( &from, 0, sizeof( from ));
- cl.frames[cl.parsecountmod].valid = false;
- @@ -756,11 +831,13 @@ An svc_packetentities has just been parsed, deal with the
- rest of the data stream.
- ==================
- */
- -void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- {
- frame_t *newframe, *oldframe;
- int oldindex, newnum, oldnum;
- + int playerbytes = 0;
- int oldpacket;
- + int bufStart;
- cl_entity_t *player;
- entity_state_t *oldent;
- int i, count;
- @@ -778,6 +855,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- newframe->first_entity = cls.next_client_entities;
- newframe->num_entities = 0;
- newframe->valid = true; // assume valid
- + memset( &newframe->graphdata, 0, sizeof( netbandwidthgraph_t ));
- if( delta )
- {
- @@ -788,25 +866,29 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- if( subtracted == 0 )
- {
- - Host_Error( "CL_DeltaPacketEntities: update too old, connection dropped.\n" );
- - return;
- + MsgDev( D_NOTE, "CL_DeltaPacketEntities: update too old (flush)\n" );
- + Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" );
- + CL_FlushEntityPacket( msg );
- + return playerbytes;
- }
- if( subtracted >= CL_UPDATE_MASK )
- {
- // we can't use this, it is too old
- + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old: overflow (flush)\n");
- Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
- CL_FlushEntityPacket( msg );
- - return;
- + return playerbytes;
- }
- oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK];
- if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - 128 ))
- {
- + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old (flush)\n");
- Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
- CL_FlushEntityPacket( msg );
- - return;
- + return playerbytes;
- }
- }
- else
- @@ -814,7 +896,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- // this is a full update that we can start delta compressing from now
- oldframe = NULL;
- oldpacket = -1; // delta too old or is initial message
- - cl.force_send_usercmd = true; // send reply
- + cl.send_reply = true; // send reply
- cls.demowaiting = false; // we can start recording now
- }
- @@ -851,8 +933,11 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- while( oldnum < newnum )
- {
- + bufStart = MSG_GetNumBytesRead( msg );
- // one or more entities from the old packet are unchanged
- CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
- + if( CL_IsPlayerIndex( oldnum ) )
- + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
- oldindex++;
- @@ -870,7 +955,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- if( oldnum == newnum )
- {
- // delta from previous state
- + bufStart = MSG_GetNumBytesRead( msg );
- CL_DeltaEntity( msg, newframe, newnum, oldent, false );
- + if( CL_IsPlayerIndex( newnum ) )
- + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
- oldindex++;
- if( oldindex >= oldframe->num_entities )
- @@ -888,7 +976,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- if( oldnum > newnum )
- {
- // delta from baseline ?
- + bufStart = MSG_GetNumBytesRead( msg );
- CL_DeltaEntity( msg, newframe, newnum, NULL, false );
- + if( CL_IsPlayerIndex( newnum ) )
- + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
- continue;
- }
- }
- @@ -897,7 +988,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- while( oldnum != MAX_ENTNUMBER )
- {
- // one or more entities from the old packet are unchanged
- + bufStart = MSG_GetNumBytesRead( msg );
- CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
- + if( CL_IsPlayerIndex( oldnum ) )
- + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
- oldindex++;
- if( oldindex >= oldframe->num_entities )
- @@ -916,7 +1010,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- cl.frame = *newframe;
- - if( !cl.frame.valid ) return;
- + if( !cl.frame.valid ) return playerbytes; // frame is not valid but message was parsed
- player = CL_GetLocalPlayer();
- @@ -950,11 +1044,15 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
- if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped )
- SCR_EndLoadingPlaque(); // get rid of loading plaque
- + cl.first_frame = true; // first server frame received
- }
- else
- {
- CL_CheckPredictionError();
- + cl.first_frame = false;
- }
- +
- + return playerbytes;
- }
- /*
- @@ -972,23 +1070,34 @@ CL_SetIdealPitch
- void CL_SetIdealPitch( void )
- {
- float angleval, sinval, cosval;
- - vec3_t top, bottom;
- - float z[MAX_FORWARD];
- + float z[MAX_FORWARD], view_z;
- + vec3_t top, bottom, origin;
- int i, j;
- int step, dir, steps;
- pmtrace_t tr;
- if( !( cl.frame.client.flags & FL_ONGROUND ))
- return;
- -
- +
- + if( CL_IsPredicted( ))
- + {
- + VectorCopy( cl.predicted.origin, origin );
- + view_z = cl.predicted.viewofs[2];
- + }
- + else
- + {
- + VectorCopy( cl.frame.client.origin, origin );
- + view_z = cl.frame.client.view_ofs[2];
- + }
- +
- angleval = cl.frame.playerstate[cl.playernum].angles[YAW] * M_PI2 / 360.0f;
- SinCos( angleval, &sinval, &cosval );
- for( i = 0; i < MAX_FORWARD; i++ )
- {
- - top[0] = cl.frame.client.origin[0] + cosval * (i + 3.0f) * 12.0f;
- - top[1] = cl.frame.client.origin[1] + sinval * (i + 3.0f) * 12.0f;
- - top[2] = cl.frame.client.origin[2] + cl.frame.client.view_ofs[2];
- + top[0] = origin[0] + cosval * (i + 3.0f) * 12.0f;
- + top[1] = origin[1] + sinval * (i + 3.0f) * 12.0f;
- + top[2] = origin[2] + view_z;
- bottom[0] = top[0];
- bottom[1] = top[1];
- @@ -1052,7 +1161,9 @@ void CL_AddPacketEntities( frame_t *frame )
- if( !ent || ent == clgame.entities )
- continue;
- - CL_UpdateEntityFields( ent );
- + if( clgame.dllFuncs.pfnInterpolateEntity != NULL )
- + clgame.dllFuncs.pfnInterpolateEntity( ent, cl.lerpFrac );
- + else CL_UpdateEntityFields( ent );
- if( ent->player ) entityType = ET_PLAYER;
- else if( ent->curstate.entityType == ENTITY_BEAM )
- diff --git b/engine/client/cl_game.c a/engine/client/cl_game.c
- index 613cbc7..2d6b729 100644
- --- b/engine/client/cl_game.c
- +++ a/engine/client/cl_game.c
- @@ -30,6 +30,7 @@ GNU General Public License for more details.
- #include "vgui_draw.h"
- #include "sound.h" // SND_STOP_LOOPING
- +#define MAX_LINELENGTH 80
- #define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels)
- #define TEXT_MSGNAME "TextMessage%i"
- @@ -88,6 +89,8 @@ static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher
- { "HUD_GetRenderInterface", (void **)&clgame.dllFuncs.pfnGetRenderInterface }, // Xash3D ext
- { "HUD_GetPlayerTeam", (void **)&clgame.dllFuncs.pfnGetPlayerTeam },
- { "HUD_ClipMoveToEntity", (void **)&clgame.dllFuncs.pfnClipMoveToEntity }, // Xash3D ext
- +{ "HUD_UpdateEntityState", (void **)&clgame.dllFuncs.pfnUpdateEntityState },
- +{ "HUD_InterpolateEntity", (void **)&clgame.dllFuncs.pfnInterpolateEntity },
- { NULL, NULL }
- };
- @@ -406,30 +409,6 @@ static void SPR_AdjustSize( float *x, float *y, float *w, float *h )
- /*
- ====================
- -TextAdjustSize
- -
- -draw hudsprite routine
- -====================
- -*/
- -void TextAdjustSize( int *x, int *y, int *w, int *h )
- -{
- - float xscale, yscale;
- -
- - if( !clgame.ds.adjust_size ) return;
- - if( !x && !y && !w && !h ) return;
- -
- - // scale for screen sizes
- - xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
- - yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
- -
- - if( x ) *x *= xscale;
- - if( y ) *y *= yscale;
- - if( w ) *w *= xscale;
- - if( h ) *h *= yscale;
- -}
- -
- -/*
- -====================
- PictAdjustSize
- draw hudsprite routine
- @@ -573,7 +552,7 @@ void CL_DrawCenterPrint( void )
- char *pText;
- int i, j, x, y;
- int width, lineLength;
- - byte *colorDefault, line[80];
- + byte *colorDefault, line[MAX_LINELENGTH];
- int charWidth, charHeight;
- if( !clgame.centerPrint.time )
- @@ -596,7 +575,7 @@ void CL_DrawCenterPrint( void )
- lineLength = 0;
- width = 0;
- - while( *pText && *pText != '\n' )
- + while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH )
- {
- byte c = *pText;
- line[lineLength] = c;
- @@ -606,6 +585,9 @@ void CL_DrawCenterPrint( void )
- pText++;
- }
- + if( lineLength == MAX_LINELENGTH )
- + lineLength--;
- +
- pText++; // Skip LineFeed
- line[lineLength] = 0;
- @@ -1084,8 +1066,10 @@ void CL_InitEdicts( void )
- {
- ASSERT( clgame.entities == NULL );
- + if( !clgame.mempool ) return; // Host_Error without client
- +
- CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
- - cls.num_client_entities = CL_UPDATE_BACKUP * 64;
- + cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
- cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
- clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
- clgame.static_entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
- @@ -1097,10 +1081,22 @@ void CL_InitEdicts( void )
- clgame.maxRemapInfos = clgame.maxEntities + 1;
- clgame.remap_info = (remap_info_t **)Mem_Alloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos );
- }
- +
- + if( clgame.drawFuncs.R_ProcessEntData != NULL )
- + {
- + // let the client.dll free custom data
- + clgame.drawFuncs.R_ProcessEntData( true );
- + }
- }
- void CL_FreeEdicts( void )
- {
- + if( clgame.drawFuncs.R_ProcessEntData != NULL )
- + {
- + // let the client.dll free custom data
- + clgame.drawFuncs.R_ProcessEntData( false );
- + }
- +
- if( clgame.entities )
- Mem_Free( clgame.entities );
- clgame.entities = NULL;
- @@ -1208,7 +1204,8 @@ HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags )
- // load new model
- if( CL_LoadHudSprite( name, &clgame.sprites[i], false, texFlags ))
- {
- - clgame.sprites[i].needload = clgame.load_sequence;
- + if( i < ( MAX_IMAGES - 1 ))
- + clgame.sprites[i].needload = clgame.load_sequence;
- return i;
- }
- return 0;
- @@ -1414,11 +1411,11 @@ static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount )
- /*
- =============
- -pfnFillRGBA
- +CL_FillRGBA
- =============
- */
- -static void pfnFillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
- +void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
- {
- r = bound( 0, r, 255 );
- g = bound( 0, g, 255 );
- @@ -2098,7 +2095,7 @@ static void pfnHookEvent( const char *filename, pfnEventHook pfn )
- if( !Q_stricmp( name, ev->name ) && ev->func != NULL )
- {
- - MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n" );
- + MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n", name );
- return;
- }
- }
- @@ -2199,6 +2196,8 @@ pfnLocalPlayerDucking
- */
- int pfnLocalPlayerDucking( void )
- {
- + if( CL_IsPredicted( ))
- + return (cl.predicted.usehull == 1);
- return cl.frame.client.bInDuck;
- }
- @@ -2214,7 +2213,7 @@ void pfnLocalPlayerViewheight( float *view_ofs )
- if( !view_ofs ) return;
- if( CL_IsPredicted( ))
- - VectorCopy( cl.predicted_viewofs, view_ofs );
- + VectorCopy( cl.predicted.viewofs, view_ofs );
- else VectorCopy( cl.frame.client.view_ofs, view_ofs );
- }
- @@ -2267,101 +2266,12 @@ physent_t *pfnGetPhysent( int idx )
- /*
- =============
- -pfnSetUpPlayerPrediction
- -
- -FIXME: finalize
- -=============
- -*/
- -void pfnSetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
- -{
- -#if 0
- - entity_state_t *playerstate = cl.frames[cl.parsecountmod].playerstate;
- - predicted_player_t *player = cls.predicted_players;
- - cl_entity_t *clent;
- - int j, v12;
- -
- - for( j = 0; j < MAX_CLIENTS; j++, player++, playerstate++ )
- - {
- - player->active = false;
- -
- - if( playerstate->messagenum != cl.parsecount )
- - continue; // not present this frame
- -
- - if( !playerstate->modelindex )
- - continue;
- -
- - // special for EF_NODRAW and local client?
- - if(( playerstate->effects & EF_NODRAW ) && !bIncludeLocalClient )
- - {
- - // don't include local player?
- - if( cl.playernum != j )
- - {
- - player->active = true;
- - player->movetype = playerstate->movetype;
- - player->solid = playerstate->solid;
- - player->usehull = playerstate->usehull;
- -
- - clent = CL_EDICT_NUM( j + 1 );
- -// CL_ComputePlayerOrigin( v9 );
- - VectorCopy( clent->origin, player->origin );
- - VectorCopy( clent->angles, player->angles );
- - }
- - else continue;
- - }
- - else
- - {
- - if( cl.playernum == j )
- - continue;
- -
- - player->active = true;
- - player->movetype = playerstate->movetype;
- - player->solid = playerstate->solid;
- - player->usehull = playerstate->usehull;
- -
- - v12 = 17080 * cl.parsecountmod + 340 * j;
- - player->origin[0] = cl.frames[0].playerstate[0].origin[0] + v12;
- - player->origin[1] = cl.frames[0].playerstate[0].origin[1] + v12;
- - player->origin[2] = cl.frames[0].playerstate[0].origin[2] + v12;
- -
- - player->angles[0] = cl.frames[0].playerstate[0].angles[0] + v12;
- - player->angles[1] = cl.frames[0].playerstate[0].angles[1] + v12;
- - player->angles[2] = cl.frames[0].playerstate[0].angles[2] + v12;
- - }
- - }
- -#endif
- -}
- -
- -/*
- -=============
- -pfnPushPMStates
- -
- -=============
- -*/
- -void pfnPushPMStates( void )
- -{
- - clgame.oldcount = clgame.pmove->numphysent;
- -}
- -
- -/*
- -=============
- -pfnPopPMStates
- -
- -=============
- -*/
- -void pfnPopPMStates( void )
- -{
- - clgame.pmove->numphysent = clgame.oldcount;
- -}
- -
- -/*
- -=============
- pfnSetTraceHull
- =============
- */
- void CL_SetTraceHull( int hull )
- {
- - clgame.old_trace_hull = clgame.pmove->usehull;
- clgame.pmove->usehull = bound( 0, hull, 3 );
- }
- @@ -2376,7 +2286,6 @@ void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pm
- {
- if( !tr ) return;
- *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
- - clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull
- }
- /*
- @@ -2389,7 +2298,6 @@ void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnor
- {
- if( !tr ) return;
- *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, -1, pfnIgnore );
- - clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull
- }
- /*
- @@ -2594,7 +2502,7 @@ const char *PlayerInfo_ValueForKey( int playerNum, const char *key )
- if(( playerNum > cl.maxclients ) || ( playerNum < 1 ))
- return NULL;
- - if(( cl.players[playerNum-1].name == NULL ) || (*(cl.players[playerNum-1].name) == 0 ))
- + if( !cl.players[playerNum-1].name[0] )
- return NULL;
- return Info_ValueForKey( cl.players[playerNum-1].userinfo, key );
- @@ -2788,6 +2696,24 @@ void pfnSetLightmapScale( float scale )
- /*
- =============
- +pfnParseFile
- +
- +handle colon separately
- +=============
- +*/
- +char *pfnParseFile( char *data, char *token )
- +{
- + char *out;
- +
- + host.com_handlecolon = true;
- + out = COM_ParseFile( data, token );
- + host.com_handlecolon = false;
- +
- + return out;
- +}
- +
- +/*
- +=============
- pfnSPR_DrawGeneric
- =============
- @@ -2808,7 +2734,11 @@ TODO: implement
- */
- int pfnDrawString( int x, int y, const char *str, int r, int g, int b )
- {
- - return 0;
- + // draw the string until we hit the null character or a newline character
- + for( ; *str != 0 && *str != '\n'; str++ )
- + x += pfnDrawCharacter( x, y, (byte)*str, r, g, b );
- +
- + return x;
- }
- /*
- @@ -2820,7 +2750,14 @@ TODO: implement
- */
- int pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b )
- {
- - return 0;
- + char *szIt;
- +
- + // find the end of the string
- + for( szIt = (char *)str; *szIt != 0; szIt++ )
- + x -= clgame.scrInfo.charWidths[(byte)*szIt];
- + pfnDrawString( x, y, str, r, g, b );
- +
- + return x;
- }
- /*
- @@ -2920,11 +2857,11 @@ void pfnPlaySoundByNameAtPitch( char *filename, float volume, int pitch )
- /*
- =============
- -pfnFillRGBABlend
- +CL_FillRGBABlend
- =============
- */
- -void pfnFillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a )
- +void CL_FillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a )
- {
- r = bound( 0, r, 255 );
- g = bound( 0, g, 255 );
- @@ -2951,7 +2888,7 @@ pfnGetAppID
- */
- int pfnGetAppID( void )
- {
- - return 220; // standard Valve value
- + return 130; // borrowed from SDLash3D
- }
- /*
- @@ -3137,7 +3074,7 @@ void TriBrightness( float brightness )
- rgba[1] = clgame.ds.triColor[1] * brightness;
- rgba[2] = clgame.ds.triColor[2] * brightness;
- - pglColor3ub( rgba[0], rgba[1], rgba[2] );
- + pglColor4ub( rgba[0], rgba[1], rgba[2], clgame.ds.triColor[3] );
- }
- /*
- @@ -3185,7 +3122,7 @@ int TriSpriteTexture( model_t *pSpriteModel, int frame )
- if( psprite->texFormat == SPR_ALPHTEST )
- {
- pglEnable( GL_ALPHA_TEST );
- - pglAlphaFunc( GL_GREATER, 0.0f );
- + pglAlphaFunc( GL_GEQUAL, 0.5f );
- }
- GL_Bind( GL_TEXTURE0, gl_texturenum );
- @@ -3322,7 +3259,8 @@ TriForParams
- */
- void TriFogParams( float flDensity, int iFogSkybox )
- {
- - // TODO: implement
- + RI.fogDensity = flDensity;
- + RI.fogCustom = iFogSkybox;
- }
- /*
- @@ -3405,7 +3343,7 @@ void NetAPI_Status( net_status_t *status )
- status->connected = NET_IsLocalAddress( cls.netchan.remote_address ) ? false : true;
- status->connection_time = host.realtime - cls.netchan.connect_time;
- status->remote_address = cls.netchan.remote_address;
- - status->packet_loss = cls.packet_loss / 100; // percent
- + status->packet_loss = cls.packet_loss / 100.0; // percent
- status->latency = cl.frame.latency;
- status->local_address = net_local;
- status->rate = cls.netchan.rate;
- @@ -3433,15 +3371,14 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
- for( i = 0; i < MAX_REQUESTS; i++ )
- {
- nr = &clgame.net_requests[i];
- - if( !nr->pfnFunc || nr->timeout < host.realtime )
- - break;
- + if( !nr->pfnFunc ) break;
- }
- if( i == MAX_REQUESTS )
- {
- double max_timeout = 0;
- - // no free requests? use older
- + // no free requests? use oldest
- for( i = 0, nr = NULL; i < MAX_REQUESTS; i++ )
- {
- if(( host.realtime - clgame.net_requests[i].timesend ) > max_timeout )
- @@ -3468,11 +3405,20 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
- if( request == NETAPI_REQUEST_SERVERLIST )
- {
- - // UNDONE: build request for master-server
- + char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
- +
- + // make sure what port is specified
- + if( !nr->resp.remote_address.port ) nr->resp.remote_address.port = MSG_BigShort( PORT_MASTER );
- +
- + // grab the list from the master server
- + Q_strcpy( &fullquery[22], GI->gamedir );
- + NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 23, fullquery, nr->resp.remote_address );
- + clgame.request_type = NET_REQUEST_CLIENT;
- + clgame.master_request = nr; // holds the master request unitl the master acking
- }
- else
- {
- - // send request over the net
- + // local servers request
- Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", PROTOCOL_VERSION, context, request );
- Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, req );
- }
- @@ -3486,15 +3432,31 @@ NetAPI_CancelRequest
- */
- void NetAPI_CancelRequest( int context )
- {
- - int i;
- + net_request_t *nr;
- + int i;
- // find a specified request
- for( i = 0; i < MAX_REQUESTS; i++ )
- {
- + nr = &clgame.net_requests[i];
- +
- if( clgame.net_requests[i].resp.context == context )
- {
- - MsgDev( D_NOTE, "Request with context %i cancelled\n", context );
- + if( nr->pfnFunc )
- + {
- + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
- + nr->resp.ping = host.realtime - nr->timesend;
- + nr->pfnFunc( &nr->resp );
- + }
- +
- memset( &clgame.net_requests[i], 0, sizeof( net_request_t ));
- +
- + if( clgame.net_requests[i].resp.type == NETAPI_REQUEST_SERVERLIST && &clgame.net_requests[i] == clgame.master_request )
- + {
- + if( clgame.request_type == NET_REQUEST_CLIENT )
- + clgame.request_type = NET_REQUEST_CANCEL;
- + clgame.master_request = NULL;
- + }
- break;
- }
- }
- @@ -3508,7 +3470,22 @@ NetAPI_CancelAllRequests
- */
- void NetAPI_CancelAllRequests( void )
- {
- + net_request_t *nr;
- + int i;
- +
- + // tell the user about cancel
- + for( i = 0; i < MAX_REQUESTS; i++ )
- + {
- + nr = &clgame.net_requests[i];
- + if( !nr->pfnFunc ) continue; // not used
- + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
- + nr->resp.ping = host.realtime - nr->timesend;
- + nr->pfnFunc( &nr->resp );
- + }
- +
- memset( clgame.net_requests, 0, sizeof( clgame.net_requests ));
- + clgame.request_type = NET_REQUEST_CANCEL;
- + clgame.master_request = NULL;
- }
- /*
- @@ -3758,9 +3735,9 @@ static event_api_t gEventApi =
- pfnLocalPlayerBounds,
- pfnIndexFromTrace,
- pfnGetPhysent,
- - pfnSetUpPlayerPrediction,
- - pfnPushPMStates,
- - pfnPopPMStates,
- + CL_SetUpPlayerPrediction,
- + CL_PushPMStates,
- + CL_PopPMStates,
- CL_SetSolidPlayers,
- CL_SetTraceHull,
- CL_PlayerTrace,
- @@ -3823,13 +3800,13 @@ static cl_enginefunc_t gEngfuncs =
- SPR_EnableScissor,
- SPR_DisableScissor,
- pfnSPR_GetList,
- - pfnFillRGBA,
- + CL_FillRGBA,
- pfnGetScreenInfo,
- pfnSetCrosshair,
- - pfnCvar_RegisterVariable,
- + pfnCvar_RegisterClientVariable,
- Cvar_VariableValue,
- Cvar_VariableString,
- - pfnAddClientCommand,
- + Cmd_AddClientCommand,
- pfnHookUserMsg,
- pfnServerCmd,
- pfnClientCmd,
- @@ -3892,7 +3869,7 @@ static cl_enginefunc_t gEngfuncs =
- VGui_GetPanel,
- VGui_ViewportPaintBackground,
- COM_LoadFile,
- - COM_ParseFile,
- + pfnParseFile,
- COM_FreeFile,
- &gTriApi,
- &gEfxApi,
- @@ -3942,7 +3919,7 @@ static cl_enginefunc_t gEngfuncs =
- pfnConstructTutorMessageDecayBuffer,
- pfnResetTutorMessageDecayData,
- pfnPlaySoundByNameAtPitch,
- - pfnFillRGBABlend,
- + CL_FillRGBABlend,
- pfnGetAppID,
- Cmd_AliasGetList,
- pfnVguiWrap2_GetMouseDelta,
- @@ -3972,7 +3949,7 @@ void CL_UnloadProgs( void )
- Mem_FreePool( &clgame.mempool );
- memset( &clgame, 0, sizeof( clgame ));
- - Cvar_Unlink();
- + Cvar_Unlink( CVAR_CLIENTDLL );
- Cmd_Unlink( CMD_CLIENTDLL );
- }
- @@ -4073,8 +4050,8 @@ qboolean CL_LoadProgs( const char *name )
- return false;
- }
- - Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE|CVAR_USERINFO, "disable client movement predicting" );
- - Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
- + Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE, "disable client movement predicting" );
- + cl_lw = Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
- Cvar_Get( "cl_lc", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable lag compensation" );
- Cvar_FullSet( "host_clientloaded", "1", CVAR_INIT );
- @@ -4086,13 +4063,12 @@ qboolean CL_LoadProgs( const char *name )
- CL_InitParticles ();
- CL_InitViewBeams ();
- CL_InitTempEnts ();
- - CL_InitEdicts (); // initailize local player and world
- - CL_InitClientMove(); // initialize pm_shared
- if( !R_InitRenderAPI()) // Xash3D extension
- - {
- MsgDev( D_WARN, "CL_LoadProgs: couldn't get render API\n" );
- - }
- +
- + CL_InitEdicts (); // initailize local player and world
- + CL_InitClientMove(); // initialize pm_shared
- // initialize game
- clgame.dllFuncs.pfnInit();
- diff --git b/engine/client/cl_menu.c a/engine/client/cl_gameui.c
- similarity index 98%
- rename from engine/client/cl_menu.c
- rename to engine/client/cl_gameui.c
- index 5f77853..6c15883 100644
- --- b/engine/client/cl_menu.c
- +++ a/engine/client/cl_gameui.c
- @@ -21,9 +21,9 @@ GNU General Public License for more details.
- #include "input.h"
- static MENUAPI GetMenuAPI;
- -static void UI_UpdateUserinfo( void );
- +static void UI_UpdateUserinfo( void );
- -menu_static_t gameui;
- +gameui_static_t gameui;
- void UI_UpdateMenu( float realtime )
- {
- @@ -891,12 +891,12 @@ static ui_enginefuncs_t gEngfuncs =
- pfnPIC_EnableScissor,
- pfnPIC_DisableScissor,
- pfnFillRGBA,
- - pfnCvar_RegisterVariable,
- + pfnCvar_RegisterGameUIVariable,
- Cvar_VariableValue,
- Cvar_VariableString,
- Cvar_Set,
- Cvar_SetFloat,
- - pfnAddClientCommand,
- + Cmd_AddGameUICommand,
- pfnClientCmd,
- Cmd_RemoveCommand,
- Cmd_Argc,
- @@ -968,9 +968,14 @@ void UI_UnloadProgs( void )
- // deinitialize game
- gameui.dllFuncs.pfnShutdown();
- + Cvar_FullSet( "host_gameuiloaded", "0", CVAR_INIT );
- +
- Com_FreeLibrary( gameui.hInstance );
- Mem_FreePool( &gameui.mempool );
- memset( &gameui, 0, sizeof( gameui ));
- +
- + Cvar_Unlink( CVAR_GAMEUIDLL );
- + Cmd_Unlink( CMD_GAMEUIDLL );
- }
- qboolean UI_LoadProgs( void )
- @@ -1019,6 +1024,8 @@ qboolean UI_LoadProgs( void )
- return false;
- }
- + Cvar_FullSet( "host_gameuiloaded", "1", CVAR_INIT );
- +
- // setup gameinfo
- for( i = 0; i < SI.numgames; i++ )
- {
- @@ -1035,4 +1042,4 @@ qboolean UI_LoadProgs( void )
- gameui.dllFuncs.pfnInit();
- return true;
- -}
- +}
- \ No newline at end of file
- diff --git b/engine/client/cl_main.c a/engine/client/cl_main.c
- index 9916d5f..7cf1978 100644
- --- b/engine/client/cl_main.c
- +++ a/engine/client/cl_main.c
- @@ -22,15 +22,15 @@ GNU General Public License for more details.
- #include "../cl_dll/kbutton.h"
- #include "vgui_draw.h"
- -#define MAX_TOTAL_CMDS 16
- -#define MIN_CMD_RATE 10.0
- -#define MAX_CMD_BUFFER 4000
- +#define MAX_TOTAL_CMDS 32
- +#define MAX_CMD_BUFFER 8000
- #define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
- convar_t *rcon_client_password;
- convar_t *rcon_address;
- -convar_t *cl_smooth;
- +convar_t *cl_nosmooth;
- +convar_t *cl_smoothtime;
- convar_t *cl_timeout;
- convar_t *cl_predict;
- convar_t *cl_showfps;
- @@ -38,13 +38,16 @@ convar_t *cl_nodelta;
- convar_t *cl_crosshair;
- convar_t *cl_cmdbackup;
- convar_t *cl_showerror;
- +convar_t *cl_bmodelinterp;
- convar_t *cl_draw_particles;
- convar_t *cl_lightstyle_lerping;
- convar_t *cl_idealpitchscale;
- convar_t *cl_solid_players;
- convar_t *cl_draw_beams;
- +convar_t *cl_updaterate;
- convar_t *cl_cmdrate;
- convar_t *cl_interp;
- +convar_t *cl_lw;
- //
- // userinfo
- @@ -170,8 +173,8 @@ qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset )
- clgame.dllFuncs.IN_ActivateMouse();
- // restore mlook state
- - if( mlook_active ) Cmd_ExecuteString( "+mlook\n", src_command );
- - if( jlook_active ) Cmd_ExecuteString( "+jlook\n", src_command );
- + if( mlook_active ) Cmd_ExecuteString( "+mlook\n" );
- + if( jlook_active ) Cmd_ExecuteString( "+jlook\n" );
- return true;
- }
- @@ -190,7 +193,7 @@ static float CL_LerpPoint( void )
- {
- float f, frac;
- - f = cl.mtime[0] - cl.mtime[1];
- + f = cl_serverframetime();
- if( !f || SV_Active( ))
- {
- @@ -284,6 +287,87 @@ CLIENT MOVEMENT COMMUNICATION
- =======================================================================
- */
- /*
- +===============
- +CL_ProcessShowTexturesCmds
- +
- +navigate around texture atlas
- +===============
- +*/
- +qboolean CL_ProcessShowTexturesCmds( usercmd_t *cmd )
- +{
- + static int oldbuttons;
- + int changed;
- + int pressed, released;
- +
- + if( !gl_showtextures->integer || gl_overview->integer )
- + return false;
- +
- + changed = (oldbuttons ^ cmd->buttons);
- + pressed = changed & cmd->buttons;
- + released = changed & (~cmd->buttons);
- +
- + if( released & ( IN_RIGHT|IN_MOVERIGHT ))
- + Cvar_SetFloat( "r_showtextures", gl_showtextures->integer + 1 );
- + if( released & ( IN_LEFT|IN_MOVELEFT ))
- + Cvar_SetFloat( "r_showtextures", max( 1, gl_showtextures->integer - 1 ));
- + oldbuttons = cmd->buttons;
- +
- + return true;
- +}
- +
- +/*
- +===============
- +CL_ProcessOverviewCmds
- +
- +Transform user movement into overview adjust
- +===============
- +*/
- +qboolean CL_ProcessOverviewCmds( usercmd_t *cmd )
- +{
- + ref_overview_t *ov = &clgame.overView;
- + int sign = 1;
- + float size = world.size[!ov->rotated] / world.size[ov->rotated];
- + float step = (2.0f / size) * host.realframetime;
- + float step2 = step * 100.0f * (2.0f / ov->flZoom);
- +
- + if( !gl_overview->integer || gl_showtextures->integer )
- + return false;
- +
- + if( ov->flZoom < 0.0f ) sign = -1;
- +
- + if( cmd->upmove > 0.0f ) ov->zNear += step;
- + else if( cmd->upmove < 0.0f ) ov->zNear -= step;
- +
- + if( cmd->buttons & IN_JUMP ) ov->zFar += step;
- + else if( cmd->buttons & IN_DUCK ) ov->zFar -= step;
- +
- + if( cmd->buttons & IN_FORWARD ) ov->origin[ov->rotated] -= sign * step2;
- + else if( cmd->buttons & IN_BACK ) ov->origin[ov->rotated] += sign * step2;
- +
- + if( ov->rotated )
- + {
- + if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
- + ov->origin[0] -= sign * step2;
- + else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
- + ov->origin[0] += sign * step2;
- + }
- + else
- + {
- + if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
- + ov->origin[1] += sign * step2;
- + else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
- + ov->origin[1] -= sign * step2;
- + }
- +
- + if( cmd->buttons & IN_ATTACK ) ov->flZoom += step;
- + else if( cmd->buttons & IN_ATTACK2 ) ov->flZoom -= step;
- +
- + if( ov->flZoom == 0.0f ) ov->flZoom = 0.0001f; // to prevent disivion by zero
- +
- + return true;
- +}
- +
- +/*
- =================
- CL_CreateCmd
- =================
- @@ -295,6 +379,7 @@ void CL_CreateCmd( void )
- color24 color;
- vec3_t angles;
- qboolean active;
- + int input_override;
- int i, ms;
- ms = host.frametime * 1000;
- @@ -302,23 +387,23 @@ void CL_CreateCmd( void )
- else if( ms <= 0 ) ms = 1; // keep time an actual
- memset( &cmd, 0, sizeof( cmd ));
- + input_override = 0;
- - // build list of all solid entities per next frame (exclude clients)
- - CL_SetSolidEntities ();
- - CL_SetSolidPlayers ( cl.playernum );
- + CL_PushPMStates();
- + CL_SetSolidPlayers( cl.playernum );
- VectorCopy( cl.refdef.cl_viewangles, angles );
- VectorCopy( cl.frame.client.origin, cl.data.origin );
- VectorCopy( cl.refdef.cl_viewangles, cl.data.viewangles );
- cl.data.iWeaponBits = cl.frame.client.weapons;
- - cl.data.fov = cl.frame.client.fov;
- + cl.data.fov = cl.scr_fov;
- - clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time );
- -
- - // grab changes
- - VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
- - cl.frame.client.weapons = cl.data.iWeaponBits;
- - cl.frame.client.fov = cl.data.fov;
- + if( clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time ))
- + {
- + // grab changes if successful
- + VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
- + cl.scr_fov = cl.data.fov;
- + }
- // allways dump the first ten messages,
- // because it may contain leftover inputs
- @@ -330,37 +415,45 @@ void CL_CreateCmd( void )
- cl.refdef.cmd = &cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].cmd;
- *cl.refdef.cmd = cmd;
- }
- +
- + CL_PopPMStates();
- return;
- }
- // message we are constructing.
- i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK;
- -
- pcmd = &cl.commands[i];
- - pcmd->senttime = cls.demoplayback ? 0.0 : host.realtime;
- - memset( &pcmd->cmd, 0, sizeof( pcmd->cmd ));
- - pcmd->receivedtime = -1.0;
- - pcmd->processedfuncs = false;
- - pcmd->heldback = false;
- - pcmd->sendsize = 0;
- + if( !cls.demoplayback )
- + {
- + pcmd->senttime = host.realtime;
- + memset( &pcmd->cmd, 0, sizeof( pcmd->cmd ));
- + pcmd->receivedtime = -1.0;
- + pcmd->processedfuncs = false;
- + pcmd->heldback = false;
- + pcmd->sendsize = 0;
- + }
- active = ( cls.state == ca_active && !cl.refdef.paused && !cls.demoplayback );
- clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &pcmd->cmd, active );
- + CL_PopPMStates();
- - R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f );
- - pcmd->cmd.lightlevel = (color.r + color.g + color.b) / 3;
- -
- - // never let client.dll calc frametime for player
- - // because is potential backdoor for cheating
- - pcmd->cmd.msec = ms;
- - pcmd->cmd.lerp_msec = cl_interp->value * 1000;
- - pcmd->cmd.lerp_msec = bound( 0, cmd.lerp_msec, 250 );
- + if( !cls.demoplayback )
- + {
- + R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f );
- + pcmd->cmd.lightlevel = (color.r + color.g + color.b) / 3;
- +
- + // never let client.dll calc frametime for player
- + // because is potential backdoor for cheating
- + pcmd->cmd.msec = ms;
- + pcmd->cmd.lerp_msec = cl_interp->value * 1000;
- + pcmd->cmd.lerp_msec = bound( 0, cmd.lerp_msec, 250 );
- + }
- - V_ProcessOverviewCmds( &pcmd->cmd );
- - V_ProcessShowTexturesCmds( &pcmd->cmd );
- + input_override |= CL_ProcessOverviewCmds( &pcmd->cmd );
- + input_override |= CL_ProcessShowTexturesCmds( &pcmd->cmd );
- - if(( cl.background && !cls.demoplayback ) || gl_overview->integer || cls.changelevel )
- + if(( cl.background && !cls.demoplayback ) || input_override || cls.changelevel )
- {
- VectorCopy( angles, cl.refdef.cl_viewangles );
- VectorCopy( angles, pcmd->cmd.viewangles );
- @@ -424,31 +517,34 @@ void CL_WritePacket( void )
- CL_ComputePacketLoss ();
- -#ifndef _DEBUG
- - if( cl_cmdrate->value < MIN_CMD_RATE )
- - {
- - Cvar_SetFloat( "cl_cmdrate", MIN_CMD_RATE );
- - }
- -#endif
- MSG_Init( &buf, "ClientData", data, sizeof( data ));
- // Determine number of backup commands to send along
- numbackup = bound( 0, cl_cmdbackup->integer, MAX_BACKUP_COMMANDS );
- if( cls.state == ca_connected ) numbackup = 0;
- + // clamp cmdrate
- + if( cl_cmdrate->integer < 0 ) Cvar_Set( "cl_cmdrate", "0" );
- + else if( cl_cmdrate->integer > 100 ) Cvar_Set( "cl_cmdrate", "100" );
- +
- // Check to see if we can actually send this command
- + // always reply at end of frame during the connection process
- + if( cls.state > ca_disconnected && cls.state < ca_active )
- + send_command = true;
- +
- // In single player, send commands as fast as possible
- // Otherwise, only send when ready and when not choking bandwidth
- - if(( cl.maxclients == 1 ) || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer ))
- + if( cl.maxclients == 1 || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer ))
- send_command = true;
- - else if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan ))
- +
- + if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan ))
- send_command = true;
- - if( cl.force_send_usercmd )
- + if( cl.send_reply )
- {
- + cl.send_reply = false;
- send_command = true;
- - cl.force_send_usercmd = false;
- }
- if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
- @@ -461,10 +557,8 @@ void CL_WritePacket( void )
- }
- if( cl_nodelta->integer )
- - {
- cl.validsequence = 0;
- - }
- -
- +
- // send a userinfo update if needed
- if( userinfo->modified )
- {
- @@ -476,8 +570,8 @@ void CL_WritePacket( void )
- {
- int outgoing_sequence;
- - if( cl_cmdrate->integer > 0 )
- - cls.nextcmdtime = host.realtime + ( 1.0f / cl_cmdrate->value );
- + if( cl_cmdrate->integer > 0 ) // clamped between 10 and 100 fps
- + cls.nextcmdtime = host.realtime + bound( 0.1f, ( 1.0f / cl_cmdrate->value ), 0.01f );
- else cls.nextcmdtime = host.realtime; // always able to send right away
- if( cls.lastoutgoingcommand == -1 )
- @@ -515,14 +609,13 @@ void CL_WritePacket( void )
- for( i = numcmds - 1; i >= 0; i-- )
- {
- cmdnumber = ( cls.netchan.outgoing_sequence - i ) & CL_UPDATE_MASK;
- - if( i == 0 ) cl.commands[cmdnumber].processedfuncs = true; // only last cmd allow to run funcs
- to = cmdnumber;
- CL_WriteUsercmd( &buf, from, to );
- from = to;
- if( MSG_CheckOverflow( &buf ))
- - Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
- + Host_Error( "CL_WritePacket: overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
- }
- // calculate a checksum over the move commands
- @@ -547,9 +640,7 @@ void CL_WritePacket( void )
- }
- if( MSG_CheckOverflow( &buf ))
- - {
- - Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
- - }
- + Host_Error( "CL_WritePacket: overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
- // remember outgoing command that we are sending
- cls.lastoutgoingcommand = cls.netchan.outgoing_sequence;
- @@ -714,7 +805,7 @@ void CL_Connect_f( void )
- return;
- }
- - Q_strncpy( server, Cmd_Argv( 1 ), sizeof( cls.servername ));
- + Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
- if( Host_ServerState())
- {
- @@ -814,6 +905,9 @@ void CL_ClearState( void )
- Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );
- cl.refdef.movevars = &clgame.movevars;
- cl.maxclients = 1; // allow to drawing player in menu
- + cl.mtime[0] = cl.mtime[1] = 1.0f; // because level starts from 1.0f second
- + NetAPI_CancelAllRequests();
- + cl.scr_fov = 90.0f;
- Cvar_SetFloat( "scr_download", 0.0f );
- Cvar_SetFloat( "scr_loading", 0.0f );
- @@ -941,7 +1035,7 @@ CL_InternetServers_f
- void CL_InternetServers_f( void )
- {
- netadr_t adr;
- - char fullquery[512] = "\x31\xFF" "0.0.0.0:0\0" "\\gamedir\\";
- + char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
- MsgDev( D_INFO, "Scanning for servers on the internet area...\n" );
- NET_Config( true ); // allow remote
- @@ -949,9 +1043,14 @@ void CL_InternetServers_f( void )
- if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
- MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
- - Q_strcpy( &fullquery[21], GI->gamedir );
- + Q_strcpy( &fullquery[22], GI->gamedir );
- +
- + NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 23, fullquery, adr );
- - NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 22, fullquery, adr );
- + // now we clearing the vgui request
- + if( clgame.master_request != NULL )
- + memset( clgame.master_request, 0, sizeof( net_request_t ));
- + clgame.request_type = NET_REQUEST_GAMEUI;
- }
- /*
- @@ -983,11 +1082,11 @@ void CL_Packet_f( void )
- return;
- }
- - if( !adr.port ) adr.port = MSG_BigShort( PORT_SERVER );
- + if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
- in = Cmd_Argv( 2 );
- out = send + 4;
- - send[0] = send[1] = send[2] = send[3] = (char)0xff;
- + send[0] = send[1] = send[2] = send[3] = (char)0xFF;
- l = Q_strlen( in );
- @@ -1058,6 +1157,70 @@ void CL_Reconnect_f( void )
- /*
- =================
- +CL_FixupColorStringsForInfoString
- +
- +all the keys and values must be ends with ^7
- +=================
- +*/
- +void CL_FixupColorStringsForInfoString( const char *in, char *out )
- +{
- + qboolean hasPrefix = false;
- + qboolean endOfKeyVal = false;
- + int color = 7;
- + int count = 0;
- +
- + if( *in == '\\' )
- + {
- + *out++ = *in++;
- + count++;
- + }
- +
- + while( *in && count < MAX_INFO_STRING )
- + {
- + if( IsColorString( in ))
- + color = ColorIndex( *(in+1));
- +
- + // color the not reset while end of key (or value) was found!
- + if( *in == '\\' && color != 7 )
- + {
- + if( IsColorString( out - 2 ))
- + {
- + *(out - 1) = '7';
- + }
- + else
- + {
- + *out++ = '^';
- + *out++ = '7';
- + count += 2;
- + }
- + color = 7;
- + }
- +
- + *out++ = *in++;
- + count++;
- + }
- +
- + // check the remaining value
- + if( color != 7 )
- + {
- + // if the ends with another color rewrite it
- + if( IsColorString( out - 2 ))
- + {
- + *(out - 1) = '7';
- + }
- + else
- + {
- + *out++ = '^';
- + *out++ = '7';
- + count += 2;
- + }
- + }
- +
- + *out = '\0';
- +}
- +
- +/*
- +=================
- CL_ParseStatusMessage
- Handle a reply from a info
- @@ -1065,10 +1228,15 @@ Handle a reply from a info
- */
- void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
- {
- - char *s;
- + static char infostring[MAX_INFO_STRING+8];
- + char *s = MSG_ReadString( msg );
- +
- + CL_FixupColorStringsForInfoString( s, infostring );
- - s = MSG_ReadString( msg );
- - UI_AddServerToList( from, s );
- + // more info about servers
- + MsgDev( D_INFO, "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
- +
- + UI_AddServerToList( from, infostring );
- }
- /*
- @@ -1078,15 +1246,27 @@ CL_ParseNETInfoMessage
- Handle a reply from a netinfo
- =================
- */
- -void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg )
- +void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg, const char *s )
- {
- - char *s;
- net_request_t *nr;
- + static char infostring[MAX_INFO_STRING+8];
- int i, context, type;
- + int errorBits = 0;
- + char *val;
- context = Q_atoi( Cmd_Argv( 1 ));
- type = Q_atoi( Cmd_Argv( 2 ));
- - s = Cmd_Argv( 3 );
- + while( *s != '\\' ) s++; // fetching infostring
- +
- + // check for errors
- + val = Info_ValueForKey( s, "neterror" );
- +
- + if( !Q_stricmp( val, "protocol" ))
- + SetBits( errorBits, NET_ERROR_PROTO_UNSUPPORTED );
- + else if( !Q_stricmp( val, "undefined" ))
- + SetBits( errorBits, NET_ERROR_UNDEFINED );
- +
- + CL_FixupColorStringsForInfoString( s, infostring );
- // find a request with specified context
- for( i = 0; i < MAX_REQUESTS; i++ )
- @@ -1095,28 +1275,81 @@ void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg )
- if( nr->resp.context == context && nr->resp.type == type )
- {
- - if( nr->timeout > host.realtime )
- - {
- - // setup the answer
- - nr->resp.response = s;
- - nr->resp.remote_address = from;
- - nr->resp.error = NET_SUCCESS;
- - nr->resp.ping = host.realtime - nr->timesend;
- - nr->pfnFunc( &nr->resp );
- -
- - if(!( nr->flags & FNETAPI_MULTIPLE_RESPONSE ))
- - memset( nr, 0, sizeof( *nr )); // done
- - }
- - else
- - {
- - memset( nr, 0, sizeof( *nr ));
- - }
- + // setup the answer
- + nr->resp.response = infostring;
- + nr->resp.remote_address = from;
- + nr->resp.error = NET_SUCCESS;
- + nr->resp.ping = host.realtime - nr->timesend;
- +
- + if( nr->timeout <= host.realtime )
- + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
- + SetBits( nr->resp.error, errorBits ); // misc error bits
- +
- + nr->pfnFunc( &nr->resp );
- +
- + if( !FBitSet( nr->flags, FNETAPI_MULTIPLE_RESPONSE ))
- + memset( nr, 0, sizeof( *nr )); // done
- return;
- }
- }
- }
- +/*
- +=================
- +CL_ProcessNetRequests
- +
- +check for timeouts
- +=================
- +*/
- +void CL_ProcessNetRequests( void )
- +{
- + net_request_t *nr;
- + int i;
- +
- + // find a request with specified context
- + for( i = 0; i < MAX_REQUESTS; i++ )
- + {
- + nr = &clgame.net_requests[i];
- + if( !nr->pfnFunc ) continue; // not used
- +
- + if( nr->timeout <= host.realtime )
- + {
- + // setup the answer
- + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
- + nr->resp.ping = host.realtime - nr->timesend;
- +
- + nr->pfnFunc( &nr->resp );
- + memset( nr, 0, sizeof( *nr )); // done
- + }
- + }
- +}
- +
- //===================================================================
- +/*
- +===============
- +CL_SetupOverviewParams
- +
- +Get initial overview values
- +===============
- +*/
- +void CL_SetupOverviewParams( void )
- +{
- + ref_overview_t *ov = &clgame.overView;
- + float mapAspect, screenAspect, aspect;
- +
- + ov->rotated = ( world.size[1] <= world.size[0] ) ? true : false;
- +
- + // calculate nearest aspect
- + mapAspect = world.size[!ov->rotated] / world.size[ov->rotated];
- + screenAspect = (float)glState.width / (float)glState.height;
- + aspect = Q_max( mapAspect, screenAspect );
- +
- + ov->zNear = world.maxs[2];
- + ov->zFar = world.mins[2];
- + ov->flZoom = ( 8192.0f / world.size[ov->rotated] ) / aspect;
- +
- + VectorAverage( world.mins, world.maxs, ov->origin );
- +}
- /*
- ======================
- @@ -1144,26 +1377,6 @@ void CL_PrepSound( void )
- }
- S_EndRegistration();
- -
- - if( host.soundList )
- - {
- - // need to reapply all ambient sounds after restarting
- - for( i = 0; i < host.numsounds; i++)
- - {
- - soundlist_t *entry = &host.soundList[i];
- - if( entry->looping && entry->entnum != -1 )
- - {
- - MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name );
- - S_AmbientSound( entry->origin, entry->entnum,
- - S_RegisterSound( entry->name ), entry->volume, entry->attenuation,
- - entry->pitch, 0 );
- - }
- - }
- - }
- -
- - host.soundList = NULL;
- - host.numsounds = 0;
- -
- cl.audio_prepped = true;
- }
- @@ -1220,7 +1433,7 @@ void CL_PrepVideo( void )
- R_NewMap(); // tell the render about new map
- - V_SetupOverviewState(); // set overview bounds
- + CL_SetupOverviewParams(); // set overview bounds
- // must be called after lightmap loading!
- clgame.dllFuncs.pfnVidInit();
- @@ -1237,44 +1450,6 @@ void CL_PrepVideo( void )
- Cvar_SetFloat( "scr_loading", 100.0f ); // all done
- - if( host.decalList )
- - {
- - // need to reapply all decals after restarting
- - for( i = 0; i < host.numdecals; i++ )
- - {
- - decallist_t *entry = &host.decalList[i];
- - cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex );
- - int decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name ));
- - int modelIndex = 0;
- -
- - if( pEdict ) modelIndex = pEdict->curstate.modelindex;
- - CL_DecalShoot( decalIndex, entry->entityIndex, modelIndex, entry->position, entry->flags );
- - }
- - Z_Free( host.decalList );
- - }
- -
- - host.decalList = NULL;
- - host.numdecals = 0;
- -
- - if( host.soundList )
- - {
- - // need to reapply all ambient sounds after restarting
- - for( i = 0; i < host.numsounds; i++ )
- - {
- - soundlist_t *entry = &host.soundList[i];
- - if( entry->looping && entry->entnum != -1 )
- - {
- - MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name );
- - S_AmbientSound( entry->origin, entry->entnum,
- - S_RegisterSound( entry->name ), entry->volume, entry->attenuation,
- - entry->pitch, 0 );
- - }
- - }
- - }
- -
- - host.soundList = NULL;
- - host.numsounds = 0;
- -
- if( host.developer <= 2 )
- Con_ClearNotify(); // clear any lines of console text
- @@ -1341,7 +1516,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
- else if( !Q_strcmp( c, "netinfo" ))
- {
- // server responding to a status broadcast
- - CL_ParseNETInfoMessage( from, msg );
- + CL_ParseNETInfoMessage( from, msg, args );
- }
- else if( !Q_strcmp( c, "cmd" ))
- {
- @@ -1386,26 +1561,69 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
- // dropped the connection but it is still getting packets from us
- CL_Disconnect();
- }
- - else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x66 && msg->pData[5] == 0x0A )
- + else if( !Q_strcmp( c, "f" ))
- {
- - dataoffset = 6;
- -
- - while( 1 )
- + // serverlist got from masterserver
- + while( MSG_GetNumBitsLeft( msg ) > 8 )
- {
- + MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
- + servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
- servadr.type = NA_IP;
- - memcpy( servadr.ip, &msg->pData[dataoffset], sizeof(servadr.ip));
- - servadr.port = *(word *)&msg->pData[dataoffset + 4];
- + // list is ends here
- if( !servadr.port )
- + {
- + if( clgame.request_type == NET_REQUEST_CLIENT && clgame.master_request != NULL )
- + {
- + net_request_t *nr = clgame.master_request;
- + net_adrlist_t *list, **prev;
- +
- + // setup the answer
- + nr->resp.remote_address = from;
- + nr->resp.error = NET_SUCCESS;
- + nr->resp.ping = host.realtime - nr->timesend;
- +
- + if( nr->timeout <= host.realtime )
- + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
- +
- + MsgDev( D_INFO, "serverlist call: %s\n", NET_AdrToString( from ));
- + nr->pfnFunc( &nr->resp );
- +
- + // throw the list, now it will be stored in user area
- + prev = &((net_adrlist_t *)nr->resp.response);
- +
- + while( 1 )
- + {
- + list = *prev;
- + if( !list ) break;
- +
- + // throw out any variables the game created
- + *prev = list->next;
- + Mem_Free( list );
- + }
- + memset( nr, 0, sizeof( *nr )); // done
- + clgame.request_type = NET_REQUEST_CANCEL;
- + clgame.master_request = NULL;
- + }
- break;
- + }
- - MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr ));
- -
- - NET_Config( true ); // allow remote
- -
- - Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
- -
- - dataoffset += 6;
- + if( clgame.request_type == NET_REQUEST_CLIENT && clgame.master_request != NULL )
- + {
- + net_request_t *nr = clgame.master_request;
- + net_adrlist_t *list;
- +
- + // adding addresses into list
- + list = Z_Malloc( sizeof( *list ));
- + list->remote_address = servadr;
- + list->next = nr->resp.response;
- + nr->resp.response = list;
- + }
- + else if( clgame.request_type == NET_REQUEST_GAMEUI )
- + {
- + NET_Config( true ); // allow remote
- + Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
- + }
- }
- }
- else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
- @@ -1477,6 +1695,7 @@ void CL_ReadNetMessage( void )
- continue; // wasn't accepted for some reason
- CL_ParseServerMessage( &net_message );
- + cl.send_reply = true;
- }
- // check for fragmentation/reassembly related packets.
- @@ -1499,6 +1718,9 @@ void CL_ReadNetMessage( void )
- }
- Netchan_UpdateProgress( &cls.netchan );
- +
- + // check requests for time-expire
- + CL_ProcessNetRequests();
- }
- void CL_ReadPackets( void )
- @@ -1516,6 +1738,9 @@ void CL_ReadPackets( void )
- #endif
- CL_UpdateFrameLerp ();
- + // build list of all solid entities per next frame (exclude clients)
- + CL_SetSolidEntities();
- +
- // singleplayer never has connection timeout
- if( NET_IsLocalAddress( cls.netchan.remote_address ))
- return;
- @@ -1641,7 +1866,7 @@ void CL_InitLocal( void )
- cls.state = ca_disconnected;
- // register our variables
- - cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE, "enable client movement prediction" );
- + cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client movement prediction" );
- cl_crosshair = Cvar_Get( "crosshair", "1", CVAR_ARCHIVE, "show weapon chrosshair" );
- cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for usercommnds" );
- cl_idealpitchscale = Cvar_Get( "cl_idealpitchscale", "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" );
- @@ -1661,18 +1886,21 @@ void CL_InitLocal( void )
- rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" );
- hltv = Cvar_Get( "hltv", "0", CVAR_USERINFO|CVAR_LATCH, "HLTV mode" );
- cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" );
- - cl_smooth = Cvar_Get ("cl_smooth", "0", CVAR_ARCHIVE, "smooth up stair climbing and interpolate position in multiplayer" );
- + cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", CVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" );
- + cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", CVAR_ARCHIVE, "time to smooth up" );
- cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", CVAR_ARCHIVE, "how many additional history commands are sent" );
- cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", CVAR_ARCHIVE, "Max number of command packets sent to server per second" );
- cl_draw_particles = Cvar_Get( "cl_draw_particles", "1", CVAR_ARCHIVE, "Disable any particle effects" );
- cl_draw_beams = Cvar_Get( "cl_draw_beams", "1", CVAR_ARCHIVE, "Disable view beams" );
- cl_lightstyle_lerping = Cvar_Get( "cl_lightstyle_lerping", "0", CVAR_ARCHIVE, "enables animated light lerping (perfomance option)" );
- cl_showerror = Cvar_Get( "cl_showerror", "0", CVAR_ARCHIVE, "show prediction error" );
- + cl_bmodelinterp = Cvar_Get( "cl_bmodelinterp", "1", CVAR_ARCHIVE, "enable bmodel interpolation" );
- Cvar_Get( "hud_scale", "0", CVAR_ARCHIVE|CVAR_LATCH, "scale hud at current resolution" );
- Cvar_Get( "skin", "", CVAR_USERINFO, "player skin" ); // XDM 3.3 want this cvar
- - Cvar_Get( "cl_updaterate", "60", CVAR_USERINFO|CVAR_ARCHIVE, "refresh rate of server messages" );
- + cl_updaterate = Cvar_Get( "cl_updaterate", "60", CVAR_USERINFO|CVAR_ARCHIVE, "refresh rate of server messages" );
- Cvar_Get( "cl_background", "0", CVAR_READ_ONLY, "indicate what background map is running" );
- + Cvar_Get( "cl_msglevel", "0", CVAR_USERINFO|CVAR_ARCHIVE, "message filter for server notifications" );
- // these two added to shut up CS 1.5 about 'unknown' commands
- Cvar_Get( "lightgamma", "1", CVAR_ARCHIVE, "ambient lighting level (legacy, unused)" );
- @@ -1755,6 +1983,43 @@ void CL_SendCommand( void )
- /*
- ==================
- +CL_PrepareFrame
- +
- +setup camera, update visible ents
- +==================
- +*/
- +void CL_PrepareFrame( void )
- +{
- + if( cls.state != ca_active )
- + return; // not in game
- +
- + if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
- + return; // still loading
- +
- + if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
- + {
- + cl.force_refdef = false;
- + V_SetupRefDef ();
- + }
- +}
- +
- +/*
- +==================
- +Host_RenderFrame
- +
- +==================
- +*/
- +void Host_RenderFrame( void )
- +{
- + // if client is not active, do nothing
- + if( !cls.initialized ) return;
- +
- + // update the screen
- + SCR_UpdateScreen ();
- +}
- +
- +/*
- +==================
- Host_ClientFrame
- ==================
- @@ -1768,6 +2033,10 @@ void Host_ClientFrame( void )
- cl.oldtime = cl.time;
- cl.time += host.frametime;
- + // demo time
- + if( cls.demorecording && !cls.demowaiting )
- + cls.demotime += host.frametime;
- +
- if( gameui.hInstance )
- {
- // menu time (not paused, not clamped)
- @@ -1796,25 +2065,43 @@ void Host_ClientFrame( void )
- if( !cl.audio_prepped ) CL_PrepSound();
- }
- - // update the screen
- - SCR_UpdateScreen ();
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + // send a new command message to the server
- + CL_SendCommand();
- +
- + // predict all unacknowledged movements
- + CL_PredictMovement();
- - // update audio
- - S_RenderFrame( &cl.refdef );
- + // setup view, add visible ents
- + CL_PrepareFrame();
- - // send a new command message to the server
- - CL_SendCommand();
- + // update audio
- + S_RenderFrame( &cl.refdef );
- + }
- + else
- + {
- + // update the screen
- + SCR_UpdateScreen ();
- - // predict all unacknowledged movements
- - CL_PredictMovement();
- + // update audio
- + S_RenderFrame( &cl.refdef );
- +
- + // send a new command message to the server
- + CL_SendCommand();
- +
- + // predict all unacknowledged movements
- + CL_PredictMovement();
- + }
- +
- + // animate lightestyles
- + CL_RunLightStyles();
- // decay dynamic lights
- CL_DecayLights ();
- SCR_RunCinematic();
- Con_RunConsole();
- -
- - cls.framecount++;
- }
- @@ -1874,4 +2161,6 @@ void CL_Shutdown( void )
- SCR_FreeCinematic (); // release AVI's *after* client.dll because custom renderer may use them
- S_Shutdown ();
- R_Shutdown ();
- +
- + Con_Shutdown ();
- }
- \ No newline at end of file
- diff --git b/engine/client/cl_netgraph.c a/engine/client/cl_netgraph.c
- new file mode 100644
- index 0000000..f88456f
- --- /dev/null
- +++ a/engine/client/cl_netgraph.c
- @@ -0,0 +1,511 @@
- +/*
- +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 PACKETLOSS_AVG_FRAC 0.5
- +#define PACKETCHOKE_AVG_FRAC 0.5
- +#define NETGRAPH_LERP_HEIGHT 24
- +#define NUM_LATENCY_SAMPLES 8
- +
- +convar_t *net_graph;
- +convar_t *net_graphpos;
- +convar_t *net_graphwidth;
- +convar_t *net_graphheight;
- +convar_t *net_scale;
- +convar_t *net_graphfillsegments;
- +
- +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_LERP_HEIGHT+5][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 netbandwidthgraph_t netstat_graph[NET_TIMINGS];
- +static float packet_loss;
- +static float packet_choke;
- +
- +/*
- +==========
- +NetGraph_DrawLine
- +
- +CL_FillRGBA shortcut
- +==========
- +*/
- +static void NetGraph_DrawRect( wrect_t *rect, byte colors[4] )
- +{
- + CL_FillRGBA( rect->left, rect->top, rect->right, rect->bottom, colors[0], colors[1], colors[2], colors[3] );
- +}
- +
- +/*
- +==========
- +NetGraph_InitColors
- +
- +init netgraph colors
- +==========
- +*/
- +void NetGraph_InitColors( void )
- +{
- + int i;
- +
- + for( i = 0; i < NETGRAPH_LERP_HEIGHT; i++ )
- + {
- + if( i <= NETGRAPH_LERP_HEIGHT / 3 )
- + {
- + netcolors[i + 5][0] = i * -7.875f + 63;
- + netcolors[i + 5][1] = i * 7.875f;
- + netcolors[i + 5][2] = i * 19.375f + 100;
- + }
- + else
- + {
- + netcolors[i + 5][0] = ( i - 8 ) * -0.3125f + 255;
- + netcolors[i + 5][1] = ( i - 8 ) * -7.9375f + 127;
- + netcolors[i + 5][2] = 0;
- + }
- + }
- +}
- +
- +/*
- +==========
- +NetGraph_GetFrameData
- +
- +get frame data info, like chokes, packet losses, also update graph, packet and cmdinfo
- +==========
- +*/
- +void NetGraph_GetFrameData( int *biggest_message, float *latency, int *latency_count )
- +{
- + int i, choke_count = 0, loss_count = 0;
- + float loss, choke;
- +
- + *biggest_message = *latency_count = 0;
- + *latency = 0.0f;
- +
- + 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->receivedtime == -2.0f ? true : false;
- + if( p->choked )
- + choke_count++;
- +
- + if( !f->valid || f->receivedtime == -2.0 )
- + {
- + p->latency = 9998; // broken delta
- + }
- + else if( f->receivedtime == -1.0 )
- + {
- + p->latency = 9999; // dropped
- + loss_count++;
- + }
- + 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( *biggest_message < g->msgbytes )
- + *biggest_message = g->msgbytes;
- + }
- +
- + 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;
- + POINT pt = { Q_max( x + w - 1 - 25, 1 ), Q_max( rect.top + rect.bottom - 4 - NETGRAPH_LERP_HEIGHT + 1, 1 ) };
- + rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
- + wrect_t fill;
- +
- + Con_DrawString( pt.x, pt.y, va( "%i/s", cl_cmdrate->integer ), colors );
- +
- + 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;
- +
- + for( j = start; j < h; j++ )
- + {
- + memcpy( colors, netcolors[j + extrap_point], sizeof( byte ) * 3 );
- + NetGraph_DrawRect( &fill, colors );
- + fill.top--;
- + }
- + }
- + else
- + {
- + int oldh = h;
- +
- + fill.top -= h;
- + h = extrap_point - h;
- +
- + for( j = 0; j < h; j++ )
- + {
- + memcpy( colors, netcolors[j + oldh], sizeof( byte ) * 3 );
- + NetGraph_DrawRect( &fill, colors );
- + fill.top--;
- + }
- + }
- +
- + fill.top = rect.top + rect.bottom - 4 - extrap_point;
- +
- + CL_FillRGBA( fill.left, fill.top, fill.right, fill.bottom, 255, 255, 255, 255 );
- +
- + fill.top = rect.top + rect.bottom - 3;
- +
- + if( !netstat_cmdinfo[i].sent )
- + CL_FillRGBA( fill.left, fill.top, fill.right, fill.bottom, 255, 0, 0, 255 );
- + }
- +}
- +
- +/*
- +===========
- +NetGraph_DrawHatches
- +
- +===========
- +*/
- +void NetGraph_DrawHatches( int x, int y, int maxmsgbytes )
- +{
- + int ystep = max((int)( 10.0 / net_scale->value ), 1 );
- + wrect_t hatch = { x, 4, y, 1 };
- + int starty;
- +
- + for( starty = hatch.top; hatch.top > 0 && ((starty - hatch.top) * net_scale->value < (maxmsgbytes + 50)); hatch.top -= ystep )
- + {
- + CL_FillRGBA( hatch.left, hatch.top, hatch.right, hatch.bottom, 63, 63, 0, 200 );
- + }
- +}
- +
- +/*
- +===========
- +NetGraph_DrawTextFields
- +
- +===========
- +*/
- +void NetGraph_DrawTextFields( int x, int y, 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 i = ( cls.netchan.outgoing_sequence - 1 ) & NET_TIMINGS_MASK;
- + float latency = count > 0 ? Q_max( 0, avg / count - 0.5 * host.frametime - 1000.0 / cl_updaterate->value ) : 0;
- + float framerate = 1.0 / host.realframetime;
- +
- + Con_DrawString( x, y - net_graphheight->integer, va( "%.1ffps" , framerate ), colors );
- + Con_DrawString( x + 75, y - net_graphheight->integer, va( "%i ms" , (int)latency ), colors );
- + Con_DrawString( x + 150, y - net_graphheight->integer, va( "%i/s" , cl_updaterate->integer ), colors );
- +
- + if( netstat_cmdinfo[i].size )
- + lastout = netstat_cmdinfo[i].size;
- +
- + Con_DrawString( x, y - net_graphheight->integer + 15, va( "in : %i %.2f k/s", netstat_graph[i].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors );
- +
- + Con_DrawString( x, y - net_graphheight->integer + 30, va( "out: %i %.2f k/s", lastout, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
- +
- + if( net_graph->integer > 2 )
- + Con_DrawString( x, y - net_graphheight->integer + 45, va( "loss: %i choke: %i", packet_loss, packet_choke ), colors );
- +
- +}
- +
- +/*
- +===========
- +NetGraph_DrawDataSegment
- +
- +===========
- +*/
- +int NetGraph_DrawDataSegment( wrect_t *fill, int bytes, byte r, byte g, byte b, byte a )
- +{
- + int h = bytes / net_scale->value;
- + byte colors[4] = { r, g, b, a };
- +
- + fill->top -= h;
- +
- + if( net_graphfillsegments->integer )
- + fill->bottom = 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 maxmsgbytes )
- +{
- + int a, i, h, lastvalidh = 0, ping;
- + 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 > net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2 )
- + h = net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2;
- +
- + fill.left = x + w - a - 1;
- + fill.top = y - h;
- + fill.right = 1;
- + fill.bottom = ping ? 1: h;
- +
- + NetGraph_DrawRect( &fill, color );
- +
- + fill.top = y;
- + fill.bottom = 1;
- +
- + color[0] = 0; color[1] = 255; color[2] = 0; color[3] = 160;
- +
- + NetGraph_DrawRect( &fill, color );
- +
- + if( net_graph->integer < 2 )
- + continue;
- +
- + fill.top = y - net_graphheight->value - 1;
- + fill.bottom = 1;
- + color[0] = color[1] = color[2] = color[3] = 255;
- +
- + 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;
- +
- + // special case for absolute usage
- + h = netstat_graph[i].msgbytes / net_scale->value;
- +
- + color[0] = color[1] = color[2] = 240; color[3] = 255;
- +
- + fill.bottom = 1;
- + fill.top = y - net_graphheight->value - 1 - h;
- +
- + if( fill.top < 2 ) continue;
- +
- + NetGraph_DrawRect( &fill, color );
- + }
- +
- + if( net_graph->integer >= 2 )
- + NetGraph_DrawHatches( x, y - net_graphheight->value - 1, maxmsgbytes );
- +}
- +
- +/*
- +===========
- +NetGraph_GetScreenPos
- +
- +===========
- +*/
- +void NetGraph_GetScreenPos( wrect_t *rect, int *w, int *x, int *y )
- +{
- + rect->left = rect->top = 0;
- + rect->right = clgame.scrInfo.iWidth;
- + rect->bottom = clgame.scrInfo.iHeight;
- +
- + *w = Q_min( NET_TIMINGS, net_graphwidth->integer );
- + if( rect->right < *w + 10 )
- + *w = rect->right - 10;
- +
- + // detect x and y position
- + switch( net_graphpos->integer )
- + {
- + 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 maxmsgbytes;
- + int w, x, y;
- +
- + if( !net_graph->integer )
- + return;
- +
- + if( net_scale->value <= 0 )
- + Cvar_SetFloat( "net_scale", 0.1f );
- +
- + NetGraph_GetScreenPos( &rect, &w, &x, &y );
- +
- + NetGraph_GetFrameData( &maxmsgbytes, &avg_ping, &ping_count );
- +
- + if( net_graph->integer < 3 )
- + {
- + NetGraph_DrawTimes( rect, x, w );
- + NetGraph_DrawDataUsage( x, y, w, maxmsgbytes );
- + }
- +
- + NetGraph_DrawTextFields( x, y, ping_count, avg_ping, packet_loss, packet_choke );
- +}
- +
- +void CL_InitNetgraph( void )
- +{
- + net_graph = Cvar_Get( "net_graph", "0", CVAR_ARCHIVE, "draw network usage graph" );
- + net_graphpos = Cvar_Get( "net_graphpos", "1", CVAR_ARCHIVE, "network usage graph position" );
- + net_scale = Cvar_Get( "net_scale", "5", CVAR_ARCHIVE, "network usage graph scale level" );
- + net_graphwidth = Cvar_Get( "net_graphwidth", "192", CVAR_ARCHIVE, "network usage graph width" );
- + net_graphheight = Cvar_Get( "net_graphheight", "64", CVAR_ARCHIVE, "network usage graph height" );
- + net_graphfillsegments = Cvar_Get( "net_graphfillsegments", "1", CVAR_ARCHIVE, "fill segments in network usage graph" );
- + packet_loss = packet_choke = 0.0;
- +
- + NetGraph_InitColors();
- +}
- \ No newline at end of file
- diff --git b/engine/client/cl_parse.c a/engine/client/cl_parse.c
- index 2cf84aa..08c1686 100644
- --- b/engine/client/cl_parse.c
- +++ a/engine/client/cl_parse.c
- @@ -285,6 +285,9 @@ void CL_ParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
- }
- else handle = cl.sound_index[sound]; // see precached sound
- + if( !cl.audio_prepped )
- + return; // too early
- +
- if( is_ambient )
- {
- S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
- @@ -354,6 +357,18 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
- /*
- ==================
- +CL_ParseServerTime
- +
- +==================
- +*/
- +void CL_ParseServerTime( sizebuf_t *msg )
- +{
- + cl.mtime[1] = cl.mtime[0];
- + cl.mtime[0] = MSG_ReadFloat( msg );
- +}
- +
- +/*
- +==================
- CL_ParseMovevars
- ==================
- @@ -371,6 +386,7 @@ void CL_ParseMovevars( sizebuf_t *msg )
- memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
- // keep features an actual!
- clgame.oldmovevars.features = clgame.movevars.features = host.features;
- + clgame.entities->curstate.scale = cl.refdef.movevars->waveHeight;
- }
- /*
- @@ -1444,7 +1460,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- char *s;
- int i, j, cmd;
- int param1, param2;
- - int bufStart;
- + int bufStart, playerbytes;
- cls_message_debug.parsing = true; // begin parsing
- starting_count = MSG_GetNumBytesRead( msg ); // updates each frame
- @@ -1513,6 +1529,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- case svc_sound:
- CL_ParseSoundPacket( msg, false );
- + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_time:
- // shuffle timestamps
- @@ -1543,12 +1560,17 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- case svc_clientdata:
- CL_ParseClientData( msg );
- + cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_packetentities:
- - CL_ParsePacketEntities( msg, false );
- + playerbytes = CL_ParsePacketEntities( msg, false );
- + cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
- + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
- break;
- case svc_deltapacketentities:
- - CL_ParsePacketEntities( msg, true );
- + playerbytes = CL_ParsePacketEntities( msg, true );
- + cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
- + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
- break;
- case svc_updatepings:
- CL_UpdateUserPings( msg );
- @@ -1561,12 +1583,14 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- case svc_restoresound:
- CL_ParseRestoreSoundPacket( msg );
- + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_spawnstatic:
- CL_ParseStaticEntity( msg );
- break;
- case svc_ambientsound:
- CL_ParseSoundPacket( msg, true );
- + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_crosshairangle:
- CL_ParseCrosshairAngle( msg );
- @@ -1576,6 +1600,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- case svc_temp_entity:
- CL_ParseTempEntity( msg );
- + cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_setpause:
- cl.refdef.paused = ( MSG_ReadOneBit( msg ) != 0 );
- @@ -1591,9 +1616,11 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- case svc_event:
- CL_ParseEvent( msg );
- + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_event_reliable:
- CL_ParseReliableEvent( msg );
- + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- case svc_updateuserinfo:
- CL_UpdateUserinfo( msg );
- @@ -1667,6 +1694,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
- break;
- default:
- CL_ParseUserMessage( msg, cmd );
- + cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
- break;
- }
- }
- diff --git b/engine/client/cl_pmove.c a/engine/client/cl_pmove.c
- index d736b64..f599843 100644
- --- b/engine/client/cl_pmove.c
- +++ a/engine/client/cl_pmove.c
- @@ -29,6 +29,119 @@ void CL_ClearPhysEnts( void )
- clgame.pmove->numphysent = 0;
- }
- +/*
- +=============
- +CL_PushPMStates
- +
- +=============
- +*/
- +void CL_PushPMStates( void )
- +{
- + if( clgame.pushed )
- + {
- + MsgDev( D_ERROR, "PushPMStates called with pushed stack\n");
- + }
- + else
- + {
- + clgame.oldphyscount = clgame.pmove->numphysent;
- + clgame.oldviscount = clgame.pmove->numvisent;
- + clgame.pushed = true;
- + }
- +
- +}
- +
- +/*
- +=============
- +CL_PopPMStates
- +
- +=============
- +*/
- +void CL_PopPMStates( void )
- +{
- + if( clgame.pushed )
- + {
- + clgame.pmove->numphysent = clgame.oldphyscount;
- + clgame.pmove->numvisent = clgame.oldviscount;
- + clgame.pushed = false;
- + }
- + else
- + {
- + MsgDev( D_ERROR, "PopPMStates called without stack\n");
- + }
- +}
- +
- +/*
- +=============
- +CL_ComputePlayerOrigin
- +
- +FIXME: implement
- +=============
- +*/
- +void CL_ComputePlayerOrigin( cl_entity_t *clent )
- +{
- +}
- +
- +/*
- +=============
- +CL_SetUpPlayerPrediction
- +
- +=============
- +*/
- +void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
- +{
- + entity_state_t *state;
- + predicted_player_t *player;
- + cl_entity_t *clent;
- + int i;
- +
- + for( i = 0; i < MAX_CLIENTS; i++ )
- + {
- + state = &cl.frames[cl.parsecountmod].playerstate[i];
- + player = &cls.predicted_players[i];
- +
- + player->active = false;
- +
- + if( state->messagenum != cl.parsecount )
- + continue; // not present this frame
- +
- + if( !state->modelindex )
- + continue;
- +
- + clent = CL_GetEntityByIndex( i + 1 );
- +
- + // special for EF_NODRAW and local client?
- + if( FBitSet( state->effects, EF_NODRAW ) && !bIncludeLocalClient )
- + {
- + // don't include local player?
- + if( cl.playernum == i ) continue;
- +
- + player->active = true;
- + player->movetype = state->movetype;
- + player->solid = state->solid;
- + player->usehull = state->usehull;
- +
- + CL_ComputePlayerOrigin( clent );
- +
- + VectorCopy( clent->origin, player->origin );
- + VectorCopy( clent->angles, player->angles );
- + }
- + else
- + {
- + player->active = true;
- + player->movetype = state->movetype;
- + player->solid = state->solid;
- + player->usehull = state->usehull;
- +
- + // don't rewrite origin and angles of local client
- + if( cl.playernum == i )
- + continue;
- +
- + VectorCopy( state->origin, player->origin );
- + VectorCopy( state->angles, player->angles );
- + }
- + }
- +}
- +
- void CL_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr )
- {
- ASSERT( tr != NULL );
- @@ -211,25 +324,35 @@ pmove must be setup with world and solid entity hulls before calling
- */
- void CL_SetSolidPlayers( int playernum )
- {
- - int j;
- - extern vec3_t player_mins;
- - extern vec3_t player_maxs;
- + entity_state_t *state;
- cl_entity_t *ent;
- physent_t *pe;
- + int i;
- if( !cl_solid_players->integer )
- return;
- - for( j = 0; j < cl.maxclients; j++ )
- + for( i = 0; i < cl.maxclients; i++ )
- {
- // the player object never gets added
- - if( j == playernum ) continue;
- + if( i == playernum ) continue;
- - ent = CL_GetEntityByIndex( j + 1 );
- + ent = CL_GetEntityByIndex( i + 1 );
- if( !ent || !ent->player )
- continue; // not present this frame
- + state = cl.frames[cl.parsecountmod].playerstate + i;
- +
- + if( state->effects & EF_NODRAW )
- + continue; // skip invisible
- +
- + if( !state->solid )
- + continue; // not solid
- +
- + if( !state->movetype )
- + continue; // dead
- +
- pe = &clgame.pmove->physents[clgame.pmove->numphysent];
- if( CL_CopyEntityToPhysEnt( pe, ent ))
- clgame.pmove->numphysent++;
- @@ -550,9 +673,10 @@ static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
- static void pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
- {
- - sound_t snd = S_RegisterSound( sample );
- + if( !clgame.pmove->runfuncs )
- + return;
- - S_StartSound( NULL, clgame.pmove->player_index + 1, channel, snd, volume, attenuation, pitch, fFlags );
- + S_StartSound( NULL, clgame.pmove->player_index + 1, channel, S_RegisterSound( sample ), volume, attenuation, pitch, fFlags );
- }
- static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, float delay, float *origin,
- @@ -857,6 +981,10 @@ void CL_RunUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboole
- // copy results back to client
- CL_FinishPMove( clgame.pmove, to );
- + cl.predicted.lastground = clgame.pmove->onground;
- + if( cl.predicted.lastground > 0 && cl.predicted.lastground < clgame.pmove->numphysent )
- + cl.predicted.lastground = clgame.pmove->physents[cl.predicted.lastground].info;
- +
- clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *time, random_seed );
- *time += (double)cmd.msec / 1000.0;
- }
- @@ -878,26 +1006,30 @@ void CL_CheckPredictionError( void )
- frame = ( cls.netchan.incoming_acknowledged ) & CL_UPDATE_MASK;
- // compare what the server returned with what we had predicted it to be
- - VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame], delta );
- + VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame], delta );
- maxspd = ( clgame.movevars.maxvelocity * host.frametime );
- len = VectorLength( delta );
- // save the prediction error for interpolation
- - if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
- +// if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
- + if( len > 64.0f )
- {
- // a teleport or something or gamepaused
- - VectorClear( cl.prediction_error );
- + VectorClear( cl.predicted.error );
- }
- else
- {
- if( cl_showerror->value && len > 0.5f )
- MsgDev( D_ERROR, "prediction error on %i: %g\n", cl.parsecount, len );
- - VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame] );
- + VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame] );
- +
- + // save for error interpolation
- + VectorCopy( delta, cl.predicted.error );
- - // save for error itnerpolation
- - VectorCopy( delta, cl.prediction_error );
- + if(( len > 0.25f ) && ( cl.maxclients > 1 ))
- + cl.predicted.correction_time = cl_smoothtime->value;
- }
- }
- @@ -912,6 +1044,8 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
- {
- local_state_t from, to;
- + memset( &from, 0, sizeof( local_state_t ));
- + memset( &to, 0, sizeof( local_state_t ));
- memcpy( from.weapondata, cl.frame.weapondata, sizeof( from.weapondata ));
- from.playerstate = cl.frame.playerstate[cl.playernum];
- from.client = cl.frame.client;
- @@ -922,6 +1056,35 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
- /*
- =================
- +CL_FakeUsercmd
- +
- +Runs client weapons prediction code
- +=================
- +*/
- +void CL_FakeUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboolean runfuncs, double *pfElapsed, unsigned int random_seed )
- +{
- + usercmd_t cmd;
- + local_state_t temp;
- + usercmd_t split;
- +
- + while( u->msec > 50 )
- + {
- + split = *u;
- + split.msec /= 2;
- + CL_FakeUsercmd( from, &temp, &split, runfuncs, pfElapsed, random_seed );
- + from = &temp;
- + u = &split;
- + }
- +
- + cmd = *u;
- + *to = *from;
- +
- + clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *pfElapsed, random_seed );
- + *pfElapsed += cmd.msec / 1000.0;
- +}
- +
- +/*
- +=================
- CL_PredictMovement
- Sets cl.predicted_origin and cl.predicted_angles
- @@ -941,22 +1104,66 @@ void CL_PredictMovement( void )
- if( cls.state != ca_active ) return;
- if( cls.demoplayback && cl.refdef.cmd != NULL )
- - {
- - // restore viewangles from cmd.angles
- - VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
- - }
- + CL_DemoInterpolateAngles();
- if( !CL_IsInGame( )) return;
- + CL_SetUpPlayerPrediction( false, false );
- +
- // unpredicted pure angled values converted into axis
- AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );
- ASSERT( cl.refdef.cmd != NULL );
- if( !CL_IsPredicted( ))
- - {
- - // run commands even if client predicting is disabled - client expected it
- - CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );
- + {
- + // fake prediction code
- + // we need to perform cl_lw prediction while cl_predict is disabled
- + // because cl_lw is enabled by default in Half-Life
- + if( !cl_lw->integer )
- + {
- + cl.predicted.viewmodel = cl.frame.client.viewmodel;
- + return;
- + }
- +
- + ack = cls.netchan.incoming_acknowledged;
- + outgoing_command = cls.netchan.outgoing_sequence;
- +
- + from = &cl.predict[cl.parsecountmod];
- + from->playerstate = cl.frame.playerstate[cl.playernum];
- + from->client = cl.frame.client;
- + memcpy( from->weapondata, cl.frame.weapondata, sizeof( from->weapondata ));
- +
- + time = cl.frame.time;
- +
- + while( 1 )
- + {
- + // we've run too far forward
- + if( frame >= ( CL_UPDATE_BACKUP - 1 ))
- + break;
- +
- + // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon
- + current_command = ack + frame;
- + current_command_mod = current_command & CL_UPDATE_MASK;
- +
- + // we've caught up to the current command.
- + if( current_command >= outgoing_command )
- + break;
- +
- + to = &cl.predict[( cl.parsecountmod + frame ) & CL_UPDATE_MASK];
- +
- + CL_FakeUsercmd( from, to, &cl.commands[current_command_mod].cmd,
- + !cl.commands[current_command_mod].processedfuncs,
- + &time, cls.netchan.incoming_acknowledged + frame );
- +
- + cl.commands[current_command_mod].processedfuncs = true;
- +
- + from = to;
- + frame++;
- + }
- +
- + if( to )
- + cl.predicted.viewmodel = to->client.viewmodel;
- return;
- }
- @@ -970,7 +1177,6 @@ void CL_PredictMovement( void )
- time = cl.frame.time;
- - CL_SetSolidEntities();
- CL_SetSolidPlayers( cl.playernum );
- while( 1 )
- @@ -995,7 +1201,7 @@ void CL_PredictMovement( void )
- cl.commands[current_command_mod].processedfuncs = true;
- // save for debug checking
- - VectorCopy( to->playerstate.origin, cl.predicted_origins[current_command_mod] );
- + VectorCopy( to->playerstate.origin, cl.predicted.origins[current_command_mod] );
- from = to;
- frame++;
- @@ -1003,9 +1209,109 @@ void CL_PredictMovement( void )
- if( to )
- {
- - VectorCopy( to->playerstate.origin, cl.predicted_origin );
- - VectorCopy( to->client.velocity, cl.predicted_velocity );
- - VectorCopy( to->client.view_ofs, cl.predicted_viewofs );
- - VectorCopy( to->client.punchangle, cl.predicted_punchangle );
- + float t0 = cl.commands[( cl.parsecountmod + frame - 1) & CL_UPDATE_MASK].senttime;
- + float t1 = cl.commands[( cl.parsecountmod + frame ) & CL_UPDATE_MASK].senttime;
- + float t;
- +
- + if( t0 == t1 )
- + {
- + t = 0.0f;
- + }
- + else
- + {
- + t = (host.realtime - t0) / (t1 - t0);
- + t = bound( 0.0f, t, 1.0f );
- + }
- +
- + // was teleported
- + if( fabs( to->playerstate.origin[0] - from->playerstate.origin[0] ) > 128.0f ||
- + fabs( to->playerstate.origin[1] - from->playerstate.origin[1] ) > 128.0f ||
- + fabs( to->playerstate.origin[2] - from->playerstate.origin[2] ) > 128.0f )
- + {
- + VectorCopy( to->playerstate.origin, cl.predicted.origin );
- + VectorCopy( to->client.velocity, cl.predicted.velocity );
- + VectorCopy( to->client.punchangle, cl.predicted.punchangle );
- + VectorCopy( to->client.view_ofs, cl.predicted.viewofs );
- + }
- + else
- + {
- + vec3_t delta_origin, delta_punch, delta_vel;
- +
- + VectorSubtract( to->playerstate.origin, from->playerstate.origin, delta_origin );
- + VectorSubtract( to->client.velocity, from->client.velocity, delta_vel );
- + VectorSubtract( to->client.punchangle, from->client.punchangle, delta_punch );
- +
- + VectorMA( from->playerstate.origin, t, delta_origin, cl.predicted.origin );
- + VectorMA( from->client.velocity, t, delta_vel, cl.predicted.velocity );
- + VectorMA( from->client.punchangle, t, delta_punch, cl.predicted.punchangle );
- +
- + if( from->playerstate.usehull == to->playerstate.usehull )
- + {
- + vec3_t delta_viewofs;
- +
- + VectorSubtract( to->client.view_ofs, from->client.view_ofs, delta_viewofs );
- + VectorMA( from->client.view_ofs, t, delta_viewofs, cl.predicted.viewofs );
- + }
- + }
- +
- + cl.predicted.waterlevel = to->client.waterlevel;
- + cl.predicted.viewmodel = to->client.viewmodel;
- + cl.predicted.usehull = to->playerstate.usehull;
- +
- + if( to->client.flags & FL_ONGROUND )
- + {
- + cl_entity_t *ent = CL_GetEntityByIndex( cl.predicted.lastground );
- +
- + cl.predicted.onground = cl.predicted.lastground;
- + cl.predicted.moving = 0;
- +
- + if( ent )
- + {
- + vec3_t delta;
- + delta[0] = ent->curstate.origin[0] - ent->prevstate.origin[0];
- + delta[1] = ent->curstate.origin[1] - ent->prevstate.origin[1];
- + delta[2] = 0.0f;
- +
- + if( VectorLength( delta ) > 0.0f )
- + {
- + cl.predicted.correction_time = 0;
- + cl.predicted.moving = 1;
- + }
- + }
- + }
- + else
- + {
- + cl.predicted.onground = -1;
- + cl.predicted.moving = 0;
- + }
- +
- + if ( cl.predicted.correction_time > 0.0 && !cl_nosmooth->value && cl_smoothtime->value )
- + {
- + float d;
- + int i;
- +
- + cl.predicted.correction_time = cl.predicted.correction_time - host.frametime;
- +
- + if( cl_smoothtime->value <= 0 )
- + Cvar_SetFloat( "cl_smoothtime", 0.1 );
- +
- + if( cl.predicted.correction_time < 0 )
- + cl.predicted.correction_time = 0;
- +
- + if( cl_smoothtime->value <= cl.predicted.correction_time )
- + cl.predicted.correction_time = cl_smoothtime->value;
- +
- + d = cl.predicted.correction_time / cl_smoothtime->value;
- +
- + for( i = 0; i < 3; i++ )
- + {
- + cl.predicted.origin[i] = cl.predicted.lastorigin[i] + ( cl.predicted.origin[i] - cl.predicted.lastorigin[i] ) * (1.0 - d);
- + }
- + }
- +
- + VectorCopy( cl.predicted.origin, cl.predicted.lastorigin );
- + CL_SetIdealPitch();
- }
- +
- + CL_CheckPredictionError();
- }
- \ No newline at end of file
- diff --git b/engine/client/cl_remap.c a/engine/client/cl_remap.c
- index ec5ff8e..869512e 100644
- --- b/engine/client/cl_remap.c
- +++ a/engine/client/cl_remap.c
- @@ -127,7 +127,6 @@ void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomco
- raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
- ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR, NULL ); // do copy
- - GL_SetTextureType( ptexture->index, TEX_REMAP );
- // restore original palette
- memcpy( pal, paletteBackup, 768 );
- diff --git b/engine/client/cl_scrn.c a/engine/client/cl_scrn.c
- index f4dd7bf..4fe17b7 100644
- --- b/engine/client/cl_scrn.c
- +++ a/engine/client/cl_scrn.c
- @@ -44,21 +44,21 @@ static qboolean scr_init = false;
- SCR_DrawFPS
- ==============
- */
- -void SCR_DrawFPS( void )
- +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;
- - double newtime;
- char fpsstring[64];
- int offset;
- - if( cls.state != ca_active ) return;
- - if( !cl_showfps->integer || cl.background ) return;
- + if( cls.state != ca_active || !cl_showfps->integer || cl.background )
- + return;
- switch( cls.scrshot_action )
- {
- @@ -74,12 +74,12 @@ void SCR_DrawFPS( void )
- {
- framerate = framecount / (newtime - lasttime);
- lasttime = newtime;
- - nexttime = max( nexttime + 1, lasttime - 1 );
- + nexttime = Q_max( nexttime + 1.0, lasttime - 1.0 );
- framecount = 0;
- }
- - framecount++;
- calc = framerate;
- + framecount++;
- if( calc < 1.0f )
- {
- @@ -100,7 +100,7 @@ void SCR_DrawFPS( void )
- }
- Con_DrawStringLen( fpsstring, &offset, NULL );
- - Con_DrawString( scr_width->integer - offset - 3, 4, fpsstring, color );
- + Con_DrawString( scr_width->integer - offset - 4, height, fpsstring, color );
- }
- /*
- @@ -116,42 +116,36 @@ void SCR_NetSpeeds( void )
- 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( !net_speeds->integer ) return;
- - if( cls.state != ca_active ) return;
- + if( !net_speeds->integer || cls.demoplayback || cls.state != ca_active )
- + return;
- - switch( net_speeds->integer )
- + if( cl_serverframetime() != 0 )
- {
- - case 1:
- - if( cls.netchan.compress )
- - {
- - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal received from server:\n Huffman %s\nUncompressed %s\n",
- - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_received ), Q_memprint( cls.netchan.total_received_uncompressed ));
- - }
- - else
- - {
- - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal received from server:\nUncompressed %s\n",
- - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_received_uncompressed ));
- - }
- - break;
- - case 2:
- - if( cls.netchan.compress )
- - {
- - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal sended to server:\nHuffman %s\nUncompressed %s\n",
- - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_sended ), Q_memprint( cls.netchan.total_sended_uncompressed ));
- - }
- - else
- - {
- - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal sended to server:\nUncompressed %s\n",
- - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_sended_uncompressed ));
- - }
- - break;
- - default: return;
- + 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;
- }
- + if( cl_clientframetime() != 0 )
- + {
- + 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 sended to server: %s\nTotal received from 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_sended ), Q_memprint( cls.netchan.total_received ));
- +
- x = scr_width->integer - 320;
- - y = 256;
- + y = 384;
- Con_DrawStringLen( NULL, NULL, &height );
- MakeRGBA( color, 255, 255, 255, 255 );
- @@ -258,7 +252,7 @@ void SCR_MakeScreenShot( void )
- {
- // snapshots don't writes message about image
- if( cls.scrshot_action != scrshot_snapshot )
- - MsgDev( D_AICONSOLE, "Write %s\n", cls.shotname );
- + MsgDev( D_REPORT, "Write %s\n", cls.shotname );
- }
- else MsgDev( D_ERROR, "Unable to write %s\n", cls.shotname );
- @@ -619,9 +613,9 @@ void SCR_Init( void )
- 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( host.state != HOST_RESTART && !UI_LoadProgs( ))
- + if( !UI_LoadProgs( ))
- {
- - Msg( "^1Error: ^7can't initialize menu.dll\n" ); // there is non fatal for us
- + Msg( "^1Error: ^7can't initialize gameui.dll\n" ); // there is non fatal for us
- if( !host.developer ) host.developer = 1; // we need console, because menu is missing
- }
- @@ -629,14 +623,12 @@ void SCR_Init( void )
- SCR_InstallParticlePalette ();
- SCR_RegisterTextures ();
- SCR_InitCinematic();
- + CL_InitNetgraph();
- SCR_VidInit();
- - if( host.state != HOST_RESTART )
- - {
- - if( host.developer && Sys_CheckParm( "-toconsole" ))
- - Cbuf_AddText( "toggleconsole\n" );
- - else UI_SetActiveMenu( true );
- - }
- + if( host.developer && Sys_CheckParm( "-toconsole" ))
- + Cbuf_AddText( "toggleconsole\n" );
- + else UI_SetActiveMenu( true );
- scr_init = true;
- }
- @@ -650,9 +642,7 @@ void SCR_Shutdown( void )
- Cmd_RemoveCommand( "skyname" );
- Cmd_RemoveCommand( "viewpos" );
- UI_SetActiveMenu( false );
- -
- - if( host.state != HOST_RESTART )
- - UI_UnloadProgs();
- + UI_UnloadProgs();
- scr_init = false;
- }
- \ No newline at end of file
- diff --git b/engine/client/cl_tent.c a/engine/client/cl_tent.c
- index d047f9c..0681936 100644
- --- b/engine/client/cl_tent.c
- +++ a/engine/client/cl_tent.c
- @@ -32,7 +32,7 @@ TEMPENTS MANAGEMENT
- ==============================================================
- */
- -#define MAX_MUZZLEFLASH 4
- +#define MAX_MUZZLEFLASH 3
- #define SHARD_VOLUME 12.0f // on shard ever n^3 units
- #define SF_FUNNEL_REVERSE 1
- @@ -65,7 +65,6 @@ void CL_RegisterMuzzleFlashes( void )
- cl_muzzleflash[0] = CL_FindModelIndex( "sprites/muzzleflash1.spr" );
- cl_muzzleflash[1] = CL_FindModelIndex( "sprites/muzzleflash2.spr" );
- cl_muzzleflash[2] = CL_FindModelIndex( "sprites/muzzleflash3.spr" );
- - cl_muzzleflash[3] = CL_FindModelIndex( "sprites/muzzleflash.spr" );
- // update registration for shellchrome
- cls.hChromeSprite = pfnSPR_Load( "sprites/shellchrome.spr" );
- @@ -442,6 +441,9 @@ void CL_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
- if( !pent || Mod_GetType( modelIndex ) == mod_bad )
- return;
- + if( pent->curstate.modelindex <= 0 )
- + return;
- +
- count = density + 1;
- density = count * 3 + 6;
- @@ -524,7 +526,7 @@ void CL_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIn
- pTemp->x = origin[0];
- pTemp->y = origin[1];
- - angle = Com_RandomLong( -M_PI, M_PI );
- + angle = Com_RandomFloat( -M_PI, M_PI );
- SinCos( angle, &sine, &cosine );
- zspeed = Com_RandomLong( 80, 140 );
- @@ -569,7 +571,7 @@ void CL_BubbleTrail( const vec3_t start, const vec3_t end, float flWaterZ, int m
- pTemp->x = origin[0];
- pTemp->y = origin[1];
- - angle = Com_RandomLong( -M_PI, M_PI );
- + angle = Com_RandomFloat( -M_PI, M_PI );
- zspeed = Com_RandomLong( 80, 140 );
- VectorSet( pTemp->entity.baseline.origin, speed * cos( angle ), speed * sin( angle ), zspeed );
- @@ -757,8 +759,8 @@ void CL_MuzzleFlash( const vec3_t pos, int type )
- int index, modelIndex, frameCount;
- float scale;
- - index = bound( 0, type % 5, MAX_MUZZLEFLASH - 1 );
- - scale = (type / 5) * 0.1f;
- + index = ( type % 10 ) % MAX_MUZZLEFLASH;
- + scale = ( type / 10 ) * 0.1f;
- if( scale == 0.0f ) scale = 0.5f;
- modelIndex = cl_muzzleflash[index];
- @@ -2343,7 +2345,7 @@ void CL_SetLightstyle( int style, const char *s, float f )
- break;
- }
- }
- - MsgDev( D_AICONSOLE, "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
- + MsgDev( D_REPORT, "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
- }
- /*
- @@ -2650,7 +2652,7 @@ int CL_DecalIndexFromName( const char *name )
- return 0;
- // look through the loaded sprite name list for SpriteName
- - for( i = 0; i < MAX_DECALS && host.draw_decals[i+1][0]; i++ )
- + for( i = 0; i < (MAX_DECALS - 1) && host.draw_decals[i+1][0]; i++ )
- {
- if( !Q_stricmp( name, host.draw_decals[i+1] ))
- return i+1;
- diff --git b/engine/client/cl_video.c a/engine/client/cl_video.c
- index 2160274..4a7dea0 100644
- --- b/engine/client/cl_video.c
- +++ a/engine/client/cl_video.c
- @@ -59,14 +59,17 @@ qboolean SCR_NextMovie( void )
- {
- string str;
- - S_StopAllSounds();
- - SCR_StopCinematic();
- -
- if( cls.movienum == -1 )
- + {
- + S_StopAllSounds();
- + SCR_StopCinematic();
- return false; // don't play movies
- + }
- if( !cls.movies[cls.movienum][0] || cls.movienum == MAX_MOVIES )
- {
- + S_StopAllSounds();
- + SCR_StopCinematic();
- cls.movienum = -1;
- return false;
- }
- @@ -146,7 +149,10 @@ void SCR_RunCinematic( void )
- return;
- if( !AVI_IsActive( cin_state ))
- + {
- + SCR_NextMovie( );
- return;
- + }
- if( UI_IsVisible( ))
- {
- diff --git b/engine/client/cl_view.c a/engine/client/cl_view.c
- index a587f65..221b49b 100644
- --- b/engine/client/cl_view.c
- +++ a/engine/client/cl_view.c
- @@ -20,194 +20,6 @@ GNU General Public License for more details.
- #include "gl_local.h"
- #include "vgui_draw.h"
- -/*
- -===============
- -V_SetupRefDef
- -
- -update refdef values each frame
- -===============
- -*/
- -void V_SetupRefDef( void )
- -{
- - cl_entity_t *clent;
- - int size;
- - int sb_lines;
- -
- - clent = CL_GetLocalPlayer ();
- -
- - clgame.entities->curstate.scale = clgame.movevars.waveHeight;
- - clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
- - clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
- - clgame.viewent.curstate.number = cl.playernum + 1;
- - clgame.viewent.curstate.entityType = ET_NORMAL;
- - clgame.viewent.index = cl.playernum + 1;
- -
- - cl.refdef.movevars = &clgame.movevars;
- - cl.refdef.onground = ( cl.frame.client.flags & FL_ONGROUND ) ? 1 : 0;
- - cl.refdef.health = cl.frame.client.health;
- - cl.refdef.playernum = cl.playernum;
- - cl.refdef.max_entities = clgame.maxEntities;
- - cl.refdef.maxclients = cl.maxclients;
- - cl.refdef.time = cl.time;
- - cl.refdef.frametime = cl.time - cl.oldtime;
- - cl.refdef.demoplayback = cls.demoplayback;
- - cl.refdef.smoothing = cl_smooth->integer;
- - cl.refdef.viewsize = scr_viewsize->integer;
- - cl.refdef.waterlevel = cl.frame.client.waterlevel;
- - cl.refdef.onlyClientDraw = 0; // reset clientdraw
- - cl.refdef.hardware = true; // always true
- - cl.refdef.spectator = (clent->curstate.spectator != 0);
- - cl.refdef.nextView = 0;
- -
- - SCR_AddDirtyPoint( 0, 0 );
- - SCR_AddDirtyPoint( scr_width->integer - 1, scr_height->integer - 1 );
- -
- - if( cl.refdef.viewsize >= 120 )
- - sb_lines = 0; // no status bar at all
- - else if( cl.refdef.viewsize >= 110 )
- - sb_lines = 24; // no inventory
- - else sb_lines = 48;
- -
- - size = min( scr_viewsize->integer, 100 );
- -
- - cl.refdef.viewport[2] = scr_width->integer * size / 100;
- - cl.refdef.viewport[3] = scr_height->integer * size / 100;
- -
- - if( cl.refdef.viewport[3] > scr_height->integer - sb_lines )
- - cl.refdef.viewport[3] = scr_height->integer - sb_lines;
- - if( cl.refdef.viewport[3] > scr_height->integer )
- - cl.refdef.viewport[3] = scr_height->integer;
- -
- - cl.refdef.viewport[0] = (scr_width->integer - cl.refdef.viewport[2]) / 2;
- - cl.refdef.viewport[1] = (scr_height->integer - sb_lines - cl.refdef.viewport[3]) / 2;
- -
- - // calc FOV
- - cl.refdef.fov_x = cl.data.fov; // this is a final fov value
- - cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] );
- -
- - // adjust FOV for widescreen
- - if( glState.wideScreen && r_adjust_fov->integer )
- - V_AdjustFov( &cl.refdef.fov_x, &cl.refdef.fov_y, cl.refdef.viewport[2], cl.refdef.viewport[3], false );
- -
- - if( CL_IsPredicted( ) && !cl.refdef.demoplayback )
- - {
- - VectorMA( cl.predicted_origin, -cl.lerpBack, cl.prediction_error, cl.refdef.simorg );
- - VectorCopy( cl.predicted_origin, cl.refdef.simorg );
- - VectorCopy( cl.predicted_velocity, cl.refdef.simvel );
- - VectorCopy( cl.predicted_viewofs, cl.refdef.viewheight );
- - VectorCopy( cl.predicted_punchangle, cl.refdef.punchangle );
- - }
- - else
- - {
- - VectorCopy( cl.frame.client.origin, cl.refdef.simorg );
- - VectorCopy( cl.frame.client.view_ofs, cl.refdef.viewheight );
- - VectorCopy( cl.frame.client.velocity, cl.refdef.simvel );
- - VectorCopy( cl.frame.client.punchangle, cl.refdef.punchangle );
- - }
- -}
- -
- -/*
- -===============
- -V_SetupOverviewState
- -
- -Get initial overview values
- -===============
- -*/
- -void V_SetupOverviewState( void )
- -{
- - ref_overview_t *ov = &clgame.overView;
- - float mapAspect, screenAspect, aspect;
- -
- - ov->rotated = ( world.size[1] <= world.size[0] ) ? true : false;
- -
- - // calculate nearest aspect
- - mapAspect = world.size[!ov->rotated] / world.size[ov->rotated];
- - screenAspect = (float)glState.width / (float)glState.height;
- - aspect = max( mapAspect, screenAspect );
- -
- - ov->zNear = world.maxs[2];
- - ov->zFar = world.mins[2];
- - ov->flZoom = ( 8192.0f / world.size[ov->rotated] ) / aspect;
- -
- - VectorAverage( world.mins, world.maxs, ov->origin );
- -}
- -
- -/*
- -===============
- -V_WriteOverviewScript
- -
- -Create overview scrip file
- -===============
- -*/
- -void V_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%.f\t%.f\t%.f\n", ov->origin[0], ov->origin[1], ov->zFar + 1 );
- - 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%.f\n", ov->zFar + 1 ); // ???
- - FS_Print( f, "}\n" );
- -
- - FS_Close( f );
- -}
- -
- -/*
- -===============
- -V_ProcessOverviewCmds
- -
- -Transform user movement into overview adjust
- -===============
- -*/
- -void V_ProcessOverviewCmds( usercmd_t *cmd )
- -{
- - ref_overview_t *ov = &clgame.overView;
- - int sign = 1;
- -
- - if( !gl_overview->integer ) return;
- -
- - if( ov->flZoom < 0.0f ) sign = -1;
- -
- - if( cmd->upmove > 0.0f ) ov->zNear += 1.0f;
- - else if( cmd->upmove < 0.0f ) ov->zNear -= 1.0f;
- -
- - if( cmd->buttons & IN_JUMP ) ov->zFar += 1.0f;
- - else if( cmd->buttons & IN_DUCK ) ov->zFar -= 1.0f;
- -
- - if( cmd->buttons & IN_FORWARD ) ov->origin[ov->rotated] -= sign * 1.0f;
- - else if( cmd->buttons & IN_BACK ) ov->origin[ov->rotated] += sign * 1.0f;
- -
- - if( ov->rotated )
- - {
- - if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
- - ov->origin[0] -= sign * 1.0f;
- - else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
- - ov->origin[0] += sign * 1.0f;
- - }
- - else
- - {
- - if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
- - ov->origin[1] += sign * 1.0f;
- - else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
- - ov->origin[1] -= sign * 1.0f;
- - }
- -
- - if( cmd->buttons & IN_ATTACK ) ov->flZoom += 0.01f;
- - else if( cmd->buttons & IN_ATTACK2 ) ov->flZoom -= 0.01f;
- -
- - if( ov->flZoom == 0.0f ) ov->flZoom = 0.0001f; // to prevent disivion by zero
- -}
- /*
- ===============
- @@ -216,7 +28,7 @@ V_MergeOverviewRefdef
- merge refdef with overview settings
- ===============
- */
- -void V_MergeOverviewRefdef( ref_params_t *fd )
- +void V_MergeOverviewRefdef( void )
- {
- ref_overview_t *ov = &clgame.overView;
- float aspect;
- @@ -243,99 +55,134 @@ void V_MergeOverviewRefdef( ref_params_t *fd )
- ov->flZoom, ov->origin[0], ov->origin[1], ov->origin[2], ov->zNear, ov->zFar, ov->rotated );
- }
- - VectorCopy( ov->origin, fd->vieworg );
- - fd->vieworg[2] = ov->zFar + ov->zNear;
- - Vector2Copy( fd->vieworg, mins );
- - Vector2Copy( fd->vieworg, maxs );
- + VectorCopy( ov->origin, cl.refdef.vieworg );
- + cl.refdef.vieworg[2] = ov->zFar + ov->zNear;
- + Vector2Copy( cl.refdef.vieworg, mins );
- + Vector2Copy( cl.refdef.vieworg, maxs );
- mins[!ov->rotated] += ov->xLeft;
- maxs[!ov->rotated] += ov->xRight;
- mins[ov->rotated] += ov->xTop;
- maxs[ov->rotated] += ov->xBottom;
- - fd->viewangles[0] = 90.0f;
- - fd->viewangles[1] = 90.0f;
- - fd->viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
- + cl.refdef.viewangles[0] = 90.0f;
- + cl.refdef.viewangles[1] = 90.0f;
- + cl.refdef.viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
- Mod_SetOrthoBounds( mins, maxs );
- }
- /*
- ===============
- -V_ProcessShowTexturesCmds
- +V_CalcViewRect
- -navigate around texture atlas
- +calc frame rectangle (Quake1 style)
- ===============
- */
- -void V_ProcessShowTexturesCmds( usercmd_t *cmd )
- +void V_CalcViewRect( void )
- {
- - static int oldbuttons;
- - int changed;
- - int pressed, released;
- + int size, sb_lines;
- +
- + if( scr_viewsize->integer >= 120 )
- + sb_lines = 0; // no status bar at all
- + else if( scr_viewsize->integer >= 110 )
- + sb_lines = 24; // no inventory
- + else sb_lines = 48;
- - if( !gl_showtextures->integer ) return;
- + size = Q_min( scr_viewsize->integer, 100 );
- +
- + cl.refdef.viewport[2] = scr_width->integer * size / 100;
- + cl.refdef.viewport[3] = scr_height->integer * size / 100;
- +
- + if( cl.refdef.viewport[3] > scr_height->integer - sb_lines )
- + cl.refdef.viewport[3] = scr_height->integer - sb_lines;
- + if( cl.refdef.viewport[3] > scr_height->integer )
- + cl.refdef.viewport[3] = scr_height->integer;
- - changed = (oldbuttons ^ cmd->buttons);
- - pressed = changed & cmd->buttons;
- - released = changed & (~cmd->buttons);
- + cl.refdef.viewport[0] = ( scr_width->integer - cl.refdef.viewport[2] ) / 2;
- + cl.refdef.viewport[1] = ( scr_height->integer - sb_lines - cl.refdef.viewport[3] ) / 2;
- - if( released & ( IN_RIGHT|IN_MOVERIGHT ))
- - Cvar_SetFloat( "r_showtextures", gl_showtextures->integer + 1 );
- - if( released & ( IN_LEFT|IN_MOVELEFT ))
- - Cvar_SetFloat( "r_showtextures", max( 1, gl_showtextures->integer - 1 ));
- - oldbuttons = cmd->buttons;
- }
- /*
- ===============
- -V_CalcRefDef
- +V_SetupRefDef
- -sets cl.refdef view values
- +update refdef values each frame
- ===============
- */
- -void V_CalcRefDef( void )
- +void V_SetupRefDef( void )
- {
- - R_Set2DMode( false );
- - tr.framecount++; // g-cont. keep actual frame for all viewpasses
- + cl_entity_t *clent;
- - do
- - {
- - clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
- - V_MergeOverviewRefdef( &cl.refdef );
- - R_RenderFrame( &cl.refdef, true );
- - cl.refdef.onlyClientDraw = false;
- - } while( cl.refdef.nextView );
- + // compute viewport rectangle
- + V_CalcViewRect();
- - // Xash3D extension. draw debug triangles on a server
- - SV_DrawDebugTriangles ();
- + clent = CL_GetLocalPlayer ();
- - SCR_AddDirtyPoint( cl.refdef.viewport[0], cl.refdef.viewport[1] );
- - SCR_AddDirtyPoint( cl.refdef.viewport[0] + cl.refdef.viewport[2] - 1, cl.refdef.viewport[1] + cl.refdef.viewport[3] - 1 );
- -}
- + clgame.entities->curstate.scale = clgame.movevars.waveHeight;
- -//============================================================================
- + cl.refdef.movevars = &clgame.movevars;
- + cl.refdef.health = cl.frame.client.health;
- + cl.refdef.playernum = cl.playernum;
- + cl.refdef.max_entities = clgame.maxEntities;
- + cl.refdef.maxclients = cl.maxclients;
- + cl.refdef.time = cl.time;
- + cl.refdef.frametime = cl.time - cl.oldtime;
- + cl.refdef.demoplayback = cls.demoplayback;
- + cl.refdef.viewsize = scr_viewsize->integer;
- + cl.refdef.onlyClientDraw = 0; // reset clientdraw
- + cl.refdef.hardware = true; // always true
- + cl.refdef.spectator = (clent->curstate.spectator != 0);
- + cl.refdef.smoothing = cl.first_frame; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
- + cl.scr_fov = bound( 1.0f, cl.scr_fov, 179.0f );
- + cl.refdef.nextView = 0;
- -/*
- -==================
- -V_RenderView
- + // calc FOV
- + cl.refdef.fov_x = cl.scr_fov; // this is a final fov value
- + cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] );
- -==================
- -*/
- -void V_RenderView( void )
- -{
- - if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
- - return; // still loading
- + // adjust FOV for widescreen
- + if( glState.wideScreen && r_adjust_fov->integer )
- + V_AdjustFov( &cl.refdef.fov_x, &cl.refdef.fov_y, cl.refdef.viewport[2], cl.refdef.viewport[3], false );
- +
- + if( CL_IsPredicted( ) && !cl.first_frame )
- + {
- + VectorCopy( cl.predicted.origin, cl.refdef.simorg );
- + VectorCopy( cl.predicted.velocity, cl.refdef.simvel );
- + VectorCopy( cl.predicted.viewofs, cl.refdef.viewheight );
- + VectorCopy( cl.predicted.punchangle, cl.refdef.punchangle );
- + cl.refdef.onground = ( cl.predicted.onground == -1 ) ? false : true;
- + cl.refdef.waterlevel = cl.predicted.waterlevel;
- + }
- + else
- + {
- + VectorCopy( cl.frame.client.origin, cl.refdef.simorg );
- + VectorCopy( cl.frame.client.view_ofs, cl.refdef.viewheight );
- + VectorCopy( cl.frame.client.velocity, cl.refdef.simvel );
- + VectorCopy( cl.frame.client.punchangle, cl.refdef.punchangle );
- + cl.refdef.onground = (cl.frame.client.flags & FL_ONGROUND) ? 1 : 0;
- + cl.refdef.waterlevel = cl.frame.client.waterlevel;
- + }
- +
- + // setup the viewent variables
- + if( cl_lw->value ) clgame.viewent.curstate.modelindex = cl.predicted.viewmodel;
- + else clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
- + clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
- + clgame.viewent.curstate.number = cl.playernum + 1;
- + clgame.viewent.curstate.entityType = ET_NORMAL;
- + clgame.viewent.index = cl.playernum + 1;
- - if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
- + // calc refdef first so viewent can get an actual
- + // player position, angles etc
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- {
- - cl.force_refdef = false;
- + clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
- + V_MergeOverviewRefdef();
- R_ClearScene ();
- CL_AddEntities ();
- - V_SetupRefDef ();
- }
- -
- - V_CalcRefDef ();
- }
- /*
- @@ -361,7 +208,7 @@ qboolean V_PreRender( void )
- {
- if(( host.realtime - cls.disable_screen ) > cl_timeout->value )
- {
- - MsgDev( D_NOTE, "V_PreRender: loading plaque timed out.\n" );
- + MsgDev( D_ERROR, "V_PreRender: loading plaque timed out\n" );
- cls.disable_screen = 0.0f;
- }
- return false;
- @@ -372,6 +219,53 @@ qboolean V_PreRender( void )
- return true;
- }
- +//============================================================================
- +
- +/*
- +==================
- +V_RenderView
- +
- +==================
- +*/
- +void V_RenderView( void )
- +{
- + if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
- + return; // still loading
- +
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
- + {
- + cl.force_refdef = false;
- +
- + R_ClearScene ();
- + CL_AddEntities ();
- + V_SetupRefDef ();
- + }
- + }
- +
- + R_Set2DMode( false );
- + SCR_AddDirtyPoint( 0, 0 );
- + SCR_AddDirtyPoint( scr_width->integer - 1, scr_height->integer - 1 );
- +
- + tr.framecount++; // g-cont. keep actual frame for all viewpasses
- +
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + do
- + {
- + clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
- + V_MergeOverviewRefdef();
- + R_RenderFrame( &cl.refdef, true );
- + cl.refdef.onlyClientDraw = false;
- + } while( cl.refdef.nextView );
- + }
- + else R_RenderFrame( &cl.refdef, true );
- +
- + // draw debug triangles on a server
- + SV_DrawDebugTriangles ();
- +}
- +
- /*
- ==================
- V_PostRender
- @@ -380,11 +274,12 @@ V_PostRender
- */
- void V_PostRender( void )
- {
- - qboolean draw_2d = false;
- + static double oldtime;
- + qboolean draw_2d = false;
- R_Set2DMode( true );
- - if( cls.state == ca_active )
- + if( cls.state == ca_active && cls.scrshot_action != scrshot_mapshot )
- {
- SCR_TileClear();
- CL_DrawHUD( CL_ACTIVE );
- @@ -404,16 +299,28 @@ void V_PostRender( void )
- {
- SCR_RSpeeds();
- SCR_NetSpeeds();
- - SCR_DrawFPS();
- + SCR_DrawNetGraph();
- SV_DrawOrthoTriangles();
- CL_DrawDemoRecording();
- - R_ShowTextures();
- CL_DrawHUD( CL_CHANGELEVEL );
- + R_ShowTextures();
- Con_DrawConsole();
- UI_UpdateMenu( host.realtime );
- Con_DrawVersion();
- Con_DrawDebug(); // must be last
- - S_ExtraUpdate();
- +
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + S_ExtraUpdate();
- + }
- +
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + // don't update sound too fast
- + if(( host.realtime - oldtime ) >= HOST_FRAMETIME )
- + {
- + oldtime = host.realtime;
- + CL_ExtraUpdate();
- + }
- }
- SCR_MakeScreenShot();
- diff --git b/engine/client/client.h a/engine/client/client.h
- index 45f9b50..bc984ba 100644
- --- b/engine/client/client.h
- +++ a/engine/client/client.h
- @@ -37,7 +37,7 @@ GNU General Public License for more details.
- #define MAX_CDTRACKS 32
- #define MAX_IMAGES 256 // SpriteTextures
- #define MAX_EFRAGS 4096
- -#define MAX_REQUESTS 32
- +#define MAX_REQUESTS 64
- // screenshot types
- #define VID_SCREENSHOT 0
- @@ -49,6 +49,19 @@ GNU General Public License for more details.
- typedef int sound_t;
- //=============================================================================
- +typedef struct netbandwithgraph_s
- +{
- + word client;
- + word players;
- + word entities; // entities bytes, except for players
- + word tentities;// temp entities
- + word sound;
- + word event;
- + word usr;
- + word msgbytes;
- + word voicebytes;
- +} netbandwidthgraph_t;
- +
- typedef struct frame_s
- {
- // received from server
- @@ -58,7 +71,8 @@ typedef struct frame_s
- clientdata_t client; // local client private data
- entity_state_t playerstate[MAX_CLIENTS];
- - weapon_data_t weapondata[64];
- + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
- + netbandwidthgraph_t graphdata;
- int num_entities;
- int first_entity; // into the circular cl_packet_entities[]
- @@ -79,6 +93,9 @@ typedef struct runcmd_s
- int sendsize;
- } runcmd_t;
- +#define ANGLE_BACKUP 16
- +#define ANGLE_MASK (ANGLE_BACKUP - 1)
- +
- #define CMD_BACKUP MULTIPLAYER_BACKUP // allow a lot of command backups for very fast systems
- #define CMD_MASK (CMD_BACKUP - 1)
- @@ -87,6 +104,27 @@ extern int CL_UPDATE_BACKUP;
- #define INVALID_HANDLE 0xFFFF // for XashXT cache system
- +#define cl_serverframetime() (cl.mtime[0] - cl.mtime[1])
- +#define cl_clientframetime() (host.frametime)
- +
- +typedef struct
- +{
- + vec3_t origin; // generated by CL_PredictMovement
- + vec3_t viewofs;
- + vec3_t velocity;
- + vec3_t punchangle;
- + vec3_t origins[CMD_BACKUP];
- + vec3_t error;
- + vec3_t lastorigin;
- + double correction_time;
- + int viewmodel;
- + int onground;
- + int waterlevel;
- + int usehull;
- + int moving;
- + int lastground;
- +} cl_predicted_data_t; // data we got from prediction system
- +
- // the client_t structure is wiped completely at every
- // server map change
- typedef struct
- @@ -111,9 +149,10 @@ typedef struct
- int last_command_ack;
- int last_incoming_sequence;
- - qboolean force_send_usercmd;
- + qboolean send_reply;
- qboolean thirdperson;
- qboolean background; // not real game, just a background
- + qboolean first_frame; // first rendering frame
- uint checksum; // for catching cheater maps
- @@ -140,12 +179,7 @@ typedef struct
- event_state_t events;
- // predicting stuff
- - vec3_t predicted_origin; // generated by CL_PredictMovement
- - vec3_t predicted_viewofs;
- - vec3_t predicted_velocity;
- - vec3_t predicted_punchangle;
- - vec3_t predicted_origins[CMD_BACKUP];
- - vec3_t prediction_error;
- + cl_predicted_data_t predicted; // generated from CL_PredictMovement
- // server state information
- int playernum;
- @@ -163,6 +197,11 @@ typedef struct
- cl_entity_t *world;
- model_t *worldmodel; // pointer to world
- +
- + // weapon predict stuff
- + float scr_fov;
- + float weaponstarttime;
- + int weaponsequence;
- } client_t;
- /*
- @@ -316,6 +355,13 @@ typedef struct
- model_t *model; // for catch model changes
- } remap_info_t;
- +typedef enum
- +{
- + NET_REQUEST_CANCEL = 0, // request was cancelled for some reasons
- + NET_REQUEST_GAMEUI, // called from GameUI
- + NET_REQUEST_CLIENT, // called from Client
- +} net_request_type_t;
- +
- typedef struct
- {
- net_response_t resp;
- @@ -351,8 +397,9 @@ typedef struct
- movevars_t oldmovevars;
- playermove_t *pmove; // pmove state
- - int old_trace_hull; // used by PM_Push\Pop state
- - int oldcount; // used by PM_Push\Pop state
- + qboolean pushed; // used by PM_Push\Pop state
- + int oldviscount; // used by PM_Push\Pop state
- + int oldphyscount; // used by PM_Push\Pop state
- vec3_t player_mins[MAX_MAP_HULLS]; // 4 hulls allowed
- vec3_t player_maxs[MAX_MAP_HULLS]; // 4 hulls allowed
- @@ -376,7 +423,9 @@ typedef struct
- client_textmessage_t *titles; // title messages, not network messages
- int numTitles;
- + net_request_type_t request_type; // filter the requests
- net_request_t net_requests[MAX_REQUESTS]; // no reason to keep more
- + net_request_t *master_request; // queued master request
- efrag_t *free_efrags; // linked efrags
- cl_entity_t viewent; // viewmodel
- @@ -401,7 +450,7 @@ typedef struct
- long logo_xres;
- long logo_yres;
- float logo_length;
- -} menu_static_t;
- +} gameui_static_t;
- typedef struct
- {
- @@ -423,7 +472,6 @@ typedef struct
- byte *mempool; // client premamnent pool: edicts etc
- - int framecount;
- int quakePort; // a 16 bit value that allows quake servers
- // to work around address translating routers
- // g-cont. this port allow many copies of engine in multiplayer game
- @@ -502,7 +550,7 @@ extern "C" {
- extern client_t cl;
- extern client_static_t cls;
- extern clgame_static_t clgame;
- -extern menu_static_t gameui;
- +extern gameui_static_t gameui;
- #ifdef __cplusplus
- }
- @@ -512,15 +560,18 @@ extern menu_static_t gameui;
- // cvars
- //
- extern convar_t *cl_predict;
- -extern convar_t *cl_smooth;
- extern convar_t *cl_showfps;
- extern convar_t *cl_envshot_size;
- extern convar_t *cl_timeout;
- extern convar_t *cl_nodelta;
- extern convar_t *cl_interp;
- extern convar_t *cl_showerror;
- +extern convar_t *cl_nosmooth;
- +extern convar_t *cl_smoothtime;
- extern convar_t *cl_crosshair;
- extern convar_t *cl_testlights;
- +extern convar_t *cl_cmdrate;
- +extern convar_t *cl_updaterate;
- extern convar_t *cl_solid_players;
- extern convar_t *cl_idealpitchscale;
- extern convar_t *cl_allow_levelshots;
- @@ -528,6 +579,9 @@ extern convar_t *cl_lightstyle_lerping;
- extern convar_t *cl_draw_particles;
- extern convar_t *cl_levelshot_name;
- extern convar_t *cl_draw_beams;
- +extern convar_t *gl_showtextures;
- +extern convar_t *cl_bmodelinterp;
- +extern convar_t *cl_lw; // local weapons
- extern convar_t *scr_centertime;
- extern convar_t *scr_viewsize;
- extern convar_t *scr_download;
- @@ -586,6 +640,7 @@ void CL_WriteDemoUserCmd( int cmdnumber );
- void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
- void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
- qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
- +void CL_DemoInterpolateAngles( void );
- void CL_WriteDemoJumpTime( void );
- void CL_CloseDemoHeader( void );
- void CL_StopPlayback( void );
- @@ -632,11 +687,13 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize );
- client_textmessage_t *CL_TextMessageGet( const char *pName );
- int pfnDecalIndexFromName( const char *szDecalName );
- int pfnIndexFromTrace( struct pmtrace_s *pTrace );
- +void NetAPI_CancelAllRequests( void );
- int CL_FindModelIndex( const char *m );
- HSPRITE pfnSPR_Load( const char *szPicName );
- HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
- -void TextAdjustSize( int *x, int *y, int *w, int *h );
- void PicAdjustSize( float *x, float *y, float *w, float *h );
- +void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a );
- +void CL_FillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a );
- void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr );
- void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), pmtrace_t *tr );
- void CL_SetTraceHull( int hull );
- @@ -672,7 +729,13 @@ void SCR_MakeScreenShot( void );
- void SCR_MakeLevelShot( void );
- void SCR_NetSpeeds( void );
- void SCR_RSpeeds( void );
- -void SCR_DrawFPS( void );
- +void SCR_DrawFPS( int height );
- +
- +//
- +// cl_netgraph.c
- +//
- +void CL_InitNetgraph( void );
- +void SCR_DrawNetGraph( void );
- //
- // cl_view.c
- @@ -683,11 +746,7 @@ void V_Shutdown( void );
- qboolean V_PreRender( void );
- void V_PostRender( void );
- void V_RenderView( void );
- -void V_SetupOverviewState( void );
- -void V_ProcessOverviewCmds( usercmd_t *cmd );
- -void V_MergeOverviewRefdef( ref_params_t *fd );
- -void V_ProcessShowTexturesCmds( usercmd_t *cmd );
- -void V_WriteOverviewScript( void );
- +void V_SetupRefDef( void );
- //
- // cl_pmove.c
- @@ -705,6 +764,9 @@ cl_entity_t *CL_GetWaterEntity( const float *rgflPos );
- void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, qboolean runfuncs, double time );
- pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
- void CL_ClearPhysEnts( void );
- +void CL_PushPMStates( void );
- +void CL_PopPMStates( void );
- +void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
- //
- // cl_studio.c
- @@ -714,12 +776,13 @@ void CL_InitStudioAPI( void );
- //
- // cl_frame.c
- //
- -void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
- +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
- qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
- void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp );
- qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius );
- void CL_UpdateEntityFields( cl_entity_t *ent );
- qboolean CL_IsPlayerIndex( int idx );
- +void CL_SetIdealPitch( void );
- //
- // cl_remap.c
- @@ -761,6 +824,7 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType );
- void CL_RegisterMuzzleFlashes( void );
- void CL_ReadPointFile_f( void );
- void CL_ReadLineFile_f( void );
- +void CL_RunLightStyles( void );
- //
- // console.c
- @@ -769,6 +833,7 @@ extern convar_t *con_fontsize;
- qboolean Con_Visible( void );
- void Con_Init( void );
- void Con_VidInit( void );
- +void Con_Shutdown( void );
- void Con_ToggleConsole_f( void );
- void Con_ClearNotify( void );
- void Con_DrawDebug( void );
- @@ -786,7 +851,7 @@ void Con_CharEvent( int key );
- void Con_RestoreFont( void );
- void Key_Console( int key );
- void Key_Message( int key );
- -void Con_Close( void );
- +void Con_FastClose( void );
- //
- // s_main.c
- @@ -810,7 +875,7 @@ void S_RenderFrame( struct ref_params_s *fd );
- void S_ExtraUpdate( void );
- //
- -// cl_menu.c
- +// cl_gameui.c
- //
- void UI_UnloadProgs( void );
- qboolean UI_LoadProgs( void );
- diff --git b/engine/client/gl_backend.c a/engine/client/gl_backend.c
- index f0188a5..6f477e3 100644
- --- b/engine/client/gl_backend.c
- +++ a/engine/client/gl_backend.c
- @@ -76,7 +76,7 @@ void GL_BackendEndFrame( void )
- 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, r_viewleaf - cl.worldmodel->leafs );
- + 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 studio models drawn\n%3i sprites drawn",
- @@ -182,10 +182,6 @@ void GL_SelectTexture( GLint tmu )
- if( tmu < glConfig.max_texture_coords )
- pglClientActiveTextureARB( tmu + GL_TEXTURE0_ARB );
- }
- - else if( pglSelectTextureSGIS )
- - {
- - pglSelectTextureSGIS( tmu + GL_TEXTURE0_SGIS );
- - }
- }
- /*
- @@ -228,20 +224,31 @@ void GL_CleanUpTextureUnits( int last )
- }
- /*
- +==============
- +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 )
- {
- pglMultiTexCoord2f( texture + GL_TEXTURE0_ARB, s, t );
- }
- - else if( pglMTexCoord2fSGIS )
- - {
- - pglMTexCoord2fSGIS( texture + GL_TEXTURE0_SGIS, s, t );
- - }
- }
- /*
- @@ -470,6 +477,37 @@ void VID_ImageAdjustGamma( byte *in, uint width, uint height )
- }
- }
- +/*
- +===============
- +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;
- @@ -519,7 +557,7 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
- width = 320;
- break;
- case VID_MAPSHOT:
- - V_WriteOverviewScript(); // store overview script too
- + VID_WriteOverviewScript(); // store overview script too
- flags |= IMAGE_RESAMPLE|IMAGE_QUANTIZE; // GoldSrc request overviews in 8-bit format
- height = 768;
- width = 1024;
- @@ -637,8 +675,8 @@ void R_ShowTextures( void )
- {
- gltexture_t *image;
- float x, y, w, h;
- - int i, j, k, base_w, base_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;
- @@ -649,15 +687,16 @@ void R_ShowTextures( void )
- if( showHelp )
- {
- - CL_CenterPrint( "use '<-' and '->' keys for view all the textures", 0.25f );
- + 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;
- - base_h = 6;
- + base_w = 8; // textures view by horizontal
- + base_h = 6; // textures view by vertical
- rebuild_page:
- total = base_w * base_h;
- @@ -698,27 +737,27 @@ rebuild_page:
- 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(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE ))
- + 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->flags & TF_TEXTURE_RECTANGLE )
- + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
- pglTexCoord2f( image->width, 0 );
- else pglTexCoord2f( 1, 0 );
- pglVertex2f( x + w, y );
- - if( image->flags & TF_TEXTURE_RECTANGLE )
- + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
- pglTexCoord2f( image->width, image->height );
- else pglTexCoord2f( 1, 1 );
- pglVertex2f( x + w, y + h );
- - if( image->flags & TF_TEXTURE_RECTANGLE )
- + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
- pglTexCoord2f( 0, image->height );
- else pglTexCoord2f( 0, 1 );
- pglVertex2f( x, y + h );
- pglEnd();
- - if(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE ))
- + 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 );
- FS_FileBase( image->name, shortname );
- @@ -735,6 +774,4 @@ rebuild_page:
- CL_DrawCenterPrint ();
- pglFinish();
- -}
- -
- -//=======================================================
- \ No newline at end of file
- +}
- \ No newline at end of file
- diff --git b/engine/client/gl_beams.c a/engine/client/gl_beams.c
- index 0697335..d601abf 100644
- --- b/engine/client/gl_beams.c
- +++ a/engine/client/gl_beams.c
- @@ -33,7 +33,6 @@ typedef struct
- vec3_t color;
- float texcoord; // Y texture coordinate
- float width;
- - float alpha;
- } beamseg_t;
- static float rgNoise[NOISE_DIVISIONS+1]; // global noise array
- @@ -88,24 +87,12 @@ static cl_entity_t *CL_GetBeamEntityByIndex( int index )
- return ent;
- }
- -void BeamNormalizeColor( BEAM *pBeam, float r, float g, float b, float brightness )
- +void BeamNormalizeColor( BEAM *pBeam, int r, int g, int b, float brightness )
- {
- - float max, scale;
- -
- - max = max( max( r, g ), b );
- -
- - if( max == 0 )
- - {
- - pBeam->r = pBeam->g = pBeam->b = 255.0f;
- - pBeam->brightness = brightness;
- - }
- -
- - scale = 255.0f / max;
- -
- - pBeam->r = r * scale;
- - pBeam->g = g * scale;
- - pBeam->b = b * scale;
- - pBeam->brightness = ( brightness > 1.0f ) ? brightness : brightness * 255.0f;
- + pBeam->r = (float)r;
- + pBeam->g = (float)g;
- + pBeam->b = (float)b;
- + pBeam->brightness = brightness;
- }
- static qboolean ComputeBeamEntPosition( int beamEnt, vec3_t pt )
- @@ -269,7 +256,6 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
- vec3_t vPoint1, vPoint2;
- ASSERT( noiseIndex < ( NOISE_DIVISIONS << 16 ));
- - nextSeg.alpha = 1.0f;
- fraction = i * div;
- @@ -350,12 +336,12 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
- VectorMA( curSeg.pos, ( curSeg.width * 0.5f ), vAveNormal, vPoint1 );
- VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vAveNormal, vPoint2 );
- - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
- + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
- pglTexCoord2f( 0.0f, curSeg.texcoord );
- pglNormal3fv( vAveNormal );
- pglVertex3fv( vPoint1 );
- - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
- + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
- pglTexCoord2f( 1.0f, curSeg.texcoord );
- pglNormal3fv( vAveNormal );
- pglVertex3fv( vPoint2 );
- @@ -371,12 +357,12 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
- VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vLastNormal, vPoint2 );
- // specify the points.
- - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
- + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
- pglTexCoord2f( 0.0f, curSeg.texcoord );
- pglNormal3fv( vLastNormal );
- pglVertex3fv( vPoint1 );
- - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
- + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
- pglTexCoord2f( 1.0f, curSeg.texcoord );
- pglNormal3fv( vLastNormal );
- pglVertex3fv( vPoint2 );
- @@ -1442,12 +1428,10 @@ void CL_DrawBeam( BEAM *pbeam )
- pStart = CL_GetBeamEntityByIndex( pbeam->startEntity );
- if( pStart && pStart->curstate.rendermode != kRenderNormal )
- pbeam->brightness = pStart->curstate.renderamt;
- - }
- -
- - VectorScale( color, ( pbeam->brightness / 255.0f ), color );
- - VectorScale( color, ( 1.0f / 255.0f ), color );
- - pglShadeModel( GL_SMOOTH );
- + VectorScale( color, ( pbeam->brightness / 255.0f ), color );
- + VectorScale( color, ( 1.0f / 255.0f ), color );
- + }
- switch( pbeam->type )
- {
- @@ -1478,7 +1462,6 @@ void CL_DrawBeam( BEAM *pbeam )
- MsgDev( D_ERROR, "CL_DrawBeam: Unknown beam type %i\n", pbeam->type );
- break;
- }
- - pglShadeModel( GL_FLAT );
- }
- /*
- @@ -1517,9 +1500,9 @@ void CL_DrawCustomBeam( cl_entity_t *pbeam )
- beam.width = pbeam->curstate.scale;
- beam.amplitude = (float)(pbeam->curstate.body * 0.1f);
- beam.brightness = pbeam->curstate.renderamt;
- - beam.r = pbeam->curstate.rendercolor.r;
- - beam.g = pbeam->curstate.rendercolor.g;
- - beam.b = pbeam->curstate.rendercolor.b;
- + beam.r = pbeam->curstate.rendercolor.r / 255.0f;
- + beam.g = pbeam->curstate.rendercolor.g / 255.0f;
- + beam.b = pbeam->curstate.rendercolor.b / 255.0f;
- beam.flags = 0;
- VectorSubtract( beam.target, beam.source, beam.delta );
- @@ -1985,9 +1968,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
- life = (float)(MSG_ReadByte( msg ) * 0.1f);
- width = (float)(MSG_ReadByte( msg ) * 0.1f);
- noise = (float)(MSG_ReadByte( msg ) * 0.1f);
- - r = (float)MSG_ReadByte( msg );
- - g = (float)MSG_ReadByte( msg );
- - b = (float)MSG_ReadByte( msg );
- + r = (float)MSG_ReadByte( msg ) / 255.0f;
- + g = (float)MSG_ReadByte( msg ) / 255.0f;
- + b = (float)MSG_ReadByte( msg ) / 255.0f;
- brightness = (float)MSG_ReadByte( msg );
- speed = (float)(MSG_ReadByte( msg ) * 0.1f);
- CL_BeamPoints( start, end, modelIndex, life, width, noise, brightness, speed, startFrame,
- @@ -2004,9 +1987,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
- life = (float)(MSG_ReadByte( msg ) * 0.1f);
- width = (float)(MSG_ReadByte( msg ) * 0.1f);
- noise = (float)(MSG_ReadByte( msg ) * 0.01f);
- - r = (float)MSG_ReadByte( msg );
- - g = (float)MSG_ReadByte( msg );
- - b = (float)MSG_ReadByte( msg );
- + r = (float)MSG_ReadByte( msg ) / 255.0f;
- + g = (float)MSG_ReadByte( msg ) / 255.0f;
- + b = (float)MSG_ReadByte( msg ) / 255.0f;
- brightness = (float)MSG_ReadByte( msg );
- speed = (float)(MSG_ReadByte( msg ) * 0.1f);
- CL_BeamEntPoint( startEnt, end, modelIndex, life, width, noise, brightness, speed, startFrame,
- @@ -2034,9 +2017,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
- life = (float)(MSG_ReadByte( msg ) * 0.1f);
- width = (float)(MSG_ReadByte( msg ) * 0.1f);
- noise = (float)(MSG_ReadByte( msg ) * 0.01f);
- - r = (float)MSG_ReadByte( msg );
- - g = (float)MSG_ReadByte( msg );
- - b = (float)MSG_ReadByte( msg );
- + r = (float)MSG_ReadByte( msg ) / 255.0f;
- + g = (float)MSG_ReadByte( msg ) / 255.0f;
- + b = (float)MSG_ReadByte( msg ) / 255.0f;
- brightness = (float)MSG_ReadByte( msg );
- speed = (float)(MSG_ReadByte( msg ) * 0.1f);
- CL_BeamEnts( startEnt, endEnt, modelIndex, life, width, noise, brightness, speed, startFrame,
- @@ -2071,9 +2054,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
- life = (float)(MSG_ReadByte( msg ) * 0.1f);
- width = (float)MSG_ReadByte( msg );
- noise = (float)(MSG_ReadByte( msg ) * 0.1f);
- - r = (float)MSG_ReadByte( msg );
- - g = (float)MSG_ReadByte( msg );
- - b = (float)MSG_ReadByte( msg );
- + r = (float)MSG_ReadByte( msg ) / 255.0f;
- + g = (float)MSG_ReadByte( msg ) / 255.0f;
- + b = (float)MSG_ReadByte( msg ) / 255.0f;
- brightness = (float)MSG_ReadByte( msg );
- speed = (float)(MSG_ReadByte( msg ) * 0.1f);
- CL_BeamCirclePoints( beamType, start, end, modelIndex, life, width, noise, brightness, speed,
- @@ -2099,9 +2082,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
- life = (float)(MSG_ReadByte( msg ) * 0.1f);
- width = (float)(MSG_ReadByte( msg ) * 0.1f);
- noise = (float)(MSG_ReadByte( msg ) * 0.1f);
- - r = (float)MSG_ReadByte( msg );
- - g = (float)MSG_ReadByte( msg );
- - b = (float)MSG_ReadByte( msg );
- + r = (float)MSG_ReadByte( msg ) / 255.0f;
- + g = (float)MSG_ReadByte( msg ) / 255.0f;
- + b = (float)MSG_ReadByte( msg ) / 255.0f;
- brightness = (float)MSG_ReadByte( msg );
- speed = (float)(MSG_ReadByte( msg ) * 0.1f);
- CL_BeamRing( startEnt, endEnt, modelIndex, life, width, noise, brightness, speed, startFrame,
- @@ -2166,7 +2149,7 @@ void CL_ReadLineFile_f( void )
- if( token[0] != '-' )
- {
- - MsgDev( D_ERROR, "%s is corrupted\n" );
- + MsgDev( D_ERROR, "%s is corrupted\n", filename );
- break;
- }
- diff --git b/engine/client/gl_cull.c a/engine/client/gl_cull.c
- index 806c6e7..72eb1cb 100644
- --- b/engine/client/gl_cull.c
- +++ a/engine/client/gl_cull.c
- @@ -180,7 +180,7 @@ qboolean R_CullSurface( msurface_t *surf, uint clipflags )
- if( r_faceplanecull->integer && glState.faceCull != 0 )
- {
- - if( RI.currentWaveHeight == 0.0f )
- + if( e->curstate.scale == 0.0f )
- {
- if( !VectorIsNull( surf->plane->normal ))
- {
- diff --git b/engine/client/gl_decals.c a/engine/client/gl_decals.c
- index 57fe7c6..20371da 100644
- --- b/engine/client/gl_decals.c
- +++ a/engine/client/gl_decals.c
- @@ -404,22 +404,23 @@ static void R_DecalVertsLight( float *v, msurface_t *surf, int vertCount )
- {
- float s, t;
- mtexinfo_t *tex;
- - int j;
- + int j, sample_size;
- + sample_size = Mod_SampleSizeForFace( surf );
- tex = surf->texinfo;
- for( j = 0; j < vertCount; j++, v += VERTEXSIZE )
- {
- // lightmap texture coordinates
- s = DotProduct( v, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
- - s += surf->light_s * LM_SAMPLE_SIZE;
- - s += LM_SAMPLE_SIZE >> 1;
- - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
- + s += surf->light_s * sample_size;
- + s += sample_size >> 1;
- + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
- t = DotProduct( v, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
- - t += surf->light_t * LM_SAMPLE_SIZE;
- - t += LM_SAMPLE_SIZE >> 1;
- - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
- + t += surf->light_t * sample_size;
- + t += sample_size >> 1;
- + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
- v[5] = s;
- v[6] = t;
- @@ -1232,7 +1233,11 @@ void R_DecalRemoveAll( int textureIndex )
- {
- pdecal = &gDecalPool[i];
- - if( !textureIndex || pdecal->texture == textureIndex )
- + // don't remove permanent decals
- + if( pdecal->flags & FDECAL_PERMANENT )
- + continue;
- +
- + if( !textureIndex || ( pdecal->texture == textureIndex ))
- R_DecalUnlink( pdecal );
- }
- }
- diff --git b/engine/client/gl_draw.c a/engine/client/gl_draw.c
- index 9c8cf7c..d8620f4 100644
- --- b/engine/client/gl_draw.c
- +++ a/engine/client/gl_draw.c
- @@ -231,7 +231,7 @@ void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height,
- tex->height = rows;
- pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
- - GL_TexFilter( tex, false );
- + GL_ApplyTextureParams( tex );
- }
- /*
- diff --git b/engine/client/gl_export.h a/engine/client/gl_export.h
- index 9aefb51..1422401 100644
- --- b/engine/client/gl_export.h
- +++ a/engine/client/gl_export.h
- @@ -235,6 +235,29 @@ typedef float GLmatrix[16];
- #define GL_PROXY_TEXTURE_2D 0x8064
- #define GL_MAX_TEXTURE_SIZE 0x0D33
- +#define GL_RG 0x8227
- +#define GL_RG_INTEGER 0x8228
- +#define GL_R8 0x8229
- +#define GL_R16 0x822A
- +#define GL_RG8 0x822B
- +#define GL_RG16 0x822C
- +#define GL_R16F 0x822D
- +#define GL_R32F 0x822E
- +#define GL_RG16F 0x822F
- +#define GL_RG32F 0x8230
- +#define GL_R8I 0x8231
- +#define GL_R8UI 0x8232
- +#define GL_R16I 0x8233
- +#define GL_R16UI 0x8234
- +#define GL_R32I 0x8235
- +#define GL_R32UI 0x8236
- +#define GL_RG8I 0x8237
- +#define GL_RG8UI 0x8238
- +#define GL_RG16I 0x8239
- +#define GL_RG16UI 0x823A
- +#define GL_RG32I 0x823B
- +#define GL_RG32UI 0x823C
- +
- // texture coord name
- #define GL_S 0x2000
- #define GL_T 0x2001
- @@ -433,7 +456,7 @@ typedef float GLmatrix[16];
- #define GL_TEXTURE_WRAP_R 0x8072
- #define GL_MAX_3D_TEXTURE_SIZE 0x8073
- #define GL_TEXTURE_BINDING_3D 0x806A
- -
- +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
- #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910
- #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911
- #define GL_STENCIL_BACK_FUNC 0x8800
- @@ -441,6 +464,24 @@ typedef float GLmatrix[16];
- #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
- #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
- +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
- +#define GL_DRAW_BUFFER0_ARB 0x8825
- +#define GL_DRAW_BUFFER1_ARB 0x8826
- +#define GL_DRAW_BUFFER2_ARB 0x8827
- +#define GL_DRAW_BUFFER3_ARB 0x8828
- +#define GL_DRAW_BUFFER4_ARB 0x8829
- +#define GL_DRAW_BUFFER5_ARB 0x882A
- +#define GL_DRAW_BUFFER6_ARB 0x882B
- +#define GL_DRAW_BUFFER7_ARB 0x882C
- +#define GL_DRAW_BUFFER8_ARB 0x882D
- +#define GL_DRAW_BUFFER9_ARB 0x882E
- +#define GL_DRAW_BUFFER10_ARB 0x882F
- +#define GL_DRAW_BUFFER11_ARB 0x8830
- +#define GL_DRAW_BUFFER12_ARB 0x8831
- +#define GL_DRAW_BUFFER13_ARB 0x8832
- +#define GL_DRAW_BUFFER14_ARB 0x8833
- +#define GL_DRAW_BUFFER15_ARB 0x8834
- +
- #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
- #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C
- #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D
- @@ -614,6 +655,15 @@ typedef float GLmatrix[16];
- #define GL_DOT3_RGB_ARB 0x86AE
- #define GL_DOT3_RGBA_ARB 0x86AF
- +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18
- +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19
- +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A
- +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B
- +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C
- +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D
- +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF
- +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E
- +
- #define GL_MULTISAMPLE_ARB 0x809D
- #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
- #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
- @@ -719,6 +769,29 @@ typedef float GLmatrix[16];
- #define GL_MAX_TEXTURE_COORDS_ARB 0x8871
- #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
- +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
- +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
- +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
- +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
- +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
- +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
- +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
- +#define GL_DEBUG_SOURCE_API_ARB 0x8246
- +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
- +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
- +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
- +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
- +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
- +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
- +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
- +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
- +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
- +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
- +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
- +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
- +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
- +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
- +
- #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
- #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
- #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
- @@ -1153,6 +1226,10 @@ void ( APIENTRY *pglDisableVertexAttribArrayARB)(GLuint index);
- void ( APIENTRY *pglBindAttribLocationARB)(GLhandleARB programObj, GLuint index, const GLcharARB *name);
- void ( APIENTRY *pglGetActiveAttribARB)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
- GLint ( APIENTRY *pglGetAttribLocationARB)(GLhandleARB programObj, const GLcharARB *name);
- +void ( APIENTRY *pglBindFragDataLocation)(GLuint programObj, GLuint index, const GLcharARB *name);
- +void ( APIENTRY *pglVertexAttrib2fARB)( GLuint index, GLfloat x, GLfloat y );
- +void ( APIENTRY *pglVertexAttrib2fvARB)( GLuint index, const GLfloat *v );
- +void ( APIENTRY *pglVertexAttrib3fvARB)( GLuint index, const GLfloat *v );
- void ( APIENTRY *pglBindBufferARB) (GLenum target, GLuint buffer);
- void ( APIENTRY *pglDeleteBuffersARB) (GLsizei n, const GLuint *buffers);
- void ( APIENTRY *pglGenBuffersARB) (GLsizei n, GLuint *buffers);
- @@ -1169,8 +1246,36 @@ void ( APIENTRY *pglEndQueryARB) (GLenum target);
- void ( APIENTRY *pglGetQueryivARB) (GLenum target, GLenum pname, GLint *params);
- void ( APIENTRY *pglGetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params);
- void ( APIENTRY *pglGetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params);
- -void ( APIENTRY * pglSelectTextureSGIS) ( GLenum );
- -void ( APIENTRY * pglMTexCoord2fSGIS) ( GLenum, GLfloat, GLfloat );
- +typedef void ( APIENTRY *pglDebugProcARB)( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLcharARB* message, GLvoid* userParam );
- +void ( APIENTRY *pglDebugMessageControlARB)( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled );
- +void ( APIENTRY *pglDebugMessageInsertARB)( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* buf );
- +void ( APIENTRY *pglDebugMessageCallbackARB)( pglDebugProcARB callback, void* userParam );
- +GLuint ( APIENTRY *pglGetDebugMessageLogARB)( GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLuint* severities, GLsizei* lengths, char* messageLog );
- +GLboolean ( APIENTRY *pglIsRenderbuffer )(GLuint renderbuffer);
- +void ( APIENTRY *pglBindRenderbuffer )(GLenum target, GLuint renderbuffer);
- +void ( APIENTRY *pglDeleteRenderbuffers )(GLsizei n, const GLuint *renderbuffers);
- +void ( APIENTRY *pglGenRenderbuffers )(GLsizei n, GLuint *renderbuffers);
- +void ( APIENTRY *pglRenderbufferStorage )(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
- +void ( APIENTRY *pglRenderbufferStorageMultisample )(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
- +void ( APIENTRY *pglGetRenderbufferParameteriv )(GLenum target, GLenum pname, GLint *params);
- +GLboolean (APIENTRY *pglIsFramebuffer )(GLuint framebuffer);
- +void ( APIENTRY *pglBindFramebuffer )(GLenum target, GLuint framebuffer);
- +void ( APIENTRY *pglDeleteFramebuffers )(GLsizei n, const GLuint *framebuffers);
- +void ( APIENTRY *pglGenFramebuffers )(GLsizei n, GLuint *framebuffers);
- +GLenum ( APIENTRY *pglCheckFramebufferStatus )(GLenum target);
- +void ( APIENTRY *pglFramebufferTexture1D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
- +void ( APIENTRY *pglFramebufferTexture2D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
- +void ( APIENTRY *pglFramebufferTexture3D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer);
- +void ( APIENTRY *pglFramebufferTextureLayer )(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
- +void ( APIENTRY *pglFramebufferRenderbuffer )(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
- +void ( APIENTRY *pglGetFramebufferAttachmentParameteriv )(GLenum target, GLenum attachment, GLenum pname, GLint *params);
- +void ( APIENTRY *pglBlitFramebuffer )(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
- +void ( APIENTRY *pglDrawBuffersARB)( GLsizei n, const GLenum *bufs );
- +void ( APIENTRY *pglGenerateMipmap )( GLenum target );
- +void ( APIENTRY *pglBindVertexArray )( GLuint array );
- +void ( APIENTRY *pglDeleteVertexArrays )( GLsizei n, const GLuint *arrays );
- +void ( APIENTRY *pglGenVertexArrays )( GLsizei n, const GLuint *arrays );
- +GLboolean ( APIENTRY *pglIsVertexArray )( GLuint array );
- void ( APIENTRY * pglSwapInterval) ( int interval );
- extern void *pglGetProcAddress( const GLubyte * );
- BOOL ( WINAPI * pwglSwapBuffers)(HDC);
- @@ -1191,5 +1296,6 @@ BOOL ( WINAPI * pwglRealizeLayerPalette)(HDC, int, BOOL);
- BOOL ( WINAPI * pwglSwapLayerBuffers)(HDC, UINT);
- BOOL ( WINAPI * pwglSwapIntervalEXT)( int interval );
- HGLRC ( WINAPI * pwglCreateContextAttribsARB)( HDC hDC, HGLRC hShareContext, const int *attribList );
- +const char *( WINAPI * pwglGetExtensionsStringEXT)( void );
- #endif//GL_EXPORT_H
- \ No newline at end of file
- diff --git b/engine/client/gl_image.c a/engine/client/gl_image.c
- index e93e5e7..46e9cf8 100644
- --- b/engine/client/gl_image.c
- +++ a/engine/client/gl_image.c
- @@ -18,16 +18,13 @@ GNU General Public License for more details.
- #include "gl_local.h"
- #include "studio.h"
- -#define TEXTURES_HASH_SIZE 64
- +#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
- -static int r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
- -static int r_textureMagFilter = GL_LINEAR;
- -static gltexture_t r_textures[MAX_TEXTURES];
- -static gltexture_t *r_texturesHashTable[TEXTURES_HASH_SIZE];
- -static int r_numTextures;
- -static byte *scaledImage = NULL; // pointer to a scaled image
- -static byte data2D[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; // intermediate texbuffer
- -static rgbdata_t r_image; // generic pixelbuffer used for internal textures
- +static gltexture_t r_textures[MAX_TEXTURES];
- +static gltexture_t *r_texturesHashTable[TEXTURES_HASH_SIZE];
- +static int r_numTextures;
- +static byte data2D[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; // intermediate texbuffer
- +static rgbdata_t r_image; // generic pixelbuffer used for internal textures
- // internal tables
- static vec3_t r_luminanceTable[256]; // RGB to luminance
- @@ -43,7 +40,25 @@ static byte r_particleTexture[8][8] =
- {0,0,0,0,0,0,0,0},
- };
- -const char *GL_Target( GLenum target )
- +/*
- +=================
- +R_GetTexture
- +
- +acess to array elem
- +=================
- +*/
- +gltexture_t *R_GetTexture( GLenum texnum )
- +{
- + ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
- + return &r_textures[texnum];
- +}
- +
- +/*
- +=================
- +GL_TargetToString
- +=================
- +*/
- +static const char *GL_TargetToString( GLenum target )
- {
- switch( target )
- {
- @@ -55,6 +70,8 @@ const char *GL_Target( GLenum target )
- return "3D";
- case GL_TEXTURE_CUBE_MAP_ARB:
- return "Cube";
- + case GL_TEXTURE_2D_ARRAY_EXT:
- + return "Array";
- case GL_TEXTURE_RECTANGLE_EXT:
- return "Rect";
- }
- @@ -69,6 +86,7 @@ GL_Bind
- void GL_Bind( GLint tmu, GLenum texnum )
- {
- gltexture_t *texture;
- + GLuint glTarget;
- // missed texture ?
- if( texnum <= 0 ) texnum = tr.defaultTexture;
- @@ -79,12 +97,16 @@ void GL_Bind( GLint tmu, GLenum texnum )
- else tmu = glState.activeTMU;
- texture = &r_textures[texnum];
- + glTarget = texture->target;
- +
- + if( glTarget == GL_TEXTURE_2D_ARRAY_EXT )
- + glTarget = GL_TEXTURE_2D;
- - if( glState.currentTextureTargets[tmu] != texture->target )
- + if( glState.currentTextureTargets[tmu] != glTarget )
- {
- if( glState.currentTextureTargets[tmu] != GL_NONE )
- pglDisable( glState.currentTextureTargets[tmu] );
- - glState.currentTextureTargets[tmu] = texture->target;
- + glState.currentTextureTargets[tmu] = glTarget;
- pglEnable( glState.currentTextureTargets[tmu] );
- }
- @@ -97,125 +119,103 @@ void GL_Bind( GLint tmu, GLenum texnum )
- /*
- =================
- -R_GetTexture
- +GL_ApplyTextureParams
- =================
- */
- -gltexture_t *R_GetTexture( GLenum texnum )
- +void GL_ApplyTextureParams( gltexture_t *tex )
- {
- - ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
- - return &r_textures[texnum];
- -}
- + vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f };
- -/*
- -=================
- -GL_SetTextureType
- -
- -Just for debug (r_showtextures uses it)
- -=================
- -*/
- -void GL_SetTextureType( GLenum texnum, GLenum type )
- -{
- - if( texnum <= 0 ) return;
- - ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
- - r_textures[texnum].texType = type;
- -}
- -
- -/*
- -=================
- -GL_TexFilter
- -=================
- -*/
- -void GL_TexFilter( gltexture_t *tex, qboolean update )
- -{
- - qboolean allowNearest;
- - vec4_t zeroClampBorder = { 0.0f, 0.0f, 0.0f, 1.0f };
- - vec4_t alphaZeroClampBorder = { 0.0f, 0.0f, 0.0f, 0.0f };
- -
- - switch( tex->texType )
- - {
- - case TEX_NOMIP:
- - case TEX_CUBEMAP:
- - case TEX_LIGHTMAP:
- - allowNearest = false;
- - break;
- - default:
- - allowNearest = true;
- - break;
- - }
- + ASSERT( tex != NULL );
- // set texture filter
- - if( tex->flags & TF_DEPTHMAP )
- + if( FBitSet( tex->flags, TF_DEPTHMAP ))
- {
- - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- -
- - if( !( tex->flags & TF_NOCOMPARE ))
- + if( !FBitSet( tex->flags, TF_NOCOMPARE ))
- {
- - pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
- pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
- + pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
- }
- - if( tex->flags & TF_LUMINANCE )
- + if( FBitSet( tex->flags, TF_LUMINANCE ))
- pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE );
- else pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY );
- + if( FBitSet( tex->flags, TF_NEAREST ))
- + {
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
- + }
- + else
- + {
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- + }
- +
- + // allow max anisotropy as 1.0f on depth textures
- if( GL_Support( GL_ANISOTROPY_EXT ))
- pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f );
- }
- - else if( tex->flags & TF_NOMIPMAP )
- + else if( FBitSet( tex->flags, TF_NOMIPMAP ) || tex->numMips <= 1 )
- {
- - if( tex->flags & TF_NEAREST )
- + if( FBitSet( tex->flags, TF_NEAREST ))
- {
- pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
- pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
- }
- else
- {
- - if( r_textureMagFilter == GL_NEAREST && allowNearest )
- - {
- - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMagFilter );
- - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
- - }
- - else
- - {
- - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- - }
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
- }
- else
- {
- - if( tex->flags & TF_NEAREST )
- + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->integer )
- {
- pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
- pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
- }
- else
- {
- - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMinFilter );
- - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
- // set texture anisotropy if available
- - if( GL_Support( GL_ANISOTROPY_EXT ) && !( tex->flags & TF_ALPHACONTRAST ))
- + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ))
- pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value );
- // set texture LOD bias if available
- - if( GL_Support( GL_TEXTURE_LODBIAS ))
- + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ))
- pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value );
- }
- - if( update ) return;
- -
- - if( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT ))
- + // check if border is not supported
- + if( FBitSet( tex->flags, TF_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT ))
- {
- - // border is not support, use clamp instead
- - tex->flags &= ~(TF_BORDER||TF_ALPHA_BORDER);
- - tex->flags |= TF_CLAMP;
- + ClearBits( tex->flags, TF_BORDER );
- + SetBits( tex->flags, TF_CLAMP );
- }
- + // only seamless cubemaps allows wrap 'clamp_to_border"
- + if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && FBitSet( tex->flags, TF_BORDER ))
- + ClearBits( tex->flags, TF_BORDER );
- +
- // set texture wrap
- - if( tex->flags & TF_CLAMP )
- + if( FBitSet( tex->flags, TF_BORDER ))
- + {
- + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
- +
- + if( tex->target != GL_TEXTURE_1D )
- + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
- +
- + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB )
- + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER );
- +
- + pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, border );
- + }
- + else if( FBitSet( tex->flags, TF_CLAMP ))
- {
- if( GL_Support( GL_CLAMPTOEDGE_EXT ))
- {
- @@ -238,21 +238,6 @@ void GL_TexFilter( gltexture_t *tex, qboolean update )
- pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP );
- }
- }
- - else if( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER ))
- - {
- - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
- -
- - if( tex->target != GL_TEXTURE_1D )
- - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
- -
- - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB )
- - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER );
- -
- - if( tex->flags & TF_BORDER )
- - pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, zeroClampBorder );
- - else if( tex->flags & TF_ALPHA_BORDER )
- - pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, alphaZeroClampBorder );
- - }
- else
- {
- pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_REPEAT );
- @@ -267,53 +252,49 @@ void GL_TexFilter( gltexture_t *tex, qboolean update )
- /*
- =================
- -R_SetTextureParameters
- +GL_UpdateTextureParams
- =================
- */
- -void R_SetTextureParameters( void )
- +static void GL_UpdateTextureParams( int iTexture )
- {
- - gltexture_t *texture;
- - int i;
- + gltexture_t *tex = &r_textures[iTexture];
- - if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST" ))
- - {
- - r_textureMinFilter = GL_NEAREST;
- - r_textureMagFilter = GL_NEAREST;
- - }
- - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR" ))
- - {
- - r_textureMinFilter = GL_LINEAR;
- - r_textureMagFilter = GL_LINEAR;
- - }
- - else if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST_MIPMAP_NEAREST" ))
- - {
- - r_textureMinFilter = GL_NEAREST_MIPMAP_NEAREST;
- - r_textureMagFilter = GL_NEAREST;
- - }
- - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR_MIPMAP_NEAREST" ))
- - {
- - r_textureMinFilter = GL_LINEAR_MIPMAP_NEAREST;
- - r_textureMagFilter = GL_LINEAR;
- - }
- - else if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST_MIPMAP_LINEAR" ))
- - {
- - r_textureMinFilter = GL_NEAREST_MIPMAP_LINEAR;
- - r_textureMagFilter = GL_NEAREST;
- - }
- - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR_MIPMAP_LINEAR" ))
- + ASSERT( tex != NULL );
- +
- + if( !tex->texnum ) return; // free slot
- +
- + GL_Bind( GL_TEXTURE0, iTexture );
- +
- + // set texture anisotropy if available
- + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP ))
- + pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value );
- +
- + // set texture LOD bias if available
- + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP ))
- + pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value );
- +
- + if( tex->numMips <= 1 ) return;
- +
- + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->integer )
- {
- - r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
- - r_textureMagFilter = GL_LINEAR;
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
- }
- else
- {
- - MsgDev( D_ERROR, "gl_texturemode invalid mode %s, defaulting to GL_LINEAR_MIPMAP_LINEAR\n", gl_texturemode->string );
- - Cvar_Set( "gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
- - r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
- - r_textureMagFilter = GL_LINEAR;
- + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
- + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
- +}
- - gl_texturemode->modified = false;
- +/*
- +=================
- +R_SetTextureParameters
- +=================
- +*/
- +void R_SetTextureParameters( void )
- +{
- + int i;
- if( GL_Support( GL_ANISOTROPY_EXT ))
- {
- @@ -323,222 +304,21 @@ void R_SetTextureParameters( void )
- Cvar_SetFloat( "gl_anisotropy", 1.0f );
- }
- - gl_texture_anisotropy->modified = false;
- -
- - if( GL_Support( GL_TEXTURE_LODBIAS ))
- + if( GL_Support( GL_TEXTURE_LOD_BIAS ))
- {
- - if( gl_texture_lodbias->value > glConfig.max_texture_lodbias )
- - Cvar_SetFloat( "gl_texture_lodbias", glConfig.max_texture_lodbias );
- - else if( gl_texture_lodbias->value < -glConfig.max_texture_lodbias )
- - Cvar_SetFloat( "gl_texture_lodbias", -glConfig.max_texture_lodbias );
- + if( gl_texture_lodbias->value < -glConfig.max_texture_lod_bias )
- + Cvar_SetFloat( "gl_texture_lodbias", -glConfig.max_texture_lod_bias );
- + else if( gl_texture_lodbias->value > glConfig.max_texture_lod_bias )
- + Cvar_SetFloat( "gl_texture_lodbias", glConfig.max_texture_lod_bias );
- }
- + gl_texture_anisotropy->modified = false;
- gl_texture_lodbias->modified = false;
- + gl_texture_nearest->modified = false;
- // change all the existing mipmapped texture objects
- - for( i = 0, texture = r_textures; i < r_numTextures; i++, texture++ )
- - {
- - if( !texture->texnum ) continue; // free slot
- - GL_Bind( GL_TEXTURE0, i );
- - GL_TexFilter( texture, true );
- - }
- -}
- -
- -/*
- -===============
- -R_TextureList_f
- -===============
- -*/
- -void R_TextureList_f( void )
- -{
- - gltexture_t *image;
- - int i, texCount, bytes = 0;
- -
- - Msg( "\n" );
- - Msg(" -w-- -h-- -size- -fmt- type -data-- -encode-- -wrap-- -name--------\n" );
- -
- - for( i = texCount = 0, image = r_textures; i < r_numTextures; i++, image++ )
- - {
- - if( !image->texnum ) continue;
- -
- - bytes += image->size;
- - texCount++;
- -
- - Msg( "%4i: ", i );
- - Msg( "%4i %4i ", image->width, image->height );
- - Msg( "%5ik ", image->size >> 10 );
- -
- - switch( image->format )
- - {
- - case GL_COMPRESSED_RGBA_ARB:
- - Msg( "CRGBA " );
- - break;
- - case GL_COMPRESSED_RGB_ARB:
- - Msg( "CRGB " );
- - break;
- - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB:
- - Msg( "CLA " );
- - break;
- - case GL_COMPRESSED_LUMINANCE_ARB:
- - Msg( "CL " );
- - break;
- - case GL_COMPRESSED_ALPHA_ARB:
- - Msg( "CA " );
- - break;
- - case GL_COMPRESSED_INTENSITY_ARB:
- - Msg( "CI " );
- - break;
- - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- - Msg( "DXT1c " );
- - break;
- - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- - Msg( "DXT1a " );
- - break;
- - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- - Msg( "DXT3 " );
- - break;
- - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- - Msg( "DXT5 " );
- - break;
- - case GL_RGBA:
- - Msg( "RGBA " );
- - break;
- - case GL_RGBA8:
- - Msg( "RGBA8 " );
- - break;
- - case GL_RGBA4:
- - Msg( "RGBA4 " );
- - break;
- - case GL_RGB:
- - Msg( "RGB " );
- - break;
- - case GL_RGB8:
- - Msg( "RGB8 " );
- - break;
- - case GL_RGB5:
- - Msg( "RGB5 " );
- - break;
- - case GL_LUMINANCE4_ALPHA4:
- - Msg( "L4A4 " );
- - break;
- - case GL_LUMINANCE_ALPHA:
- - case GL_LUMINANCE8_ALPHA8:
- - Msg( "L8A8 " );
- - break;
- - case GL_LUMINANCE4:
- - Msg( "L4 " );
- - break;
- - case GL_LUMINANCE:
- - case GL_LUMINANCE8:
- - Msg( "L8 " );
- - break;
- - case GL_ALPHA8:
- - Msg( "A8 " );
- - break;
- - case GL_INTENSITY8:
- - Msg( "I8 " );
- - break;
- - case GL_DEPTH_COMPONENT:
- - case GL_DEPTH_COMPONENT24:
- - Msg( "DEPTH24" );
- - break;
- - case GL_DEPTH_COMPONENT32F:
- - Msg( "DEPTH32" );
- - break;
- - case GL_LUMINANCE16F_ARB:
- - Msg( "L16F " );
- - break;
- - case GL_LUMINANCE32F_ARB:
- - Msg( "L32F " );
- - break;
- - case GL_LUMINANCE_ALPHA16F_ARB:
- - Msg( "LA16F " );
- - break;
- - case GL_LUMINANCE_ALPHA32F_ARB:
- - Msg( "LA32F " );
- - break;
- - case GL_RGB16F_ARB:
- - Msg( "RGB16F" );
- - break;
- - case GL_RGB32F_ARB:
- - Msg( "RGB32F" );
- - break;
- - case GL_RGBA16F_ARB:
- - Msg( "RGBA16F" );
- - break;
- - case GL_RGBA32F_ARB:
- - Msg( "RGBA32F" );
- - break;
- - default:
- - Msg( "????? " );
- - break;
- - }
- -
- - switch( image->target )
- - {
- - case GL_TEXTURE_1D:
- - Msg( " 1D " );
- - break;
- - case GL_TEXTURE_2D:
- - Msg( " 2D " );
- - break;
- - case GL_TEXTURE_3D:
- - Msg( " 3D " );
- - break;
- - case GL_TEXTURE_CUBE_MAP_ARB:
- - Msg( "CUBE " );
- - break;
- - case GL_TEXTURE_RECTANGLE_EXT:
- - Msg( "RECT " );
- - break;
- - default:
- - Msg( "???? " );
- - break;
- - }
- -
- - if( image->flags & TF_NORMALMAP )
- - Msg( "normal " );
- - else Msg( "diffuse " );
- -
- - switch( image->encode )
- - {
- - case DXT_ENCODE_COLOR_YCoCg:
- - Msg( "YCoCg " );
- - break;
- - case DXT_ENCODE_NORMAL_AG_ORTHO:
- - Msg( "ortho " );
- - break;
- - case DXT_ENCODE_NORMAL_AG_STEREO:
- - Msg( "stereo " );
- - break;
- - case DXT_ENCODE_NORMAL_AG_PARABOLOID:
- - Msg( "parabolic " );
- - break;
- - case DXT_ENCODE_NORMAL_AG_QUARTIC:
- - Msg( "quartic " );
- - break;
- - case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
- - Msg( "azimuthal " );
- - break;
- - default:
- - Msg( "default " );
- - break;
- - }
- -
- - if( image->flags & TF_CLAMP )
- - Msg( "clamp " );
- - else if( image->flags & TF_BORDER )
- - Msg( "border " );
- - else if( image->flags & TF_ALPHA_BORDER )
- - Msg( "aborder" );
- - else Msg( "repeat " );
- - Msg( " %s\n", image->name );
- - }
- -
- - Msg( "---------------------------------------------------------\n" );
- - Msg( "%i total textures\n", texCount );
- - Msg( "%s total memory used\n", Q_memprint( bytes ));
- - Msg( "\n" );
- + for( i = 0; i < r_numTextures; i++ )
- + GL_UpdateTextureParams( i );
- }
- /*
- @@ -546,259 +326,407 @@ void R_TextureList_f( void )
- GL_CalcTextureSamples
- ================
- */
- -int GL_CalcTextureSamples( int flags )
- +static int GL_CalcTextureSamples( int flags )
- {
- - if( flags & IMAGE_HAS_COLOR )
- - return (flags & IMAGE_HAS_ALPHA) ? 4 : 3;
- - return (flags & IMAGE_HAS_ALPHA) ? 2 : 1;
- + if( FBitSet( flags, IMAGE_HAS_COLOR ))
- + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 4 : 3;
- + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 2 : 1;
- }
- /*
- -================
- -GL_ImageFlagsFromSamples
- -================
- +==================
- +GL_CalcImageSize
- +==================
- */
- -int GL_ImageFlagsFromSamples( int samples )
- +static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int depth )
- {
- - switch( samples )
- + size_t size = 0;
- +
- + // check the depth error
- + depth = Q_max( 1, depth );
- +
- + switch( format )
- {
- - case 2: return IMAGE_HAS_ALPHA;
- - case 3: return IMAGE_HAS_COLOR;
- - case 4: return (IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA);
- + case PF_RGB_24:
- + case PF_BGR_24:
- + size = width * height * depth * 3;
- + break;
- + case PF_BGRA_32:
- + case PF_RGBA_32:
- + size = width * height * depth * 4;
- + break;
- + case PF_DXT1:
- + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth;
- + break;
- + case PF_DXT3:
- + case PF_DXT5:
- + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth;
- + break;
- }
- - return 0;
- + return size;
- }
- /*
- -================
- -GL_CalcImageSamples
- -================
- +==================
- +GL_CalcTextureSize
- +==================
- */
- -int GL_CalcImageSamples( int s1, int s2 )
- +static size_t GL_CalcTextureSize( GLenum format, int width, int height, int depth )
- {
- - int samples;
- + size_t size = 0;
- - if( s1 == 1 ) samples = s2;
- - else if( s1 == 2 )
- + // check the depth error
- + depth = Q_max( 1, depth );
- +
- + switch( format )
- {
- - if( s2 == 3 || s2 == 4 )
- - samples = 4;
- - else samples = 2;
- + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth;
- + break;
- + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth;
- + break;
- + case GL_RGBA8:
- + case GL_RGBA:
- + size = width * height * depth * 4;
- + break;
- + case GL_RGB8:
- + case GL_RGB:
- + size = width * height * depth * 4;
- + break;
- + case GL_INTENSITY:
- + case GL_LUMINANCE:
- + case GL_INTENSITY8:
- + case GL_LUMINANCE8:
- + size = (width * height * depth);
- + break;
- + case GL_LUMINANCE_ALPHA:
- + case GL_LUMINANCE8_ALPHA8:
- + size = width * height * depth * 2;
- + break;
- + case GL_R8:
- + size = width * height * depth;
- + break;
- + case GL_RG8:
- + size = width * height * depth * 2;
- + break;
- + case GL_R16:
- + size = width * height * depth * 2;
- + break;
- + case GL_RG16:
- + size = width * height * depth * 4;
- + break;
- + case GL_R16F:
- + case GL_LUMINANCE16F_ARB:
- + size = width * height * depth * 2; // half-floats
- + break;
- + case GL_R32F:
- + case GL_LUMINANCE32F_ARB:
- + size = width * height * depth * 4;
- + break;
- + case GL_RG16F:
- + case GL_LUMINANCE_ALPHA16F_ARB:
- + size = width * height * depth * 4;
- + break;
- + case GL_RG32F:
- + case GL_LUMINANCE_ALPHA32F_ARB:
- + size = width * height * depth * 8;
- + break;
- + case GL_RGB16F_ARB:
- + case GL_RGBA16F_ARB:
- + size = width * height * depth * 8;
- + break;
- + case GL_RGB32F_ARB:
- + case GL_RGBA32F_ARB:
- + size = width * height * depth * 16;
- + break;
- + case GL_DEPTH_COMPONENT16:
- + size = width * height * depth * 2;
- + break;
- + case GL_DEPTH_COMPONENT24:
- + size = width * height * depth * 4;
- + break;
- + case GL_DEPTH_COMPONENT32F:
- + size = width * height * depth * 4;
- + break;
- + default:
- + Host_Error( "GL_CalcTextureSize: bad texture internal format (%u)\n", format );
- + break;
- }
- - else if( s1 == 3 )
- +
- + return size;
- +}
- +
- +static int GL_CalcMipmapCount( gltexture_t *tex, qboolean haveBuffer )
- +{
- + int width, height;
- + int mipcount;
- +
- + ASSERT( tex != NULL );
- +
- + if( !haveBuffer || tex->target == GL_TEXTURE_3D )
- + return 1;
- +
- + // generate mip-levels by user request
- + if( FBitSet( tex->flags, TF_NOMIPMAP ))
- + return 1;
- +
- + // mip-maps can't exceeds 16
- + for( mipcount = 0; mipcount < 16; mipcount++ )
- {
- - if( s2 == 2 || s2 == 4 )
- - samples = 4;
- - else samples = 3;
- + width = Q_max( 1, ( tex->width >> mipcount ));
- + height = Q_max( 1, ( tex->height >> mipcount ));
- + if( width == 1 && height == 1 )
- + break;
- }
- - else samples = s1;
- - return samples;
- + return mipcount + 1;
- }
- /*
- ================
- -GL_RoundImageDimensions
- +GL_SetTextureDimensions
- ================
- */
- -void GL_RoundImageDimensions( word *width, word *height, texFlags_t flags, qboolean force )
- +static void GL_SetTextureDimensions( gltexture_t *tex, int width, int height, int depth )
- {
- - int scaledWidth, scaledHeight;
- -
- - scaledWidth = *width;
- - scaledHeight = *height;
- + int maxTextureSize;
- + int maxDepthSize = 1;
- - if( flags & ( TF_TEXTURE_1D|TF_TEXTURE_3D )) return;
- + ASSERT( tex != NULL );
- - if( force || !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
- + switch( tex->target )
- {
- - // find nearest power of two, rounding down if desired
- - scaledWidth = NearestPOW( scaledWidth, gl_round_down->integer );
- - scaledHeight = NearestPOW( scaledHeight, gl_round_down->integer );
- + case GL_TEXTURE_1D:
- + case GL_TEXTURE_2D:
- + maxTextureSize = glConfig.max_2d_texture_size;
- + break;
- + case GL_TEXTURE_2D_ARRAY_EXT:
- + maxDepthSize = glConfig.max_2d_texture_layers;
- + maxTextureSize = glConfig.max_2d_texture_size;
- + break;
- + case GL_TEXTURE_RECTANGLE_EXT:
- + maxTextureSize = glConfig.max_2d_rectangle_size;
- + break;
- + case GL_TEXTURE_CUBE_MAP_ARB:
- + maxTextureSize = glConfig.max_cubemap_size;
- + break;
- + case GL_TEXTURE_3D:
- + maxDepthSize = glConfig.max_3d_texture_size;
- + maxTextureSize = glConfig.max_3d_texture_size;
- + break;
- }
- - if( flags & TF_SKYSIDE )
- - {
- - // let people sample down the sky textures for speed
- - scaledWidth >>= gl_skymip->integer;
- - scaledHeight >>= gl_skymip->integer;
- - }
- - else if(!( flags & TF_NOPICMIP ))
- + // store original sizes
- + tex->srcWidth = width;
- + tex->srcHeight = height;
- +
- + if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
- {
- - // let people sample down the world textures for speed
- - scaledWidth >>= gl_picmip->integer;
- - scaledHeight >>= gl_picmip->integer;
- + width = (width + 3) & ~3;
- + height = (height + 3) & ~3;
- }
- - if( flags & TF_CUBEMAP )
- + if( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize )
- {
- - while( scaledWidth > glConfig.max_cubemap_size || scaledHeight > glConfig.max_cubemap_size )
- + if( tex->target == GL_TEXTURE_1D )
- {
- - scaledWidth >>= 1;
- - scaledHeight >>= 1;
- + while( width > maxTextureSize )
- + width >>= 1;
- }
- - }
- - else
- - {
- - if( flags & TF_TEXTURE_RECTANGLE )
- + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
- {
- - while( scaledWidth > glConfig.max_2d_rectangle_size || scaledHeight > glConfig.max_2d_rectangle_size )
- + while( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize )
- {
- - scaledWidth >>= 1;
- - scaledHeight >>= 1;
- + width >>= 1;
- + height >>= 1;
- + depth >>= 1;
- }
- }
- - else
- + else // all remaining cases
- {
- - while( scaledWidth > glConfig.max_2d_texture_size || scaledHeight > glConfig.max_2d_texture_size )
- + while( width > maxTextureSize || height > maxTextureSize )
- {
- - scaledWidth >>= 1;
- - scaledHeight >>= 1;
- + width >>= 1;
- + height >>= 1;
- }
- }
- }
- - if( scaledWidth < 1 ) scaledWidth = 1;
- - if( scaledHeight < 1 ) scaledHeight = 1;
- + // apply custom downscales
- + if( FBitSet( tex->flags, TF_SKYSIDE ))
- + {
- + // let people sample down the sky textures for speed
- + width >>= gl_skymip->integer;
- + height >>= gl_skymip->integer;
- + }
- + else if( !FBitSet( tex->flags, TF_NOPICMIP ))
- + {
- + // let people sample down the world textures for speed
- + width >>= gl_picmip->integer;
- + height >>= gl_picmip->integer;
- + }
- - *width = scaledWidth;
- - *height = scaledHeight;
- + // set the texture dimensions
- + tex->width = Q_max( 1, width );
- + tex->height = Q_max( 1, height );
- + tex->depth = Q_max( 1, depth );
- }
- /*
- ===============
- -GL_TextureFormat
- +GL_SetTextureTarget
- ===============
- */
- -static GLenum GL_TextureFormat( gltexture_t *tex, int *samples )
- +static void GL_SetTextureTarget( gltexture_t *tex, rgbdata_t *pic )
- {
- - qboolean compress;
- - GLenum format;
- + ASSERT( pic != NULL );
- + ASSERT( tex != NULL );
- +
- + // correct depth size
- + pic->depth = Q_max( 1, pic->depth );
- + tex->numMips = 0; // begin counting
- +
- + // correct mip count
- + pic->numMips = max( 1, pic->numMips );
- +
- + // trying to determine texture type
- + if( pic->width > 1 && pic->height <= 1 )
- + tex->target = GL_TEXTURE_1D;
- + else if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
- + tex->target = GL_TEXTURE_CUBE_MAP_ARB;
- + else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 )
- + tex->target = GL_TEXTURE_2D_ARRAY_EXT;
- + else if( pic->width > 1 && pic->height > 1 && pic->depth > 1 )
- + tex->target = GL_TEXTURE_3D;
- + else if( FBitSet( tex->flags, TF_TEXTURE_RECTANGLE ) && pic->width == glState.width && pic->height == glState.height )
- + tex->target = GL_TEXTURE_RECTANGLE_EXT;
- + else tex->target = GL_TEXTURE_2D; // default case
- +
- + // check for hardware support
- + if(( tex->target == GL_TEXTURE_CUBE_MAP_ARB ) && !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- + tex->target = GL_NONE;
- +
- + if(( tex->target == GL_TEXTURE_RECTANGLE_EXT ) && !GL_Support( GL_TEXTURE_2D_RECT_EXT ))
- + tex->target = GL_TEXTURE_2D; // fallback
- +
- + if(( tex->target == GL_TEXTURE_2D_ARRAY_EXT ) && !GL_Support( GL_TEXTURE_ARRAY_EXT ))
- + tex->target = GL_NONE;
- +
- + if(( tex->target == GL_TEXTURE_3D ) && !GL_Support( GL_TEXTURE_3D_EXT ))
- + tex->target = GL_NONE;
- +
- + // depth cubemaps only allowed when GL_EXT_gpu_shader4 is supported
- + if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_EXT_GPU_SHADER4 ) && FBitSet( tex->flags, TF_DEPTHMAP ))
- + tex->target = GL_NONE;
- +}
- - // check if it should be compressed
- - if( !gl_compress_textures->integer || ( tex->flags & TF_UNCOMPRESSED ))
- - compress = false;
- - else compress = GL_Support( GL_TEXTURE_COMPRESSION_EXT );
- +/*
- +===============
- +GL_SetTextureFormat
- +===============
- +*/
- +static void GL_SetTextureFormat( gltexture_t *tex, pixformat_t format, int channelMask )
- +{
- + qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR );
- + qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA );
- + qboolean compressImage = false;
- - // set texture format
- - if( tex->flags & TF_DEPTHMAP )
- + ASSERT( tex != NULL );
- +
- + if( !FBitSet( tex->flags, TF_UNCOMPRESSED ) && !ImageDXT( format ))
- {
- - if( tex->flags & TF_FLOAT && GL_Support( GL_ARB_DEPTH_FLOAT_EXT ))
- - format = GL_DEPTH_COMPONENT32F;
- - else format = GL_DEPTH_COMPONENT24;
- - tex->flags &= ~TF_INTENSITY;
- + // check if it should be compressed
- + if( gl_compress_textures->integer && GL_Support( GL_TEXTURE_COMPRESSION_EXT ))
- + compressImage = true;
- }
- - else if( tex->flags & TF_FLOAT && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT ))
- - {
- - int bits = glw_state.desktopBitsPixel;
- - switch( *samples )
- + if( ImageDXT( format ))
- + {
- + switch( format )
- {
- - case 1:
- - switch( bits )
- - {
- - case 16: format = GL_LUMINANCE16F_ARB; break;
- - default: format = GL_LUMINANCE32F_ARB; break;
- - }
- - break;
- - case 2:
- - switch( bits )
- - {
- - case 16: format = GL_LUMINANCE_ALPHA16F_ARB; break;
- - default: format = GL_LUMINANCE_ALPHA32F_ARB; break;
- - }
- - break;
- - case 3:
- - switch( bits )
- - {
- - case 16: format = GL_RGB16F_ARB; break;
- - default: format = GL_RGB32F_ARB; break;
- - }
- - break;
- - case 4:
- - default:
- - switch( bits )
- - {
- - case 16: format = GL_RGBA16F_ARB; break;
- - default: format = GL_RGBA32F_ARB; break;
- - }
- - break;
- + case PF_DXT1: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; // never use DXT1 with 1-bit alpha
- + case PF_DXT3: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
- + case PF_DXT5: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
- }
- + return;
- + }
- + else if( FBitSet( tex->flags, TF_DEPTHMAP ))
- + {
- + if( FBitSet( tex->flags, TF_ARB_16BIT ))
- + tex->format = GL_DEPTH_COMPONENT16;
- + else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_DEPTH_FLOAT_EXT ))
- + tex->format = GL_DEPTH_COMPONENT32F;
- + else tex->format = GL_DEPTH_COMPONENT24;
- }
- - else if( compress )
- + else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT ))
- {
- - switch( *samples )
- + if( haveColor && haveAlpha )
- {
- - case 1: format = GL_COMPRESSED_LUMINANCE_ARB; break;
- - case 2: format = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
- - case 3: format = GL_COMPRESSED_RGB_ARB; break;
- - case 4:
- - default: format = GL_COMPRESSED_RGBA_ARB; break;
- + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
- + tex->format = GL_RGBA16F_ARB;
- + else tex->format = GL_RGBA32F_ARB;
- + }
- + else if( haveColor )
- + {
- + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
- + tex->format = GL_RGB16F_ARB;
- + else tex->format = GL_RGB32F_ARB;
- + }
- + else if( haveAlpha )
- + {
- + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
- + tex->format = GL_LUMINANCE_ALPHA16F_ARB;
- + else tex->format = GL_LUMINANCE_ALPHA32F_ARB;
- + }
- + else
- + {
- + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
- + tex->format = GL_LUMINANCE16F_ARB;
- + else tex->format = GL_LUMINANCE32F_ARB;
- + }
- + }
- + else if( compressImage )
- + {
- + switch( GL_CalcTextureSamples( channelMask ))
- + {
- + case 1: tex->format = GL_LUMINANCE8; break;
- + case 2: tex->format = GL_LUMINANCE8_ALPHA8; break;
- + case 3: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
- + case 4: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
- }
- -
- - if( tex->flags & TF_INTENSITY )
- - format = GL_COMPRESSED_INTENSITY_ARB;
- - tex->flags &= ~TF_INTENSITY;
- }
- else
- {
- + // NOTE: not all the types will be compressed
- int bits = glw_state.desktopBitsPixel;
- - switch( *samples )
- + switch( GL_CalcTextureSamples( channelMask ) )
- {
- - case 1: format = GL_LUMINANCE8; break;
- - case 2: format = GL_LUMINANCE8_ALPHA8; break;
- + case 1: tex->format = GL_LUMINANCE8; break;
- + case 2: tex->format = GL_LUMINANCE8_ALPHA8; break;
- case 3:
- - if( gl_luminance_textures->integer && !( tex->flags & TF_UNCOMPRESSED ))
- - {
- - switch( bits )
- - {
- - case 16: format = GL_LUMINANCE4; break;
- - case 32: format = GL_LUMINANCE8; break;
- - default: format = GL_LUMINANCE; break;
- - }
- - *samples = 1; // merge for right calc statistics
- - }
- - else
- + switch( bits )
- {
- - switch( bits )
- - {
- - case 16: format = GL_RGB5; break;
- - case 32: format = GL_RGB8; break;
- - default: format = GL_RGB; break;
- - }
- + case 16: tex->format = GL_RGB5; break;
- + case 32: tex->format = GL_RGB8; break;
- + default: tex->format = GL_RGB; break;
- }
- - break;
- + break;
- case 4:
- default:
- - if( gl_luminance_textures->integer && !( tex->flags & TF_UNCOMPRESSED ))
- - {
- - switch( bits )
- - {
- - case 16: format = GL_LUMINANCE4_ALPHA4; break;
- - case 32: format = GL_LUMINANCE8_ALPHA8; break;
- - default: format = GL_LUMINANCE_ALPHA; break;
- - }
- - *samples = 2; // merge for right calc statistics
- - }
- - else
- + switch( bits )
- {
- - switch( bits )
- - {
- - case 16: format = GL_RGBA4; break;
- - case 32: format = GL_RGBA8; break;
- - default: format = GL_RGBA; break;
- - }
- + case 16: tex->format = GL_RGBA4; break;
- + case 32: tex->format = GL_RGBA8; break;
- + default: tex->format = GL_RGBA; break;
- }
- break;
- }
- -
- - if( tex->flags & TF_INTENSITY )
- - format = GL_INTENSITY8;
- - tex->flags &= ~TF_INTENSITY;
- }
- - return format;
- }
- /*
- @@ -815,6 +743,7 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
- uint p1[0x1000], p2[0x1000];
- byte *pix1, *pix2, *pix3, *pix4;
- uint *out, *inRow1, *inRow2;
- + static byte *scaledImage = NULL; // pointer to a scaled image
- vec3_t normal;
- int i, x, y;
- @@ -842,8 +771,8 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
- {
- for( y = 0; y < outHeight; y++, out += outWidth )
- {
- - inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight/outHeight);
- - inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight/outHeight);
- + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
- + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
- for( x = 0; x < outWidth; x++ )
- {
- @@ -852,16 +781,16 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
- pix3 = (byte *)inRow2 + p1[x];
- pix4 = (byte *)inRow2 + p2[x];
- - normal[0] = (pix1[0] * (1.0f/127.0f) - 1.0f) + (pix2[0] * (1.0f/127.0f) - 1.0f) + (pix3[0] * (1.0f/127.0f) - 1.0f) + (pix4[0] * (1.0f/127.0f) - 1.0f);
- - normal[1] = (pix1[1] * (1.0f/127.0f) - 1.0f) + (pix2[1] * (1.0f/127.0f) - 1.0f) + (pix3[1] * (1.0f/127.0f) - 1.0f) + (pix4[1] * (1.0f/127.0f) - 1.0f);
- - normal[2] = (pix1[2] * (1.0f/127.0f) - 1.0f) + (pix2[2] * (1.0f/127.0f) - 1.0f) + (pix3[2] * (1.0f/127.0f) - 1.0f) + (pix4[2] * (1.0f/127.0f) - 1.0f);
- + normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] );
- + normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] );
- + normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] );
- if( !VectorNormalizeLength( normal ))
- - VectorSet( normal, 0.0f, 0.0f, 1.0f );
- + VectorSet( normal, 0.5f, 0.5f, 1.0f );
- - ((byte *)(out+x))[0] = (byte)(128 + 127 * normal[0]);
- - ((byte *)(out+x))[1] = (byte)(128 + 127 * normal[1]);
- - ((byte *)(out+x))[2] = (byte)(128 + 127 * normal[2]);
- + ((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]);
- + ((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]);
- + ((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]);
- ((byte *)(out+x))[3] = 255;
- }
- }
- @@ -870,8 +799,8 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
- {
- for( y = 0; y < outHeight; y++, out += outWidth )
- {
- - inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight/outHeight);
- - inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight/outHeight);
- + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
- + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
- for( x = 0; x < outWidth; x++ )
- {
- @@ -887,6 +816,7 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
- }
- }
- }
- +
- return scaledImage;
- }
- @@ -922,96 +852,82 @@ GL_BuildMipMap
- Operates in place, quartering the size of the texture
- =================
- */
- -static void GL_BuildMipMap( byte *in, int width, int height, qboolean isNormalMap )
- +static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, qboolean isNormalMap )
- {
- byte *out = in;
- + int instride = ALIGN( srcWidth * 4, 1 );
- + int mipWidth, mipHeight, outpadding;
- + int row, x, y, z;
- vec3_t normal;
- - int x, y;
- -
- - width <<= 2;
- - height >>= 1;
- -
- - if( isNormalMap )
- - {
- - for( y = 0; y < height; y++, in += width )
- - {
- - for( x = 0; x < width; x += 8, in += 8, out += 4 )
- - {
- - normal[0] = (in[0] * (1.0f/127.0f) - 1.0f) + (in[4] * (1.0f/127.0f) - 1.0f) + (in[width+0] * (1.0f/127.0f) - 1.0f) + (in[width+4] * (1.0f/127.0f) - 1.0f);
- - normal[1] = (in[1] * (1.0f/127.0f) - 1.0f) + (in[5] * (1.0f/127.0f) - 1.0f) + (in[width+1] * (1.0f/127.0f) - 1.0f) + (in[width+5] * (1.0f/127.0f) - 1.0f);
- - normal[2] = (in[2] * (1.0f/127.0f) - 1.0f) + (in[6] * (1.0f/127.0f) - 1.0f) + (in[width+2] * (1.0f/127.0f) - 1.0f) + (in[width+6] * (1.0f/127.0f) - 1.0f);
- - if( !VectorNormalizeLength( normal ))
- - VectorSet( normal, 0.0f, 0.0f, 1.0f );
- -
- - out[0] = (byte)(128 + 127 * normal[0]);
- - out[1] = (byte)(128 + 127 * normal[1]);
- - out[2] = (byte)(128 + 127 * normal[2]);
- - out[3] = 255;
- - }
- - }
- - }
- - else
- - {
- - for( y = 0; y < height; y++, in += width )
- - {
- - for( x = 0; x < width; x += 8, in += 8, out += 4 )
- - {
- - out[0] = (in[0] + in[4] + in[width+0] + in[width+4]) >> 2;
- - out[1] = (in[1] + in[5] + in[width+1] + in[width+5]) >> 2;
- - out[2] = (in[2] + in[6] + in[width+2] + in[width+6]) >> 2;
- - out[3] = (in[3] + in[7] + in[width+3] + in[width+7]) >> 2;
- - }
- - }
- - }
- -}
- -
- -/*
- -===============
- -GL_GenerateMipmaps
- -
- -sgis generate mipmap
- -===============
- -*/
- -void GL_GenerateMipmaps( byte *buffer, rgbdata_t *pic, gltexture_t *tex, GLenum glTarget, GLenum inFormat, int side, qboolean subImage )
- -{
- - int mipLevel;
- - int dataType = GL_UNSIGNED_BYTE;
- - int w, h;
- -
- - // not needs
- - if( tex->flags & TF_NOMIPMAP )
- - return;
- -
- - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
- - {
- - pglHint( GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST );
- - pglTexParameteri( glTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
- - pglGetError(); // clear error queue on mips generate
- - return;
- - }
- -
- - // screen texture?
- - if( !buffer ) return;
- -
- - mipLevel = 0;
- - w = tex->width;
- - h = tex->height;
- -
- - // software mipmap generator
- - while( w > 1 || h > 1 )
- - {
- - // build the mipmap
- - if( tex->flags & TF_ALPHACONTRAST ) memset( buffer, pic->width >> mipLevel, w * h * 4 );
- - else GL_BuildMipMap( buffer, w, h, ( tex->flags & TF_NORMALMAP ));
- + if( !in ) return;
- - w = (w+1)>>1;
- - h = (h+1)>>1;
- - mipLevel++;
- + mipWidth = max( 1, ( srcWidth >> 1 ));
- + mipHeight = max( 1, ( srcHeight >> 1 ));
- + outpadding = ALIGN( mipWidth * 4, 1 ) - mipWidth * 4;
- + row = srcWidth << 2;
- - if( subImage ) pglTexSubImage2D( tex->target + side, mipLevel, 0, 0, w, h, inFormat, dataType, buffer );
- - else pglTexImage2D( tex->target + side, mipLevel, tex->format, w, h, 0, inFormat, dataType, buffer );
- - if( pglGetError( )) break; // can't create mip levels
- + // move through all layers
- + for( z = 0; z < srcDepth; z++ )
- + {
- + if( isNormalMap )
- + {
- + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding )
- + {
- + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in;
- + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 )
- + {
- + if((( x << 1 ) + 1 ) < srcWidth )
- + {
- + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( in[row+4] )
- + + MAKE_SIGNED( next[row+0] ) + MAKE_SIGNED( next[row+4] );
- + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( in[row+5] )
- + + MAKE_SIGNED( next[row+1] ) + MAKE_SIGNED( next[row+5] );
- + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( in[row+6] )
- + + MAKE_SIGNED( next[row+2] ) + MAKE_SIGNED( next[row+6] );
- + }
- + else
- + {
- + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( next[row+0] );
- + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( next[row+1] );
- + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( next[row+2] );
- + }
- +
- +
- + if( !VectorNormalizeLength( normal ))
- + VectorSet( normal, 0.5f, 0.5f, 1.0f );
- +
- + out[0] = 128 + (byte)(127.0f * normal[0]);
- + out[1] = 128 + (byte)(127.0f * normal[1]);
- + out[2] = 128 + (byte)(127.0f * normal[2]);
- + out[3] = 255;
- + }
- + }
- + }
- + else
- + {
- + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding )
- + {
- + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in;
- + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 )
- + {
- + if((( x << 1 ) + 1 ) < srcWidth )
- + {
- + out[0] = (in[row+0] + in[row+4] + next[row+0] + next[row+4]) >> 2;
- + out[1] = (in[row+1] + in[row+5] + next[row+1] + next[row+5]) >> 2;
- + out[2] = (in[row+2] + in[row+6] + next[row+2] + next[row+6]) >> 2;
- + out[3] = (in[row+3] + in[row+7] + next[row+3] + next[row+7]) >> 2;
- + }
- + else
- + {
- + out[0] = (in[row+0] + next[row+0]) >> 1;
- + out[1] = (in[row+1] + next[row+1]) >> 1;
- + out[2] = (in[row+2] + next[row+2]) >> 1;
- + out[3] = (in[row+3] + next[row+3]) >> 1;
- + }
- + }
- + }
- + }
- }
- }
- @@ -1045,193 +961,85 @@ void GL_MakeLuminance( rgbdata_t *in )
- }
- }
- -static void GL_TextureImage( GLenum inFormat, GLenum outFormat, GLenum glTarget, GLint side, GLint level, GLint width, GLint height, GLint depth, qboolean subImage, size_t size, const void *data )
- +static void GL_TextureImageRAW( gltexture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, GLint type, const void *data )
- {
- + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
- + qboolean subImage = ( tex->flags & TF_IMG_UPLOADED );
- + GLenum inFormat = PFDesc[type].glFormat;
- GLint dataType = GL_UNSIGNED_BYTE;
- - if( glTarget == GL_TEXTURE_1D )
- + ASSERT( tex != NULL );
- +
- + if( tex->flags & TF_DEPTHMAP )
- + inFormat = GL_DEPTH_COMPONENT;
- +
- + if( tex->target == GL_TEXTURE_1D )
- {
- - if( subImage ) pglTexSubImage1D( glTarget, level, 0, width, inFormat, dataType, data );
- - else pglTexImage1D( glTarget, level, outFormat, width, 0, inFormat, dataType, data );
- + if( subImage ) pglTexSubImage1D( tex->target, level, 0, width, inFormat, dataType, data );
- + else pglTexImage1D( tex->target, level, tex->format, width, 0, inFormat, dataType, data );
- }
- - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
- + else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB )
- {
- - if( subImage ) pglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, 0, 0, width, height, inFormat, dataType, data );
- - else pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, outFormat, width, height, 0, inFormat, dataType, data );
- + if( subImage ) pglTexSubImage2D( cubeTarget + side, level, 0, 0, width, height, inFormat, dataType, data );
- + else pglTexImage2D( cubeTarget + side, level, tex->format, width, height, 0, inFormat, dataType, data );
- }
- - else if( glTarget == GL_TEXTURE_3D )
- + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
- {
- - if( subImage ) pglTexSubImage3D( glTarget, level, 0, 0, 0, width, height, depth, inFormat, dataType, data );
- - else pglTexImage3D( glTarget, level, outFormat, width, height, depth, 0, inFormat, dataType, data );
- + if( subImage ) pglTexSubImage3D( tex->target, level, 0, 0, 0, width, height, depth, inFormat, dataType, data );
- + else pglTexImage3D( tex->target, level, tex->format, width, height, depth, 0, inFormat, dataType, data );
- }
- - else
- + else // 2D or RECT
- {
- - if( subImage ) pglTexSubImage2D( glTarget, level, 0, 0, width, height, inFormat, dataType, data );
- - else pglTexImage2D( glTarget, level, outFormat, width, height, 0, inFormat, dataType, data );
- + if( subImage ) pglTexSubImage2D( tex->target, level, 0, 0, width, height, inFormat, dataType, data );
- + else pglTexImage2D( tex->target, level, tex->format, width, height, 0, inFormat, dataType, data );
- }
- }
- -static void GL_TextureImageDXT( GLenum format, GLenum glTarget, GLint side, GLint level, GLint width, GLint height, GLint depth, qboolean subImage, size_t size, const void *data )
- +static void GL_TextureImageDXT( gltexture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data )
- {
- - if( glTarget == GL_TEXTURE_1D )
- + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
- + qboolean subImage = ( tex->flags & TF_IMG_UPLOADED );
- +
- + ASSERT( tex != NULL );
- +
- + if( tex->target == GL_TEXTURE_1D )
- {
- - if( subImage ) pglCompressedTexSubImage1DARB( glTarget, level, 0, width, format, size, data );
- - else pglCompressedTexImage1DARB( glTarget, level, format, width, 0, size, data );
- + if( subImage ) pglCompressedTexSubImage1DARB( tex->target, level, 0, width, tex->format, size, data );
- + else pglCompressedTexImage1DARB( tex->target, level, tex->format, width, 0, size, data );
- }
- - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
- + else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB )
- {
- - if( subImage ) pglCompressedTexSubImage2DARB( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, 0, 0, width, height, format, size, data );
- - else pglCompressedTexImage2DARB( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, format, width, height, 0, size, data );
- + if( subImage ) pglCompressedTexSubImage2DARB( cubeTarget + side, level, 0, 0, width, height, tex->format, size, data );
- + else pglCompressedTexImage2DARB( cubeTarget + side, level, tex->format, width, height, 0, size, data );
- }
- - else if( glTarget == GL_TEXTURE_3D )
- + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
- {
- - if( subImage ) pglCompressedTexSubImage3DARB( glTarget, level, 0, 0, 0, width, height, depth, format, size, data );
- - else pglCompressedTexImage3DARB( glTarget, level, format, width, height, depth, 0, size, data );
- + if( subImage ) pglCompressedTexSubImage3DARB( tex->target, level, 0, 0, 0, width, height, depth, tex->format, size, data );
- + else pglCompressedTexImage3DARB( tex->target, level, tex->format, width, height, depth, 0, size, data );
- }
- else // 2D or RECT
- {
- - if( subImage ) pglCompressedTexSubImage2DARB( glTarget, level, 0, 0, width, height, format, size, data );
- - else pglCompressedTexImage2DARB( glTarget, level, format, width, height, 0, size, data );
- + if( subImage ) pglCompressedTexSubImage2DARB( tex->target, level, 0, 0, width, height, tex->format, size, data );
- + else pglCompressedTexImage2DARB( tex->target, level, tex->format, width, height, 0, size, data );
- }
- }
- /*
- ===============
- -GL_UploadTextureDXT
- +GL_CheckTexImageError
- -upload compressed texture into video memory
- +show GL-errors on load images
- ===============
- */
- -static void GL_UploadTextureDXT( rgbdata_t *pic, gltexture_t *tex, qboolean subImage, imgfilter_t *filter )
- +static void GL_CheckTexImageError( gltexture_t *tex )
- {
- - byte *buf;
- - const byte *bufend;
- - GLenum inFormat, glTarget;
- - uint width, height, depth;
- - int texsize = 0, samples;
- - uint i, j, s, numSides;
- - int numMips, err;
- -
- - ASSERT( pic != NULL && tex != NULL );
- -
- - tex->srcWidth = tex->width = pic->width;
- - tex->srcHeight = tex->height = pic->height;
- - s = tex->srcWidth * tex->srcHeight;
- -
- - tex->fogParams[0] = pic->fogParams[0];
- - tex->fogParams[1] = pic->fogParams[1];
- - tex->fogParams[2] = pic->fogParams[2];
- - tex->fogParams[3] = pic->fogParams[3];
- -
- - // NOTE: normalmaps must be power of two or software mip generator will stop working
- - GL_RoundImageDimensions( &tex->width, &tex->height, tex->flags, ( tex->flags & TF_NORMALMAP ));
- -
- - if( s&3 )
- - {
- - // will be resample, just tell me for debug targets
- - MsgDev( D_NOTE, "GL_Upload: %s s&3 [%d x %d]\n", tex->name, tex->srcWidth, tex->srcHeight );
- - }
- -
- - // clear all the unsupported flags
- - tex->flags &= ~TF_KEEP_8BIT;
- - tex->flags &= ~TF_KEEP_RGBDATA;
- - tex->flags |= TF_NOPICMIP;
- - tex->encode = pic->encode; // share encode method
- -
- - samples = GL_CalcTextureSamples( pic->flags );
- -
- - if( pic->flags & IMAGE_HAS_ALPHA )
- - tex->flags |= TF_HAS_ALPHA;
- -
- - if( !pic->numMips ) tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request
- -
- - // determine format
- - inFormat = PFDesc[pic->type].glFormat;
- -
- - if( ImageDXT( pic->type ))
- - tex->format = inFormat;
- - else tex->format = GL_TextureFormat( tex, &samples );
- -
- - if( !( tex->flags & TF_HAS_ALPHA ) && inFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )
- - tex->format = inFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // OpenGL hint
- -
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_2D;
- -
- - numMips = (pic->numMips > 0) ? pic->numMips : 1;
- - numSides = 1;
- -
- - if( pic->flags & IMAGE_CUBEMAP )
- - {
- - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
- - {
- - numSides = 6;
- - tex->target = glTarget = GL_TEXTURE_CUBE_MAP_ARB;
- - tex->flags |= TF_CUBEMAP;
- -
- - if( !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && ( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER )))
- - {
- - // don't use border for cubemaps (but allow for seamless cubemaps)
- - tex->flags &= ~(TF_BORDER|TF_ALPHA_BORDER);
- - tex->flags |= TF_CLAMP;
- - }
- - }
- - else
- - {
- - MsgDev( D_WARN, "GL_UploadTexture: cubemaps isn't supported, %s ignored\n", tex->name );
- - tex->flags &= ~TF_CUBEMAP;
- - }
- - }
- - else if( tex->flags & TF_TEXTURE_1D || pic->height <= 1 )
- - {
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_1D;
- - }
- - else if( tex->flags & TF_TEXTURE_RECTANGLE )
- - {
- - if( glConfig.max_2d_rectangle_size )
- - tex->target = glTarget = glConfig.texRectangle;
- - // or leave as GL_TEXTURE_2D
- - }
- - else if( tex->flags & TF_TEXTURE_3D )
- - {
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_3D;
- - }
- -
- - pglBindTexture( tex->target, tex->texnum );
- -
- - buf = pic->buffer;
- - bufend = pic->buffer + pic->size;
- - tex->size = pic->size;
- -
- - // uploading texture into video memory
- - for( i = 0; i < numSides; i++ )
- - {
- - if( buf != NULL && buf >= bufend )
- - Host_Error( "GL_UploadTextureDXT: %s image buffer overflow\n", tex->name );
- -
- - width = pic->width;
- - height = pic->height;
- - depth = pic->depth;
- -
- - for( j = 0; j < numMips; j++ )
- - {
- - width = max( 1, ( pic->width >> j ));
- - height = max( 1, ( pic->height >> j ));
- - texsize = Image_DXTGetLinearSize( pic->type, width, height, depth );
- - if( ImageDXT( pic->type ))
- - GL_TextureImageDXT( inFormat, glTarget, i, j, width, height, depth, subImage, texsize, buf );
- - else GL_TextureImage( inFormat, tex->format, glTarget, i, j, width, height, depth, subImage, texsize, buf );
- -
- - buf += texsize; // move pointer
- + int err;
- - // catch possible errors
- - if(( err = pglGetError()) != GL_NO_ERROR )
- - MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_Target( glTarget ));
- + ASSERT( tex != NULL );
- - }
- - }
- + // catch possible errors
- + if(( err = pglGetError()) != GL_NO_ERROR )
- + MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_TargetToString( tex->target ));
- }
- /*
- @@ -1241,211 +1049,192 @@ GL_UploadTexture
- upload texture into video memory
- ===============
- */
- -static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImage, imgfilter_t *filter )
- +static qboolean GL_UploadTexture( gltexture_t *tex, rgbdata_t *pic )
- {
- byte *buf, *data;
- + size_t texsize, size;
- + uint width, height;
- + uint i, j, numSides;
- + uint offset = 0;
- + qboolean normalMap;
- const byte *bufend;
- - GLenum outFormat, inFormat, glTarget;
- - uint i, s, numSides, offset = 0, err;
- - int texsize = 0, img_flags = 0, samples;
- - GLint dataType = GL_UNSIGNED_BYTE;
- - ASSERT( pic != NULL && tex != NULL );
- + ASSERT( pic != NULL );
- + ASSERT( tex != NULL );
- - if( pic->flags & IMAGE_DDS_FORMAT )
- + GL_SetTextureTarget( tex, pic ); // must be first
- +
- + // make sure what target is correct
- + if( tex->target == GL_NONE )
- {
- - // special case for DDS textures
- - GL_UploadTextureDXT( pic, tex, subImage, filter );
- - return;
- + MsgDev( D_ERROR, "GL_UploadTexture: %s is not supported by your hardware\n", tex->name );
- + return false;
- }
- - tex->srcWidth = tex->width = pic->width;
- - tex->srcHeight = tex->height = pic->height;
- - s = tex->srcWidth * tex->srcHeight;
- + GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth );
- + GL_SetTextureFormat( tex, pic->type, pic->flags );
- tex->fogParams[0] = pic->fogParams[0];
- tex->fogParams[1] = pic->fogParams[1];
- tex->fogParams[2] = pic->fogParams[2];
- tex->fogParams[3] = pic->fogParams[3];
- - // NOTE: normalmaps must be power of two or software mip generator will stop working
- - GL_RoundImageDimensions( &tex->width, &tex->height, tex->flags, ( tex->flags & TF_NORMALMAP ));
- -
- - if( s&3 )
- - {
- - // will be resample, just tell me for debug targets
- - MsgDev( D_NOTE, "GL_Upload: %s s&3 [%d x %d]\n", tex->name, tex->srcWidth, tex->srcHeight );
- - }
- -
- - // copy flag about luma pixels
- - if( pic->flags & IMAGE_HAS_LUMA )
- - tex->flags |= TF_HAS_LUMA;
- -
- - // create luma texture from quake texture
- - if( tex->flags & TF_MAKELUMA )
- + if(( pic->width * pic->height ) & 3 )
- {
- - img_flags |= IMAGE_MAKE_LUMA;
- - tex->flags &= ~TF_MAKELUMA;
- + // will be resampled, just tell me for debug targets
- + MsgDev( D_NOTE, "GL_UploadTexture: %s s&3 [%d x %d]\n", tex->name, pic->width, pic->height );
- }
- - if( !subImage && tex->flags & TF_KEEP_8BIT )
- - tex->original = FS_CopyImage( pic ); // because current pic will be expanded to rgba
- -
- - if( !subImage && tex->flags & TF_KEEP_RGBDATA )
- - tex->original = pic; // no need to copy
- -
- - // we need to expand image into RGBA buffer
- - if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
- - img_flags |= IMAGE_FORCE_RGBA;
- + buf = pic->buffer;
- + bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps
- + offset = GL_CalcImageSize( pic->type, pic->width, pic->height, pic->depth );
- + texsize = GL_CalcTextureSize( tex->format, tex->width, tex->height, tex->depth );
- + normalMap = ( tex->flags & TF_NORMALMAP ) ? true : false;
- + numSides = ( pic->flags & IMAGE_CUBEMAP ) ? 6 : 1;
- - // processing image before uploading (force to rgba, make luma etc)
- - if( pic->buffer ) Image_Process( &pic, 0, 0, 0.0f, img_flags, filter );
- + // uploading texture into video memory
- + pglBindTexture( tex->target, tex->texnum );
- - if( tex->flags & TF_LUMINANCE )
- + for( i = 0; i < numSides; i++ )
- {
- - if( !( tex->flags & TF_DEPTHMAP ))
- + // track the buffer bounds
- + if( buf != NULL && buf >= bufend )
- + Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name );
- +
- + if( ImageDXT( pic->type ))
- {
- - GL_MakeLuminance( pic );
- - tex->flags &= ~TF_LUMINANCE;
- + for( j = 0; j < max( 1, pic->numMips ); j++ )
- + {
- + width = max( 1, ( tex->width >> j ));
- + height = max( 1, ( tex->height >> j ));
- + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
- + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
- + GL_TextureImageDXT( tex, i, j, width, height, tex->depth, size, buf );
- + tex->size += texsize;
- + buf += size; // move pointer
- + tex->numMips++;
- +
- + GL_CheckTexImageError( tex );
- + }
- }
- - pic->flags &= ~IMAGE_HAS_COLOR;
- - }
- -
- - samples = GL_CalcTextureSamples( pic->flags );
- -
- - if( pic->flags & IMAGE_HAS_ALPHA )
- - tex->flags |= TF_HAS_ALPHA;
- -
- - // determine format
- - inFormat = PFDesc[pic->type].glFormat;
- - outFormat = GL_TextureFormat( tex, &samples );
- - tex->format = outFormat;
- + else if( max( 1, pic->numMips ) > 1 ) // not-compressed DDS
- + {
- + for( j = 0; j < max( 1, pic->numMips ); j++ )
- + {
- + width = max( 1, ( tex->width >> j ));
- + height = max( 1, ( tex->height >> j ));
- + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
- + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
- + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, buf );
- + tex->size += texsize;
- + buf += size; // move pointer
- + tex->numMips++;
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_2D;
- - numSides = 1;
- + GL_CheckTexImageError( tex );
- - if( tex->flags & TF_FLOATDATA )
- - dataType = GL_FLOAT;
- + }
- + }
- + else // RGBA32
- + {
- + int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL ));
- - if( tex->flags & TF_DEPTHMAP )
- - inFormat = GL_DEPTH_COMPONENT;
- + // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
- + if(( tex->depth == 1 ) && ( pic->width != tex->width ) || ( pic->height != tex->height ))
- + data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap );
- + else data = buf;
- - if( pic->flags & IMAGE_CUBEMAP )
- - {
- - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
- - {
- - numSides = 6;
- - tex->target = glTarget = GL_TEXTURE_CUBE_MAP_ARB;
- - tex->flags |= TF_CUBEMAP;
- + if( !glConfig.deviceSupportsGamma )
- + {
- + if( !ImageDXT( pic->type ) && !( tex->flags & TF_NOMIPMAP ) && !( tex->flags & TF_SKYSIDE ))
- + data = GL_ApplyGamma( data, tex->width * tex->height * tex->depth, ( tex->flags & TF_NORMALMAP ));
- + }
- - if( !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && ( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER )))
- + // mips will be auto-generated if desired
- + for( j = 0; j < mipCount; j++ )
- {
- - // don't use border for cubemaps
- - tex->flags &= ~(TF_BORDER|TF_ALPHA_BORDER);
- - tex->flags |= TF_CLAMP;
- + width = max( 1, ( tex->width >> j ));
- + height = max( 1, ( tex->height >> j ));
- + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
- + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
- + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, data );
- + if( mipCount > 1 )
- + GL_BuildMipMap( data, width, height, tex->depth, normalMap );
- + tex->size += texsize;
- + tex->numMips++;
- +
- + GL_CheckTexImageError( tex );
- }
- +
- + // move to next side
- + if( numSides > 1 && ( buf != NULL ))
- + buf += GL_CalcImageSize( pic->type, pic->width, pic->height, 1 );
- }
- - else
- - {
- - MsgDev( D_WARN, "GL_UploadTexture: cubemaps isn't supported, %s ignored\n", tex->name );
- - tex->flags &= ~TF_CUBEMAP;
- - }
- - }
- - else if( tex->flags & TF_TEXTURE_1D )
- - {
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_1D;
- - }
- - else if( tex->flags & TF_TEXTURE_RECTANGLE )
- - {
- - if( glConfig.max_2d_rectangle_size )
- - tex->target = glTarget = glConfig.texRectangle;
- - // or leave as GL_TEXTURE_2D
- - }
- - else if( tex->flags & TF_TEXTURE_3D )
- - {
- - // determine target
- - tex->target = glTarget = GL_TEXTURE_3D;
- }
- - pglBindTexture( tex->target, tex->texnum );
- + tex->flags |= TF_IMG_UPLOADED; // done
- - buf = pic->buffer;
- - bufend = pic->buffer + pic->size;
- - offset = pic->width * pic->height * PFDesc[pic->type].bpp;
- + return true;
- +}
- - // NOTE: probably this code relies when gl_compressed_textures is enabled
- - texsize = tex->width * tex->height * samples;
- +/*
- +===============
- +GL_ProcessImage
- - // determine some texTypes
- - if( tex->flags & TF_NOPICMIP )
- - tex->texType = TEX_NOMIP;
- - else if( tex->flags & TF_CUBEMAP )
- - tex->texType = TEX_CUBEMAP;
- - else if(( tex->flags & TF_DECAL ) == TF_DECAL )
- - tex->texType = TEX_DECAL;
- +do specified actions on pixels
- +===============
- +*/
- +static void GL_ProcessImage( gltexture_t *tex, rgbdata_t *pic, imgfilter_t *filter )
- +{
- + uint img_flags = 0;
- - // uploading texture into video memory
- - for( i = 0; i < numSides; i++ )
- - {
- - if( buf != NULL && buf >= bufend )
- - Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name );
- + // force upload texture as RGB or RGBA (detail textures requires this)
- + if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
- + if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA;
- - // copy or resample the texture
- - if(( tex->width == tex->srcWidth && tex->height == tex->srcHeight ) || ( tex->flags & ( TF_TEXTURE_1D|TF_TEXTURE_3D )))
- - {
- - data = buf;
- - }
- - else
- - {
- - data = GL_ResampleTexture( buf, tex->srcWidth, tex->srcHeight, tex->width, tex->height, ( tex->flags & TF_NORMALMAP ));
- - }
- + tex->encode = pic->encode; // share encode method
- - if( !glConfig.deviceSupportsGamma )
- - {
- - if(!( tex->flags & TF_NOMIPMAP ) && !( tex->flags & TF_SKYSIDE ) && !( tex->flags & TF_TEXTURE_3D ))
- - data = GL_ApplyGamma( data, tex->width * tex->height, ( tex->flags & TF_NORMALMAP ));
- - }
- + if( ImageDXT( pic->type ))
- + {
- + if( !pic->numMips )
- + tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request
- - if( glTarget == GL_TEXTURE_1D )
- - {
- - if( subImage ) pglTexSubImage1D( tex->target, 0, 0, tex->width, inFormat, dataType, data );
- - else pglTexImage1D( tex->target, 0, outFormat, tex->width, 0, inFormat, dataType, data );
- - }
- - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
- - {
- - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & TF_NORMALMAP ))
- - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
- - if( subImage ) pglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, 0, 0, 0, tex->width, tex->height, inFormat, dataType, data );
- - else pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, 0, outFormat, tex->width, tex->height, 0, inFormat, dataType, data );
- - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ) || ( tex->flags & TF_NORMALMAP ))
- - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
- - }
- - else if( glTarget == GL_TEXTURE_3D )
- - {
- - if( subImage ) pglTexSubImage3D( tex->target, 0, 0, 0, 0, tex->width, tex->height, pic->depth, inFormat, dataType, data );
- - else pglTexImage3D( tex->target, 0, outFormat, tex->width, tex->height, pic->depth, 0, inFormat, dataType, data );
- - }
- - else
- + // clear all the unsupported flags
- + tex->flags &= ~TF_KEEP_8BIT;
- + tex->flags &= ~TF_KEEP_RGBDATA;
- + tex->flags |= TF_NOPICMIP;
- + }
- + else
- + {
- + // copy flag about luma pixels
- + if( pic->flags & IMAGE_HAS_LUMA )
- + tex->flags |= TF_HAS_LUMA;
- +
- + // create luma texture from quake texture
- + if( tex->flags & TF_MAKELUMA )
- {
- - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
- - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
- - if( subImage ) pglTexSubImage2D( tex->target, 0, 0, 0, tex->width, tex->height, inFormat, dataType, data );
- - else pglTexImage2D( tex->target, 0, outFormat, tex->width, tex->height, 0, inFormat, dataType, data );
- - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ) || ( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
- - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
- + img_flags |= IMAGE_MAKE_LUMA;
- + tex->flags &= ~TF_MAKELUMA;
- }
- - if( numSides > 1 && buf != NULL )
- - buf += offset;
- - tex->size += texsize;
- + if( !( tex->flags & TF_IMG_UPLOADED ) && ( tex->flags & ( TF_KEEP_8BIT|TF_KEEP_RGBDATA )))
- + tex->original = FS_CopyImage( pic ); // because current pic will be expanded to rgba
- +
- + // we need to expand image into RGBA buffer
- + if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
- + img_flags |= IMAGE_FORCE_RGBA;
- - // catch possible errors
- - err = pglGetError();
- + // processing image before uploading (force to rgba, make luma etc)
- + if( pic->buffer ) Image_Process( &pic, 0, 0, 0.0f, img_flags, filter );
- - if( err != GL_NO_ERROR )
- - MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_Target( glTarget ));
- + if( tex->flags & TF_LUMINANCE )
- + {
- + if( !( tex->flags & TF_DEPTHMAP ))
- + {
- + GL_MakeLuminance( pic );
- + tex->flags &= ~TF_LUMINANCE;
- + }
- + pic->flags &= ~IMAGE_HAS_COLOR;
- + }
- }
- }
- @@ -1499,9 +1288,6 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i
- pic = FS_LoadImage( name, buf, size );
- if( !pic ) return 0; // couldn't loading image
- - // force upload texture as RGB or RGBA (detail textures requires this)
- - if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
- -
- // find a free texture slot
- if( r_numTextures == MAX_TEXTURES )
- Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
- @@ -1525,11 +1311,192 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i
- tex->texnum = tr.skyboxbasenum++;
- else tex->texnum = i; // texnum is used for fast acess into r_textures array too
- - GL_UploadTexture( pic, tex, false, filter );
- - GL_TexFilter( tex, false ); // update texture filter, wrap etc
- + GL_ProcessImage( tex, pic, filter );
- +
- + if( !GL_UploadTexture( tex, pic ))
- + {
- + memset( tex, 0, sizeof( gltexture_t ));
- + FS_FreeImage( pic ); // release source texture
- + return 0;
- + }
- +
- + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
- + FS_FreeImage( pic ); // release source texture
- +
- + // add to hash table
- + hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE );
- + tex->nextHash = r_texturesHashTable[hash];
- + r_texturesHashTable[hash] = tex;
- +
- + // NOTE: always return texnum as index in array or engine will stop work !!!
- + return i;
- +}
- +
- +/*
- +================
- +GL_LoadTextureArray
- +================
- +*/
- +int GL_LoadTextureArray( const char **names, int flags, imgfilter_t *filter )
- +{
- + gltexture_t *tex;
- + rgbdata_t *pic, *src;
- + char basename[256];
- + uint numLayers = 0;
- + uint picFlags = 0;
- + char name[256];
- + uint i, j, hash;
- +
- + if( !names || !names[0] || !glw_state.initialized )
- + return 0;
- +
- + // count layers (g-cont. this is pontentially unsafe loop)
- + for( i = 0; i < glConfig.max_2d_texture_layers && ( *names[i] != '\0' ); i++ )
- + numLayers++;
- + name[0] = '\0';
- +
- + if( numLayers <= 0 ) return 0;
- +
- + // create complexname from layer names
- + for( i = 0; i < numLayers; i++ )
- + {
- + FS_FileBase( names[i], basename );
- + Q_strncat( name, va( "%s", basename ), sizeof( name ));
- + if( i != ( numLayers - 1 )) Q_strncat( name, "|", sizeof( name ));
- + }
- +
- + Q_strncat( name, va( "[%i]", numLayers ), sizeof( name ));
- +
- + if( Q_strlen( name ) >= sizeof( r_textures->name ))
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: too long name %s\n", name );
- + return 0;
- + }
- +
- + // see if already loaded
- + hash = Com_HashKey( name, TEXTURES_HASH_SIZE );
- +
- + for( tex = r_texturesHashTable[hash]; tex != NULL; tex = tex->nextHash )
- + {
- + if( !Q_stricmp( tex->name, name ))
- + {
- + // prolonge registration
- + tex->cacheframe = world.load_sequence;
- + return (tex - r_textures);
- + }
- + }
- +
- + // load all the images and pack it into single image
- + for( i = 0, pic = NULL; i < numLayers; i++ )
- + {
- + size_t srcsize, dstsize, mipsize;
- +
- + src = FS_LoadImage( names[i], NULL, 0 );
- + if( !src ) break; // coldn't find layer
- +
- + if( pic )
- + {
- + // mixed mode: DXT + RGB
- + if( pic->type != src->type )
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch image format for %s and %s\n", names[0], names[i] );
- + break;
- + }
- +
- + // different mipcount
- + if( pic->numMips != src->numMips )
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch mip count for %s and %s\n", names[0], names[i] );
- + break;
- + }
- +
- + if( pic->encode != src->encode )
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch custom encoding for %s and %s\n", names[0], names[i] );
- + break;
- + }
- +
- + // but allow to rescale raw images
- + if( ImageRAW( pic->type ) && ImageRAW( src->type ) && ( pic->width != src->width || pic->height != src->height ))
- + Image_Process( &src, pic->width, pic->height, 0.0f, IMAGE_RESAMPLE, NULL );
- +
- + if( pic->size != src->size )
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch image size for %s and %s\n", names[0], names[i] );
- + break;
- + }
- + }
- + else
- + {
- + // create new image
- + pic = Mem_Alloc( host.imagepool, sizeof( rgbdata_t ));
- + memcpy( pic, src, sizeof( rgbdata_t ));
- +
- + // expand pic buffer for all layers
- + pic->buffer = Mem_Alloc( host.imagepool, pic->size * numLayers );
- + pic->depth = 0;
- + }
- +
- + mipsize = srcsize = dstsize = 0;
- +
- + for( j = 0; j < max( 1, pic->numMips ); j++ )
- + {
- + int width = max( 1, ( pic->width >> j ));
- + int height = max( 1, ( pic->height >> j ));
- + mipsize = GL_CalcImageSize( pic->type, width, height, 1 );
- + memcpy( pic->buffer + dstsize + mipsize * i, src->buffer + srcsize, mipsize );
- + dstsize += mipsize * numLayers;
- + srcsize += mipsize;
- + }
- +
- + FS_FreeImage( src );
- +
- + // increase layers
- + pic->depth++;
- + }
- +
- + // there were errors
- + if( !pic || ( pic->depth != numLayers ))
- + {
- + MsgDev( D_ERROR, "GL_LoadTextureArray: not all layers were loaded. Texture array is not created\n" );
- + if( pic ) FS_FreeImage( pic );
- + return 0;
- + }
- +
- + // it's multilayer image!
- + pic->flags |= IMAGE_MULTILAYER;
- + pic->size *= numLayers;
- +
- + // find a free texture slot
- + if( r_numTextures == MAX_TEXTURES )
- + Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
- +
- + // find a free texture_t slot
- + for( i = 0, tex = r_textures; i < r_numTextures; i++, tex++ )
- + if( !tex->name[0] ) break;
- +
- + if( i == r_numTextures )
- + {
- + if( r_numTextures == MAX_TEXTURES )
- + Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
- + r_numTextures++;
- + }
- +
- + tex = &r_textures[i];
- + Q_strncpy( tex->name, name, sizeof( tex->name ));
- + tex->flags = flags;
- + tex->texnum = i; // texnum is used for fast acess into r_textures array too
- - if(!( flags & ( TF_KEEP_8BIT|TF_KEEP_RGBDATA )))
- + GL_ProcessImage( tex, pic, filter );
- + if( !GL_UploadTexture( tex, pic ))
- + {
- + memset( tex, 0, sizeof( gltexture_t ));
- FS_FreeImage( pic ); // release source texture
- + return 0;
- + }
- +
- + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
- + FS_FreeImage( pic ); // release source texture
- // add to hash table
- hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE );
- @@ -1579,9 +1546,6 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
- Host_Error( "Couldn't find texture %s for update\n", name );
- }
- - // force upload texture as RGB or RGBA (detail textures requires this)
- - if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
- -
- // find a free texture slot
- if( r_numTextures == MAX_TEXTURES )
- Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
- @@ -1610,8 +1574,15 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
- tex->flags |= flags;
- }
- - GL_UploadTexture( pic, tex, update, NULL );
- - GL_TexFilter( tex, update ); // update texture filter, wrap etc
- + GL_ProcessImage( tex, pic, NULL );
- + if( !GL_UploadTexture( tex, pic ))
- + {
- + memset( tex, 0, sizeof( gltexture_t ));
- + FS_FreeImage( pic ); // release source texture
- + return 0;
- + }
- +
- + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
- if( !update )
- {
- @@ -1628,7 +1599,7 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
- ================
- GL_CreateTexture
- -creates an empty 32-bit texture (just reserve slot)
- +creates texture from buffer
- ================
- */
- int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
- @@ -1654,7 +1625,7 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
- if( !GL_Support( GL_TEXTURE_3D_EXT ))
- return 0;
- - r_empty.depth = r_empty.width;
- + r_empty.depth = r_empty.width; // HACKHACK
- r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4;
- }
- else if( flags & TF_CUBEMAP )
- @@ -1666,9 +1637,43 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
- texture = GL_LoadTextureInternal( name, &r_empty, flags, false );
- - if( flags & TF_DEPTHMAP )
- - GL_SetTextureType( texture, TEX_DEPTHMAP );
- - else GL_SetTextureType( texture, TEX_CUSTOM );
- + return texture;
- +}
- +
- +/*
- +================
- +GL_CreateTextureArray
- +
- +creates texture array from buffer
- +================
- +*/
- +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags )
- +{
- + rgbdata_t r_empty;
- + int texture;
- +
- + memset( &r_empty, 0, sizeof( r_empty ));
- + r_empty.width = width;
- + r_empty.height = height;
- + r_empty.depth = depth;
- + r_empty.type = PF_RGBA_32;
- + r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4;
- + r_empty.flags = IMAGE_HAS_COLOR | (( flags & TF_HAS_ALPHA ) ? IMAGE_HAS_ALPHA : 0 );
- + r_empty.buffer = (byte *)buffer;
- +
- + if( flags & TF_TEXTURE_3D )
- + {
- + if( !GL_Support( GL_TEXTURE_3D_EXT ))
- + return 0;
- + }
- + else
- + {
- + if( !GL_Support( GL_TEXTURE_ARRAY_EXT ))
- + return 0;
- + r_empty.flags |= IMAGE_MULTILAYER;
- + }
- +
- + texture = GL_LoadTextureInternal( name, &r_empty, flags, false );
- return texture;
- }
- @@ -1703,7 +1708,7 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
- return;
- }
- - if(!( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT)) || !image->original )
- + if( !image->original )
- {
- MsgDev( D_ERROR, "GL_ProcessTexture: no input data for %s\n", image->name );
- return;
- @@ -1719,8 +1724,8 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
- pic = FS_CopyImage( image->original );
- Image_Process( &pic, topColor, bottomColor, gamma, flags, NULL );
- - GL_UploadTexture( pic, image, true, NULL );
- - GL_TexFilter( image, true ); // update texture filter, wrap etc
- + GL_UploadTexture( image, pic );
- + GL_ApplyTextureParams( image ); // update texture filter, wrap etc
- FS_FreeImage( pic );
- }
- @@ -1777,7 +1782,7 @@ void GL_FreeImage( const char *name )
- if( Q_strlen( name ) >= sizeof( r_textures->name ))
- {
- - MsgDev( D_ERROR, "GL_FreeImage: too long name %s\n", name, sizeof( r_textures->name ));
- + MsgDev( D_ERROR, "GL_FreeImage: too long name %s\n", name );
- return;
- }
- @@ -1847,7 +1852,7 @@ void R_FreeImage( gltexture_t *image )
- }
- // release source
- - if( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT) && image->original )
- + if( image->original )
- FS_FreeImage( image->original );
- pglDeleteTextures( 1, &image->texnum );
- @@ -2272,7 +2277,7 @@ static rgbdata_t *R_InitNormalizeCubemap( texFlags_t *flags )
- float s, t;
- vec3_t normal;
- - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- return NULL;
- // normal cube map texture
- @@ -2328,7 +2333,7 @@ static rgbdata_t *R_InitDlightCubemap( texFlags_t *flags )
- byte *dataCM = data2D;
- int dx2, dy, d;
- - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- return NULL;
- // normal cube map texture
- @@ -2372,7 +2377,7 @@ static rgbdata_t *R_InitGrayCubemap( texFlags_t *flags )
- int size = 4;
- byte *dataCM = data2D;
- - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- return NULL;
- // gray cubemap - just stub for pointlights
- @@ -2399,7 +2404,7 @@ static rgbdata_t *R_InitWhiteCubemap( texFlags_t *flags )
- int size = 4;
- byte *dataCM = data2D;
- - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- return NULL;
- // white cubemap - just stub for pointlights
- @@ -2418,29 +2423,6 @@ static rgbdata_t *R_InitWhiteCubemap( texFlags_t *flags )
- /*
- ==================
- -R_InitAlphaContrast
- -==================
- -*/
- -static rgbdata_t *R_InitAlphaContrast( texFlags_t *flags )
- -{
- - int size = 64;
- - byte *data = data2D;
- -
- - *flags = (TF_NOPICMIP|TF_UNCOMPRESSED|TF_ALPHACONTRAST|TF_INTENSITY);
- -
- - r_image.width = r_image.height = 64;
- - r_image.size = r_image.width * r_image.height * 4;
- -
- - memset( data, size, r_image.size );
- -
- - r_image.buffer = data2D;
- - r_image.type = PF_RGBA_32;
- -
- - return &r_image;
- -}
- -
- -/*
- -==================
- R_InitVSDCTCubemap
- ==================
- */
- @@ -2488,33 +2470,32 @@ static void R_InitBuiltinTextures( void )
- char *name;
- int *texnum;
- rgbdata_t *(*init)( texFlags_t *flags );
- - int texType;
- }
- +
- textures[] =
- {
- - { "*default", &tr.defaultTexture, R_InitDefaultTexture, TEX_SYSTEM },
- - { "*white", &tr.whiteTexture, R_InitWhiteTexture, TEX_SYSTEM },
- - { "*gray", &tr.grayTexture, R_InitGrayTexture, TEX_SYSTEM },
- - { "*black", &tr.blackTexture, R_InitBlackTexture, TEX_SYSTEM },
- - { "*particle", &tr.particleTexture, R_InitParticleTexture, TEX_SYSTEM },
- - { "*particle2", &tr.particleTexture2, R_InitParticleTexture2, TEX_SYSTEM },
- - { "*cintexture", &tr.cinTexture, R_InitCinematicTexture, TEX_NOMIP }, // force linear filter
- - { "*dlight", &tr.dlightTexture, R_InitDlightTexture, TEX_LIGHTMAP },
- - { "*dlight2", &tr.dlightTexture2, R_InitDlightTexture2, TEX_LIGHTMAP },
- - { "*atten", &tr.attenuationTexture, R_InitAttenuationTexture, TEX_SYSTEM },
- - { "*atten2", &tr.attenuationTexture2, R_InitAttenuationTexture2, TEX_SYSTEM },
- - { "*atten3", &tr.attenuationTexture3, R_InitAttenuationTexture3, TEX_SYSTEM },
- - { "*attnno", &tr.attenuationStubTexture, R_InitAttenuationTextureNoAtten, TEX_SYSTEM },
- - { "*normalize", &tr.normalizeTexture, R_InitNormalizeCubemap, TEX_CUBEMAP },
- - { "*blankbump", &tr.blankbumpTexture, R_InitBlankBumpTexture, TEX_SYSTEM },
- - { "*blankdeluxe", &tr.blankdeluxeTexture, R_InitBlankDeluxeTexture, TEX_SYSTEM },
- - { "*lightCube", &tr.dlightCubeTexture, R_InitDlightCubemap, TEX_CUBEMAP },
- - { "*grayCube", &tr.grayCubeTexture, R_InitGrayCubemap, TEX_CUBEMAP },
- - { "*whiteCube", &tr.whiteCubeTexture, R_InitWhiteCubemap, TEX_CUBEMAP },
- - { "*atten3D", &tr.attenuationTexture3D, R_InitAttenTexture3D, TEX_SYSTEM },
- - { "*sky", &tr.skyTexture, R_InitSkyTexture, TEX_SYSTEM },
- - { "*alphaContrast", &tr.acontTexture, R_InitAlphaContrast, TEX_SYSTEM },
- - { "*vsdct", &tr.vsdctCubeTexture, R_InitVSDCTCubemap, TEX_SYSTEM },
- + { "*default", &tr.defaultTexture, R_InitDefaultTexture },
- + { "*white", &tr.whiteTexture, R_InitWhiteTexture },
- + { "*gray", &tr.grayTexture, R_InitGrayTexture },
- + { "*black", &tr.blackTexture, R_InitBlackTexture },
- + { "*particle", &tr.particleTexture, R_InitParticleTexture },
- + { "*particle2", &tr.particleTexture2, R_InitParticleTexture2 },
- + { "*cintexture", &tr.cinTexture, R_InitCinematicTexture }, // force linear filter
- + { "*dlight", &tr.dlightTexture, R_InitDlightTexture },
- + { "*dlight2", &tr.dlightTexture2, R_InitDlightTexture2 },
- + { "*atten", &tr.attenuationTexture, R_InitAttenuationTexture },
- + { "*atten2", &tr.attenuationTexture2, R_InitAttenuationTexture2 },
- + { "*atten3", &tr.attenuationTexture3, R_InitAttenuationTexture3 },
- + { "*attnno", &tr.attenuationStubTexture, R_InitAttenuationTextureNoAtten },
- + { "*normalize", &tr.normalizeTexture, R_InitNormalizeCubemap },
- + { "*blankbump", &tr.blankbumpTexture, R_InitBlankBumpTexture },
- + { "*blankdeluxe", &tr.blankdeluxeTexture, R_InitBlankDeluxeTexture },
- + { "*lightCube", &tr.dlightCubeTexture, R_InitDlightCubemap },
- + { "*grayCube", &tr.grayCubeTexture, R_InitGrayCubemap },
- + { "*whiteCube", &tr.whiteCubeTexture, R_InitWhiteCubemap },
- + { "*atten3D", &tr.attenuationTexture3D, R_InitAttenTexture3D },
- + { "*sky", &tr.skyTexture, R_InitSkyTexture },
- + { "*vsdct", &tr.vsdctCubeTexture, R_InitVSDCTCubemap },
- { NULL, NULL, NULL }
- };
- size_t i, num_builtin_textures = sizeof( textures ) / sizeof( textures[0] ) - 1;
- @@ -2527,9 +2508,206 @@ static void R_InitBuiltinTextures( void )
- pic = textures[i].init( &flags );
- if( pic == NULL ) continue;
- *textures[i].texnum = GL_LoadTextureInternal( textures[i].name, pic, flags, false );
- + }
- +}
- +
- +/*
- +===============
- +R_TextureList_f
- +===============
- +*/
- +void R_TextureList_f( void )
- +{
- + gltexture_t *image;
- + int i, texCount, bytes = 0;
- +
- + Msg( "\n" );
- + Msg(" -w-- -h-- -size- -fmt- type -data-- -encode-- -wrap-- -depth- -name--------\n" );
- +
- + for( i = texCount = 0, image = r_textures; i < r_numTextures; i++, image++ )
- + {
- + if( !image->texnum ) continue;
- +
- + bytes += image->size;
- + texCount++;
- +
- + Msg( "%4i: ", i );
- + Msg( "%4i %4i ", image->width, image->height );
- + Msg( "%5ik ", image->size >> 10 );
- +
- + switch( image->format )
- + {
- + case GL_COMPRESSED_RGBA_ARB:
- + Msg( "CRGBA " );
- + break;
- + case GL_COMPRESSED_RGB_ARB:
- + Msg( "CRGB " );
- + break;
- + case GL_COMPRESSED_LUMINANCE_ALPHA_ARB:
- + Msg( "CLA " );
- + break;
- + case GL_COMPRESSED_LUMINANCE_ARB:
- + Msg( "CL " );
- + break;
- + case GL_COMPRESSED_ALPHA_ARB:
- + Msg( "CA " );
- + break;
- + case GL_COMPRESSED_INTENSITY_ARB:
- + Msg( "CI " );
- + break;
- + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- + Msg( "DXT1c " );
- + break;
- + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- + Msg( "DXT1a " );
- + break;
- + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- + Msg( "DXT3 " );
- + break;
- + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- + Msg( "DXT5 " );
- + break;
- + case GL_RGBA:
- + Msg( "RGBA " );
- + break;
- + case GL_RGBA8:
- + Msg( "RGBA8 " );
- + break;
- + case GL_RGBA4:
- + Msg( "RGBA4 " );
- + break;
- + case GL_RGB:
- + Msg( "RGB " );
- + break;
- + case GL_RGB8:
- + Msg( "RGB8 " );
- + break;
- + case GL_RGB5:
- + Msg( "RGB5 " );
- + break;
- + case GL_LUMINANCE4_ALPHA4:
- + Msg( "L4A4 " );
- + break;
- + case GL_LUMINANCE_ALPHA:
- + case GL_LUMINANCE8_ALPHA8:
- + Msg( "L8A8 " );
- + break;
- + case GL_LUMINANCE4:
- + Msg( "L4 " );
- + break;
- + case GL_LUMINANCE:
- + case GL_LUMINANCE8:
- + Msg( "L8 " );
- + break;
- + case GL_ALPHA8:
- + Msg( "A8 " );
- + break;
- + case GL_INTENSITY8:
- + Msg( "I8 " );
- + break;
- + case GL_DEPTH_COMPONENT:
- + case GL_DEPTH_COMPONENT24:
- + Msg( "DPTH24" );
- + break;
- + case GL_DEPTH_COMPONENT32F:
- + Msg( "DPTH32" );
- + break;
- + case GL_LUMINANCE16F_ARB:
- + Msg( "L16F " );
- + break;
- + case GL_LUMINANCE32F_ARB:
- + Msg( "L32F " );
- + break;
- + case GL_LUMINANCE_ALPHA16F_ARB:
- + Msg( "LA16F " );
- + break;
- + case GL_LUMINANCE_ALPHA32F_ARB:
- + Msg( "LA32F " );
- + break;
- + case GL_RGB16F_ARB:
- + Msg( "RGB16F" );
- + break;
- + case GL_RGB32F_ARB:
- + Msg( "RGB32F" );
- + break;
- + case GL_RGBA16F_ARB:
- + Msg( "RGBA16F" );
- + break;
- + case GL_RGBA32F_ARB:
- + Msg( "RGBA32F" );
- + break;
- + default:
- + Msg( "????? " );
- + break;
- + }
- +
- + switch( image->target )
- + {
- + case GL_TEXTURE_1D:
- + Msg( " 1D " );
- + break;
- + case GL_TEXTURE_2D:
- + Msg( " 2D " );
- + break;
- + case GL_TEXTURE_3D:
- + Msg( " 3D " );
- + break;
- + case GL_TEXTURE_CUBE_MAP_ARB:
- + Msg( "CUBE " );
- + break;
- + case GL_TEXTURE_RECTANGLE_EXT:
- + Msg( "RECT " );
- + break;
- + case GL_TEXTURE_2D_ARRAY_EXT:
- + Msg( "ARRAY " );
- + break;
- + default:
- + Msg( "???? " );
- + break;
- + }
- +
- + if( image->flags & TF_NORMALMAP )
- + Msg( "normal " );
- + else Msg( "diffuse " );
- +
- + switch( image->encode )
- + {
- + case DXT_ENCODE_COLOR_YCoCg:
- + Msg( "YCoCg " );
- + break;
- + case DXT_ENCODE_NORMAL_AG_ORTHO:
- + Msg( "ortho " );
- + break;
- + case DXT_ENCODE_NORMAL_AG_STEREO:
- + Msg( "stereo " );
- + break;
- + case DXT_ENCODE_NORMAL_AG_PARABOLOID:
- + Msg( "parabolic " );
- + break;
- + case DXT_ENCODE_NORMAL_AG_QUARTIC:
- + Msg( "quartic " );
- + break;
- + case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
- + Msg( "azimuthal " );
- + break;
- + default:
- + Msg( "default " );
- + break;
- + }
- - GL_SetTextureType( *textures[i].texnum, textures[i].texType );
- + if( image->flags & TF_CLAMP )
- + Msg( "clamp " );
- + else if( image->flags & TF_BORDER )
- + Msg( "border " );
- + else Msg( "repeat " );
- + Msg( " %d ", image->depth );
- + Msg( " %s\n", image->name );
- }
- +
- + Msg( "---------------------------------------------------------\n" );
- + Msg( "%i total textures\n", texCount );
- + Msg( "%s total memory used\n", Q_memprint( bytes ));
- + Msg( "\n" );
- }
- /*
- @@ -2542,10 +2720,9 @@ void R_InitImages( void )
- uint i, hash;
- float f;
- - r_numTextures = 0;
- - scaledImage = NULL;
- memset( r_textures, 0, sizeof( r_textures ));
- memset( r_texturesHashTable, 0, sizeof( r_texturesHashTable ));
- + r_numTextures = 0;
- // create unused 0-entry
- Q_strncpy( r_textures->name, "*unused*", sizeof( r_textures->name ));
- @@ -2568,6 +2745,7 @@ void R_InitImages( void )
- R_InitBuiltinTextures();
- R_ParseTexFilters( "scripts/texfilter.txt" );
- + Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
- }
- /*
- @@ -2582,23 +2760,11 @@ void R_ShutdownImages( void )
- if( !glw_state.initialized ) return;
- - for( i = ( MAX_TEXTURE_UNITS - 1); i >= 0; i-- )
- - {
- - if( i >= GL_MaxTextureUnits( ))
- - continue;
- -
- - GL_SelectTexture( i );
- - pglBindTexture( GL_TEXTURE_2D, 0 );
- -
- - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
- - pglBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
- - }
- + Cmd_RemoveCommand( "texturelist" );
- + GL_CleanupAllTextureUnits();
- for( i = 0, image = r_textures; i < r_numTextures; i++, image++ )
- - {
- - if( !image->texnum ) continue;
- - GL_FreeTexture( i );
- - }
- + R_FreeImage( image );
- memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
- memset( r_texturesHashTable, 0, sizeof( r_texturesHashTable ));
- diff --git b/engine/client/gl_local.h a/engine/client/gl_local.h
- index 1a9deb1..314c199 100644
- --- b/engine/client/gl_local.h
- +++ a/engine/client/gl_local.h
- @@ -48,7 +48,7 @@ extern byte *r_temppool;
- #define RP_FLIPFRONTFACE BIT( 4 ) // e.g. for mirrors drawing
- #define RP_NONVIEWERREF (RP_MIRRORVIEW|RP_ENVVIEW)
- -#define R_StudioOpaque( e ) ( e->curstate.rendermode == kRenderNormal || e->curstate.rendermode == kRenderTransAlpha )
- +#define R_StudioOpaque( rm ) ( rm == kRenderNormal || rm == kRenderTransAlpha )
- #define RP_LOCALCLIENT( e ) (CL_GetLocalPlayer() && ((e)->index == CL_GetLocalPlayer()->index && e->curstate.entityType == ET_PLAYER ))
- #define RP_NORMALPASS() ((RI.params & RP_NONVIEWERREF) == 0 )
- @@ -64,6 +64,8 @@ typedef struct gltexture_s
- word srcHeight;
- word width; // upload width\height
- word height;
- + word depth; // texture depth or count of layers for 2D_ARRAY
- + byte numMips; // mipmap count
- uint cacheframe; // worldmodel->load_sequence
- @@ -78,7 +80,6 @@ typedef struct gltexture_s
- rgbdata_t *original; // keep original image
- // debug info
- - byte texType; // used for gl_showtextures
- size_t size; // upload size for debug targets
- // detail textures stuff
- @@ -113,6 +114,8 @@ typedef struct
- int viewport[4];
- mplane_t frustum[6];
- + mleaf_t *viewleaf;
- + mleaf_t *oldviewleaf;
- vec3_t pvsorigin;
- vec3_t vieworg; // locked vieworigin
- vec3_t vforward;
- @@ -135,9 +138,6 @@ typedef struct
- float fogEnd;
- int cached_contents; // in water
- - float waveHeight; // global waveHeight
- - float currentWaveHeight; // current entity waveHeight
- -
- float skyMins[2][6];
- float skyMaxs[2][6];
- @@ -147,8 +147,7 @@ typedef struct
- matrix4x4 projectionMatrix;
- matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix
- - int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
- - float lightcache[MAX_LIGHTSTYLES];
- + byte visbytes[(MAX_MAP_LEAFS+7)/8];// actual PVS for current frame
- float viewplanedist;
- mplane_t clipPlane;
- @@ -161,7 +160,6 @@ typedef struct
- int whiteTexture;
- int grayTexture;
- int blackTexture;
- - int acontTexture;
- int defaultTexture; // use for bad textures
- int particleTexture; // particle texture
- int particleTexture2; // unsmoothed particle texture
- @@ -211,6 +209,9 @@ typedef struct
- int realframecount; // not including passes
- int framecount;
- + int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
- + float lightcache[MAX_LIGHTSTYLES];
- +
- // cull info
- vec3_t modelorg; // relative to viewpoint
- } ref_globals_t;
- @@ -265,6 +266,7 @@ 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 );
- @@ -302,13 +304,14 @@ void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height,
- //
- void R_SetTextureParameters( void );
- gltexture_t *R_GetTexture( GLenum texnum );
- -void GL_SetTextureType( GLenum texnum, GLenum type );
- 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_TexFilter( gltexture_t *tex, qboolean update );
- +void GL_ApplyTextureParams( gltexture_t *tex );
- void R_FreeImage( gltexture_t *image );
- int GL_FindTexture( const char *name );
- void GL_FreeTexture( GLenum texnum );
- @@ -422,16 +425,15 @@ void R_InitSky( struct mip_s *mt, struct texture_s *tx );
- void R_AddSkyBoxSurface( msurface_t *fa );
- void R_ClearSkyBox( void );
- void R_DrawSkyBox( void );
- -void EmitSkyLayers( msurface_t *fa );
- -void EmitSkyPolys( msurface_t *fa );
- -void EmitWaterPolys( glpoly_t *polys, qboolean noCull );
- -void R_DrawSkyChain( msurface_t *s );
- +void R_DrawClouds( void );
- +void EmitWaterPolys( glpoly_t *polys, qboolean noCull, qboolean direction );
- //
- // gl_vidnt.c
- //
- #define GL_CheckForErrors() GL_CheckForErrors_( __FILE__, __LINE__ )
- void GL_CheckForErrors_( const char *filename, const int fileline );
- +void *GL_GetProcAddress( const char *name );
- void GL_UpdateSwapInterval( void );
- void GL_UpdateGammaRamp( void );
- qboolean GL_DeleteContext( void );
- @@ -492,40 +494,36 @@ void R_NewMap( void );
- enum
- {
- GL_OPENGL_110 = 0, // base
- + GL_WGL_EXTENSIONS,
- GL_WGL_SWAPCONTROL,
- GL_WGL_PROCADDRESS,
- - GL_HARDWARE_GAMMA_CONTROL,
- GL_ARB_VERTEX_BUFFER_OBJECT_EXT,
- - GL_ENV_COMBINE_EXT,
- + GL_ARB_VERTEX_ARRAY_OBJECT_EXT,
- GL_ARB_MULTITEXTURE,
- - GL_TEXTURECUBEMAP_EXT,
- - GL_DOT3_ARB_EXT,
- + GL_TEXTURE_CUBEMAP_EXT,
- GL_ANISOTROPY_EXT,
- - GL_TEXTURE_LODBIAS,
- + GL_TEXTURE_LOD_BIAS,
- GL_OCCLUSION_QUERIES_EXT,
- GL_TEXTURE_COMPRESSION_EXT,
- GL_SHADER_GLSL100_EXT,
- - GL_SGIS_MIPMAPS_EXT,
- GL_DRAW_RANGEELEMENTS_EXT,
- - GL_LOCKARRAYS_EXT,
- + GL_TEXTURE_2D_RECT_EXT,
- + GL_TEXTURE_ARRAY_EXT,
- GL_TEXTURE_3D_EXT,
- GL_CLAMPTOEDGE_EXT,
- - GL_BLEND_MINMAX_EXT,
- - GL_STENCILTWOSIDE_EXT,
- - GL_BLEND_SUBTRACT_EXT,
- GL_SHADER_OBJECTS_EXT,
- - GL_VERTEX_SHADER_EXT, // glsl vertex program
- - GL_FRAGMENT_SHADER_EXT, // glsl fragment program
- - GL_EXT_POINTPARAMETERS,
- - GL_SEPARATESTENCIL_EXT,
- GL_ARB_TEXTURE_NPOT_EXT,
- - GL_CUSTOM_VERTEX_ARRAY_EXT,
- - GL_TEXTURE_ENV_ADD_EXT,
- GL_CLAMP_TEXBORDER_EXT,
- GL_ARB_TEXTURE_FLOAT_EXT,
- + GL_ARB_HALF_FLOAT_EXT,
- GL_ARB_DEPTH_FLOAT_EXT,
- GL_ARB_SEAMLESS_CUBEMAP,
- + GL_FRAMEBUFFER_OBJECT,
- + GL_DRAW_BUFFERS_EXT,
- + GL_EXT_GPU_SHADER4, // shaders only
- + GL_ARB_TEXTURE_RG,
- GL_DEPTH_TEXTURE,
- + GL_DEBUG_OUTPUT,
- GL_SHADOW_EXT,
- GL_EXTCOUNT, // must be last
- };
- @@ -540,14 +538,24 @@ enum
- 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
- +} 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;
- @@ -555,12 +563,13 @@ typedef struct
- 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;
- - GLint texRectangle;
- + GLint max_draw_buffers;
- GLfloat max_texture_anisotropy;
- - GLfloat max_texture_lodbias;
- + GLfloat max_texture_lod_bias;
- GLint max_vertex_uniforms;
- GLint max_vertex_attribs;
- @@ -570,6 +579,9 @@ typedef struct
- int depth_bits;
- int stencil_bits;
- + gl_context_type_t context;
- + gles_wrapper_t wrapper;
- +
- qboolean softwareGammaUpdate;
- qboolean deviceSupportsGamma;
- int prev_mode;
- @@ -608,8 +620,8 @@ typedef struct
- int desktopWidth;
- int desktopHeight;
- - qboolean software; // OpenGL software emulation
- qboolean initialized; // OpenGL subsystem started
- + qboolean extended; // extended context allows to GL_Debug
- } glwstate_t;
- extern glconfig_t glConfig;
- @@ -619,7 +631,6 @@ extern glwstate_t glw_state;
- //
- // renderer cvars
- //
- -extern convar_t *gl_allow_software;
- extern convar_t *gl_texture_anisotropy;
- extern convar_t *gl_extensions;
- extern convar_t *gl_stencilbits;
- @@ -627,11 +638,9 @@ extern convar_t *gl_ignorehwgamma;
- extern convar_t *gl_swapInterval;
- extern convar_t *gl_check_errors;
- extern convar_t *gl_round_down;
- -extern convar_t *gl_texturemode;
- extern convar_t *gl_texture_lodbias;
- -extern convar_t *gl_showtextures;
- +extern convar_t *gl_texture_nearest;
- extern convar_t *gl_compress_textures;
- -extern convar_t *gl_luminance_textures;
- extern convar_t *gl_compensate_gamma_screenshots;
- extern convar_t *gl_keeptjunctions;
- extern convar_t *gl_detailscale;
- @@ -672,7 +681,6 @@ extern convar_t *r_fastsky;
- extern convar_t *vid_displayfrequency;
- extern convar_t *vid_fullscreen;
- extern convar_t *vid_gamma;
- -extern convar_t *vid_texgamma;
- extern convar_t *vid_mode;
- #endif//GL_LOCAL_H
- \ No newline at end of file
- diff --git b/engine/client/gl_mirror.c a/engine/client/gl_mirror.c
- index 797ed0c..72983dc 100644
- --- b/engine/client/gl_mirror.c
- +++ a/engine/client/gl_mirror.c
- @@ -160,7 +160,6 @@ int R_AllocateMirrorTexture( void )
- r_screen.flags = IMAGE_HAS_COLOR;
- r_screen.buffer = NULL; // create empty texture for now
- tr.mirrorTextures[i] = GL_LoadTextureInternal( txName, &r_screen, TF_IMAGE, false );
- - GL_SetTextureType( tr.mirrorTextures[i], TEX_SCREENCOPY );
- texture = tr.mirrorTextures[i];
- }
- @@ -291,10 +290,6 @@ void R_DrawMirrors( void )
- VectorCopy( origin, RI.pvsorigin );
- - // combine two leafs from client and mirror views
- - r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes );
- - r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
- -
- if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
- {
- // allow screen size
- @@ -341,7 +336,6 @@ void R_DrawMirrors( void )
- tr.mirror_entities[i].ent = NULL;
- }
- - r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame
- tr.framecount = oldframecount; // restore real framecount
- tr.num_mirror_entities = 0;
- tr.num_mirrors_used = 0;
- diff --git b/engine/client/gl_rlight.c a/engine/client/gl_rlight.c
- index 9e7a28a..19048eb 100644
- --- b/engine/client/gl_rlight.c
- +++ a/engine/client/gl_rlight.c
- @@ -29,11 +29,11 @@ DYNAMIC LIGHTS
- */
- /*
- ==================
- -R_AnimateLight
- +CL_RunLightStyles
- ==================
- */
- -void R_AnimateLight( void )
- +void CL_RunLightStyles( void )
- {
- int i, k, flight, clight;
- float l, c, lerpfrac, backlerp;
- @@ -51,36 +51,36 @@ void R_AnimateLight( void )
- {
- if( r_fullbright->integer || !cl.worldmodel->lightdata )
- {
- - RI.lightstylevalue[i] = 256 * 256;
- - RI.lightcache[i] = 3.0f;
- + tr.lightstylevalue[i] = 256 * 256;
- + tr.lightcache[i] = 3.0f;
- continue;
- }
- if( !RI.refdef.paused && RI.refdef.frametime <= 0.1f )
- ls->time += RI.refdef.frametime; // evaluate local time
- - flight = (int)floor( ls->time * 10 );
- - clight = (int)ceil( ls->time * 10 );
- + 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 )
- {
- - RI.lightstylevalue[i] = 256 * scale;
- - RI.lightcache[i] = 3.0f * scale;
- + tr.lightstylevalue[i] = 256 * scale;
- + tr.lightcache[i] = 3.0f * scale;
- continue;
- }
- else if( ls->length == 1 )
- {
- // single length style so don't bother interpolating
- - RI.lightstylevalue[i] = ls->map[0] * 22 * scale;
- - RI.lightcache[i] = ( ls->map[0] / 12.0f ) * 3.0f * scale;
- + tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
- + tr.lightcache[i] = ( ls->map[0] / 12.0f ) * 3.0f * scale;
- continue;
- }
- else if( !ls->interp || !cl_lightstyle_lerping->integer )
- {
- - RI.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
- - RI.lightcache[i] = ( ls->map[flight%ls->length] / 12.0f ) * 3.0f * scale;
- + tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
- + tr.lightcache[i] = ( ls->map[flight%ls->length] / 12.0f ) * 3.0f * scale;
- continue;
- }
- @@ -95,8 +95,8 @@ void R_AnimateLight( void )
- l += (float)( k * 22.0f ) * lerpfrac;
- c += (float)( k / 12.0f ) * lerpfrac;
- - RI.lightstylevalue[i] = (int)l * scale;
- - RI.lightcache[i] = c * 3.0f * scale;
- + tr.lightstylevalue[i] = (int)l * scale;
- + tr.lightcache[i] = c * 3.0f * scale;
- }
- }
- @@ -237,6 +237,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
- {
- float front, back, frac;
- int i, map, side, size, s, t;
- + int sample_size;
- msurface_t *surf;
- mtexinfo_t *tex;
- color24 *lm;
- @@ -269,6 +270,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
- // check for impact on this node
- surf = model->surfaces + node->firstsurface;
- + sample_size = Mod_SampleSizeForFace( surf );
- for( i = 0; i < node->numsurfaces; i++, surf++ )
- {
- @@ -283,20 +285,20 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
- if(( s < 0 || s > surf->extents[0] ) || ( t < 0 || t > surf->extents[1] ))
- continue;
- - s /= LM_SAMPLE_SIZE;
- - t /= LM_SAMPLE_SIZE;
- + s /= sample_size;
- + t /= sample_size;
- if( !surf->samples )
- return true;
- VectorClear( r_pointColor );
- - lm = surf->samples + (t * ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) + s);
- - size = ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) * ((surf->extents[1] / LM_SAMPLE_SIZE) + 1);
- + lm = surf->samples + (t * ((surf->extents[0] / sample_size) + 1) + s);
- + size = ((surf->extents[0] / sample_size) + 1) * ((surf->extents[1] / sample_size) + 1);
- for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
- {
- - uint scale = RI.lightstylevalue[surf->styles[map]];
- + uint scale = tr.lightstylevalue[surf->styles[map]];
- r_pointColor[0] += TextureToTexGamma( lm->r ) * scale;
- r_pointColor[1] += TextureToTexGamma( lm->g ) * scale;
- diff --git b/engine/client/gl_rmain.c a/engine/client/gl_rmain.c
- index 8ac980b..6b5592e 100644
- --- b/engine/client/gl_rmain.c
- +++ a/engine/client/gl_rmain.c
- @@ -30,9 +30,6 @@ float gldepthmin, gldepthmax;
- ref_params_t r_lastRefdef;
- ref_instance_t RI, prevRI;
- -mleaf_t *r_viewleaf, *r_oldviewleaf;
- -mleaf_t *r_viewleaf2, *r_oldviewleaf2;
- -
- static int R_RankForRenderMode( cl_entity_t *ent )
- {
- switch( ent->curstate.rendermode )
- @@ -370,16 +367,16 @@ int R_ComputeFxBlend( cl_entity_t *e )
- break;
- }
- - if( e->model->type != mod_brush )
- + if( e->model && e->model->type != mod_brush )
- {
- // NOTE: never pass sprites with rendercolor '0 0 0' it's a stupid Valve Hammer Editor bug
- if( !e->curstate.rendercolor.r && !e->curstate.rendercolor.g && !e->curstate.rendercolor.b )
- e->curstate.rendercolor.r = e->curstate.rendercolor.g = e->curstate.rendercolor.b = 255;
- - }
- - // apply scale to studiomodels and sprites only
- - if( e->model && e->model->type != mod_brush && !e->curstate.scale )
- - e->curstate.scale = 1.0f;
- + // apply scale to studiomodels and sprites only
- + if( !e->curstate.scale )
- + e->curstate.scale = 1.0f;
- + }
- blend = bound( 0, blend, 255 );
- @@ -745,35 +742,8 @@ R_FindViewLeaf
- */
- void R_FindViewLeaf( void )
- {
- - float height;
- - mleaf_t *leaf;
- - vec3_t tmp;
- -
- - r_oldviewleaf = r_viewleaf;
- - r_oldviewleaf2 = r_viewleaf2;
- - leaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
- - r_viewleaf2 = r_viewleaf = leaf;
- - height = RI.waveHeight ? RI.waveHeight : 16;
- -
- - // check above and below so crossing solid water doesn't draw wrong
- - if( leaf->contents == CONTENTS_EMPTY )
- - {
- - // look down a bit
- - VectorCopy( RI.pvsorigin, tmp );
- - tmp[2] -= height;
- - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes );
- - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 ))
- - r_viewleaf2 = leaf;
- - }
- - else
- - {
- - // look up a bit
- - VectorCopy( RI.pvsorigin, tmp );
- - tmp[2] += height;
- - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes );
- - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 ))
- - r_viewleaf2 = leaf;
- - }
- + RI.oldviewleaf = RI.viewleaf;
- + RI.viewleaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
- }
- /*
- @@ -805,7 +775,6 @@ static void R_SetupFrame( void )
- VectorCopy( RI.vup, RI.cull_vup );
- }
- - R_AnimateLight();
- R_RunViewmodelEvents();
- // sort opaque entities by model type to avoid drawing model shadows under alpha-surfaces
- @@ -820,11 +789,8 @@ static void R_SetupFrame( void )
- // current viewleaf
- if( RI.drawWorld )
- {
- - RI.waveHeight = cl.refdef.movevars->waveHeight * 2.0f; // set global waveheight
- RI.isSkyVisible = false; // unknown at this moment
- -
- - if(!( RI.params & RP_OLDVIEWLEAF ))
- - R_FindViewLeaf();
- + R_FindViewLeaf();
- }
- }
- @@ -999,13 +965,13 @@ static void R_CheckFog( void )
- RI.fogEnabled = false;
- - if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !r_viewleaf )
- + if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !RI.viewleaf )
- return;
- ent = CL_GetWaterEntity( RI.vieworg );
- if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 )
- cnt = ent->curstate.skin;
- - else cnt = r_viewleaf->contents;
- + else cnt = RI.viewleaf->contents;
- if( IsLiquidContents( RI.cached_contents ) && !IsLiquidContents( cnt ))
- {
- @@ -1038,8 +1004,8 @@ static void R_CheckFog( void )
- }
- else
- {
- - tex = R_RecursiveFindWaterTexture( r_viewleaf->parent, NULL, false );
- - if( tex ) RI.cached_contents = r_viewleaf->contents;
- + tex = R_RecursiveFindWaterTexture( RI.viewleaf->parent, NULL, false );
- + if( tex ) RI.cached_contents = RI.viewleaf->contents;
- }
- if( !tex ) return; // no valid fogs
- @@ -1167,7 +1133,10 @@ void R_DrawEntitiesOnList( void )
- }
- if( RI.drawWorld )
- + {
- + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- clgame.dllFuncs.pfnDrawTransparentTriangles ();
- + }
- if( !RI.refdef.onlyClientDraw )
- {
- @@ -1185,7 +1154,8 @@ void R_DrawEntitiesOnList( void )
- R_DrawViewModel();
- - CL_ExtraUpdate();
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + CL_ExtraUpdate();
- }
- /*
- @@ -1213,7 +1183,8 @@ void R_RenderScene( const ref_params_t *fd )
- R_CheckFog();
- R_DrawWorld();
- - CL_ExtraUpdate (); // don't let sound get messed up if going slow
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + CL_ExtraUpdate (); // don't let sound get messed up if going slow
- R_DrawEntitiesOnList();
- @@ -1248,7 +1219,7 @@ void R_BeginFrame( qboolean clearScene )
- else
- {
- glConfig.softwareGammaUpdate = true;
- - BuildGammaTable( vid_gamma->value, vid_texgamma->value );
- + BuildGammaTable( vid_gamma->value, GAMMA );
- GL_RebuildLightmaps();
- glConfig.softwareGammaUpdate = false;
- }
- @@ -1259,15 +1230,15 @@ void R_BeginFrame( qboolean clearScene )
- // draw buffer stuff
- pglDrawBuffer( GL_BACK );
- - // texturemode stuff
- // update texture parameters
- - if( gl_texturemode->modified || gl_texture_anisotropy->modified || gl_texture_lodbias->modified )
- + if( gl_texture_nearest->modified || gl_texture_anisotropy->modified || gl_texture_lodbias->modified )
- R_SetTextureParameters();
- // swapinterval stuff
- GL_UpdateSwapInterval();
- - CL_ExtraUpdate ();
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + CL_ExtraUpdate ();
- }
- /*
- @@ -1343,7 +1314,10 @@ void R_EndFrame( void )
- R_Set2DMode( false );
- if( !pwglSwapBuffers( glw_state.hDC ))
- - Sys_Error( "wglSwapBuffers() failed!\n" );
- + {
- + Msg( "Error: WGL: failed to swap buffers\n" );
- + Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" );
- + }
- }
- /*
- @@ -1382,7 +1356,7 @@ void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size )
- R_RenderScene( fd );
- - r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame
- + RI.oldviewleaf = RI.viewleaf = NULL; // force markleafs next frame
- }
- static int GL_RenderGetParm( int parm, int arg )
- @@ -1409,6 +1383,12 @@ static int GL_RenderGetParm( int parm, int arg )
- case PARM_TEX_ENCODE:
- glt = R_GetTexture( arg );
- return glt->encode;
- + case PARM_TEX_MIPCOUNT:
- + glt = R_GetTexture( arg );
- + return glt->numMips;
- + case PARM_TEX_DEPTH:
- + glt = R_GetTexture( arg );
- + return glt->depth;
- case PARM_TEX_SKYBOX:
- ASSERT( arg >= 0 && arg < 6 );
- return tr.skyboxTextures[arg];
- @@ -1418,7 +1398,7 @@ static int GL_RenderGetParm( int parm, int arg )
- ASSERT( arg >= 0 && arg < MAX_LIGHTMAPS );
- return tr.lightmapTextures[arg];
- case PARM_SKY_SPHERE:
- - return world.sky_sphere;
- + return world.sky_sphere && !world.custom_skybox;
- case PARM_WORLD_VERSION:
- if( cls.state != ca_active )
- return bmodel_version;
- @@ -1455,9 +1435,6 @@ static int GL_RenderGetParm( int parm, int arg )
- return glt->cacheframe;
- case PARM_MAP_HAS_DELUXE:
- return (world.deluxedata != NULL);
- - case PARM_TEX_TYPE:
- - glt = R_GetTexture( arg );
- - return glt->texType;
- case PARM_CACHEFRAME:
- return world.load_sequence;
- case PARM_MAX_IMAGE_UNITS:
- @@ -1466,6 +1443,16 @@ static int GL_RenderGetParm( int parm, int arg )
- return (cls.state == ca_active);
- case PARM_REBUILD_GAMMA:
- return glConfig.softwareGammaUpdate;
- + case PARM_DEDICATED_SERVER:
- + return (host.type == HOST_DEDICATED);
- + case PARM_SURF_SAMPLESIZE:
- + if( arg >= 0 && arg < cl.worldmodel->numsurfaces )
- + return Mod_SampleSizeForFace( &cl.worldmodel->surfaces[arg] );
- + return LM_SAMPLE_SIZE;
- + case PARM_GL_CONTEXT_TYPE:
- + return glConfig.context;
- + case PARM_GLES_WRAPPER:
- + return glConfig.wrapper;
- }
- return 0;
- }
- @@ -1604,6 +1591,11 @@ static int GL_LoadTextureNoFilter( const char *name, const byte *buf, size_t siz
- return GL_LoadTexture( name, buf, size, flags, NULL );
- }
- +static int GL_LoadTextureArrayNoFilter( const char **names, int flags )
- +{
- + return GL_LoadTextureArray( names, flags, NULL );
- +}
- +
- static const ref_overview_t *GL_GetOverviewParms( void )
- {
- return &clgame.overView;
- @@ -1616,6 +1608,7 @@ static void *R_Mem_Alloc( size_t cb, const char *filename, const int fileline )
- static void R_Mem_Free( void *mem, const char *filename, const int fileline )
- {
- + if( !mem ) return;
- _Mem_Free( mem, filename, fileline );
- }
- @@ -1662,8 +1655,8 @@ static render_api_t gRenderAPI =
- GL_TextureData,
- GL_LoadTextureNoFilter,
- GL_CreateTexture,
- - GL_SetTextureType,
- - GL_TextureUpdateCache,
- + GL_LoadTextureArrayNoFilter,
- + GL_CreateTextureArray,
- GL_FreeTexture,
- DrawSingleDecal,
- R_DecalSetupVerts,
- @@ -1683,7 +1676,7 @@ static render_api_t gRenderAPI =
- GL_TexGen,
- GL_TextureTarget,
- GL_SetTexCoordArrayMode,
- - NULL,
- + GL_GetProcAddress,
- NULL,
- NULL,
- NULL,
- @@ -1718,7 +1711,7 @@ qboolean R_InitRenderAPI( void )
- {
- if( clgame.dllFuncs.pfnGetRenderInterface( CL_RENDER_INTERFACE_VERSION, &gRenderAPI, &clgame.drawFuncs ))
- {
- - MsgDev( D_AICONSOLE, "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
- + MsgDev( D_REPORT, "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
- return true;
- }
- diff --git b/engine/client/gl_rmisc.c a/engine/client/gl_rmisc.c
- index a1160b5..bf8624c 100644
- --- b/engine/client/gl_rmisc.c
- +++ a/engine/client/gl_rmisc.c
- @@ -291,7 +291,6 @@ void R_ParseDetailTextures( const char *filename )
- {
- gltexture_t *glt;
- - GL_SetTextureType( tex->dt_texturenum, TEX_DETAIL );
- glt = R_GetTexture( tex->gl_texturenum );
- glt->xscale = xScale;
- glt->yscale = yScale;
- @@ -460,7 +459,6 @@ void R_NewMap( void )
- cl.worldmodel->leafs[i+1].efrags = NULL;
- tr.skytexturenum = -1;
- - r_viewleaf = r_oldviewleaf = NULL;
- // clearing texture chains
- for( i = 0; i < cl.worldmodel->numtextures; i++ )
- diff --git b/engine/client/gl_rpart.c a/engine/client/gl_rpart.c
- index e42d40c..5fb971f 100644
- --- b/engine/client/gl_rpart.c
- +++ a/engine/client/gl_rpart.c
- @@ -843,20 +843,64 @@ void CL_BloodStream( const vec3_t org, const vec3_t dir, int pcolor, int speed )
- {
- particle_t *p;
- int i, j;
- + float arc;
- - for( i = 0; i < speed * 20; i++ )
- + for( arc = 0.05f, i = 0; i < 100; i++, arc -= 0.005f )
- {
- p = CL_AllocParticle( NULL );
- +
- if( !p ) return;
- - p->die += Com_RandomFloat( 0.2f, 0.8f );
- + p->die += 2.0f;
- p->type = pt_vox_grav;
- - p->color = pcolor;
- + p->color = pcolor + Com_RandomLong( 0, 9 );
- - for( j = 0; j < 3; j++ )
- + VectorCopy( org, p->org );
- + VectorCopy( dir, p->vel );
- +
- + p->vel[2] -= arc;
- + arc -= 0.005f;
- +
- + VectorScale( p->vel, speed, p->vel );
- + }
- +
- + for( arc = 0.075f, i = 0; i < speed / 2; i++, arc -= 0.005f )
- + {
- + float num;
- +
- + p = CL_AllocParticle( NULL );
- + if( !p ) return;
- +
- + p->die += 3.0f;
- + p->color = pcolor + Com_RandomLong( 0, 9 );
- + p->type = pt_vox_slowgrav;
- +
- + VectorCopy( org, p->org );
- + VectorCopy( dir, p->vel );
- +
- + p->vel[2] -= arc;
- +
- + num = Com_RandomFloat( 0.0f, 1.0f );
- + num = 1.7f * num * (int)(num * speed);
- + VectorScale( p->vel, num, p->vel );
- +
- + for( j = 0; j < 2; j++ )
- {
- - p->org[j] = org[j];
- - p->vel[j] = dir[j] * speed;
- + p = CL_AllocParticle( NULL );
- + if( !p ) return;
- +
- + p->die += 3.0f;
- + p->color = pcolor + Com_RandomLong( 0, 9 );
- + p->type = pt_vox_slowgrav;
- +
- + p->org[0] = org[0] + Com_RandomFloat( -1.0f, 1.0f );
- + p->org[1] = org[1] + Com_RandomFloat( -1.0f, 1.0f );
- + p->org[2] = org[2] + Com_RandomFloat( -1.0f, 1.0f );
- +
- + VectorCopy( dir, p->vel );
- + p->vel[2] -= arc;
- +
- + VectorScale( p->vel, num, p->vel );
- }
- }
- }
- diff --git b/engine/client/gl_rsurf.c a/engine/client/gl_rsurf.c
- index a8ede91..2391c3a 100644
- --- b/engine/client/gl_rsurf.c
- +++ a/engine/client/gl_rsurf.c
- @@ -31,7 +31,6 @@ typedef struct
- static int nColinElim; // stats
- static vec2_t world_orthocenter;
- static vec2_t world_orthohalf;
- -static byte visbytes[MAX_MAP_LEAFS/8];
- static uint r_blocklights[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*3];
- static glpoly_t *fullbright_polys[MAX_TEXTURES];
- static qboolean draw_fullbrights = false;
- @@ -44,7 +43,7 @@ static void LM_UploadBlock( int lightmapnum );
- byte *Mod_GetCurrentVis( void )
- {
- - return Mod_LeafPVS( r_viewleaf, cl.worldmodel );
- + return RI.visbytes;
- }
- void Mod_SetOrthoBounds( float *mins, float *maxs )
- @@ -79,6 +78,7 @@ static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs )
- static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts )
- {
- int i, j, k, f, b;
- + int sample_size;
- vec3_t mins, maxs;
- float m, frac, s, t, *v, vertsDiv;
- vec3_t front[SUBDIVIDE_SIZE], back[SUBDIVIDE_SIZE], total;
- @@ -88,6 +88,7 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
- if( numverts > ( SUBDIVIDE_SIZE - 4 ))
- Host_Error( "Mod_SubdividePolygon: too many vertexes on face ( %i )\n", numverts );
- + sample_size = Mod_SampleSizeForFace( warpface );
- BoundPoly( numverts, verts, mins, maxs );
- for( i = 0; i < 3; i++ )
- @@ -182,15 +183,15 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
- // lightmap texture coordinates
- s = DotProduct( verts, warpface->texinfo->vecs[0] ) + warpface->texinfo->vecs[0][3];
- s -= warpface->texturemins[0];
- - s += warpface->light_s * LM_SAMPLE_SIZE;
- - s += LM_SAMPLE_SIZE >> 1;
- - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
- + s += warpface->light_s * sample_size;
- + s += sample_size >> 1;
- + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
- t = DotProduct( verts, warpface->texinfo->vecs[1] ) + warpface->texinfo->vecs[1][3];
- t -= warpface->texturemins[1];
- - t += warpface->light_t * LM_SAMPLE_SIZE;
- - t += LM_SAMPLE_SIZE >> 1;
- - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
- + t += warpface->light_t * sample_size;
- + t += sample_size >> 1;
- + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
- poly->verts[i+1][5] = s;
- poly->verts[i+1][6] = t;
- @@ -285,8 +286,8 @@ GL_BuildPolygonFromSurface
- void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
- {
- int i, lindex, lnumverts;
- + int vertpage, sample_size;
- medge_t *pedges, *r_pedge;
- - int vertpage;
- texture_t *tex;
- gltexture_t *glt;
- float *vec;
- @@ -310,6 +311,8 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
- glt->srcHeight = tex->height;
- }
- + sample_size = Mod_SampleSizeForFace( fa );
- +
- // reconstruct the polygon
- pedges = mod->edges;
- lnumverts = fa->numedges;
- @@ -350,15 +353,15 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
- // lightmap texture coordinates
- s = DotProduct( vec, fa->texinfo->vecs[0] ) + fa->texinfo->vecs[0][3];
- s -= fa->texturemins[0];
- - s += fa->light_s * LM_SAMPLE_SIZE;
- - s += LM_SAMPLE_SIZE >> 1;
- - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
- + s += fa->light_s * sample_size;
- + s += sample_size >> 1;
- + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
- t = DotProduct( vec, fa->texinfo->vecs[1] ) + fa->texinfo->vecs[1][3];
- t -= fa->texturemins[1];
- - t += fa->light_t * LM_SAMPLE_SIZE;
- - t += LM_SAMPLE_SIZE >> 1;
- - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
- + t += fa->light_t * sample_size;
- + t += sample_size >> 1;
- + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
- poly->verts[i][5] = s;
- poly->verts[i][6] = t;
- @@ -467,6 +470,7 @@ void R_AddDynamicLights( msurface_t *surf )
- int lnum, s, t, sd, td, smax, tmax;
- float sl, tl, sacc, tacc;
- vec3_t impact, origin_l;
- + int sample_size;
- mtexinfo_t *tex;
- dlight_t *dl;
- uint *bl;
- @@ -474,8 +478,9 @@ void R_AddDynamicLights( msurface_t *surf )
- // no dlighted surfaces here
- if( !R_CountSurfaceDlights( surf )) return;
- - smax = (surf->extents[0] / LM_SAMPLE_SIZE) + 1;
- - tmax = (surf->extents[1] / LM_SAMPLE_SIZE) + 1;
- + sample_size = Mod_SampleSizeForFace( surf );
- + smax = (surf->extents[0] / sample_size) + 1;
- + tmax = (surf->extents[1] / sample_size) + 1;
- tex = surf->texinfo;
- for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ )
- @@ -512,12 +517,12 @@ void R_AddDynamicLights( msurface_t *surf )
- tl = DotProduct( impact, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
- bl = r_blocklights;
- - for( t = 0, tacc = 0; t < tmax; t++, tacc += LM_SAMPLE_SIZE )
- + for( t = 0, tacc = 0; t < tmax; t++, tacc += sample_size )
- {
- td = tl - tacc;
- if( td < 0 ) td = -td;
- - for( s = 0, sacc = 0; s < smax; s++, sacc += LM_SAMPLE_SIZE, bl += 3 )
- + for( s = 0, sacc = 0; s < smax; s++, sacc += sample_size, bl += 3 )
- {
- sd = sl - sacc;
- if( sd < 0 ) sd = -sd;
- @@ -547,7 +552,7 @@ void R_SetCacheState( msurface_t *surf )
- for( maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++ )
- {
- - surf->cached_light[maps] = RI.lightstylevalue[surf->styles[maps]];
- + surf->cached_light[maps] = tr.lightstylevalue[surf->styles[maps]];
- }
- }
- @@ -637,7 +642,6 @@ static void LM_UploadBlock( qboolean dynamic )
- r_lightmap.flags = ( world.version == Q1BSP_VERSION ) ? 0 : IMAGE_HAS_COLOR;
- r_lightmap.buffer = gl_lms.lightmap_buffer;
- tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT, false );
- - GL_SetTextureType( tr.lightmapTextures[i], TEX_LIGHTMAP );
- if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
- Host_Error( "AllocBlock: full\n" );
- @@ -657,10 +661,12 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
- int smax, tmax;
- uint *bl, scale;
- int i, map, size, s, t;
- + int sample_size;
- color24 *lm;
- - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
- - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
- + sample_size = Mod_SampleSizeForFace( surf );
- + smax = ( surf->extents[0] / sample_size ) + 1;
- + tmax = ( surf->extents[1] / sample_size ) + 1;
- size = smax * tmax;
- lm = surf->samples;
- @@ -670,7 +676,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
- // add all the lightmaps
- for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255 && lm; map++ )
- {
- - scale = RI.lightstylevalue[surf->styles[map]];
- + scale = tr.lightstylevalue[surf->styles[map]];
- for( i = 0, bl = r_blocklights; i < size; i++, bl += 3, lm++ )
- {
- @@ -716,6 +722,8 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
- cl_entity_t *e = RI.currententity;
- int i, hasScale = false;
- + if( !p ) return;
- +
- // special hack for non-lightmapped surfaces
- if( p->flags & SURF_DRAWTILED )
- GL_ResetFogColor();
- @@ -879,10 +887,12 @@ void R_BlendLightmaps( void )
- for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->lightmapchain )
- {
- int smax, tmax;
- + int sample_size;
- byte *base;
- - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
- - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
- + sample_size = Mod_SampleSizeForFace( surf );
- + smax = ( surf->extents[0] / sample_size ) + 1;
- + tmax = ( surf->extents[1] / sample_size ) + 1;
- info = SURF_INFO( surf, RI.currentmodel );
- if( LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
- @@ -996,7 +1006,7 @@ void R_RenderFullbrights( void )
- for( p = fullbright_polys[i]; p; p = p->next )
- {
- if( p->flags & SURF_DRAWTURB )
- - EmitWaterPolys( p, ( p->flags & SURF_NOCULL ));
- + EmitWaterPolys( p, ( p->flags & SURF_NOCULL ), false );
- else DrawGLPoly( p, 0.0f, 0.0f );
- }
- @@ -1086,15 +1096,8 @@ void R_RenderBrushPoly( msurface_t *fa )
- else r_stats.c_brush_polys++;
- if( fa->flags & SURF_DRAWSKY )
- - {
- - if( world.sky_sphere )
- - {
- - // warp texture, no lightmaps
- - EmitSkyLayers( fa );
- - }
- - return;
- - }
- -
- + return; // already handled
- +
- t = R_TextureAnimation( fa->texinfo->texture, fa - RI.currententity->model->surfaces );
- if( RP_NORMALPASS() && fa->flags & SURF_REFLECT )
- @@ -1122,13 +1125,13 @@ void R_RenderBrushPoly( msurface_t *fa )
- if( fa->flags & SURF_DRAWTURB )
- {
- // warp texture, no lightmaps
- - EmitWaterPolys( fa->polys, ( fa->flags & SURF_NOCULL ));
- + EmitWaterPolys( fa->polys, ( fa->flags & SURF_NOCULL ), false );
- if( is_mirror ) R_EndDrawMirror();
- // END WATER STUFF
- return;
- }
- - if( t->fb_texturenum )
- + if( t->fb_texturenum && fa->polys )
- {
- // HACKHACK: store fullbrights in poly->next (only for non-water surfaces)
- fa->polys->next = fullbright_polys[t->fb_texturenum];
- @@ -1182,7 +1185,7 @@ void R_RenderBrushPoly( msurface_t *fa )
- // check for lightmap modification
- for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
- {
- - if( RI.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
- + if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
- goto dynamic;
- }
- @@ -1199,10 +1202,12 @@ dynamic:
- if(( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != tr.framecount ))
- {
- byte temp[132*132*4];
- + int sample_size;
- int smax, tmax;
- - smax = ( fa->extents[0] / LM_SAMPLE_SIZE ) + 1;
- - tmax = ( fa->extents[1] / LM_SAMPLE_SIZE ) + 1;
- + sample_size = Mod_SampleSizeForFace( fa );
- + smax = ( fa->extents[0] / sample_size ) + 1;
- + tmax = ( fa->extents[1] / sample_size ) + 1;
- R_BuildLightMap( fa, temp, smax * 4, true );
- R_SetCacheState( fa );
- @@ -1249,31 +1254,40 @@ void R_DrawTextureChains( void )
- RI.currententity = clgame.entities;
- RI.currentmodel = RI.currententity->model;
- + if( world.sky_sphere && !world.custom_skybox )
- + {
- + pglDisable( GL_TEXTURE_2D );
- + pglColor3f( 1.0f, 1.0f, 1.0f );
- + }
- +
- // clip skybox surfaces
- for( s = skychain; s != NULL; s = s->texturechain )
- R_AddSkyBoxSurface( s );
- + if( world.sky_sphere && !world.custom_skybox )
- + {
- + pglEnable( GL_TEXTURE_2D );
- +
- + if( skychain )
- + R_DrawClouds();
- + skychain = NULL;
- + }
- +
- for( i = 0; i < cl.worldmodel->numtextures; i++ )
- {
- t = cl.worldmodel->textures[i];
- if( !t ) continue;
- s = t->texturechain;
- - if( !s ) continue;
- - if( i == tr.skytexturenum )
- - {
- - if( world.sky_sphere )
- - R_DrawSkyChain( s );
- - }
- - else
- - {
- - if(( s->flags & SURF_DRAWTURB ) && cl.refdef.movevars->wateralpha < 1.0f )
- - continue; // draw translucent water later
- + if( !s || ( i == tr.skytexturenum ))
- + continue;
- - for( ; s != NULL; s = s->texturechain )
- - R_RenderBrushPoly( s );
- - }
- + if(( s->flags & SURF_DRAWTURB ) && cl.refdef.movevars->wateralpha < 1.0f )
- + continue; // draw translucent water later
- +
- + for( ; s != NULL; s = s->texturechain )
- + R_RenderBrushPoly( s );
- t->texturechain = NULL;
- }
- @@ -1298,6 +1312,10 @@ void R_DrawWaterSurfaces( void )
- if( cl.refdef.movevars->wateralpha >= 1.0f )
- return;
- + // restore worldmodel
- + RI.currententity = clgame.entities;
- + RI.currentmodel = RI.currententity->model;
- +
- // go back to the world matrix
- R_LoadIdentity();
- @@ -1323,7 +1341,7 @@ void R_DrawWaterSurfaces( void )
- GL_Bind( GL_TEXTURE0, t->gl_texturenum );
- for( ; s; s = s->texturechain )
- - EmitWaterPolys( s->polys, ( s->flags & SURF_NOCULL ));
- + EmitWaterPolys( s->polys, ( s->flags & SURF_NOCULL ), false );
- t->texturechain = NULL;
- }
- @@ -1389,7 +1407,6 @@ void R_DrawBrushModel( cl_entity_t *e )
- if( !RI.drawWorld ) return;
- clmodel = e->model;
- - RI.currentWaveHeight = RI.currententity->curstate.scale * 32.0f;
- // don't reflect this entity in mirrors
- if( e->curstate.effects & EF_NOREFLECT && RI.params & RP_MIRRORVIEW )
- @@ -1551,7 +1568,7 @@ void R_DrawStaticModel( cl_entity_t *e )
- if( R_CullSurface( psurf, RI.clipFlags ))
- continue;
- - if( psurf->flags & SURF_DRAWSKY && !world.sky_sphere )
- + if( psurf->flags & SURF_DRAWSKY )
- {
- // make sky chain to right clip the skybox
- psurf->texturechain = skychain;
- @@ -1677,7 +1694,7 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
- if( R_CullSurface( surf, clipflags ))
- continue;
- - if( surf->flags & SURF_DRAWSKY && !world.sky_sphere )
- + if( surf->flags & SURF_DRAWSKY )
- {
- // make sky chain to right clip the skybox
- surf->texturechain = skychain;
- @@ -1900,7 +1917,6 @@ void R_DrawWorld( void )
- memset( fullbright_polys, 0, sizeof( fullbright_polys ));
- memset( detail_surfaces, 0, sizeof( detail_surfaces ));
- - RI.currentWaveHeight = RI.waveHeight;
- GL_SetRenderMode( kRenderNormal );
- gl_lms.dynamic_surfaces = NULL;
- @@ -1941,7 +1957,6 @@ Mark the leaves and nodes that are in the PVS for the current leaf
- */
- void R_MarkLeaves( void )
- {
- - byte *vis;
- mnode_t *node;
- int i;
- @@ -1952,21 +1967,20 @@ void R_MarkLeaves( void )
- // force recalc viewleaf
- r_novis->modified = false;
- tr.fResetVis = false;
- - r_viewleaf = NULL;
- + RI.viewleaf = NULL;
- }
- - if( r_viewleaf == r_oldviewleaf && r_viewleaf2 == r_oldviewleaf2 && !r_novis->integer && r_viewleaf != NULL )
- + if( RI.viewleaf == RI.oldviewleaf && !r_novis->integer && RI.viewleaf != NULL )
- return;
- // development aid to let you run around
- // and see exactly where the pvs ends
- if( r_lockpvs->integer ) return;
- + RI.oldviewleaf = RI.viewleaf;
- tr.visframecount++;
- - r_oldviewleaf = r_viewleaf;
- - r_oldviewleaf2 = r_viewleaf2;
- -
- - if( r_novis->integer || RI.drawOrtho || !r_viewleaf || !cl.worldmodel->visdata )
- +
- + if( r_novis->integer || RI.drawOrtho || !RI.viewleaf || !cl.worldmodel->visdata )
- {
- // mark everything
- for( i = 0; i < cl.worldmodel->numleafs; i++ )
- @@ -1976,26 +1990,11 @@ void R_MarkLeaves( void )
- return;
- }
- - // may have to combine two clusters
- - // because of solid water boundaries
- - vis = Mod_LeafPVS( r_viewleaf, cl.worldmodel );
- -
- - if( r_viewleaf != r_viewleaf2 )
- - {
- - int longs = ( cl.worldmodel->numleafs + 31 ) >> 5;
- -
- - memcpy( visbytes, vis, longs << 2 );
- - vis = Mod_LeafPVS( r_viewleaf2, cl.worldmodel );
- -
- - for( i = 0; i < longs; i++ )
- - ((int *)visbytes)[i] |= ((int *)vis)[i];
- -
- - vis = visbytes;
- - }
- + Mod_FatPVS( RI.pvsorigin, REFPVS_RADIUS, RI.visbytes, world.visbytes, FBitSet( RI.params, RP_OLDVIEWLEAF ), r_novis->integer );
- for( i = 0; i < cl.worldmodel->numleafs; i++ )
- {
- - if( vis[i>>3] & ( 1<<( i & 7 )))
- + if( CHECKVISBIT( RI.visbytes, i ))
- {
- node = (mnode_t *)&cl.worldmodel->leafs[i+1];
- do
- @@ -2017,14 +2016,16 @@ GL_CreateSurfaceLightmap
- void GL_CreateSurfaceLightmap( msurface_t *surf )
- {
- int smax, tmax;
- + int sample_size;
- byte *base;
- if( !cl.worldmodel->lightdata ) return;
- if( surf->flags & SURF_DRAWTILED )
- return;
- - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
- - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
- + sample_size = Mod_SampleSizeForFace( surf );
- + smax = ( surf->extents[0] / sample_size ) + 1;
- + tmax = ( surf->extents[1] / sample_size ) + 1;
- if( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ))
- {
- @@ -2075,7 +2076,7 @@ void GL_RebuildLightmaps( void )
- gl_lms.current_lightmap_texture = 0;
- // setup all the lightstyles
- - R_AnimateLight();
- + CL_RunLightStyles();
- LM_InitBlock();
- @@ -2131,7 +2132,7 @@ void GL_BuildLightmaps( void )
- memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
- memset( tr.mirror_entities, 0, sizeof( tr.mirror_entities ));
- memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures ));
- - memset( visbytes, 0x00, sizeof( visbytes ));
- + memset( &RI, 0, sizeof( RI ));
- skychain = NULL;
- @@ -2142,7 +2143,7 @@ void GL_BuildLightmaps( void )
- nColinElim = 0;
- // setup all the lightstyles
- - R_AnimateLight();
- + CL_RunLightStyles();
- LM_InitBlock();
- @@ -2166,9 +2167,6 @@ void GL_BuildLightmaps( void )
- if( m->surfaces[j].flags & SURF_DRAWTURB )
- continue;
- - if( m->surfaces[j].flags & SURF_DRAWSKY && world.sky_sphere )
- - continue;
- -
- GL_BuildPolygonFromSurface( m, m->surfaces + j );
- }
- diff --git b/engine/client/gl_sprite.c a/engine/client/gl_sprite.c
- index 331e5d6..e07dc25 100644
- --- b/engine/client/gl_sprite.c
- +++ a/engine/client/gl_sprite.c
- @@ -104,8 +104,6 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t
- pspriteframe->gl_texturenum = gl_texturenum;
- *ppframe = pspriteframe;
- - GL_SetTextureType( pspriteframe->gl_texturenum, TEX_SPRITE );
- -
- return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height );
- }
- @@ -200,10 +198,10 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
- psprite->radius = pin->boundingradius;
- psprite->synctype = pin->synctype;
- - mod->mins[0] = mod->mins[1] = -pin->bounds[0] / 2;
- - mod->maxs[0] = mod->maxs[1] = pin->bounds[0] / 2;
- - mod->mins[2] = -pin->bounds[1] / 2;
- - mod->maxs[2] = pin->bounds[1] / 2;
- + mod->mins[0] = mod->mins[1] = -pin->bounds[0] * 0.5f;
- + mod->maxs[0] = mod->maxs[1] = pin->bounds[0] * 0.5f;
- + mod->mins[2] = -pin->bounds[1] * 0.5f;
- + mod->maxs[2] = pin->bounds[1] * 0.5f;
- numi = (short *)(pin + 1);
- if( host.type == HOST_DEDICATED )
- @@ -336,7 +334,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
- psprite->type = SPR_FWD_PARALLEL_ORIENTED;
- psprite->texFormat = SPR_ALPHTEST;
- psprite->numframes = mod->numframes = numframes;
- - psprite->radius = sqrt((( w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1)));
- + psprite->radius = sqrt(((w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1)));
- mod->mins[0] = mod->mins[1] = -w / 2;
- mod->maxs[0] = mod->maxs[1] = w / 2;
- @@ -384,8 +382,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
- pspriteframe->down = ( h >> 1 ) - h;
- pspriteframe->right = w + -( w >> 1 );
- pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE, false );
- - GL_SetTextureType( pspriteframe->gl_texturenum, TEX_NOMIP );
- -
- +
- xl += w;
- if( xl >= pix->width )
- {
- @@ -462,13 +459,16 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
- mspritegroup_t *pspritegroup;
- mspriteframe_t *pspriteframe = NULL;
- float *pintervals, fullinterval;
- - float targettime, time;
- int i, numframes;
- + float targettime;
- ASSERT( pModel );
- psprite = pModel->cache.data;
- - if( frame < 0 ) frame = 0;
- + if( frame < 0 )
- + {
- + frame = 0;
- + }
- else if( frame >= psprite->numframes )
- {
- MsgDev( D_WARN, "R_GetSpriteFrame: no such frame %d (%s)\n", frame, pModel->name );
- @@ -485,11 +485,10 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
- pintervals = pspritegroup->intervals;
- numframes = pspritegroup->numframes;
- fullinterval = pintervals[numframes-1];
- - time = cl.time;
- // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
- // are positive, so we don't have to worry about division by zero
- - targettime = time - ((int)(time / fullinterval)) * fullinterval;
- + targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
- for( i = 0; i < (numframes - 1); i++ )
- {
- @@ -520,98 +519,89 @@ between frames where are we lerping
- */
- float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe, mspriteframe_t **curframe )
- {
- - msprite_t *psprite;
- - mspritegroup_t *pspritegroup;
- - int i, j, numframes, frame;
- - float lerpFrac, time, jtime, jinterval;
- - float *pintervals, fullinterval, targettime;
- - int m_fDoInterp;
- + msprite_t *psprite;
- + float lerpFrac = 1.0f, frame;
- + int m_fDoInterp, oldf, newf;
- + float frametime = 0.0f;
- + int i, j, iframe;
- psprite = ent->model->cache.data;
- - frame = (int)ent->curstate.frame;
- - lerpFrac = 1.0f;
- +
- + if( ent->curstate.framerate > 0.0f )
- + frametime = (1.0f / ent->curstate.framerate);
- +
- + frame = Q_max( 0.0f, ent->curstate.frame - host.frametime * ent->curstate.framerate );
- + iframe = (int)frame;
- // misc info
- - if( r_sprite_lerping->integer )
- + if( r_sprite_lerping->integer && psprite->numframes > 1 )
- m_fDoInterp = (ent->curstate.effects & EF_NOINTERP) ? false : true;
- else m_fDoInterp = false;
- - if( frame < 0 )
- + if( m_fDoInterp == false )
- {
- - frame = 0;
- - }
- - else if( frame >= psprite->numframes )
- + // interpolation disabled for some reasons
- + *oldframe = *curframe = R_GetSpriteFrame( ent->model, ent->curstate.frame, ent->angles[YAW] );
- + return lerpFrac;
- + }
- +
- + if( iframe < 0 )
- + {
- + iframe = 0;
- + }
- + else if( iframe >= psprite->numframes )
- {
- MsgDev( D_WARN, "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name );
- - frame = psprite->numframes - 1;
- + iframe = psprite->numframes - 1;
- }
- - if( psprite->frames[frame].type == FRAME_SINGLE )
- + // calc interpolant range
- + oldf = (int)Q_floor( frame );
- + newf = (int)Q_ceil( frame );
- +
- + // allow interp between first and last frame
- + oldf = oldf % ( psprite->numframes - 1 );
- + newf = newf % ( psprite->numframes - 1 );
- +
- + // NOTE: we allow interpolation between single and angled frames e.g. for Doom monsters
- + if( psprite->frames[iframe].type == FRAME_SINGLE || psprite->frames[iframe].type == FRAME_ANGLED )
- {
- - if( m_fDoInterp )
- - {
- - if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_SINGLE )
- - {
- - // this can be happens when rendering switched between single and angled frames
- - // or change model on replace delta-entity
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 1.0f;
- - }
- -
- - if( ent->latched.prevanimtime < RI.refdef.time )
- - {
- - if( frame != ent->latched.prevblending[1] )
- - {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1];
- - ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 0.0f;
- - }
- - else lerpFrac = (RI.refdef.time - ent->latched.prevanimtime) * 10;
- - }
- - else
- - {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 0.0f;
- - }
- - }
- - else
- + // frame was changed
- + if( newf != ent->latched.prevframe )
- {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - lerpFrac = 1.0f;
- + ent->latched.prevanimtime = cl.time + frametime;
- + ent->latched.prevframe = newf;
- + lerpFrac = 1.0f; // reset lerp
- }
- +
- + if( ent->latched.prevanimtime != 0.0f && ent->latched.prevanimtime > cl.time )
- + lerpFrac = (ent->latched.prevanimtime - cl.time) * ent->curstate.framerate;
- - if( ent->latched.prevblending[0] >= psprite->numframes )
- - {
- - // reset interpolation on change model
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 0.0f;
- - }
- + // compute lerp factor
- + lerpFrac = (int)(10000 * lerpFrac) / 10000.0f;
- + lerpFrac = bound( 0.0f, 1.0f - lerpFrac, 1.0f );
- // get the interpolated frames
- - if( oldframe ) *oldframe = psprite->frames[ent->latched.prevblending[0]].frameptr;
- - if( curframe ) *curframe = psprite->frames[frame].frameptr;
- + if( oldframe ) *oldframe = R_GetSpriteFrame( ent->model, oldf, ent->angles[YAW] );
- + if( curframe ) *curframe = R_GetSpriteFrame( ent->model, newf, ent->angles[YAW] );
- }
- - else if( psprite->frames[frame].type == FRAME_GROUP )
- + else if( psprite->frames[iframe].type == FRAME_GROUP )
- {
- - pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
- - pintervals = pspritegroup->intervals;
- - numframes = pspritegroup->numframes;
- - fullinterval = pintervals[numframes-1];
- + mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[iframe].frameptr;
- + float *pintervals = pspritegroup->intervals;
- + float fullinterval, targettime, jinterval;
- + float jtime = 0.0f;
- +
- + fullinterval = pintervals[pspritegroup->numframes-1];
- jinterval = pintervals[1] - pintervals[0];
- - time = RI.refdef.time;
- - jtime = 0.0f;
- // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
- // are positive, so we don't have to worry about division by zero
- - targettime = time - ((int)(time / fullinterval)) * fullinterval;
- + targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
- // LordHavoc: since I can't measure the time properly when it loops from numframes - 1 to 0,
- // i instead measure the time of the first frame, hoping it is consistent
- - for( i = 0, j = numframes - 1; i < (numframes - 1); i++ )
- + for( i = 0, j = (pspritegroup->numframes - 1); i < (pspritegroup->numframes - 1); i++ )
- {
- if( pintervals[i] > targettime )
- break;
- @@ -620,61 +610,12 @@ float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe,
- jtime = pintervals[i];
- }
- - if( m_fDoInterp )
- - lerpFrac = (targettime - jtime) / jinterval;
- - else j = i; // no lerping
- + lerpFrac = (targettime - jtime) / jinterval;
- // get the interpolated frames
- if( oldframe ) *oldframe = pspritegroup->frames[j];
- if( curframe ) *curframe = pspritegroup->frames[i];
- }
- - else if( psprite->frames[frame].type == FRAME_ANGLED )
- - {
- - // e.g. doom-style sprite monsters
- - float yaw = ent->angles[YAW];
- - int angleframe = (int)(Q_rint(( RI.refdef.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7;
- -
- - if( m_fDoInterp )
- - {
- - if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_ANGLED )
- - {
- - // this can be happens when rendering switched between single and angled frames
- - // or change model on replace delta-entity
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 1.0f;
- - }
- -
- - if( ent->latched.prevanimtime < RI.refdef.time )
- - {
- - if( frame != ent->latched.prevblending[1] )
- - {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1];
- - ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 0.0f;
- - }
- - else lerpFrac = (RI.refdef.time - ent->latched.prevanimtime) * ent->curstate.framerate;
- - }
- - else
- - {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - ent->latched.prevanimtime = RI.refdef.time;
- - lerpFrac = 0.0f;
- - }
- - }
- - else
- - {
- - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
- - lerpFrac = 1.0f;
- - }
- -
- - pspritegroup = (mspritegroup_t *)psprite->frames[ent->latched.prevblending[0]].frameptr;
- - if( oldframe ) *oldframe = pspritegroup->frames[angleframe];
- -
- - pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
- - if( curframe ) *curframe = pspritegroup->frames[angleframe];
- - }
- return lerpFrac;
- }
- diff --git b/engine/client/gl_studio.c a/engine/client/gl_studio.c
- index 8f6fbf0..0bb18c4 100644
- --- b/engine/client/gl_studio.c
- +++ a/engine/client/gl_studio.c
- @@ -28,7 +28,7 @@ GNU General Public License for more details.
- #define STUDIO_MERGE_TEXTURES
- #define EVENT_CLIENT 5000 // less than this value it's a server-side studio events
- -#define MAXARRAYVERTS 20000 // used for draw shadows
- +#define MAXARRAYVERTS 32768 // used for draw shadows
- #define LEGS_BONES_COUNT 8
- static vec3_t hullcolor[8] =
- @@ -138,7 +138,7 @@ R_StudioInit
- */
- void R_StudioInit( void )
- {
- - float pixelAspect;
- + float pixelAspect, fov_x = 90.0f, fov_y;
- r_studio_lambert = Cvar_Get( "r_studio_lambert", "2", CVAR_ARCHIVE, "bonelighting lambert value" );
- r_studio_lerping = Cvar_Get( "r_studio_lerping", "1", CVAR_ARCHIVE, "enables studio animation lerping" );
- @@ -156,7 +156,8 @@ void R_StudioInit( void )
- pixelAspect *= (320.0f / 240.0f);
- else pixelAspect *= (640.0f / 480.0f);
- - aliasXscale = (float)scr_width->integer / RI.refdef.fov_y;
- + fov_y = V_CalcFov( &fov_x, scr_width->integer, scr_height->integer );
- + aliasXscale = (float)scr_width->integer / fov_y; // stub
- aliasYscale = aliasXscale * pixelAspect;
- Matrix3x4_LoadIdentity( g_aliastransform );
- @@ -257,10 +258,22 @@ static qboolean R_StudioComputeBBox( cl_entity_t *e, vec3_t bbox[8] )
- // rotate the bounding box
- VectorCopy( e->angles, angles );
- -
- +#if 0
- if( e->player ) angles[PITCH] = 0.0f; // don't rotate player model, only aim
- AngleVectors( angles, vectors[0], vectors[1], vectors[2] );
- +#else
- + vectors[0][0] = g_rotationmatrix[0][0];
- + vectors[0][1] = g_rotationmatrix[1][0];
- + vectors[0][2] = g_rotationmatrix[2][0];
- +
- + vectors[1][0] = g_rotationmatrix[0][1];
- + vectors[1][1] = g_rotationmatrix[1][1];
- + vectors[1][2] = g_rotationmatrix[2][1];
- + vectors[2][0] = g_rotationmatrix[0][2];
- + vectors[2][1] = g_rotationmatrix[1][2];
- + vectors[2][2] = g_rotationmatrix[2][2];
- +#endif
- // compute a full bounding box
- for( i = 0; i < 8; i++ )
- {
- @@ -270,7 +283,7 @@ static qboolean R_StudioComputeBBox( cl_entity_t *e, vec3_t bbox[8] )
- // rotate by YAW
- p2[0] = DotProduct( p1, vectors[0] );
- - p2[1] = DotProduct( p1, vectors[1] );
- + p2[1] = -DotProduct( p1, vectors[1] );
- p2[2] = DotProduct( p1, vectors[2] );
- if( bbox ) VectorAdd( p2, e->origin, bbox[i] );
- @@ -736,7 +749,7 @@ StudioCalcBoneAdj
- void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen )
- {
- mstudiobonecontroller_t *pbonecontroller;
- - float value;
- + float value = 0.0f;
- int i, j;
- pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex);
- @@ -875,13 +888,13 @@ void R_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudi
- if( !VectorCompare( angle1, angle2 ))
- {
- - AngleQuaternion( angle1, q1 );
- - AngleQuaternion( angle2, q2 );
- + AngleQuaternion( angle1, q1, true );
- + AngleQuaternion( angle2, q2, true );
- QuaternionSlerp( q1, q2, s, q );
- }
- else
- {
- - AngleQuaternion( angle1, q );
- + AngleQuaternion( angle1, q, true );
- }
- }
- @@ -2017,10 +2030,10 @@ static void R_StudioDrawPoints( void )
- pglColor4ub( clr->r, clr->g, clr->b, 255 );
- alpha = 1.0f;
- }
- - else if( g_nFaceFlags & STUDIO_NF_TRANSPARENT && R_StudioOpaque( RI.currententity ))
- + else if( g_nFaceFlags & STUDIO_NF_TRANSPARENT && R_StudioOpaque( g_iRenderMode ))
- {
- GL_SetRenderMode( kRenderTransAlpha );
- - pglAlphaFunc( GL_GREATER, 0.0f );
- + pglAlphaFunc( GL_GEQUAL, 0.5f );
- alpha = 1.0f;
- }
- else if( g_nFaceFlags & STUDIO_NF_ADDITIVE )
- @@ -2443,7 +2456,7 @@ static model_t *R_StudioSetupPlayerModel( int index )
- if( cls.key_dest == key_menu && !index )
- {
- - // we are in menu.
- + // we are in gameui.
- info = &gameui.playerinfo;
- }
- else
- @@ -2565,15 +2578,16 @@ R_StudioSetupRenderer
- */
- static void R_StudioSetupRenderer( int rendermode )
- {
- + if( rendermode > kRenderTransAdd ) rendermode = 0;
- g_iRenderMode = bound( 0, rendermode, kRenderTransAdd );
- - pglShadeModel( GL_SMOOTH ); // enable gouraud shading
- if( clgame.ds.cullMode != GL_NONE ) GL_Cull( GL_FRONT );
- // enable depthmask on studiomodels
- if( glState.drawTrans && g_iRenderMode != kRenderTransAdd )
- pglDepthMask( GL_TRUE );
- - pglAlphaFunc( GL_GREATER, 0.0f );
- + pglAlphaFunc( GL_GEQUAL, 0.5f );
- + pglShadeModel( GL_SMOOTH );
- if( g_iBackFaceCull )
- GL_FrontFace( true );
- @@ -2588,7 +2602,6 @@ R_StudioRestoreRenderer
- static void R_StudioRestoreRenderer( void )
- {
- pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
- - pglShadeModel( GL_FLAT );
- // restore depthmask state for sprites etc
- if( glState.drawTrans && g_iRenderMode != kRenderTransAdd )
- @@ -2948,7 +2961,7 @@ R_StudioDrawPlayer
- static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer )
- {
- int m_nPlayerIndex;
- - float gaitframe, gaityaw;
- + float gaitframe = 0.0f, gaityaw = 0.0f;
- vec3_t dir, prevgaitorigin;
- alight_t lighting;
- @@ -3305,6 +3318,10 @@ void R_RunViewmodelEvents( void )
- RI.currentmodel = RI.currententity->model;
- if( !RI.currentmodel ) return;
- + if( !cl.weaponstarttime ) cl.weaponstarttime = cl.time;
- + RI.currententity->curstate.animtime = cl.weaponstarttime;
- + RI.currententity->curstate.sequence = cl.weaponsequence;
- +
- pStudioDraw->StudioDrawModel( STUDIO_EVENTS );
- RI.currententity = NULL;
- @@ -3344,6 +3361,10 @@ void R_DrawViewModel( void )
- if( r_lefthand->integer == 1 || g_iBackFaceCull )
- GL_FrontFace( !glState.frontFace );
- + if( !cl.weaponstarttime ) cl.weaponstarttime = cl.time;
- + RI.currententity->curstate.animtime = cl.weaponstarttime;
- + RI.currententity->curstate.sequence = cl.weaponsequence;
- +
- pStudioDraw->StudioDrawModel( STUDIO_RENDER );
- // restore depth range
- @@ -3433,7 +3454,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
- filter = R_FindTexFilter( va( "%s.mdl/%s", mdlname, name )); // grab texture filter
- // NOTE: colormaps must have the palette for properly work. Ignore it.
- - if( Mod_AllowMaterials( ) && !( ptexture->flags & STUDIO_NF_COLORMAP ))
- + if( Mod_AllowMaterials( ) && !FBitSet( ptexture->flags, STUDIO_NF_COLORMAP ))
- {
- int gl_texturenum = 0;
- @@ -3455,7 +3476,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
- ptexture->index = (int)((byte *)phdr) + ptexture->index;
- size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768;
- - if( host.features & ENGINE_DISABLE_HDTEXTURES && ptexture->flags & STUDIO_NF_TRANSPARENT )
- + if( FBitSet( host.features, ENGINE_DISABLE_HDTEXTURES ) && FBitSet( ptexture->flags, STUDIO_NF_TRANSPARENT ))
- flags |= TF_KEEP_8BIT; // Paranoia2 alpha-tracing
- // build the texname
- @@ -3473,7 +3494,6 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
- {
- // duplicate texnum for easy acess
- if( tx ) tx->gl_texturenum = ptexture->index;
- - GL_SetTextureType( ptexture->index, TEX_STUDIO );
- }
- }
- diff --git b/engine/client/gl_vidnt.c a/engine/client/gl_vidnt.c
- index 482bed3..96700ce 100644
- --- b/engine/client/gl_vidnt.c
- +++ a/engine/client/gl_vidnt.c
- @@ -22,35 +22,28 @@ GNU General Public License for more details.
- #define VID_AUTOMODE "-1"
- #define VID_DEFAULTMODE 2.0f
- #define DISP_CHANGE_BADDUALVIEW -6 // MSVC 6.0 doesn't
- -#define num_vidmodes ( sizeof( vidmode ) / sizeof( vidmode[0] ))
- +#define num_vidmodes ARRAYSIZE( vidmode )
- #define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_SYSMENU|WS_CAPTION|WS_VISIBLE)
- #define WINDOW_EX_STYLE (0)
- -#define WINDOW_NAME "Xash Window" // Half-Life
- -
- -#ifdef WIN32
- -// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
- -__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
- -#endif
- +#define WINDOW_NAME "Xash3D Window" // Half-Life
- convar_t *renderinfo;
- -convar_t *gl_allow_software;
- convar_t *gl_extensions;
- convar_t *gl_alphabits;
- convar_t *gl_stencilbits;
- convar_t *gl_ignorehwgamma;
- convar_t *gl_texture_anisotropy;
- +convar_t *gl_texture_lodbias;
- +convar_t *gl_texture_nearest;
- convar_t *gl_compress_textures;
- -convar_t *gl_luminance_textures;
- convar_t *gl_compensate_gamma_screenshots;
- convar_t *gl_keeptjunctions;
- -convar_t *gl_texture_lodbias;
- convar_t *gl_showtextures;
- convar_t *gl_detailscale;
- convar_t *gl_swapInterval;
- convar_t *gl_check_errors;
- convar_t *gl_allow_static;
- convar_t *gl_allow_mirrors;
- -convar_t *gl_texturemode;
- convar_t *gl_wireframe;
- convar_t *gl_round_down;
- convar_t *gl_overview;
- @@ -90,7 +83,6 @@ convar_t *r_fastsky;
- convar_t *vid_displayfrequency;
- convar_t *vid_fullscreen;
- convar_t *vid_gamma;
- -convar_t *vid_texgamma;
- convar_t *vid_mode;
- byte *r_temppool;
- @@ -147,328 +139,403 @@ vidmode_t vidmode[] =
- static dllfunc_t opengl_110funcs[] =
- {
- -{ "glClearColor" , (void **)&pglClearColor },
- -{ "glClear" , (void **)&pglClear },
- -{ "glAlphaFunc" , (void **)&pglAlphaFunc },
- -{ "glBlendFunc" , (void **)&pglBlendFunc },
- -{ "glCullFace" , (void **)&pglCullFace },
- -{ "glDrawBuffer" , (void **)&pglDrawBuffer },
- -{ "glReadBuffer" , (void **)&pglReadBuffer },
- -{ "glEnable" , (void **)&pglEnable },
- -{ "glDisable" , (void **)&pglDisable },
- -{ "glEnableClientState" , (void **)&pglEnableClientState },
- -{ "glDisableClientState" , (void **)&pglDisableClientState },
- -{ "glGetBooleanv" , (void **)&pglGetBooleanv },
- -{ "glGetDoublev" , (void **)&pglGetDoublev },
- -{ "glGetFloatv" , (void **)&pglGetFloatv },
- -{ "glGetIntegerv" , (void **)&pglGetIntegerv },
- -{ "glGetError" , (void **)&pglGetError },
- -{ "glGetString" , (void **)&pglGetString },
- -{ "glFinish" , (void **)&pglFinish },
- -{ "glFlush" , (void **)&pglFlush },
- -{ "glClearDepth" , (void **)&pglClearDepth },
- -{ "glDepthFunc" , (void **)&pglDepthFunc },
- -{ "glDepthMask" , (void **)&pglDepthMask },
- -{ "glDepthRange" , (void **)&pglDepthRange },
- -{ "glFrontFace" , (void **)&pglFrontFace },
- -{ "glDrawElements" , (void **)&pglDrawElements },
- -{ "glColorMask" , (void **)&pglColorMask },
- -{ "glIndexPointer" , (void **)&pglIndexPointer },
- -{ "glVertexPointer" , (void **)&pglVertexPointer },
- -{ "glNormalPointer" , (void **)&pglNormalPointer },
- -{ "glColorPointer" , (void **)&pglColorPointer },
- -{ "glTexCoordPointer" , (void **)&pglTexCoordPointer },
- -{ "glArrayElement" , (void **)&pglArrayElement },
- -{ "glColor3f" , (void **)&pglColor3f },
- -{ "glColor3fv" , (void **)&pglColor3fv },
- -{ "glColor4f" , (void **)&pglColor4f },
- -{ "glColor4fv" , (void **)&pglColor4fv },
- -{ "glColor3ub" , (void **)&pglColor3ub },
- -{ "glColor4ub" , (void **)&pglColor4ub },
- -{ "glColor4ubv" , (void **)&pglColor4ubv },
- -{ "glTexCoord1f" , (void **)&pglTexCoord1f },
- -{ "glTexCoord2f" , (void **)&pglTexCoord2f },
- -{ "glTexCoord3f" , (void **)&pglTexCoord3f },
- -{ "glTexCoord4f" , (void **)&pglTexCoord4f },
- -{ "glTexGenf" , (void **)&pglTexGenf },
- -{ "glTexGenfv" , (void **)&pglTexGenfv },
- -{ "glTexGeni" , (void **)&pglTexGeni },
- -{ "glVertex2f" , (void **)&pglVertex2f },
- -{ "glVertex3f" , (void **)&pglVertex3f },
- -{ "glVertex3fv" , (void **)&pglVertex3fv },
- -{ "glNormal3f" , (void **)&pglNormal3f },
- -{ "glNormal3fv" , (void **)&pglNormal3fv },
- -{ "glBegin" , (void **)&pglBegin },
- -{ "glEnd" , (void **)&pglEnd },
- -{ "glLineWidth" , (void**)&pglLineWidth },
- -{ "glPointSize" , (void**)&pglPointSize },
- -{ "glMatrixMode" , (void **)&pglMatrixMode },
- -{ "glOrtho" , (void **)&pglOrtho },
- -{ "glRasterPos2f" , (void **)&pglRasterPos2f },
- -{ "glFrustum" , (void **)&pglFrustum },
- -{ "glViewport" , (void **)&pglViewport },
- -{ "glPushMatrix" , (void **)&pglPushMatrix },
- -{ "glPopMatrix" , (void **)&pglPopMatrix },
- -{ "glPushAttrib" , (void **)&pglPushAttrib },
- -{ "glPopAttrib" , (void **)&pglPopAttrib },
- -{ "glLoadIdentity" , (void **)&pglLoadIdentity },
- -{ "glLoadMatrixd" , (void **)&pglLoadMatrixd },
- -{ "glLoadMatrixf" , (void **)&pglLoadMatrixf },
- -{ "glMultMatrixd" , (void **)&pglMultMatrixd },
- -{ "glMultMatrixf" , (void **)&pglMultMatrixf },
- -{ "glRotated" , (void **)&pglRotated },
- -{ "glRotatef" , (void **)&pglRotatef },
- -{ "glScaled" , (void **)&pglScaled },
- -{ "glScalef" , (void **)&pglScalef },
- -{ "glTranslated" , (void **)&pglTranslated },
- -{ "glTranslatef" , (void **)&pglTranslatef },
- -{ "glReadPixels" , (void **)&pglReadPixels },
- -{ "glDrawPixels" , (void **)&pglDrawPixels },
- -{ "glStencilFunc" , (void **)&pglStencilFunc },
- -{ "glStencilMask" , (void **)&pglStencilMask },
- -{ "glStencilOp" , (void **)&pglStencilOp },
- -{ "glClearStencil" , (void **)&pglClearStencil },
- -{ "glIsEnabled" , (void **)&pglIsEnabled },
- -{ "glIsList" , (void **)&pglIsList },
- -{ "glIsTexture" , (void **)&pglIsTexture },
- -{ "glTexEnvf" , (void **)&pglTexEnvf },
- -{ "glTexEnvfv" , (void **)&pglTexEnvfv },
- -{ "glTexEnvi" , (void **)&pglTexEnvi },
- -{ "glTexParameterf" , (void **)&pglTexParameterf },
- -{ "glTexParameterfv" , (void **)&pglTexParameterfv },
- -{ "glTexParameteri" , (void **)&pglTexParameteri },
- -{ "glHint" , (void **)&pglHint },
- -{ "glPixelStoref" , (void **)&pglPixelStoref },
- -{ "glPixelStorei" , (void **)&pglPixelStorei },
- -{ "glGenTextures" , (void **)&pglGenTextures },
- -{ "glDeleteTextures" , (void **)&pglDeleteTextures },
- -{ "glBindTexture" , (void **)&pglBindTexture },
- -{ "glTexImage1D" , (void **)&pglTexImage1D },
- -{ "glTexImage2D" , (void **)&pglTexImage2D },
- -{ "glTexSubImage1D" , (void **)&pglTexSubImage1D },
- -{ "glTexSubImage2D" , (void **)&pglTexSubImage2D },
- -{ "glCopyTexImage1D" , (void **)&pglCopyTexImage1D },
- -{ "glCopyTexImage2D" , (void **)&pglCopyTexImage2D },
- -{ "glCopyTexSubImage1D" , (void **)&pglCopyTexSubImage1D },
- -{ "glCopyTexSubImage2D" , (void **)&pglCopyTexSubImage2D },
- -{ "glScissor" , (void **)&pglScissor },
- -{ "glGetTexEnviv" , (void **)&pglGetTexEnviv },
- -{ "glPolygonOffset" , (void **)&pglPolygonOffset },
- -{ "glPolygonMode" , (void **)&pglPolygonMode },
- -{ "glPolygonStipple" , (void **)&pglPolygonStipple },
- -{ "glClipPlane" , (void **)&pglClipPlane },
- -{ "glGetClipPlane" , (void **)&pglGetClipPlane },
- -{ "glShadeModel" , (void **)&pglShadeModel },
- -{ "glFogfv" , (void **)&pglFogfv },
- -{ "glFogf" , (void **)&pglFogf },
- -{ "glFogi" , (void **)&pglFogi },
- -{ NULL, NULL }
- -};
- -
- -static dllfunc_t pointparametersfunc[] =
- -{
- -{ "glPointParameterfEXT" , (void **)&pglPointParameterfEXT },
- -{ "glPointParameterfvEXT" , (void **)&pglPointParameterfvEXT },
- -{ NULL, NULL }
- +{ "glClearColor" , (void **)&pglClearColor },
- +{ "glClear" , (void **)&pglClear },
- +{ "glAlphaFunc" , (void **)&pglAlphaFunc },
- +{ "glBlendFunc" , (void **)&pglBlendFunc },
- +{ "glCullFace" , (void **)&pglCullFace },
- +{ "glDrawBuffer" , (void **)&pglDrawBuffer },
- +{ "glReadBuffer" , (void **)&pglReadBuffer },
- +{ "glAccum" , (void **)&pglAccum },
- +{ "glEnable" , (void **)&pglEnable },
- +{ "glDisable" , (void **)&pglDisable },
- +{ "glEnableClientState" , (void **)&pglEnableClientState },
- +{ "glDisableClientState" , (void **)&pglDisableClientState },
- +{ "glGetBooleanv" , (void **)&pglGetBooleanv },
- +{ "glGetDoublev" , (void **)&pglGetDoublev },
- +{ "glGetFloatv" , (void **)&pglGetFloatv },
- +{ "glGetIntegerv" , (void **)&pglGetIntegerv },
- +{ "glGetError" , (void **)&pglGetError },
- +{ "glGetString" , (void **)&pglGetString },
- +{ "glFinish" , (void **)&pglFinish },
- +{ "glFlush" , (void **)&pglFlush },
- +{ "glClearDepth" , (void **)&pglClearDepth },
- +{ "glDepthFunc" , (void **)&pglDepthFunc },
- +{ "glDepthMask" , (void **)&pglDepthMask },
- +{ "glDepthRange" , (void **)&pglDepthRange },
- +{ "glFrontFace" , (void **)&pglFrontFace },
- +{ "glDrawElements" , (void **)&pglDrawElements },
- +{ "glDrawArrays" , (void **)&pglDrawArrays },
- +{ "glColorMask" , (void **)&pglColorMask },
- +{ "glIndexPointer" , (void **)&pglIndexPointer },
- +{ "glVertexPointer" , (void **)&pglVertexPointer },
- +{ "glNormalPointer" , (void **)&pglNormalPointer },
- +{ "glColorPointer" , (void **)&pglColorPointer },
- +{ "glTexCoordPointer" , (void **)&pglTexCoordPointer },
- +{ "glArrayElement" , (void **)&pglArrayElement },
- +{ "glColor3f" , (void **)&pglColor3f },
- +{ "glColor3fv" , (void **)&pglColor3fv },
- +{ "glColor4f" , (void **)&pglColor4f },
- +{ "glColor4fv" , (void **)&pglColor4fv },
- +{ "glColor3ub" , (void **)&pglColor3ub },
- +{ "glColor4ub" , (void **)&pglColor4ub },
- +{ "glColor4ubv" , (void **)&pglColor4ubv },
- +{ "glTexCoord1f" , (void **)&pglTexCoord1f },
- +{ "glTexCoord2f" , (void **)&pglTexCoord2f },
- +{ "glTexCoord3f" , (void **)&pglTexCoord3f },
- +{ "glTexCoord4f" , (void **)&pglTexCoord4f },
- +{ "glTexCoord1fv" , (void **)&pglTexCoord1fv },
- +{ "glTexCoord2fv" , (void **)&pglTexCoord2fv },
- +{ "glTexCoord3fv" , (void **)&pglTexCoord3fv },
- +{ "glTexCoord4fv" , (void **)&pglTexCoord4fv },
- +{ "glTexGenf" , (void **)&pglTexGenf },
- +{ "glTexGenfv" , (void **)&pglTexGenfv },
- +{ "glTexGeni" , (void **)&pglTexGeni },
- +{ "glVertex2f" , (void **)&pglVertex2f },
- +{ "glVertex3f" , (void **)&pglVertex3f },
- +{ "glVertex3fv" , (void **)&pglVertex3fv },
- +{ "glNormal3f" , (void **)&pglNormal3f },
- +{ "glNormal3fv" , (void **)&pglNormal3fv },
- +{ "glBegin" , (void **)&pglBegin },
- +{ "glEnd" , (void **)&pglEnd },
- +{ "glLineWidth" , (void**)&pglLineWidth },
- +{ "glPointSize" , (void**)&pglPointSize },
- +{ "glMatrixMode" , (void **)&pglMatrixMode },
- +{ "glOrtho" , (void **)&pglOrtho },
- +{ "glRasterPos2f" , (void **) &pglRasterPos2f },
- +{ "glFrustum" , (void **)&pglFrustum },
- +{ "glViewport" , (void **)&pglViewport },
- +{ "glPushMatrix" , (void **)&pglPushMatrix },
- +{ "glPopMatrix" , (void **)&pglPopMatrix },
- +{ "glPushAttrib" , (void **)&pglPushAttrib },
- +{ "glPopAttrib" , (void **)&pglPopAttrib },
- +{ "glLoadIdentity" , (void **)&pglLoadIdentity },
- +{ "glLoadMatrixd" , (void **)&pglLoadMatrixd },
- +{ "glLoadMatrixf" , (void **)&pglLoadMatrixf },
- +{ "glMultMatrixd" , (void **)&pglMultMatrixd },
- +{ "glMultMatrixf" , (void **)&pglMultMatrixf },
- +{ "glRotated" , (void **)&pglRotated },
- +{ "glRotatef" , (void **)&pglRotatef },
- +{ "glScaled" , (void **)&pglScaled },
- +{ "glScalef" , (void **)&pglScalef },
- +{ "glTranslated" , (void **)&pglTranslated },
- +{ "glTranslatef" , (void **)&pglTranslatef },
- +{ "glReadPixels" , (void **)&pglReadPixels },
- +{ "glDrawPixels" , (void **)&pglDrawPixels },
- +{ "glStencilFunc" , (void **)&pglStencilFunc },
- +{ "glStencilMask" , (void **)&pglStencilMask },
- +{ "glStencilOp" , (void **)&pglStencilOp },
- +{ "glClearStencil" , (void **)&pglClearStencil },
- +{ "glIsEnabled" , (void **)&pglIsEnabled },
- +{ "glIsList" , (void **)&pglIsList },
- +{ "glIsTexture" , (void **)&pglIsTexture },
- +{ "glTexEnvf" , (void **)&pglTexEnvf },
- +{ "glTexEnvfv" , (void **)&pglTexEnvfv },
- +{ "glTexEnvi" , (void **)&pglTexEnvi },
- +{ "glTexParameterf" , (void **)&pglTexParameterf },
- +{ "glTexParameterfv" , (void **)&pglTexParameterfv },
- +{ "glTexParameteri" , (void **)&pglTexParameteri },
- +{ "glHint" , (void **)&pglHint },
- +{ "glPixelStoref" , (void **)&pglPixelStoref },
- +{ "glPixelStorei" , (void **)&pglPixelStorei },
- +{ "glGenTextures" , (void **)&pglGenTextures },
- +{ "glDeleteTextures" , (void **)&pglDeleteTextures },
- +{ "glBindTexture" , (void **)&pglBindTexture },
- +{ "glTexImage1D" , (void **)&pglTexImage1D },
- +{ "glTexImage2D" , (void **)&pglTexImage2D },
- +{ "glTexSubImage1D" , (void **)&pglTexSubImage1D },
- +{ "glTexSubImage2D" , (void **)&pglTexSubImage2D },
- +{ "glCopyTexImage1D" , (void **)&pglCopyTexImage1D },
- +{ "glCopyTexImage2D" , (void **)&pglCopyTexImage2D },
- +{ "glCopyTexSubImage1D" , (void **)&pglCopyTexSubImage1D },
- +{ "glCopyTexSubImage2D" , (void **)&pglCopyTexSubImage2D },
- +{ "glScissor" , (void **)&pglScissor },
- +{ "glGetTexImage" , (void **)&pglGetTexImage },
- +{ "glGetTexEnviv" , (void **)&pglGetTexEnviv },
- +{ "glPolygonOffset" , (void **)&pglPolygonOffset },
- +{ "glPolygonMode" , (void **)&pglPolygonMode },
- +{ "glPolygonStipple" , (void **)&pglPolygonStipple },
- +{ "glClipPlane" , (void **)&pglClipPlane },
- +{ "glGetClipPlane" , (void **)&pglGetClipPlane },
- +{ "glShadeModel" , (void **)&pglShadeModel },
- +{ "glGetTexLevelParameteriv" , (void **)&pglGetTexLevelParameteriv },
- +{ "glGetTexLevelParameterfv" , (void **)&pglGetTexLevelParameterfv },
- +{ "glFogfv" , (void **)&pglFogfv },
- +{ "glFogf" , (void **)&pglFogf },
- +{ "glFogi" , (void **)&pglFogi },
- +{ NULL , NULL }
- };
- static dllfunc_t drawrangeelementsfuncs[] =
- {
- -{ "glDrawRangeElements" , (void **)&pglDrawRangeElements },
- -{ NULL, NULL }
- +{ "glDrawRangeElements" , (void **)&pglDrawRangeElements },
- +{ NULL , NULL }
- };
- static dllfunc_t drawrangeelementsextfuncs[] =
- {
- -{ "glDrawRangeElementsEXT" , (void **)&pglDrawRangeElementsEXT },
- -{ NULL, NULL }
- +{ "glDrawRangeElementsEXT" , (void **)&pglDrawRangeElementsEXT },
- +{ NULL , NULL }
- };
- -static dllfunc_t sgis_multitexturefuncs[] =
- +static dllfunc_t debugoutputfuncs[] =
- {
- -{ "glSelectTextureSGIS" , (void **)&pglSelectTextureSGIS },
- -{ "glMTexCoord2fSGIS" , (void **)&pglMTexCoord2fSGIS },
- -{ NULL, NULL }
- +{ "glDebugMessageControlARB" , (void **)&pglDebugMessageControlARB },
- +{ "glDebugMessageInsertARB" , (void **)&pglDebugMessageInsertARB },
- +{ "glDebugMessageCallbackARB" , (void **)&pglDebugMessageCallbackARB },
- +{ "glGetDebugMessageLogARB" , (void **)&pglGetDebugMessageLogARB },
- +{ NULL , NULL }
- };
- static dllfunc_t multitexturefuncs[] =
- {
- -{ "glMultiTexCoord1fARB" , (void **)&pglMultiTexCoord1f },
- -{ "glMultiTexCoord2fARB" , (void **)&pglMultiTexCoord2f },
- -{ "glMultiTexCoord3fARB" , (void **)&pglMultiTexCoord3f },
- -{ "glMultiTexCoord4fARB" , (void **)&pglMultiTexCoord4f },
- -{ "glActiveTextureARB" , (void **)&pglActiveTextureARB },
- -{ "glClientActiveTextureARB" , (void **)&pglClientActiveTexture },
- -{ "glClientActiveTextureARB" , (void **)&pglClientActiveTextureARB },
- -{ NULL, NULL }
- -};
- -
- -static dllfunc_t compiledvertexarrayfuncs[] =
- -{
- -{ "glLockArraysEXT" , (void **)&pglLockArraysEXT },
- -{ "glUnlockArraysEXT" , (void **)&pglUnlockArraysEXT },
- -{ "glDrawArrays" , (void **)&pglDrawArrays },
- -{ NULL, NULL }
- +{ "glMultiTexCoord1fARB" , (void **)&pglMultiTexCoord1f },
- +{ "glMultiTexCoord2fARB" , (void **)&pglMultiTexCoord2f },
- +{ "glMultiTexCoord3fARB" , (void **)&pglMultiTexCoord3f },
- +{ "glMultiTexCoord4fARB" , (void **)&pglMultiTexCoord4f },
- +{ "glActiveTextureARB" , (void **)&pglActiveTexture },
- +{ "glActiveTextureARB" , (void **)&pglActiveTextureARB },
- +{ "glClientActiveTextureARB" , (void **)&pglClientActiveTexture },
- +{ "glClientActiveTextureARB" , (void **)&pglClientActiveTextureARB },
- +{ NULL , NULL }
- };
- static dllfunc_t texture3dextfuncs[] =
- {
- -{ "glTexImage3DEXT" , (void **)&pglTexImage3D },
- -{ "glTexSubImage3DEXT" , (void **)&pglTexSubImage3D },
- -{ "glCopyTexSubImage3DEXT" , (void **)&pglCopyTexSubImage3D },
- -{ NULL, NULL }
- +{ "glTexImage3DEXT" , (void **)&pglTexImage3D },
- +{ "glTexSubImage3DEXT" , (void **)&pglTexSubImage3D },
- +{ "glCopyTexSubImage3DEXT" , (void **)&pglCopyTexSubImage3D },
- +{ NULL , NULL }
- };
- -static dllfunc_t atiseparatestencilfuncs[] =
- +static dllfunc_t shaderobjectsfuncs[] =
- {
- -{ "glStencilOpSeparateATI" , (void **)&pglStencilOpSeparate },
- -{ "glStencilFuncSeparateATI" , (void **)&pglStencilFuncSeparate },
- -{ NULL, NULL }
- +{ "glDeleteObjectARB" , (void **)&pglDeleteObjectARB },
- +{ "glGetHandleARB" , (void **)&pglGetHandleARB },
- +{ "glDetachObjectARB" , (void **)&pglDetachObjectARB },
- +{ "glCreateShaderObjectARB" , (void **)&pglCreateShaderObjectARB },
- +{ "glShaderSourceARB" , (void **)&pglShaderSourceARB },
- +{ "glCompileShaderARB" , (void **)&pglCompileShaderARB },
- +{ "glCreateProgramObjectARB" , (void **)&pglCreateProgramObjectARB },
- +{ "glAttachObjectARB" , (void **)&pglAttachObjectARB },
- +{ "glLinkProgramARB" , (void **)&pglLinkProgramARB },
- +{ "glUseProgramObjectARB" , (void **)&pglUseProgramObjectARB },
- +{ "glValidateProgramARB" , (void **)&pglValidateProgramARB },
- +{ "glUniform1fARB" , (void **)&pglUniform1fARB },
- +{ "glUniform2fARB" , (void **)&pglUniform2fARB },
- +{ "glUniform3fARB" , (void **)&pglUniform3fARB },
- +{ "glUniform4fARB" , (void **)&pglUniform4fARB },
- +{ "glUniform1iARB" , (void **)&pglUniform1iARB },
- +{ "glUniform2iARB" , (void **)&pglUniform2iARB },
- +{ "glUniform3iARB" , (void **)&pglUniform3iARB },
- +{ "glUniform4iARB" , (void **)&pglUniform4iARB },
- +{ "glUniform1fvARB" , (void **)&pglUniform1fvARB },
- +{ "glUniform2fvARB" , (void **)&pglUniform2fvARB },
- +{ "glUniform3fvARB" , (void **)&pglUniform3fvARB },
- +{ "glUniform4fvARB" , (void **)&pglUniform4fvARB },
- +{ "glUniform1ivARB" , (void **)&pglUniform1ivARB },
- +{ "glUniform2ivARB" , (void **)&pglUniform2ivARB },
- +{ "glUniform3ivARB" , (void **)&pglUniform3ivARB },
- +{ "glUniform4ivARB" , (void **)&pglUniform4ivARB },
- +{ "glUniformMatrix2fvARB" , (void **)&pglUniformMatrix2fvARB },
- +{ "glUniformMatrix3fvARB" , (void **)&pglUniformMatrix3fvARB },
- +{ "glUniformMatrix4fvARB" , (void **)&pglUniformMatrix4fvARB },
- +{ "glGetObjectParameterfvARB" , (void **)&pglGetObjectParameterfvARB },
- +{ "glGetObjectParameterivARB" , (void **)&pglGetObjectParameterivARB },
- +{ "glGetInfoLogARB" , (void **)&pglGetInfoLogARB },
- +{ "glGetAttachedObjectsARB" , (void **)&pglGetAttachedObjectsARB },
- +{ "glGetUniformLocationARB" , (void **)&pglGetUniformLocationARB },
- +{ "glGetActiveUniformARB" , (void **)&pglGetActiveUniformARB },
- +{ "glGetUniformfvARB" , (void **)&pglGetUniformfvARB },
- +{ "glGetUniformivARB" , (void **)&pglGetUniformivARB },
- +{ "glGetShaderSourceARB" , (void **)&pglGetShaderSourceARB },
- +{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
- +{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
- +{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
- +{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
- +{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
- +{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
- +{ "glVertexAttrib2f" , (void **)&pglVertexAttrib2fARB },
- +{ "glVertexAttrib2fv" , (void **)&pglVertexAttrib2fvARB },
- +{ "glVertexAttrib3fv" , (void **)&pglVertexAttrib3fvARB },
- +{ NULL , NULL }
- };
- -static dllfunc_t gl2separatestencilfuncs[] =
- +static dllfunc_t vbofuncs[] =
- {
- -{ "glStencilOpSeparate" , (void **)&pglStencilOpSeparate },
- -{ "glStencilFuncSeparate" , (void **)&pglStencilFuncSeparate },
- -{ NULL, NULL }
- +{ "glBindBufferARB" , (void **)&pglBindBufferARB },
- +{ "glDeleteBuffersARB" , (void **)&pglDeleteBuffersARB },
- +{ "glGenBuffersARB" , (void **)&pglGenBuffersARB },
- +{ "glIsBufferARB" , (void **)&pglIsBufferARB },
- +{ "glMapBufferARB" , (void **)&pglMapBufferARB },
- +{ "glUnmapBufferARB" , (void **)&pglUnmapBufferARB },
- +{ "glBufferDataARB" , (void **)&pglBufferDataARB },
- +{ "glBufferSubDataARB" , (void **)&pglBufferSubDataARB },
- +{ NULL , NULL}
- };
- -static dllfunc_t stenciltwosidefuncs[] =
- +static dllfunc_t vaofuncs[] =
- {
- -{ "glActiveStencilFaceEXT" , (void **)&pglActiveStencilFaceEXT },
- -{ NULL, NULL }
- +{ "glBindVertexArray" , (void **)&pglBindVertexArray },
- +{ "glDeleteVertexArrays" , (void **)&pglDeleteVertexArrays },
- +{ "glGenVertexArrays" , (void **)&pglGenVertexArrays },
- +{ "glIsVertexArray" , (void **)&pglIsVertexArray },
- +{ NULL , NULL }
- };
- -static dllfunc_t blendequationfuncs[] =
- +static dllfunc_t arbfbofuncs[] =
- {
- -{ "glBlendEquationEXT" , (void **)&pglBlendEquationEXT },
- -{ NULL, NULL }
- +{ "glIsRenderbuffer" , (void **)&pglIsRenderbuffer },
- +{ "glBindRenderbuffer" , (void **)&pglBindRenderbuffer },
- +{ "glDeleteRenderbuffers" , (void **)&pglDeleteRenderbuffers },
- +{ "glGenRenderbuffers" , (void **)&pglGenRenderbuffers },
- +{ "glRenderbufferStorage" , (void **)&pglRenderbufferStorage },
- +{ "glRenderbufferStorageMultisample" , (void **)&pglRenderbufferStorageMultisample }, // not in GL_EXT_framebuffer_object
- +{ "glGetRenderbufferParameteriv" , (void **)&pglGetRenderbufferParameteriv },
- +{ "glIsFramebuffer" , (void **)&pglIsFramebuffer },
- +{ "glBindFramebuffer" , (void **)&pglBindFramebuffer },
- +{ "glDeleteFramebuffers" , (void **)&pglDeleteFramebuffers },
- +{ "glGenFramebuffers" , (void **)&pglGenFramebuffers },
- +{ "glCheckFramebufferStatus" , (void **)&pglCheckFramebufferStatus },
- +{ "glFramebufferTexture1D" , (void **)&pglFramebufferTexture1D },
- +{ "glFramebufferTexture2D" , (void **)&pglFramebufferTexture2D },
- +{ "glFramebufferTexture3D" , (void **)&pglFramebufferTexture3D },
- +{ "glFramebufferTextureLayer" , (void **)&pglFramebufferTextureLayer }, // not in GL_EXT_framebuffer_object
- +{ "glFramebufferRenderbuffer" , (void **)&pglFramebufferRenderbuffer },
- +{ "glGetFramebufferAttachmentParameteriv" , (void **)&pglGetFramebufferAttachmentParameteriv },
- +{ "glBlitFramebuffer" , (void **)&pglBlitFramebuffer }, // not in GL_EXT_framebuffer_object
- +{ "glGenerateMipmap" , (void **)&pglGenerateMipmap },
- +{ NULL , NULL}
- };
- -static dllfunc_t shaderobjectsfuncs[] =
- +static dllfunc_t extfbofuncs[] =
- {
- -{ "glDeleteObjectARB" , (void **)&pglDeleteObjectARB },
- -{ "glGetHandleARB" , (void **)&pglGetHandleARB },
- -{ "glDetachObjectARB" , (void **)&pglDetachObjectARB },
- -{ "glCreateShaderObjectARB" , (void **)&pglCreateShaderObjectARB },
- -{ "glShaderSourceARB" , (void **)&pglShaderSourceARB },
- -{ "glCompileShaderARB" , (void **)&pglCompileShaderARB },
- -{ "glCreateProgramObjectARB" , (void **)&pglCreateProgramObjectARB },
- -{ "glAttachObjectARB" , (void **)&pglAttachObjectARB },
- -{ "glLinkProgramARB" , (void **)&pglLinkProgramARB },
- -{ "glUseProgramObjectARB" , (void **)&pglUseProgramObjectARB },
- -{ "glValidateProgramARB" , (void **)&pglValidateProgramARB },
- -{ "glUniform1fARB" , (void **)&pglUniform1fARB },
- -{ "glUniform2fARB" , (void **)&pglUniform2fARB },
- -{ "glUniform3fARB" , (void **)&pglUniform3fARB },
- -{ "glUniform4fARB" , (void **)&pglUniform4fARB },
- -{ "glUniform1iARB" , (void **)&pglUniform1iARB },
- -{ "glUniform2iARB" , (void **)&pglUniform2iARB },
- -{ "glUniform3iARB" , (void **)&pglUniform3iARB },
- -{ "glUniform4iARB" , (void **)&pglUniform4iARB },
- -{ "glUniform1fvARB" , (void **)&pglUniform1fvARB },
- -{ "glUniform2fvARB" , (void **)&pglUniform2fvARB },
- -{ "glUniform3fvARB" , (void **)&pglUniform3fvARB },
- -{ "glUniform4fvARB" , (void **)&pglUniform4fvARB },
- -{ "glUniform1ivARB" , (void **)&pglUniform1ivARB },
- -{ "glUniform2ivARB" , (void **)&pglUniform2ivARB },
- -{ "glUniform3ivARB" , (void **)&pglUniform3ivARB },
- -{ "glUniform4ivARB" , (void **)&pglUniform4ivARB },
- -{ "glUniformMatrix2fvARB" , (void **)&pglUniformMatrix2fvARB },
- -{ "glUniformMatrix3fvARB" , (void **)&pglUniformMatrix3fvARB },
- -{ "glUniformMatrix4fvARB" , (void **)&pglUniformMatrix4fvARB },
- -{ "glGetObjectParameterfvARB" , (void **)&pglGetObjectParameterfvARB },
- -{ "glGetObjectParameterivARB" , (void **)&pglGetObjectParameterivARB },
- -{ "glGetInfoLogARB" , (void **)&pglGetInfoLogARB },
- -{ "glGetAttachedObjectsARB" , (void **)&pglGetAttachedObjectsARB },
- -{ "glGetUniformLocationARB" , (void **)&pglGetUniformLocationARB },
- -{ "glGetActiveUniformARB" , (void **)&pglGetActiveUniformARB },
- -{ "glGetUniformfvARB" , (void **)&pglGetUniformfvARB },
- -{ "glGetUniformivARB" , (void **)&pglGetUniformivARB },
- -{ "glGetShaderSourceARB" , (void **)&pglGetShaderSourceARB },
- -{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
- -{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
- -{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
- -{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
- -{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
- -{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
- -{ NULL, NULL }
- +{ "glIsRenderbufferEXT" , (void **)&pglIsRenderbuffer },
- +{ "glBindRenderbufferEXT" , (void **)&pglBindRenderbuffer },
- +{ "glDeleteRenderbuffersEXT" , (void **)&pglDeleteRenderbuffers },
- +{ "glGenRenderbuffersEXT" , (void **)&pglGenRenderbuffers },
- +{ "glRenderbufferStorageEXT" , (void **)&pglRenderbufferStorage },
- +{ "glGetRenderbufferParameterivEXT" , (void **)&pglGetRenderbufferParameteriv },
- +{ "glIsFramebufferEXT" , (void **)&pglIsFramebuffer },
- +{ "glBindFramebufferEXT" , (void **)&pglBindFramebuffer },
- +{ "glDeleteFramebuffersEXT" , (void **)&pglDeleteFramebuffers },
- +{ "glGenFramebuffersEXT" , (void **)&pglGenFramebuffers },
- +{ "glCheckFramebufferStatusEXT" , (void **)&pglCheckFramebufferStatus },
- +{ "glFramebufferTexture1DEXT" , (void **)&pglFramebufferTexture1D },
- +{ "glFramebufferTexture2DEXT" , (void **)&pglFramebufferTexture2D },
- +{ "glFramebufferTexture3DEXT" , (void **)&pglFramebufferTexture3D },
- +{ "glFramebufferRenderbufferEXT" , (void **)&pglFramebufferRenderbuffer },
- +{ "glGetFramebufferAttachmentParameterivEXT" , (void **)&pglGetFramebufferAttachmentParameteriv },
- +{ "glGenerateMipmapEXT" , (void **)&pglGenerateMipmap },
- +{ NULL, NULL}
- };
- -static dllfunc_t vertexshaderfuncs[] =
- +static dllfunc_t occlusionfunc[] =
- {
- -{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
- -{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
- -{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
- -{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
- -{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
- -{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
- -{ NULL, NULL }
- +{ "glGenQueriesARB" , (void **)&pglGenQueriesARB },
- +{ "glDeleteQueriesARB" , (void **)&pglDeleteQueriesARB },
- +{ "glIsQueryARB" , (void **)&pglIsQueryARB },
- +{ "glBeginQueryARB" , (void **)&pglBeginQueryARB },
- +{ "glEndQueryARB" , (void **)&pglEndQueryARB },
- +{ "glGetQueryivARB" , (void **)&pglGetQueryivARB },
- +{ "glGetQueryObjectivARB" , (void **)&pglGetQueryObjectivARB },
- +{ "glGetQueryObjectuivARB" , (void **)&pglGetQueryObjectuivARB },
- +{ NULL , NULL }
- };
- -static dllfunc_t vbofuncs[] =
- +static dllfunc_t texturecompressionfuncs[] =
- {
- -{ "glBindBufferARB" , (void **)&pglBindBufferARB },
- -{ "glDeleteBuffersARB" , (void **)&pglDeleteBuffersARB },
- -{ "glGenBuffersARB" , (void **)&pglGenBuffersARB },
- -{ "glIsBufferARB" , (void **)&pglIsBufferARB },
- -{ "glMapBufferARB" , (void **)&pglMapBufferARB },
- -{ "glUnmapBufferARB" , (void **)&pglUnmapBufferARB },
- -{ "glBufferDataARB" , (void **)&pglBufferDataARB },
- -{ "glBufferSubDataARB" , (void **)&pglBufferSubDataARB },
- -{ NULL, NULL}
- +{ "glCompressedTexImage3DARB" , (void **)&pglCompressedTexImage3DARB },
- +{ "glCompressedTexImage2DARB" , (void **)&pglCompressedTexImage2DARB },
- +{ "glCompressedTexImage1DARB" , (void **)&pglCompressedTexImage1DARB },
- +{ "glCompressedTexSubImage3DARB" , (void **)&pglCompressedTexSubImage3DARB },
- +{ "glCompressedTexSubImage2DARB" , (void **)&pglCompressedTexSubImage2DARB },
- +{ "glCompressedTexSubImage1DARB" , (void **)&pglCompressedTexSubImage1DARB },
- +{ "glGetCompressedTexImageARB" , (void **)&pglGetCompressedTexImage },
- +{ NULL , NULL }
- };
- -static dllfunc_t occlusionfunc[] =
- +static dllfunc_t drawbuffersfuncs[] =
- {
- -{ "glGenQueriesARB" , (void **)&pglGenQueriesARB },
- -{ "glDeleteQueriesARB" , (void **)&pglDeleteQueriesARB },
- -{ "glIsQueryARB" , (void **)&pglIsQueryARB },
- -{ "glBeginQueryARB" , (void **)&pglBeginQueryARB },
- -{ "glEndQueryARB" , (void **)&pglEndQueryARB },
- -{ "glGetQueryivARB" , (void **)&pglGetQueryivARB },
- -{ "glGetQueryObjectivARB" , (void **)&pglGetQueryObjectivARB },
- -{ "glGetQueryObjectuivARB" , (void **)&pglGetQueryObjectuivARB },
- -{ NULL, NULL }
- +{ "glDrawBuffersARB" , (void **)&pglDrawBuffersARB },
- +{ NULL , NULL }
- };
- -static dllfunc_t texturecompressionfuncs[] =
- +static dllfunc_t wgl_funcs[] =
- {
- -{ "glCompressedTexImage3DARB" , (void **)&pglCompressedTexImage3DARB },
- -{ "glCompressedTexImage2DARB" , (void **)&pglCompressedTexImage2DARB },
- -{ "glCompressedTexImage1DARB" , (void **)&pglCompressedTexImage1DARB },
- -{ "glCompressedTexSubImage3DARB" , (void **)&pglCompressedTexSubImage3DARB },
- -{ "glCompressedTexSubImage2DARB" , (void **)&pglCompressedTexSubImage2DARB },
- -{ "glCompressedTexSubImage1DARB" , (void **)&pglCompressedTexSubImage1DARB },
- -{ "glGetCompressedTexImageARB" , (void **)&pglGetCompressedTexImage },
- -{ NULL, NULL }
- +{ "wglSwapBuffers" , (void **)&pwglSwapBuffers },
- +{ "wglCreateContext" , (void **)&pwglCreateContext },
- +{ "wglDeleteContext" , (void **)&pwglDeleteContext },
- +{ "wglMakeCurrent" , (void **)&pwglMakeCurrent },
- +{ "wglGetCurrentContext" , (void **)&pwglGetCurrentContext },
- +{ NULL , NULL }
- };
- -static dllfunc_t wgl_funcs[] =
- +static dllfunc_t wglproc_funcs[] =
- {
- -{ "wglSwapBuffers" , (void **)&pwglSwapBuffers },
- -{ "wglCreateContext" , (void **)&pwglCreateContext },
- -{ "wglDeleteContext" , (void **)&pwglDeleteContext },
- -{ "wglMakeCurrent" , (void **)&pwglMakeCurrent },
- -{ "wglGetCurrentContext" , (void **)&pwglGetCurrentContext },
- +{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
- { NULL, NULL }
- };
- -static dllfunc_t wglproc_funcs[] =
- +static dllfunc_t wglswapintervalfuncs[] =
- {
- -{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
- +{ "wglSwapIntervalEXT" , (void **)&pwglSwapIntervalEXT },
- { NULL, NULL }
- };
- -static dllfunc_t wglswapintervalfuncs[] =
- +static dllfunc_t wglgetextensionsstring[] =
- {
- -{ "wglSwapIntervalEXT" , (void **)&pwglSwapIntervalEXT },
- +{ "wglGetExtensionsStringEXT" , (void **)&pwglGetExtensionsStringEXT },
- { NULL, NULL }
- };
- dll_info_t opengl_dll = { "opengl32.dll", wgl_funcs, true };
- /*
- +========================
- +DebugCallback
- +
- +For ARB_debug_output
- +========================
- +*/
- +static void CALLBACK GL_DebugOutput( GLuint source, GLuint type, GLuint id, GLuint severity, GLint length, const GLcharARB *message, GLvoid *userParam )
- +{
- + switch( type )
- + {
- + case GL_DEBUG_TYPE_ERROR_ARB:
- + if( host.developer < D_ERROR ) // "-dev 2"
- + return;
- + Con_Printf( "^1OpenGL Error:^7 %s\n", message );
- + break;
- + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
- + if( host.developer < D_WARN ) // "-dev 3"
- + return;
- + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
- + break;
- + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
- + if( host.developer < D_WARN ) // "-dev 3"
- + return;
- + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
- + break;
- + case GL_DEBUG_TYPE_PORTABILITY_ARB:
- + if( host.developer < D_REPORT ) // "-dev 4"
- + return;
- + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
- + break;
- + case GL_DEBUG_TYPE_PERFORMANCE_ARB:
- + if( host.developer < D_REPORT ) // "-dev 4"
- + return;
- + Con_Printf( "OpenGL Notify: %s\n", message );
- + break;
- + case GL_DEBUG_TYPE_OTHER_ARB:
- + default: if( host.developer < D_NOTE ) // "-dev 5"
- + return;
- + Con_Printf( "OpenGL: %s\n", message );
- + break;
- + }
- +}
- +
- +/*
- =================
- GL_SetExtension
- =================
- @@ -502,7 +569,7 @@ GL_MaxTextureUnits
- int GL_MaxTextureUnits( void )
- {
- if( GL_Support( GL_SHADER_GLSL100_EXT ))
- - return min( max( glConfig.max_texture_coords, glConfig.max_teximage_units ), MAX_TEXTURE_UNITS );
- + return Q_min( Q_max( glConfig.max_texture_coords, glConfig.max_teximage_units ), MAX_TEXTURE_UNITS );
- return glConfig.max_texture_units;
- }
- @@ -531,6 +598,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
- {
- const dllfunc_t *func;
- convar_t *parm;
- + const char *extensions_string;
- MsgDev( D_NOTE, "GL_CheckExtension: %s ", name );
- @@ -548,7 +616,12 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
- GL_SetExtension( r_ext, 1 );
- }
- - if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name ))
- + extensions_string = glConfig.extensions_string;
- +
- + if( name[0] == 'W' && name[1] == 'G' && name[2] == 'L' && glConfig.wgl_extensions_string != NULL )
- + extensions_string = glConfig.wgl_extensions_string;
- +
- + if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( extensions_string, name ))
- {
- GL_SetExtension( r_ext, false ); // update render info
- MsgDev( D_NOTE, "- ^1failed\n" );
- @@ -579,8 +652,9 @@ GL_BuildGammaTable
- */
- void GL_BuildGammaTable( void )
- {
- + double invGamma;
- + double div;
- int i, v;
- - double invGamma, div;
- invGamma = 1.0 / bound( 0.5, vid_gamma->value, 2.3 );
- div = (double) 1.0 / 255.5;
- @@ -699,13 +773,15 @@ qboolean GL_CreateContext( void )
- {
- HGLRC hBaseRC;
- + glw_state.extended = false;
- +
- if(!( glw_state.hGLRC = pwglCreateContext( glw_state.hDC )))
- return GL_DeleteContext();
- if(!( pwglMakeCurrent( glw_state.hDC, glw_state.hGLRC )))
- return GL_DeleteContext();
- - if( !Sys_CheckParm( "-gldebug" ) || host.developer < 1 ) // debug bit the kills perfomance
- + if( !Sys_CheckParm( "-gldebug" ) || host.developer < D_INFO ) // debug bit the kills perfomance
- return true;
- pwglCreateContextAttribsARB = GL_GetProcAddress( "wglCreateContextAttribsARB" );
- @@ -741,6 +817,7 @@ qboolean GL_CreateContext( void )
- MsgDev( D_NOTE, "GL_CreateContext: using extended context\n" );
- pwglDeleteContext( hBaseRC ); // release first context
- + glw_state.extended = true;
- }
- return true;
- @@ -762,6 +839,8 @@ qboolean GL_UpdateContext( void )
- /*
- =================
- GL_DeleteContext
- +
- +always return false
- =================
- */
- qboolean GL_DeleteContext( void )
- @@ -842,6 +921,13 @@ static int VID_ChoosePFD( PIXELFORMATDESCRIPTOR *pfd, int colorBits, int alphaBi
- return pixelFormat;
- }
- +/*
- +=================
- +pfnEnumWnd
- +
- +callback to enumerate active windows
- +=================
- +*/
- BOOL CALLBACK pfnEnumWnd( HWND hwnd, LPARAM lParam )
- {
- string wndname;
- @@ -854,6 +940,11 @@ BOOL CALLBACK pfnEnumWnd( HWND hwnd, LPARAM lParam )
- return true;
- }
- +/*
- +=================
- +VID_EnumerateInstances
- +=================
- +*/
- uint VID_EnumerateInstances( void )
- {
- num_instances = 0;
- @@ -863,6 +954,11 @@ uint VID_EnumerateInstances( void )
- return 1;
- }
- +/*
- +=================
- +VID_StartupGamma
- +=================
- +*/
- void VID_StartupGamma( void )
- {
- size_t gamma_size;
- @@ -882,14 +978,11 @@ void VID_StartupGamma( void )
- if( gl_ignorehwgamma->integer )
- {
- glConfig.deviceSupportsGamma = false; // even if supported!
- - BuildGammaTable( vid_gamma->value, vid_texgamma->value );
- + BuildGammaTable( vid_gamma->value, GAMMA );
- MsgDev( D_NOTE, "VID_StartupGamma: software gamma initialized\n" );
- return;
- }
- - // share this extension so engine can grab them
- - GL_SetExtension( GL_HARDWARE_GAMMA_CONTROL, glConfig.deviceSupportsGamma );
- -
- savedGamma = FS_LoadFile( "gamma.dat", &gamma_size, false );
- if( !savedGamma || gamma_size != sizeof( glState.stateRamp ))
- @@ -956,6 +1049,11 @@ void VID_StartupGamma( void )
- vid_gamma->modified = true;
- }
- +/*
- +=================
- +VID_RestoreGamma
- +=================
- +*/
- void VID_RestoreGamma( void )
- {
- if( !glw_state.hDC || !glConfig.deviceSupportsGamma )
- @@ -1021,12 +1119,6 @@ qboolean GL_SetPixelformat( void )
- if( PFD.dwFlags & PFD_GENERIC_ACCELERATED )
- {
- MsgDev( D_NOTE, "VID_ChoosePFD: using Generic MCD acceleration\n" );
- - glw_state.software = false;
- - }
- - else if( gl_allow_software->integer )
- - {
- - MsgDev( D_NOTE, "VID_ChoosePFD: using software emulation\n" );
- - glw_state.software = true;
- }
- else
- {
- @@ -1037,7 +1129,6 @@ qboolean GL_SetPixelformat( void )
- else
- {
- MsgDev( D_NOTE, "VID_ChoosePFD: using hardware acceleration\n");
- - glw_state.software = false;
- }
- glConfig.color_bits = PFD.cColorBits;
- @@ -1055,6 +1146,11 @@ qboolean GL_SetPixelformat( void )
- return true;
- }
- +/*
- +=================
- +R_SaveVideoMode
- +=================
- +*/
- void R_SaveVideoMode( int vid_mode )
- {
- int mode = bound( 0, vid_mode, num_vidmodes ); // check range
- @@ -1070,6 +1166,11 @@ void R_SaveVideoMode( int vid_mode )
- MsgDev( D_NOTE, "Set: %s [%dx%d]\n", vidmode[mode].desc, vidmode[mode].width, vidmode[mode].height );
- }
- +/*
- +=================
- +R_DescribeVIDMode
- +=================
- +*/
- qboolean R_DescribeVIDMode( int width, int height )
- {
- int i;
- @@ -1087,16 +1188,21 @@ qboolean R_DescribeVIDMode( int width, int height )
- return false;
- }
- +/*
- +=================
- +VID_CreateWindow
- +=================
- +*/
- qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
- {
- - WNDCLASS wc;
- - RECT rect;
- int x = 0, y = 0, w, h;
- int stylebits = WINDOW_STYLE;
- int exstyle = WINDOW_EX_STYLE;
- static string wndname;
- HWND window;
- -
- + RECT rect;
- + WNDCLASS wc;
- +
- Q_strncpy( wndname, GI->title, sizeof( wndname ));
- // register the frame class
- @@ -1109,22 +1215,22 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
- wc.hbrBackground = (void *)COLOR_3DSHADOW;
- wc.lpszClassName = WINDOW_NAME;
- wc.lpszMenuName = 0;
- + wc.hIcon = 0;
- // find the icon file in the filesystem
- if( FS_FileExists( GI->iconpath, true ))
- {
- - char localPath[MAX_PATH];
- -
- - Q_snprintf( localPath, sizeof( localPath ), "%s/%s", GI->gamedir, GI->iconpath );
- - wc.hIcon = LoadImage( NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
- -
- - if( !wc.hIcon )
- + if( FS_GetDiskPath( GI->iconpath, true ))
- {
- - MsgDev( D_INFO, "Extract %s from pak if you want to see it.\n", GI->iconpath );
- - wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
- + string localPath;
- + Q_snprintf( localPath, sizeof( localPath ), "%s/%s", GI->gamedir, GI->iconpath );
- + wc.hIcon = LoadImage( NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
- }
- + else MsgDev( D_INFO, "Extract %s from pak if you want to see it.\n", GI->iconpath );
- }
- - else wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
- +
- + // couldn't loaded for some reasons? use default
- + if( !wc.hIcon ) wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
- if( !RegisterClass( &wc ))
- {
- @@ -1172,13 +1278,13 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
- if( host.hWnd != window )
- {
- - // probably never happens
- + // make sure what CreateWindowEx call the IN_WndProc
- MsgDev( D_WARN, "VID_CreateWindow: bad hWnd for '%s'\n", wndname );
- }
- - // host.hWnd must be filled in IN_WndProc
- if( !host.hWnd )
- {
- + // host.hWnd must be filled in IN_WndProc
- MsgDev( D_ERROR, "VID_CreateWindow: couldn't create '%s'\n", wndname );
- return false;
- }
- @@ -1218,6 +1324,11 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
- return true;
- }
- +/*
- +=================
- +VID_DestroyWindow
- +=================
- +*/
- void VID_DestroyWindow( void )
- {
- if( pwglMakeCurrent )
- @@ -1244,6 +1355,11 @@ void VID_DestroyWindow( void )
- }
- }
- +/*
- +=================
- +R_ChangeDisplaySettings
- +=================
- +*/
- rserr_t R_ChangeDisplaySettings( int vid_mode, qboolean fullscreen )
- {
- int width, height;
- @@ -1346,7 +1462,7 @@ rserr_t R_ChangeDisplaySettings( int vid_mode, qboolean fullscreen )
- return rserr_invalid_mode;
- if( freq_specified )
- - MsgDev( D_ERROR, "VID_SetMode: display frequency %i Hz not supported by your display\n", freq_specified );
- + MsgDev( D_ERROR, "VID_SetMode: display frequency %i Hz is not supported\n", freq_specified );
- glState.fullScreen = true;
- return rserr_ok;
- }
- @@ -1375,8 +1491,6 @@ qboolean VID_SetMode( void )
- qboolean fullscreen;
- rserr_t err;
- - gl_swapInterval->modified = true;
- -
- if( vid_mode->integer == -1 ) // trying to get resolution automatically by default
- {
- HDC hDCScreen = GetDC( NULL );
- @@ -1398,6 +1512,7 @@ qboolean VID_SetMode( void )
- }
- fullscreen = vid_fullscreen->integer;
- + gl_swapInterval->modified = true;
- if(( err = R_ChangeDisplaySettings( vid_mode->integer, fullscreen )) == rserr_ok )
- {
- @@ -1447,10 +1562,10 @@ void VID_CheckChanges( void )
- if( renderinfo->modified )
- {
- - if( !VID_SetMode())
- + if( !VID_SetMode( ))
- {
- - // can't initialize video subsystem
- - Host_NewInstance( va("#%s", GI->gamefolder ), "fallback to dedicated mode\n" );
- + Msg( "Error: can't initialize video subsystem\n" );
- + Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" );
- }
- else
- {
- @@ -1472,7 +1587,8 @@ qboolean R_Init_OpenGL( void )
- if( !opengl_dll.link )
- return false;
- - GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
- + if( Sys_CheckParm( "-gldebug" ) && host.developer >= 1 )
- + GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
- return VID_SetMode();
- }
- @@ -1493,7 +1609,7 @@ void R_Free_OpenGL( void )
- Sys_FreeLibrary( &opengl_dll );
- // now all extensions are disabled
- - memset( glConfig.extension, 0, sizeof( glConfig.extension[0] ) * GL_EXTCOUNT );
- + memset( glConfig.extension, 0, sizeof( glConfig.extension ));
- glw_state.initialized = false;
- }
- @@ -1504,8 +1620,6 @@ GL_SetDefaults
- */
- static void GL_SetDefaults( void )
- {
- - int i;
- -
- pglFinish();
- pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
- @@ -1529,39 +1643,20 @@ static void GL_SetDefaults( void )
- pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- pglPolygonOffset( -1.0f, -2.0f );
- - // properly disable multitexturing at startup
- - for( i = (MAX_TEXTURE_UNITS - 1); i > 0; i-- )
- - {
- - if( i >= GL_MaxTextureUnits( ))
- - continue;
- + GL_CleanupAllTextureUnits();
- - GL_SelectTexture( i );
- - pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- - pglDisable( GL_BLEND );
- - pglDisable( GL_TEXTURE_2D );
- - }
- -
- - GL_SelectTexture( 0 );
- pglDisable( GL_BLEND );
- pglDisable( GL_ALPHA_TEST );
- pglDisable( GL_POLYGON_OFFSET_FILL );
- - pglAlphaFunc( GL_GREATER, 0.0f );
- + pglAlphaFunc( GL_GEQUAL, 0.5f );
- pglEnable( GL_TEXTURE_2D );
- - pglShadeModel( GL_FLAT );
- + pglShadeModel( GL_SMOOTH );
- pglPointSize( 1.2f );
- pglLineWidth( 1.2f );
- - GL_Cull( 0 );
- + GL_Cull( GL_NONE );
- GL_FrontFace( 0 );
- -
- - R_SetTextureParameters();
- -
- - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
- - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- -
- - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
- }
- /*
- @@ -1577,19 +1672,26 @@ void R_RenderInfo_f( void )
- Msg( "GL_VERSION: %s\n", glConfig.version_string );
- // don't spam about extensions
- - if( host.developer >= 4 )
- + if( host.developer >= D_REPORT )
- + {
- Msg( "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
- + if( glConfig.wgl_extensions_string != NULL )
- + Msg( "\nWGL_EXTENSIONS: %s\n", glConfig.wgl_extensions_string );
- + }
- +
- Msg( "GL_MAX_TEXTURE_SIZE: %i\n", glConfig.max_2d_texture_size );
- if( GL_Support( GL_ARB_MULTITEXTURE ))
- Msg( "GL_MAX_TEXTURE_UNITS_ARB: %i\n", glConfig.max_texture_units );
- - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + if( GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- Msg( "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: %i\n", glConfig.max_cubemap_size );
- if( GL_Support( GL_ANISOTROPY_EXT ))
- Msg( "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: %.1f\n", glConfig.max_texture_anisotropy );
- - if( glConfig.texRectangle )
- - Msg( "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV: %i\n", glConfig.max_2d_rectangle_size );
- + if( GL_Support( GL_TEXTURE_2D_RECT_EXT ))
- + Msg( "GL_MAX_RECTANGLE_TEXTURE_SIZE: %i\n", glConfig.max_2d_rectangle_size );
- + if( GL_Support( GL_TEXTURE_ARRAY_EXT ))
- + Msg( "GL_MAX_ARRAY_TEXTURE_LAYERS_EXT: %i\n", glConfig.max_2d_texture_layers );
- if( GL_Support( GL_SHADER_GLSL100_EXT ))
- {
- Msg( "GL_MAX_TEXTURE_COORDS_ARB: %i\n", glConfig.max_texture_coords );
- @@ -1599,12 +1701,11 @@ void R_RenderInfo_f( void )
- }
- Msg( "\n" );
- - Msg( "MODE: %i, %i x %i %s\n", vid_mode->integer, r_width->integer, r_height->integer );
- + Msg( "MODE: %i, %i x %i %s\n", vid_mode->integer, r_width->integer, r_height->integer, vidmode[vid_mode->integer].desc );
- Msg( "GAMMA: %s\n", (glConfig.deviceSupportsGamma) ? "hardware" : "software" );
- Msg( "\n" );
- Msg( "PICMIP: %i\n", gl_picmip->integer );
- Msg( "SKYMIP: %i\n", gl_skymip->integer );
- - Msg( "TEXTUREMODE: %s\n", gl_texturemode->string );
- Msg( "VERTICAL SYNC: %s\n", gl_swapInterval->integer ? "enabled" : "disabled" );
- Msg( "Color %d bits, Alpha %d bits, Depth %d bits, Stencil %d bits\n", glConfig.color_bits,
- glConfig.alpha_bits, glConfig.depth_bits, glConfig.stencil_bits );
- @@ -1612,9 +1713,13 @@ void R_RenderInfo_f( void )
- //=======================================================================
- +/*
- +=================
- +GL_InitCommands
- +=================
- +*/
- void GL_InitCommands( void )
- {
- - Cbuf_AddText( "vidlatch\n" );
- Cbuf_Execute();
- // system screen width and height (don't suppose for change from console at all)
- @@ -1631,7 +1736,7 @@ void GL_InitCommands( void )
- r_novis = Cvar_Get( "r_novis", "0", 0, "ignore vis information (perfomance test)" );
- r_nocull = Cvar_Get( "r_nocull", "0", 0, "ignore frustrum culling (perfomance test)" );
- r_faceplanecull = Cvar_Get( "r_faceplanecull", "1", 0, "ignore face plane culling (perfomance test)" );
- - r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use \"2\" for auto-generate mapname_detail.txt" );
- + r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use '2' for autogenerate detail.txt" );
- r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT, "lockpvs area at current point (pvs test)" );
- r_lockcull = Cvar_Get( "r_lockcull", "0", CVAR_CHEAT, "lock frustrum area at current point (cull test)" );
- r_dynamic = Cvar_Get( "r_dynamic", "1", CVAR_ARCHIVE, "allow dynamic lighting (dlights, lightstyles)" );
- @@ -1647,9 +1752,8 @@ void GL_InitCommands( void )
- gl_picmip = Cvar_Get( "gl_picmip", "0", CVAR_GLCONFIG, "reduces resolution of textures by powers of 2" );
- gl_skymip = Cvar_Get( "gl_skymip", "0", CVAR_GLCONFIG, "reduces resolution of skybox textures by powers of 2" );
- gl_ignorehwgamma = Cvar_Get( "gl_ignorehwgamma", "0", CVAR_GLCONFIG, "ignore hardware gamma" );
- - gl_allow_software = Cvar_Get( "gl_allow_software", "0", CVAR_ARCHIVE, "allow OpenGL software emulation" );
- gl_alphabits = Cvar_Get( "gl_alphabits", "8", CVAR_GLCONFIG, "pixelformat alpha bits (0 - auto)" );
- - gl_texturemode = Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "texture filter" );
- + gl_texture_nearest = Cvar_Get( "gl_texture_nearest", "0", CVAR_ARCHIVE, "disable texture filter" );
- gl_round_down = Cvar_Get( "gl_round_down", "0", CVAR_GLCONFIG, "down size non-power of two textures" );
- gl_max_size = Cvar_Get( "gl_max_size", "512", CVAR_ARCHIVE, "no effect in Xash3D just a legacy" );
- gl_stencilbits = Cvar_Get( "gl_stencilbits", "8", CVAR_GLCONFIG, "pixelformat stencil bits (0 - auto)" );
- @@ -1658,19 +1762,18 @@ void GL_InitCommands( void )
- gl_extensions = Cvar_Get( "gl_extensions", "1", CVAR_GLCONFIG, "allow gl_extensions" );
- gl_detailscale = Cvar_Get( "gl_detailscale", "4.0", CVAR_ARCHIVE, "default scale applies while auto-generate list of detail textures" );
- gl_texture_anisotropy = Cvar_Get( "gl_anisotropy", "2.0", CVAR_ARCHIVE, "textures anisotropic filter" );
- - gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures" );
- + gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures (prefomance|quality)" );
- gl_compress_textures = Cvar_Get( "gl_compress_textures", "0", CVAR_GLCONFIG, "compress textures to safe video memory" );
- - gl_luminance_textures = Cvar_Get( "gl_luminance_textures", "0", CVAR_GLCONFIG, "force all textures to luminance" );
- - gl_compensate_gamma_screenshots = Cvar_Get( "gl_compensate_gamma_screenshots", "0", CVAR_ARCHIVE, "allow to apply gamma value for screenshots and snapshots" );
- - gl_keeptjunctions = Cvar_Get( "gl_keeptjunctions", "1", CVAR_ARCHIVE, "disable to reduce vertexes count but removing tjuncs causes blinking pixels" );
- + gl_compensate_gamma_screenshots = Cvar_Get( "gl_compensate_gamma_screenshots", "0", CVAR_ARCHIVE, "allow to apply gamma for screenshots" );
- + gl_keeptjunctions = Cvar_Get( "gl_keeptjunctions", "1", CVAR_ARCHIVE, "but removing tjuncs causes blinking pixels" );
- gl_allow_static = Cvar_Get( "gl_allow_static", "0", CVAR_ARCHIVE, "force to drawing non-moveable brushes as part of world (save FPS)" );
- gl_allow_mirrors = Cvar_Get( "gl_allow_mirrors", "1", CVAR_ARCHIVE, "allow to draw mirror surfaces" );
- - gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures (type values from 1 to 13)" );
- + gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures" );
- gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE, "use glFinish instead of glFlush" );
- gl_nosort = Cvar_Get( "gl_nosort", "0", CVAR_ARCHIVE, "disable sorting of translucent surfaces" );
- gl_clear = Cvar_Get( "gl_clear", "0", CVAR_ARCHIVE, "clearing screen after each frame" );
- gl_test = Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" );
- - gl_wireframe = Cvar_Get( "gl_wireframe", "0", 0, "show wireframe overlay" );
- + gl_wireframe = Cvar_Get( "gl_wireframe", "0", CVAR_ARCHIVE, "show wireframe overlay" );
- gl_overview = Cvar_Get( "dev_overview", "0", 0, "show level overview" );
- // these cvar not used by engine but some mods requires this
- @@ -1680,21 +1783,28 @@ void GL_InitCommands( void )
- gl_swapInterval->modified = true;
- vid_gamma = Cvar_Get( "gamma", "1.0", CVAR_ARCHIVE, "gamma amount" );
- - vid_texgamma = Cvar_Get( "texgamma", "2.2", CVAR_GLCONFIG, "texgamma amount (default Half-Life artwork gamma)" );
- vid_mode = Cvar_Get( "vid_mode", VID_AUTOMODE, CVAR_RENDERINFO, "display resolution mode" );
- vid_fullscreen = Cvar_Get( "fullscreen", "0", CVAR_RENDERINFO, "set in 1 to enable fullscreen mode" );
- vid_displayfrequency = Cvar_Get ( "vid_displayfrequency", "0", CVAR_RENDERINFO, "fullscreen refresh rate" );
- Cmd_AddCommand( "r_info", R_RenderInfo_f, "display renderer info" );
- - Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
- }
- +/*
- +=================
- +GL_RemoveCommands
- +=================
- +*/
- void GL_RemoveCommands( void )
- {
- Cmd_RemoveCommand( "r_info");
- - Cmd_RemoveCommand( "texturelist" );
- }
- +/*
- +=================
- +GL_InitExtensions
- +=================
- +*/
- void GL_InitExtensions( void )
- {
- // initialize gl extensions
- @@ -1707,6 +1817,35 @@ void GL_InitExtensions( void )
- glConfig.extensions_string = pglGetString( GL_EXTENSIONS );
- MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string );
- + // intialize wrapper type
- + glConfig.context = CONTEXT_TYPE_GL;
- + glConfig.wrapper = GLES_WRAPPER_NONE;
- +
- + if( Q_stristr( glConfig.renderer_string, "geforce" ))
- + glConfig.hardware_type = GLHW_NVIDIA;
- + else if( Q_stristr( glConfig.renderer_string, "quadro fx" ))
- + glConfig.hardware_type = GLHW_NVIDIA;
- + else if( Q_stristr(glConfig.renderer_string, "rv770" ))
- + glConfig.hardware_type = GLHW_RADEON;
- + else if( Q_stristr(glConfig.renderer_string, "radeon hd" ))
- + glConfig.hardware_type = GLHW_RADEON;
- + else if( Q_stristr( glConfig.renderer_string, "eah4850" ) || Q_stristr( glConfig.renderer_string, "eah4870" ))
- + glConfig.hardware_type = GLHW_RADEON;
- + else if( Q_stristr( glConfig.renderer_string, "radeon" ))
- + glConfig.hardware_type = GLHW_RADEON;
- + else glConfig.hardware_type = GLHW_GENERIC;
- +
- + // initalize until base opengl functions loaded (old-context)
- + if( !Sys_CheckParm( "-gldebug" ) || host.developer < D_INFO )
- + GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
- +
- + // windows-specific extensions
- + GL_CheckExtension( "WGL Extensions String", wglgetextensionsstring, NULL, GL_WGL_EXTENSIONS );
- +
- + if( pwglGetExtensionsStringEXT != NULL )
- + glConfig.wgl_extensions_string = pwglGetExtensionsStringEXT();
- + else glConfig.wgl_extensions_string = NULL;
- +
- // initalize until base opengl functions loaded
- GL_CheckExtension( "WGL_EXT_swap_control", wglswapintervalfuncs, NULL, GL_WGL_SWAPCONTROL );
- @@ -1715,26 +1854,15 @@ void GL_InitExtensions( void )
- if( !GL_Support( GL_DRAW_RANGEELEMENTS_EXT ))
- GL_CheckExtension( "GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "gl_drawrangeelments", GL_DRAW_RANGEELEMENTS_EXT );
- + // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
- + if( pglDrawRangeElementsEXT == NULL ) pglDrawRangeElementsEXT = pglDrawRangeElements;
- +
- // multitexture
- glConfig.max_texture_units = glConfig.max_texture_coords = glConfig.max_teximage_units = 1;
- GL_CheckExtension( "GL_ARB_multitexture", multitexturefuncs, "gl_arb_multitexture", GL_ARB_MULTITEXTURE );
- if( GL_Support( GL_ARB_MULTITEXTURE ))
- - {
- pglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glConfig.max_texture_units );
- - GL_CheckExtension( "GL_ARB_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT );
- -
- - if( !GL_Support( GL_ENV_COMBINE_EXT ))
- - GL_CheckExtension( "GL_EXT_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT );
- -
- - if( GL_Support( GL_ENV_COMBINE_EXT ))
- - GL_CheckExtension( "GL_ARB_texture_env_dot3", NULL, "gl_texture_env_dot3", GL_DOT3_ARB_EXT );
- - }
- - else
- - {
- - GL_CheckExtension( "GL_SGIS_multitexture", sgis_multitexturefuncs, "gl_sgis_multitexture", GL_ARB_MULTITEXTURE );
- - if( GL_Support( GL_ARB_MULTITEXTURE )) glConfig.max_texture_units = 2;
- - }
- if( glConfig.max_texture_units == 1 )
- GL_SetExtension( GL_ARB_MULTITEXTURE, false );
- @@ -1753,12 +1881,18 @@ void GL_InitExtensions( void )
- }
- }
- - GL_CheckExtension( "GL_SGIS_generate_mipmap", NULL, "gl_sgis_generate_mipmaps", GL_SGIS_MIPMAPS_EXT );
- + // 2d texture array support
- + GL_CheckExtension( "GL_EXT_texture_array", texture3dextfuncs, "gl_texture_2d_array", GL_TEXTURE_ARRAY_EXT );
- +
- + if( GL_Support( GL_TEXTURE_ARRAY_EXT ))
- + pglGetIntegerv( GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &glConfig.max_2d_texture_layers );
- // hardware cubemaps
- - GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURECUBEMAP_EXT );
- + GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURE_CUBEMAP_EXT );
- - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
- + GL_CheckExtension( "GL_ARB_draw_buffers", drawbuffersfuncs, "gl_draw_buffers", GL_DRAW_BUFFERS_EXT );
- +
- + if( GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
- {
- pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size );
- @@ -1766,15 +1900,8 @@ void GL_InitExtensions( void )
- GL_CheckExtension( "GL_ARB_seamless_cube_map", NULL, "gl_seamless_cubemap", GL_ARB_SEAMLESS_CUBEMAP );
- }
- - // point particles extension
- - GL_CheckExtension( "GL_EXT_point_parameters", pointparametersfunc, NULL, GL_EXT_POINTPARAMETERS );
- -
- GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT );
- GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_dds_hardware_support", GL_TEXTURE_COMPRESSION_EXT );
- - GL_CheckExtension( "GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT );
- -
- - if( !GL_Support( GL_CUSTOM_VERTEX_ARRAY_EXT ))
- - GL_CheckExtension( "GL_SGI_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT );
- GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT );
- @@ -1787,47 +1914,56 @@ void GL_InitExtensions( void )
- if( GL_Support( GL_ANISOTROPY_EXT ))
- pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy );
- - GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_ext_texture_lodbias", GL_TEXTURE_LODBIAS );
- - if( GL_Support( GL_TEXTURE_LODBIAS ))
- - pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lodbias );
- -
- - GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT );
- -
- - GL_CheckExtension( "GL_EXT_blend_minmax", blendequationfuncs, "gl_ext_customblend", GL_BLEND_MINMAX_EXT );
- - GL_CheckExtension( "GL_EXT_blend_subtract", blendequationfuncs, "gl_ext_customblend", GL_BLEND_SUBTRACT_EXT );
- + GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_ext_texture_lod_bias", GL_TEXTURE_LOD_BIAS );
- - GL_CheckExtension( "glStencilOpSeparate", gl2separatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT );
- + if( GL_Support( GL_TEXTURE_LOD_BIAS ))
- + pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lod_bias );
- - if( !GL_Support( GL_SEPARATESTENCIL_EXT ))
- - GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT );
- + GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT );
- - GL_CheckExtension( "GL_EXT_stencil_two_side", stenciltwosidefuncs, "gl_stenciltwoside", GL_STENCILTWOSIDE_EXT );
- GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT );
- -
- - // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
- - if( pglDrawRangeElementsEXT == NULL ) pglDrawRangeElementsEXT = pglDrawRangeElements;
- -
- - GL_CheckExtension( "GL_ARB_texture_env_add", NULL, "gl_texture_env_add", GL_TEXTURE_ENV_ADD_EXT );
- + GL_CheckExtension( "GL_ARB_vertex_array_object", vaofuncs, "gl_vertex_array_object", GL_ARB_VERTEX_ARRAY_OBJECT_EXT );
- + GL_CheckExtension( "GL_ARB_half_float_pixel", NULL, "gl_half_float", GL_ARB_HALF_FLOAT_EXT );
- // vp and fp shaders
- GL_CheckExtension( "GL_ARB_shader_objects", shaderobjectsfuncs, "gl_shaderobjects", GL_SHADER_OBJECTS_EXT );
- - GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT );
- - GL_CheckExtension( "GL_ARB_vertex_shader", vertexshaderfuncs, "gl_vertexshader", GL_VERTEX_SHADER_EXT );
- - GL_CheckExtension( "GL_ARB_fragment_shader", NULL, "gl_pixelshader", GL_FRAGMENT_SHADER_EXT );
- + GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_shading_language", GL_SHADER_GLSL100_EXT );
- GL_CheckExtension( "GL_ARB_depth_texture", NULL, "gl_depthtexture", GL_DEPTH_TEXTURE );
- GL_CheckExtension( "GL_ARB_shadow", NULL, "gl_arb_shadow", GL_SHADOW_EXT );
- GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_arb_texture_float", GL_ARB_TEXTURE_FLOAT_EXT );
- GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT );
- + GL_CheckExtension( "GL_ARB_texture_rg", NULL, "gl_arb_texture_rg", GL_ARB_TEXTURE_RG );
- + GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, "gl_ext_gpu_shader4", GL_EXT_GPU_SHADER4 );
- +
- + // this won't work without extended context
- + if( glw_state.extended )
- + GL_CheckExtension( "GL_ARB_debug_output", debugoutputfuncs, "gl_debug_output", GL_DEBUG_OUTPUT );
- +
- + // FBO support
- + GL_CheckExtension( "GL_ARB_framebuffer_object", arbfbofuncs, "gl_framebuffer_object", GL_FRAMEBUFFER_OBJECT );
- +
- + if( !GL_Support( GL_FRAMEBUFFER_OBJECT ))
- + GL_CheckExtension( "GL_EXT_framebuffer_object", extfbofuncs, "gl_framebuffer_object", GL_FRAMEBUFFER_OBJECT );
- // occlusion queries
- GL_CheckExtension( "GL_ARB_occlusion_query", occlusionfunc, "gl_occlusion_queries", GL_OCCLUSION_QUERIES_EXT );
- + // rectangle textures support
- + GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT );
- +
- if( GL_Support( GL_SHADER_GLSL100_EXT ))
- {
- pglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &glConfig.max_texture_coords );
- pglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &glConfig.max_teximage_units );
- +
- + // check for hardware skinning
- + pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms );
- + pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs );
- +
- + if( glConfig.hardware_type == GLHW_RADEON )
- + glConfig.max_vertex_uniforms /= 4; // radeon returns not correct info
- }
- else
- {
- @@ -1835,42 +1971,41 @@ void GL_InitExtensions( void )
- glConfig.max_texture_coords = glConfig.max_teximage_units = glConfig.max_texture_units;
- }
- - // rectangle textures support
- - if( Q_strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ))
- - {
- - glConfig.texRectangle = GL_TEXTURE_RECTANGLE_NV;
- - pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &glConfig.max_2d_rectangle_size );
- - }
- - else if( Q_strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ))
- - {
- - glConfig.texRectangle = GL_TEXTURE_RECTANGLE_EXT;
- - pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &glConfig.max_2d_rectangle_size );
- - }
- - else glConfig.texRectangle = glConfig.max_2d_rectangle_size = 0; // no rectangle
- -
- - glConfig.max_2d_texture_size = 0;
- pglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.max_2d_texture_size );
- if( glConfig.max_2d_texture_size <= 0 ) glConfig.max_2d_texture_size = 256;
- + pglGetIntegerv( GL_MAX_DRAW_BUFFERS_ARB, &glConfig.max_draw_buffers );
- +
- + if( GL_Support( GL_TEXTURE_2D_RECT_EXT ))
- + pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &glConfig.max_2d_rectangle_size );
- +
- Cvar_Get( "gl_max_texture_size", "0", CVAR_INIT, "opengl texture max dims" );
- Cvar_Set( "gl_max_texture_size", va( "%i", glConfig.max_2d_texture_size ));
- - pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms );
- - pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs );
- -
- // MCD has buffering issues
- - if(Q_strstr( glConfig.renderer_string, "gdi" ))
- + if( Q_stristr( glConfig.renderer_string, "gdi" ))
- Cvar_SetFloat( "gl_finish", 1 );
- Cvar_Set( "gl_anisotropy", va( "%f", bound( 0, gl_texture_anisotropy->value, glConfig.max_texture_anisotropy )));
- - // software mipmap generator does wrong result with NPOT textures ...
- - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ))
- - GL_SetExtension( GL_ARB_TEXTURE_NPOT_EXT, false );
- -
- if( GL_Support( GL_TEXTURE_COMPRESSION_EXT ))
- Image_AddCmdFlags( IL_DDS_HARDWARE );
- + // enable gldebug if allowed
- + if( GL_Support( GL_DEBUG_OUTPUT ))
- + {
- + if( host.developer >= D_ERROR )
- + pglDebugMessageCallbackARB( GL_DebugOutput, NULL );
- +
- + // force everything to happen in the main thread instead of in a separate driver thread
- + if( host.developer >= D_WARN )
- + pglEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
- +
- + // enable all the low priority messages
- + if( host.developer >= D_REPORT )
- + pglDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, true );
- + }
- +
- glw_state.initialized = true;
- tr.framecount = tr.visframecount = 1;
- @@ -1898,8 +2033,8 @@ qboolean R_Init( void )
- GL_RemoveCommands();
- R_Free_OpenGL();
- - // can't initialize video subsystem
- - Host_NewInstance( va("#%s", GI->gamefolder ), "fallback to dedicated mode\n" );
- + Msg( "^1Error:^7 can't initialize video subsystem\n" );
- + Host_NewInstance( va( "#%s", GI->gamefolder ), "stopped" );
- return false;
- }
- @@ -1990,5 +2125,5 @@ void GL_CheckForErrors_( const char *filename, const int fileline )
- break;
- }
- - Host_Error( "GL_CheckForErrors: %s (called at %s:%i)\n", str, filename, fileline );
- + MsgDev( D_ERROR, "OpenGL: %s (called at %s:%i)\n", str, filename, fileline );
- }
- \ No newline at end of file
- diff --git b/engine/client/gl_warp.c a/engine/client/gl_warp.c
- index 5023b70..06903ec 100644
- --- b/engine/client/gl_warp.c
- +++ a/engine/client/gl_warp.c
- @@ -19,9 +19,9 @@ GNU General Public License for more details.
- #include "com_model.h"
- #include "wadfile.h"
- -#define MAX_CLIP_VERTS 64 // skybox clip vertices
- +#define SKYCLOUDS_QUALITY 12
- +#define MAX_CLIP_VERTS 128 // skybox clip vertices
- #define TURBSCALE ( 256.0f / ( M_PI2 ))
- -static float speedscale;
- static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
- static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
- @@ -127,6 +127,8 @@ void DrawSkyPolygon( int nump, vec3_t vecs )
- 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;
- @@ -302,6 +304,7 @@ void R_AddSkyBoxSurface( msurface_t *fa )
- {
- vec3_t verts[MAX_CLIP_VERTS];
- glpoly_t *p;
- + float *v;
- int i;
- if( r_fastsky->integer )
- @@ -317,6 +320,20 @@ void R_AddSkyBoxSurface( msurface_t *fa )
- }
- }
- + if( world.sky_sphere && fa->polys && !world.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 )
- {
- @@ -347,6 +364,7 @@ void R_UnloadSkybox( void )
- tr.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes)
- memset( tr.skyboxTextures, 0, sizeof( tr.skyboxTextures ));
- + world.custom_skybox = false;
- }
- /*
- @@ -445,11 +463,14 @@ void R_SetupSky( const char *skyboxname )
- {
- Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
- tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
- - GL_SetTextureType( tr.skyboxTextures[i], TEX_CUBEMAP );
- if( !tr.skyboxTextures[i] ) break;
- }
- - if( i == 6 ) return; // loaded
- + if( i == 6 )
- + {
- + world.custom_skybox = true;
- + return; // loaded
- + }
- // clear previous and try again
- R_UnloadSkybox();
- @@ -458,16 +479,193 @@ void R_SetupSky( const char *skyboxname )
- {
- Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
- tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
- - GL_SetTextureType( tr.skyboxTextures[i], TEX_CUBEMAP );
- if( !tr.skyboxTextures[i] ) break;
- }
- - if( i == 6 ) return; // loaded
- +
- + if( i == 6 )
- + {
- + world.custom_skybox = true;
- + return; // loaded
- + }
- // completely couldn't load skybox (probably never happens)
- MsgDev( D_ERROR, "R_SetupSky: couldn't load skybox '%s'\n", skyboxname );
- 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;
- +
- + pglDepthFunc( GL_GEQUAL );
- + pglDepthMask( 0 );
- +
- + 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 );
- + }
- +
- + pglDepthMask( GL_TRUE );
- + pglDepthFunc( GL_LEQUAL );
- +}
- +
- /*
- =============
- R_InitSky
- @@ -502,7 +700,7 @@ void R_InitSky( mip_t *mt, texture_t *tx )
- }
- // make sure what sky image is valid
- - if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 )
- + 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 );
- FS_FreeImage( r_sky );
- @@ -567,9 +765,6 @@ void R_InitSky( mip_t *mt, texture_t *tx )
- // load it in
- tr.alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_UNCOMPRESSED|TF_NOMIPMAP, false );
- - GL_SetTextureType( tr.solidskyTexture, TEX_BRUSH );
- - GL_SetTextureType( tr.alphaskyTexture, TEX_BRUSH );
- -
- // clean up
- FS_FreeImage( r_sky );
- Mem_Free( trans );
- @@ -582,17 +777,20 @@ EmitWaterPolys
- Does a water warp on the pre-fragmented glpoly_t chain
- =============
- */
- -void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
- +void EmitWaterPolys( glpoly_t *polys, qboolean noCull, qboolean direction )
- {
- - glpoly_t *p;
- + glpoly_t *p = polys;
- float *v, nv, waveHeight;
- float s, t, os, ot;
- int i;
- + if( !polys ) return;
- if( noCull ) pglDisable( GL_CULL_FACE );
- // set the current waveheight
- - waveHeight = RI.currentWaveHeight;
- + if( p->verts[0][2] >= RI.refdef.vieworg[2] )
- + waveHeight = -RI.currententity->curstate.scale;
- + else waveHeight = RI.currententity->curstate.scale;
- // reset fog color for nonlightmapped water
- GL_ResetFogColor();
- @@ -601,29 +799,37 @@ void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
- {
- pglBegin( GL_POLYGON );
- - for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
- + if( direction )
- + v = p->verts[0] + ( p->numverts - 1 ) * VERTEXSIZE;
- + else v = p->verts[0];
- +
- + for( i = 0; i < p->numverts; i++ )
- {
- if( waveHeight )
- {
- - nv = v[2] + waveHeight + ( waveHeight * sin(v[0] * 0.02f + cl.time)
- - * sin(v[1] * 0.02 + cl.time) * sin(v[2] * 0.02f + cl.time));
- - nv -= 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 = 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 = ot + r_turbsin[(int)((os * 0.125f + cl.time) * TURBSCALE) & 255];
- t *= ( 1.0f / SUBDIVIDE_SIZE );
- if( glState.activeTMU != 0 )
- GL_MultiTexCoord2f( glState.activeTMU, s, t );
- else pglTexCoord2f( s, t );
- pglVertex3f( v[0], v[1], nv );
- +
- + if( direction )
- + v -= VERTEXSIZE;
- + else v += VERTEXSIZE;
- }
- pglEnd();
- }
- @@ -632,103 +838,4 @@ void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
- if( noCull ) pglEnable( GL_CULL_FACE );
- GL_SetupFogColorForSurfaces();
- -}
- -
- -/*
- -=============
- -EmitSkyPolys
- -=============
- -*/
- -void EmitSkyPolys( msurface_t *fa )
- -{
- - glpoly_t *p;
- - float *v;
- - int i;
- - float s, t;
- - vec3_t dir;
- - float length;
- -
- - for( p = fa->polys; p; p = p->next )
- - {
- - pglBegin( GL_POLYGON );
- -
- - for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
- - {
- - VectorSubtract( v, RI.vieworg, dir );
- - dir[2] *= 3.0f; // flatten the sphere
- -
- - length = VectorLength( dir );
- - length = 6.0f * 63.0f / length;
- -
- - dir[0] *= length;
- - dir[1] *= length;
- -
- - s = ( speedscale + dir[0] ) * (1.0f / 128.0f);
- - t = ( speedscale + dir[1] ) * (1.0f / 128.0f);
- -
- - pglTexCoord2f( s, t );
- - pglVertex3fv( v );
- - }
- - pglEnd ();
- - }
- -}
- -
- -/*
- -=================
- -R_DrawSkyChain
- -=================
- -*/
- -void R_DrawSkyChain( msurface_t *s )
- -{
- - msurface_t *fa;
- -
- - GL_SetRenderMode( kRenderNormal );
- - GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
- -
- - speedscale = cl.time * 8.0f;
- - speedscale -= (int)speedscale & ~127;
- -
- - for( fa = s; fa; fa = fa->texturechain )
- - EmitSkyPolys( fa );
- -
- - GL_SetRenderMode( kRenderTransTexture );
- - GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
- -
- - speedscale = cl.time * 16.0f;
- - speedscale -= (int)speedscale & ~127;
- -
- - for( fa = s; fa; fa = fa->texturechain )
- - EmitSkyPolys( fa );
- -
- - pglDisable( GL_BLEND );
- -}
- -
- -/*
- -===============
- -EmitBothSkyLayers
- -
- -Does a sky warp on the pre-fragmented glpoly_t chain
- -This will be called for brushmodels, the world
- -will have them chained together.
- -===============
- -*/
- -void EmitSkyLayers( msurface_t *fa )
- -{
- - GL_SetRenderMode( kRenderNormal );
- - GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
- -
- - speedscale = cl.time * 8.0f;
- - speedscale -= (int)speedscale & ~127;
- -
- - EmitSkyPolys( fa );
- -
- - GL_SetRenderMode( kRenderTransTexture );
- - GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
- -
- - speedscale = cl.time * 16.0f;
- - speedscale -= (int)speedscale & ~127;
- -
- - EmitSkyPolys( fa );
- -
- - pglDisable( GL_BLEND );
- }
- \ No newline at end of file
- diff --git b/engine/client/s_backend.c a/engine/client/s_backend.c
- index 071d55d..2221c5f 100644
- --- b/engine/client/s_backend.c
- +++ a/engine/client/s_backend.c
- @@ -361,7 +361,7 @@ int SNDDMA_Init( void *hInst )
- else
- {
- if( snd_firsttime )
- - MsgDev( D_ERROR, "SNDDMA_Init: can't initialize sound device\n" );
- + MsgDev( D_ERROR, "Audio: can't initialize sound device\n" );
- return false;
- }
- diff --git b/engine/client/s_dsp.c a/engine/client/s_dsp.c
- index cc7e01d..efed07c 100644
- --- b/engine/client/s_dsp.c
- +++ a/engine/client/s_dsp.c
- @@ -14,5445 +14,917 @@ GNU General Public License for more details.
- */
- #include "common.h"
- +#include "client.h"
- #include "sound.h"
- -#define SIGN( d ) (( d ) < 0 ? -1 : 1 )
- -#define ABS( a ) abs( a )
- -#define MSEC_TO_SAMPS( a ) ((( a ) * SOUND_DMA_SPEED) / 1000 ) // convert milliseconds to # samples in equivalent time
- -#define SEC_TO_SAMPS( a ) (( a ) * SOUND_DMA_SPEED) // conver seconds to # samples in equivalent time
- -#define CLIP_DSP( x ) ( x )
- -#define SOUND_MS_PER_FT 1 // sound travels approx 1 foot per millisecond
- -#define ROOM_MAX_SIZE 1000 // max size in feet of room simulation for dsp
- +#define MAX_DELAY 0.4f
- +#define MAX_ROOM_TYPES ARRAYSIZE( rgsxpre )
- -// Performance notes:
- +#define MONODLY 0
- +#define MAX_MONO_DELAY 0.4f
- -// DSP processing should take no more than 3ms total time per frame to remain on par with hl1
- -// Assume a min frame rate of 24fps = 42ms per frame
- -// at 24fps, to maintain 44.1khz output rate, we must process about 1840 mono samples per frame.
- -// So we must process 1840 samples in 3ms.
- +#define REVERBPOS 1
- +#define MAX_REVERB_DELAY 0.1f
- -// on a 1Ghz CPU (mid-low end CPU) 3ms provides roughly 3,000,000 cycles.
- -// Thus we have 3e6 / 1840 = 1630 cycles per sample.
- +#define STEREODLY 3
- +#define MAX_STEREO_DELAY 0.1f
- -#define PBITS 12 // parameter bits
- -#define PMAX ((1 << PBITS)-1) // parameter max size
- +#define REVERB_XFADE 32
- -// crossfade from y2 to y1 at point r (0 < r < PMAX )
- -#define XFADE( y1, y2, r ) (((y1) * (r)) >> PBITS) + (((y2) * (PMAX - (r))) >> PBITS);
- -#define XFADEF( y1, y2, r ) (((y1) * (r)) / (float)(PMAX)) + (((y2) * (PMAX - (r))) / (float)(PMAX));
- +#define MAXDLY (STEREODLY + 1)
- +#define MAXLP 10
- +#define MAXPRESETS ARRAYSIZE( rgsxpre )
- -/////////////////////
- -// dsp helpers
- -/////////////////////
- -
- -// dot two integer vectors of length M+1
- -// M is filter order, h is filter vector, w is filter state vector
- -_inline int dot ( int M, int *h, int *w )
- -{
- - int i, y;
- -
- - for( y = 0, i = 0; i <= M; i++ )
- - y += ( h[i] * w[i] ) >> PBITS;
- - return y;
- -}
- -
- -// delay array w[] by D samples
- -// w[0] = input, w[D] = output
- -// practical for filters, but not for large values of D
- -_inline void delay( int D, int *w )
- -{
- - int i;
- -
- - for( i = D; i >= 1; i-- ) // reverse order updating
- - w[i] = w[i-1];
- -}
- -
- -// circular wrap of pointer p, relative to array w
- -// D delay line size in samples w[0...D]
- -// w delay line buffer pointer, dimension D+1
- -// p circular pointer
- -_inline void wrap( int D, int *w, int **p )
- -{
- - if( *p > w + D ) *p -= D + 1; // when *p = w + D + 1, it wraps around to *p = w
- - if( *p < w ) *p += D + 1; // when *p = w - 1, it wraps around to *p = w + D
- -}
- -
- -// simple averaging filter for performance - a[] is 0, b[] is 1, L is # of samples to average
- -_inline int avg_filter( int M, int *a, int L, int *b, int *w, int x )
- -{
- - int i, y = 0;
- -
- - w[0] = x;
- -
- - // output adder
- - switch( L )
- - {
- - default:
- - case 12: y += w[12];
- - case 11: y += w[11];
- - case 10: y += w[10];
- - case 9: y += w[9];
- - case 8: y += w[8];
- - case 7: y += w[7];
- - case 6: y += w[6];
- - case 5: y += w[5];
- - case 4: y += w[4];
- - case 3: y += w[3];
- - case 2: y += w[2];
- - case 1: y += w[1];
- - case 0: y += w[0];
- - }
- -
- - for( i = L; i >= 1; i-- ) // reverse update internal state
- - w[i] = w[i-1];
- -
- - switch( L )
- - {
- - default:
- - case 12: return y / 13;
- - case 11: return y / 12;
- - case 10: return y / 11;
- - case 9: return y / 10;
- - case 8: return y / 9;
- - case 7: return y >> 3;
- - case 6: return y / 7;
- - case 5: return y / 6;
- - case 4: return y / 5;
- - case 3: return y >> 2;
- - case 2: return y / 3;
- - case 1: return y >> 1;
- - case 0: return y;
- - }
- -}
- -
- -// IIR filter, cannonical form
- -// returns single sample y for current input value x
- -// x is input sample
- -// w = internal state vector, dimension max(M,L) + 1
- -// L, M numerator and denominator filter orders
- -// a,b are M+1 dimensional arrays of filter params
- -//
- -// for M = 4:
- -//
- -// 1 w0(n) b0
- -// x(n)--->(+)--(*)-----.------(*)->(+)---> y(n)
- -// ^ | ^
- -// | [Delay d] |
- -// | | |
- -// | -a1 |W1 b1 |
- -// ----(*)---.------(*)----
- -// ^ | ^
- -// | [Delay d] |
- -// | | |
- -// | -a2 |W2 b2 |
- -// ----(*)---.------(*)----
- -// ^ | ^
- -// | [Delay d] |
- -// | | |
- -// | -a3 |W3 b3 |
- -// ----(*)---.------(*)----
- -// ^ | ^
- -// | [Delay d] |
- -// | | |
- -// | -a4 |W4 b4 |
- -// ----(*)---.------(*)----
- -//
- -// for each input sample x, do:
- -// w0 = x - a1*w1 - a2*w2 - ... aMwM
- -// y = b0*w0 + b1*w1 + ...bL*wL
- -// wi = wi-1, i = K, K-1, ..., 1
- -
- -_inline int iir_filter( int M, int *a, int L, int *b, int *w, int x )
- -{
- - int K, i, y, x0;
- -
- - if( M == 0 )
- - return avg_filter( M, a, L, b, w, x );
- -
- - y = 0;
- - x0 = x;
- -
- - K = max ( M, L );
- -
- - // for (i = 1; i <= M; i++) // input adder
- - // w[0] -= ( a[i] * w[i] ) >> PBITS;
- -
- - // M is clamped between 1 and FLT_M
- - // change this switch statement if FLT_M changes!
- -
- - switch( M )
- - {
- - case 12: x0 -= ( a[12] * w[12] ) >> PBITS;
- - case 11: x0 -= ( a[11] * w[11] ) >> PBITS;
- - case 10: x0 -= ( a[10] * w[10] ) >> PBITS;
- - case 9: x0 -= ( a[9] * w[9] ) >> PBITS;
- - case 8: x0 -= ( a[8] * w[8] ) >> PBITS;
- - case 7: x0 -= ( a[7] * w[7] ) >> PBITS;
- - case 6: x0 -= ( a[6] * w[6] ) >> PBITS;
- - case 5: x0 -= ( a[5] * w[5] ) >> PBITS;
- - case 4: x0 -= ( a[4] * w[4] ) >> PBITS;
- - case 3: x0 -= ( a[3] * w[3] ) >> PBITS;
- - case 2: x0 -= ( a[2] * w[2] ) >> PBITS;
- - default:
- - case 1: x0 -= ( a[1] * w[1] ) >> PBITS;
- - }
- -
- - w[0] = x0;
- -
- - // for( i = 0; i <= L; i++ ) // output adder
- - // y += ( b[i] * w[i] ) >> PBITS;
- -
- - switch( L )
- - {
- - case 12: y += ( b[12] * w[12] ) >> PBITS;
- - case 11: y += ( b[11] * w[11] ) >> PBITS;
- - case 10: y += ( b[10] * w[10] ) >> PBITS;
- - case 9: y += ( b[9] * w[9] ) >> PBITS;
- - case 8: y += ( b[8] * w[8] ) >> PBITS;
- - case 7: y += ( b[7] * w[7] ) >> PBITS;
- - case 6: y += ( b[6] * w[6] ) >> PBITS;
- - case 5: y += ( b[5] * w[5] ) >> PBITS;
- - case 4: y += ( b[4] * w[4] ) >> PBITS;
- - case 3: y += ( b[3] * w[3] ) >> PBITS;
- - case 2: y += ( b[2] * w[2] ) >> PBITS;
- - default:
- - case 1: y += ( b[1] * w[1] ) >> PBITS;
- - case 0: y += ( b[0] * w[0] ) >> PBITS;
- - }
- -
- - for( i = K; i >= 1; i-- ) // reverse update internal state
- - w[i] = w[i-1];
- -
- - return y; // current output sample
- -}
- -
- -// IIR filter, cannonical form, using dot product and delay implementation
- -// (may be easier to optimize this routine.)
- -_inline int iir_filter2( int M, int *a, int L, int *b, int *w, int x )
- -{
- - int K, y;
- -
- - K = max( M, L ); // K = max (M, L)
- - w[0] = 0; // needed for dot (M, a, w)
- -
- - w[0] = x - dot( M, a, w ); // input adder
- - y = dot( L, b, w ); // output adder
- -
- - delay( K, w ); // update delay line
- -
- - return y; // current output sample
- -}
- -
- -
- -// fir filter - no feedback = high stability but also may be more expensive computationally
- -_inline int fir_filter( int M, int *h, int *w, int x )
- -{
- - int i, y;
- -
- - w[0] = x;
- -
- - for( y = 0, i = 0; i <= M; i++ )
- - y += h[i] * w[i];
- -
- - for( i = M; i >= -1; i-- )
- - w[i] = w[i-1];
- -
- - return y;
- -}
- -
- -// fir filter, using dot product and delay implementation
- -_inline int fir_filter2( int M, int *h, int *w, int x )
- -{
- - int y;
- -
- - w[0] = x;
- - y = dot( M, h, w );
- - delay( M, w );
- -
- - return y;
- -}
- -
- -
- -// tap - i-th tap of circular delay line buffer
- -// D delay line size in samples
- -// w delay line buffer pointer, of dimension D+1
- -// p circular pointer
- -// t = 0...D
- -int tap( int D, int *w, int *p, int t )
- -{
- - return w[(p - w + t) % (D + 1)];
- -}
- -
- -// tapi - interpolated tap output of a delay line
- -// interpolates sample between adjacent samples in delay line for 'frac' part of delay
- -// D delay line size in samples
- -// w delay line buffer pointer, of dimension D+1
- -// p circular pointer
- -// t - delay tap integer value 0...D. (complete delay is t.frac )
- -// frac - varying 16 bit fractional delay value 0...32767 (normalized to 0.0 - 1.0)
- -_inline int tapi( int D, int *w, int *p, int t, int frac )
- -{
- - int i, j;
- - int si, sj;
- -
- - i = t; // tap value, interpolate between adjacent samples si and sj
- - j = (i + 1) % (D+1); // if i = D, then j = 0; otherwise, j = i + 1
- -
- - si = tap( D, w, p, i ); // si(n) = x(n - i)
- - sj = tap( D, w, p, j ); // sj(n) = x(n - j)
- -
- - return si + (((frac) * (sj - si) ) >> 16);
- -}
- -
- -// circular delay line, D-fold delay
- -// D delay line size in samples w[0..D]
- -// w delay line buffer pointer, dimension D+1
- -// p circular pointer
- -_inline void cdelay( int D, int *w, int **p )
- -{
- - (*p)--; // decrement pointer and wrap modulo (D+1)
- - wrap ( D, w, p ); // when *p = w-1, it wraps around to *p = w+D
- -}
- -
- -// plain reverberator with circular delay line
- -// D delay line size in samples
- -// t tap from this location - <= D
- -// w delay line buffer pointer of dimension D+1
- -// p circular pointer, must be init to &w[0] before first call
- -// a feedback value, 0-PMAX (normalized to 0.0-1.0)
- -// b gain
- -// x input sample
- -
- -// w0(n) b
- -// x(n)--->(+)--------.-----(*)-> y(n)
- -// ^ |
- -// | [Delay d]
- -// | |
- -// | a |Wd(n)
- -// ----(*)---.
- -
- -_inline int dly_plain( int D, int t, int *w, int **p, int a, int b, int x )
- -{
- - int y, sD;
- -
- - sD = tap( D, w, *p, t ); // Tth tap delay output
- - y = x + (( a * sD ) >> PBITS); // filter output
- - **p = y; // delay input
- - cdelay( D, w, p ); // update delay line
- -
- - return (( y * b ) >> PBITS );
- -}
- -
- -// straight delay line
- -//
- -// D delay line size in samples
- -// t tap from this location - <= D
- -// w delay line buffer pointer of dimension D+1
- -// p circular pointer, must be init to &w[0] before first call
- -// x input sample
- -//
- -// x(n)--->[Delay d]---> y(n)
- -//
- -_inline int dly_linear ( int D, int t, int *w, int **p, int x )
- -{
- - int y;
- -
- - y = tap( D, w, *p, t ); // Tth tap delay output
- - **p = x; // delay input
- - cdelay( D, w, p ); // update delay line
- -
- - return y;
- -}
- -
- -// lowpass reverberator, replace feedback multiplier 'a' in
- -// plain reverberator with a low pass filter
- -// D delay line size in samples
- -// t tap from this location - <= D
- -// w delay line buffer pointer of dimension D+1
- -// p circular pointer, must be init to &w[0] before first call
- -// a feedback gain
- -// b output gain
- -// M filter order
- -// bf filter numerator, 0-PMAX (normalized to 0.0-1.0), M+1 dimensional
- -// af filter denominator, 0-PMAX (normalized to 0.0-1.0), M+1 dimensional
- -// vf filter state, M+1 dimensional
- -// x input sample
- -// w0(n) b
- -// x(n)--->(+)--------------.----(*)--> y(n)
- -// ^ |
- -// | [Delay d]
- -// | |
- -// | a |Wd(n)
- -// --(*)--[Filter])-
- -
- -int dly_lowpass( int D, int t, int *w, int **p, int a, int b, int M, int *af, int L, int *bf, int *vf, int x )
- -{
- - int y, sD;
- -
- - sD = tap( D, w, *p, t ); // delay output is filter input
- - y = x + ((iir_filter ( M, af, L, bf, vf, sD ) * a) >> PBITS); // filter output with gain
- - **p = y; // delay input
- - cdelay( D, w, p ); // update delay line
- -
- - return (( y * b ) >> PBITS ); // output with gain
- -}
- -
- -// allpass reverberator with circular delay line
- -// D delay line size in samples
- -// t tap from this location - <= D
- -// w delay line buffer pointer of dimension D+1
- -// p circular pointer, must be init to &w[0] before first call
- -// a feedback value, 0-PMAX (normalized to 0.0-1.0)
- -// b gain
- -
- -// w0(n) -a b
- -// x(n)--->(+)--------.-----(*)-->(+)--(*)-> y(n)
- -// ^ | ^
- -// | [Delay d] |
- -// | | |
- -// | a |Wd(n) |
- -// ----(*)---.-------------
- -//
- -// for each input sample x, do:
- -// w0 = x + a*Wd
- -// y = -a*w0 + Wd
- -// delay (d, W) - w is the delay buffer array
- -//
- -// or, using circular delay, for each input sample x do:
- -//
- -// Sd = tap (D,w,p,D)
- -// S0 = x + a*Sd
- -// y = -a*S0 + Sd
- -// *p = S0
- -// cdelay(D, w, &p)
- -
- -_inline int dly_allpass( int D, int t, int *w, int **p, int a, int b, int x )
- -{
- - int y, s0, sD;
- -
- - sD = tap( D, w, *p, t ); // Dth tap delay output
- - s0 = x + (( a * sD ) >> PBITS);
- -
- - y = (( -a * s0 ) >> PBITS ) + sD; // filter output
- - **p = s0; // delay input
- - cdelay( D, w, p ); // update delay line
- -
- - return (( y * b ) >> PBITS );
- -}
- -
- -
- -///////////////////////////////////////////////////////////////////////////////////
- -// fixed point math for real-time wave table traversing, pitch shifting, resampling
- -///////////////////////////////////////////////////////////////////////////////////
- -#define FIX20_BITS 20 // 20 bits of fractional part
- -#define FIX20_SCALE (1 << FIX20_BITS)
- -#define FIX20_INTMAX ((1 << (32 - FIX20_BITS))-1) // maximum step integer
- -#define FLOAT_TO_FIX20(a) ((int)((a) * (float)FIX20_SCALE)) // convert float to fixed point
- -#define INT_TO_FIX20(a) (((int)(a)) << FIX20_BITS) // convert int to fixed point
- -#define FIX20_TO_FLOAT(a) ((float)(a) / (float)FIX20_SCALE) // convert fix20 to float
- -#define FIX20_INTPART(a) (((int)(a)) >> FIX20_BITS) // get integer part of fixed point
- -#define FIX20_FRACPART(a) ((a) - (((a) >> FIX20_BITS) << FIX20_BITS)) // get fractional part of fixed point
- -#define FIX20_FRACTION(a,b) (FIX(a)/(b)) // convert int a to fixed point, divide by b
- -
- -typedef int fix20int;
- -
- -/////////////////////////////////
- -// DSP processor parameter block
- -/////////////////////////////////
- -
- -// NOTE: these prototypes must match the XXX_Params ( prc_t *pprc ) and XXX_GetNext ( XXX_t *p, int x ) functions
- -
- -typedef void * (*prc_Param_t)( void *pprc ); // individual processor allocation functions
- -typedef int (*prc_GetNext_t)( void *pdata, int x ); // get next function for processor
- -typedef int (*prc_GetNextN_t)( void *pdata, portable_samplepair_t *pbuffer, int SampleCount, int op); // batch version of getnext
- -typedef void (*prc_Free_t)( void *pdata ); // free function for processor
- -typedef void (*prc_Mod_t)(void *pdata, float v); // modulation function for processor
- -
- -#define OP_LEFT 0 // batch process left channel in place
- -#define OP_RIGHT 1 // batch process right channel in place
- -#define OP_LEFT_DUPLICATE 2 // batch process left channel in place, duplicate to right channel
- -
- -#define PRC_NULL 0 // pass through - must be 0
- -#define PRC_DLY 1 // simple feedback reverb
- -#define PRC_RVA 2 // parallel reverbs
- -#define PRC_FLT 3 // lowpass or highpass filter
- -#define PRC_CRS 4 // chorus
- -#define PRC_PTC 5 // pitch shifter
- -#define PRC_ENV 6 // adsr envelope
- -#define PRC_LFO 7 // lfo
- -#define PRC_EFO 8 // envelope follower
- -#define PRC_MDY 9 // mod delay
- -#define PRC_DFR 10 // diffusor - n series allpass delays
- -#define PRC_AMP 11 // amplifier with distortion
- -
- -#define QUA_LO 0 // quality of filter or reverb. Must be 0,1,2,3.
- -#define QUA_MED 1
- -#define QUA_HI 2
- -#define QUA_VHI 3
- -#define QUA_MAX QUA_VHI
- -
- -#define CPRCPARAMS 16 // up to 16 floating point params for each processor type
- -
- -// processor definition - one for each running instance of a dsp processor
- -typedef struct
- -{
- - int type; // PRC type
- -
- - float prm[CPRCPARAMS]; // dsp processor parameters - array of floats
- -
- - prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
- - prc_GetNext_t pfnGetNext; // get next function
- - prc_GetNextN_t pfnGetNextN; // batch version of get next
- - prc_Free_t pfnFree; // free function
- - prc_Mod_t pfnMod; // modulation function
- -
- - void *pdata; // processor state data - ie: pdly, pflt etc.
- -} prc_t;
- -
- -// processor parameter ranges - for validating parameters during allocation of new processor
- -typedef struct prm_rng_s
- -{
- - int iprm; // parameter index
- - float lo; // min value of parameter
- - float hi; // max value of parameter
- -} prm_rng_t;
- -
- -void PRC_CheckParams( prc_t *pprc, prm_rng_t *prng );
- -
- -///////////
- -// Filters
- -///////////
- -
- -#define CFLTS 64 // max number of filters simultaneously active
- -#define FLT_M 12 // max order of any filter
- -
- -#define FLT_LP 0 // lowpass filter
- -#define FLT_HP 1 // highpass filter
- -#define FTR_MAX FLT_HP
- -
- -// flt parameters
- -
- -typedef struct
- -{
- - qboolean fused; // true if slot in use
- -
- - int b[FLT_M+1]; // filter numerator parameters (convert 0.0-1.0 to 0-PMAX representation)
- - int a[FLT_M+1]; // filter denominator parameters (convert 0.0-1.0 to 0-PMAX representation)
- - int w[FLT_M+1]; // filter state - samples (dimension of max (M, L))
- - int L; // filter order numerator (dimension of a[M+1])
- - int M; // filter order denominator (dimension of b[L+1])
- -} flt_t;
- -
- -// flt flts
- -flt_t flts[CFLTS];
- -
- -void FLT_Init( flt_t *pf ) { if( pf ) memset( pf, 0, sizeof( flt_t )); }
- -void FLT_InitAll( void ) { int i; for( i = 0; i < CFLTS; i++ ) FLT_Init( &flts[i] ); }
- -void FLT_Free( flt_t *pf ) { if( pf ) memset( pf, 0, sizeof( flt_t )); }
- -void FLT_FreeAll( void ) { int i; for( i = 0; i < CFLTS; i++ ) FLT_Free( &flts[i] ); }
- -
- -
- -// find a free filter from the filter pool
- -// initialize filter numerator, denominator b[0..M], a[0..L]
- -flt_t * FLT_Alloc( int M, int L, int *a, int *b )
- -{
- - int i, j;
- - flt_t *pf = NULL;
- -
- - for( i = 0; i < CFLTS; i++ )
- - {
- - if( !flts[i].fused )
- - {
- - pf = &flts[i];
- -
- - // transfer filter params into filter struct
- - pf->M = M;
- - pf->L = L;
- - for( j = 0; j <= M; j++ )
- - pf->a[j] = a[j];
- -
- - for( j = 0; j <= L; j++ )
- - pf->b[j] = b[j];
- -
- - pf->fused = true;
- - break;
- - }
- - }
- -
- - ASSERT( pf ); // make sure we're not trying to alloc more than CFLTS flts
- -
- - return pf;
- -}
- -
- -// convert filter params cutoff and type into
- -// iir transfer function params M, L, a[], b[]
- -// iir filter, 1st order, transfer function is H(z) = b0 + b1 Z^-1 / a0 + a1 Z^-1
- -// or H(z) = b0 - b1 Z^-1 / a0 + a1 Z^-1 for lowpass
- -// design cutoff filter at 3db (.5 gain) p579
- -void FLT_Design_3db_IIR( float cutoff, float ftype, int *pM, int *pL, int *a, int *b )
- -{
- - // ftype: FLT_LP, FLT_HP, FLT_BP
- -
- - double Wc = M_PI2 * cutoff / SOUND_DMA_SPEED; // radians per sample
- - double Oc;
- - double fa;
- - double fb;
- -
- - // calculations:
- - // Wc = 2pi * fc/44100 convert to radians
- - // Oc = tan (Wc/2) * Gc / sqt ( 1 - Gc^2) get analog version, low pass
- - // Oc = tan (Wc/2) * (sqt (1 - Gc^2)) / Gc analog version, high pass
- - // Gc = 10 ^ (-Ac/20) gain at cutoff. Ac = 3db, so Gc^2 = 0.5
- - // a = ( 1 - Oc ) / ( 1 + Oc )
- - // b = ( 1 - a ) / 2
- -
- - Oc = tan( Wc / 2.0 );
- -
- - fa = ( 1.0 - Oc ) / ( 1.0 + Oc );
- -
- - fb = ( 1.0 - fa ) / 2.0;
- -
- - if( ftype == FLT_HP )
- - fb = ( 1.0 + fa ) / 2.0;
- -
- - a[0] = 0; // a0 always ignored
- - a[1] = (int)( -fa * PMAX ); // quantize params down to 0-PMAX >> PBITS
- - b[0] = (int)( fb * PMAX );
- - b[1] = b[0];
- -
- - if( ftype == FLT_HP )
- - b[1] = -b[1];
- -
- - *pM = *pL = 1;
- -}
- -
- -
- -// convolution of x[n] with h[n], resulting in y[n]
- -// h, x, y filter, input and output arrays (double precision)
- -// M = filter order, L = input length
- -// h is M+1 dimensional
- -// x is L dimensional
- -// y is L+M dimensional
- -void conv( int M, double *h, int L, double *x, double *y )
- -{
- - int n, m;
- -
- - for( n = 0; n < L+M; n++ )
- - {
- - for( y[n] = 0, m = max(0, n-L+1); m <= min(n, M); m++ )
- - {
- - y[n] += h[m] * x[n-m];
- - }
- - }
- -}
- -
- -// cas2can - convert cascaded, second order section parameter arrays to
- -// canonical numerator/denominator arrays. Canonical implementations
- -// have half as many multiplies as cascaded implementations.
- -
- -// K is number of cascaded sections
- -// A is Kx3 matrix of sos params A[K] = A[0]..A[K-1]
- -// a is (2K + 1) -dimensional output of canonical params
- -
- -#define KMAX 32 // max # of sos sections - 8 is the most we should ever see at runtime
- -
- -void cas2can( int K, double A[KMAX+1][3], int *aout )
- -{
- - int i, j;
- - double d[2*KMAX + 1];
- - double a[2*KMAX + 1];
- -
- - ASSERT( K <= KMAX );
- -
- - memset( d, 0, sizeof( double ) * ( 2 * KMAX + 1 ));
- - memset( a, 0, sizeof( double ) * ( 2 * KMAX + 1 ));
- -
- - a[0] = 1;
- -
- - for( i = 0; i < K; i++ )
- - {
- - conv( 2, A[i], 2 * i + 1, a, d );
- -
- - for( j = 0; j < 2 * i + 3; j++ )
- - a[j] = d[j];
- - }
- -
- - for( i = 0; i < (2*K + 1); i++ )
- - aout[i] = a[i] * PMAX;
- -}
- -
- -
- -// chebyshev IIR design, type 2, Lowpass or Highpass
- -
- -#define lnf( e ) ( 2.303 * log10( e ))
- -#define acosh( e ) ( lnf( (e) + sqrt(( e ) * ( e ) - 1) ))
- -#define asinh( e ) ( lnf( (e) + sqrt(( e ) * ( e ) + 1) ))
- -
- -
- -// returns a[], b[] which are Kx3 matrices of cascaded second-order sections
- -// these matrices may be passed directly to the iir_cas() routine for evaluation
- -// Nmax - maximum order of filter
- -// cutoff, ftype, qwidth - filter cutoff in hz, filter type FLT_LOWPASS/HIGHPASS, qwidth in hz
- -// pM - denominator order
- -// pL - numerator order
- -// a - array of canonical filter params
- -// b - array of canonical filter params
- -void FLT_Design_Cheb( int Nmax, float cutoff, float ftype, float qwidth, int *pM, int *pL, int *a, int *b )
- -{
- -// p769 - converted from MATLAB
- -
- - double s = (ftype == FLT_LP ? 1 : -1 ); // 1 for LP, -1 for HP
- - double fs = SOUND_DMA_SPEED; // sampling frequency
- - double fpass = cutoff; // cutoff frequency
- - double fstop = fpass + max (2000, qwidth); // stop frequency
- - double Apass = 0.5; // max attenuation of pass band UNDONE: use Quality to select this
- - double Astop = 10; // max amplitude of stop band UNDONE: use Quality to select this
- -
- - double Wpass, Wstop, epass, estop, Nex, aa;
- - double W3, f3, W0, G, Wi2, W02, a1, a2, th, Wi, D, b1;
- - int i, K, r, N;
- - double A[KMAX+1][3]; // denominator output matrices, second order sections
- - double B[KMAX+1][3]; // numerator output matrices, second order sections
- -
- - Wpass = tan( M_PI * fpass / fs );
- - Wpass = pow( Wpass, s );
- - Wstop = tan( M_PI * fstop / fs );
- - Wstop = pow( Wstop, s );
- -
- - epass = sqrt( pow( (float)10.0f, (float)Apass/10.0f ) - 1 );
- - estop = sqrt( pow( (float)10.0f, (float)Astop/10.0f ) - 1 );
- -
- - // calculate filter order N
- -
- - Nex = acosh( estop/epass ) / acosh ( Wstop/Wpass );
- - N = min ( ceil(Nex), Nmax ); // don't exceed Nmax for filter order
- - r = ( (int)N & 1); // r == 1 if N is odd
- - K = (N - r ) / 2;
- -
- - aa = asinh ( estop ) / N;
- - W3 = Wstop / cosh( acosh( estop ) / N );
- - f3 = (fs / M_PI) * atan( pow( W3, s ));
- -
- - W0 = sinh( aa ) / Wstop;
- - W02 = W0 * W0;
- -
- - // 1st order section for N odd
- - if( r == 1 )
- - {
- - G = 1 / (1 + W0);
- - A[0][0] = 1; A[0][1] = s * (2*G-1); A[0][2] = 0;
- - B[0][0] = G; B[0][1] = G * s; B[0][2] = 0;
- - }
- - else
- - {
- - A[0][0] = 1; A[0][1] = 0; A[0][2] = 0;
- - B[0][0] = 1; B[0][1] = 0; B[0][2] = 0;
- - }
- -
- - for( i = 1; i <= K ; i++ )
- - {
- - th = M_PI * (N - 1 + 2 * i) / (2 * N);
- - Wi = sin( th ) / Wstop;
- - Wi2 = Wi * Wi;
- -
- - D = 1 - 2 * W0 * cos( th ) + W02 + Wi2;
- - G = ( 1 + Wi2 ) / D;
- -
- - b1 = 2 * ( 1 - Wi2 ) / ( 1 + Wi2 );
- - a1 = 2 * ( 1 - W02 - Wi2) / D;
- - a2 = ( 1 + 2 * W0 * cos( th ) + W02 + Wi2) / D;
- -
- - A[i][0] = 1;
- - A[i][1] = s * a1;
- - A[i][2] = a2;
- -
- - B[i][0] = G;
- - B[i][1] = G* s* b1;
- - B[i][2] = G;
- - }
- -
- - // convert cascade parameters to canonical parameters
- -
- - cas2can( K, A, a );
- - *pM = 2*K + 1;
- -
- - cas2can( K, B, b );
- - *pL = 2*K + 1;
- -}
- -
- -// filter parameter order
- -
- -typedef enum
- -{
- - flt_iftype,
- - flt_icutoff,
- - flt_iqwidth,
- - flt_iquality,
- -
- - flt_cparam // # of params
- -} flt_e;
- -
- -// filter parameter ranges
- -
- -prm_rng_t flt_rng[] =
- -{
- -{ flt_cparam, 0, 0 }, // first entry is # of parameters
- -{ flt_iftype, 0, FTR_MAX }, // filter type FLT_LP, FLT_HP, FLT_BP (UNDONE: FLT_BP currently ignored)
- -{ flt_icutoff, 10, 22050 }, // cutoff frequency in hz at -3db gain
- -{ flt_iqwidth, 100, 11025 }, // width of BP, or steepness of LP/HP (ie: fcutoff + qwidth = -60db gain point)
- -{ flt_iquality, 0, QUA_MAX }, // QUA_LO, _MED, _HI 0,1,2,3
- -};
- -
- -
- -// convert prc float params to iir filter params, alloc filter and return ptr to it
- -// filter quality set by prc quality - 0,1,2
- -flt_t * FLT_Params ( prc_t *pprc )
- -{
- - float qual = pprc->prm[flt_iquality];
- - float cutoff = pprc->prm[flt_icutoff];
- - float ftype = pprc->prm[flt_iftype];
- - float qwidth = pprc->prm[flt_iqwidth];
- -
- - int L = 0; // numerator order
- - int M = 0; // denominator order
- - int b[FLT_M+1]; // numerator params 0..PMAX
- - int a[FLT_M+1]; // denominator params 0..PMAX
- -
- - // low pass and highpass filter design
- -
- - if( (int)qual == QUA_LO )
- - qual = QUA_MED; // disable lowest quality filter - check perf on lowend KDB
- -
- - switch ( (int)qual )
- - {
- - case QUA_LO:
- - // lowpass averaging filter: perf KDB
- - ASSERT( ftype == FLT_LP );
- - ASSERT( cutoff <= SOUND_DMA_SPEED );
- - M = 0;
- -
- - // L is # of samples to average
- -
- - L = 0;
- - if( cutoff <= SOUND_DMA_SPEED / 4 ) L = 1; // 11k
- - if( cutoff <= SOUND_DMA_SPEED / 8 ) L = 2; // 5.5k
- - if( cutoff <= SOUND_DMA_SPEED / 16 ) L = 4; // 2.75k
- - if( cutoff <= SOUND_DMA_SPEED / 32 ) L = 8; // 1.35k
- - if( cutoff <= SOUND_DMA_SPEED / 64 ) L = 12; // 750hz
- -
- - break;
- - case QUA_MED:
- - // 1st order IIR filter, 3db cutoff at fc
- - FLT_Design_3db_IIR( cutoff, ftype, &M, &L, a, b );
- -
- - M = bound( 1, M, FLT_M );
- - L = bound( 1, L, FLT_M );
- - break;
- - case QUA_HI:
- - // type 2 chebyshev N = 4 IIR
- - FLT_Design_Cheb( 4, cutoff, ftype, qwidth, &M, &L, a, b );
- -
- - M = bound( 1, M, FLT_M );
- - L = bound( 1, L, FLT_M );
- - break;
- - case QUA_VHI:
- - // type 2 chebyshev N = 7 IIR
- - FLT_Design_Cheb( 8, cutoff, ftype, qwidth, &M, &L, a, b );
- -
- - M = bound( 1, M, FLT_M );
- - L = bound( 1, L, FLT_M );
- - break;
- - }
- -
- - return FLT_Alloc( M, L, a, b );
- -}
- -
- -_inline void * FLT_VParams( void *p )
- -{
- - PRC_CheckParams(( prc_t *)p, flt_rng );
- - return (void *)FLT_Params ((prc_t *)p);
- -}
- -
- -_inline void FLT_Mod( void *p, float v )
- -{
- -}
- -
- -// get next filter value for filter pf and input x
- -_inline int FLT_GetNext( flt_t *pf, int x )
- -{
- - return iir_filter( pf->M, pf->a, pf->L, pf->b, pf->w, x );
- -}
- -
- -// batch version for performance
- -_inline void FLT_GetNextN( flt_t *pflt, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = FLT_GetNext( pflt, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = FLT_GetNext( pflt, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = FLT_GetNext( pflt, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -///////////////////////////////////////////////////////////////////////////
- -// Positional updaters for pitch shift etc
- -///////////////////////////////////////////////////////////////////////////
- -
- -// looping position within a wav, with integer and fractional parts
- -// used for pitch shifting, upsampling/downsampling
- -// 20 bits of fraction, 8+ bits of integer
- -typedef struct
- -{
- -
- - fix20int step; // wave table whole and fractional step value
- - fix20int cstep; // current cummulative step value
- - int pos; // current position within wav table
- -
- - int D; // max dimension of array w[0...D] ie: # of samples = D+1
- -} pos_t;
- -
- -// circular wrap of pointer p, relative to array w
- -// D max buffer index w[0...D] (count of samples in buffer is D+1)
- -// i circular index
- -_inline void POS_Wrap( int D, int *i )
- -{
- - if( *i > D ) *i -= D + 1; // when *pi = D + 1, it wraps around to *pi = 0
- - if( *i < 0 ) *i += D + 1; // when *pi = - 1, it wraps around to *pi = D
- -}
- -
- -// set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
- -// D is array max dimension w[0...D] (ie: size D+1)
- -// w is ptr to array
- -// p is ptr to pos_t to initialize
- -_inline void POS_Init( pos_t *p, int D, float fstep )
- -{
- - float step = fstep;
- -
- - // make sure int part of step is capped at fix20_intmax
- -
- - if( (int)step > FIX20_INTMAX )
- - step = (step - (int)step) + FIX20_INTMAX;
- -
- - p->step = FLOAT_TO_FIX20( step ); // convert fstep to fixed point
- - p->cstep = 0;
- - p->pos = 0; // current update value
- - p->D = D; // always init to end value, in case we're stepping backwards
- -}
- -
- -// change step value - this is an instantaneous change, not smoothed.
- -_inline void POS_ChangeVal( pos_t *p, float fstepnew )
- -{
- - p->step = FLOAT_TO_FIX20( fstepnew ); // convert fstep to fixed point
- -}
- -
- -// return current integer position, then update internal position value
- -_inline int POS_GetNext ( pos_t *p )
- -{
- - // float f = FIX20_TO_FLOAT( p->cstep );
- - // int i1 = FIX20_INTPART( p->cstep );
- - // float f1 = FIX20_TO_FLOAT( FIX20_FRACPART( p->cstep ));
- - // float f2 = FIX20_TO_FLOAT( p->step );
- -
- - p->cstep += p->step; // update accumulated fraction step value (fixed point)
- - p->pos += FIX20_INTPART( p->cstep ); // update pos with integer part of accumulated step
- - p->cstep = FIX20_FRACPART( p->cstep ); // throw away the integer part of accumulated step
- -
- - // wrap pos around either end of buffer if needed
- - POS_Wrap( p->D, &( p->pos ));
- -
- - // make sure returned position is within array bounds
- - ASSERT( p->pos <= p->D );
- -
- - return p->pos;
- -}
- -
- -// oneshot position within wav
- -typedef struct
- -{
- - pos_t p; // pos_t
- - qboolean fhitend; // flag indicating we hit end of oneshot wav
- -} pos_one_t;
- -
- -// set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
- -// one shot position - play only once, don't wrap, when hit end of buffer, return last position
- -_inline void POS_ONE_Init( pos_one_t *p1, int D, float fstep )
- -{
- - POS_Init( &p1->p, D, fstep ) ;
- -
- - p1->fhitend = false;
- -}
- -
- -// return current integer position, then update internal position value
- -_inline int POS_ONE_GetNext( pos_one_t *p1 )
- -{
- - int pos;
- - pos_t *p0;
- -
- - pos = p1->p.pos; // return current position
- -
- - if( p1->fhitend )
- - return pos;
- -
- - p0 = &(p1->p);
- - p0->cstep += p0->step; // update accumulated fraction step value (fixed point)
- - p0->pos += FIX20_INTPART( p0->cstep ); // update pos with integer part of accumulated step
- - //p0->cstep = SIGN(p0->cstep) * FIX20_FRACPART( p0->cstep );
- - p0->cstep = FIX20_FRACPART( p0->cstep ); // throw away the integer part of accumulated step
- -
- - // if we wrapped, stop updating, always return last position
- - // if step value is 0, return hit end
- -
- - if( !p0->step || p0->pos < 0 || p0->pos >= p0->D )
- - p1->fhitend = true;
- - else pos = p0->pos;
- -
- - // make sure returned value is within array bounds
- - ASSERT( pos <= p0->D );
- -
- - return pos;
- -}
- -
- -/////////////////////
- -// Reverbs and delays
- -/////////////////////
- -#define CDLYS 128 // max delay lines active. Also used for lfos.
- -
- -#define DLY_PLAIN 0 // single feedback loop
- -#define DLY_ALLPASS 1 // feedback and feedforward loop - flat frequency response (diffusor)
- -#define DLY_LOWPASS 2 // lowpass filter in feedback loop
- -#define DLY_LINEAR 3 // linear delay, no feedback, unity gain
- -#define DLY_MAX DLY_LINEAR
- -
- -// delay line
- -typedef struct
- -{
- - qboolean fused; // true if dly is in use
- - int type; // delay type
- - int D; // delay size, in samples
- - int t; // current tap, <= D
- - int D0; // original delay size (only relevant if calling DLY_ChangeVal)
- - int *p; // circular buffer pointer
- - int *w; // array of samples
- - int a; // feedback value 0..PMAX,normalized to 0-1.0
- - int b; // gain value 0..PMAX, normalized to 0-1.0
- - flt_t *pflt; // pointer to filter, if type DLY_LOWPASS
- - HANDLE h; // memory handle for sample array
- -} dly_t;
- -
- -dly_t dlys[CDLYS]; // delay lines
- -
- -void DLY_Init( dly_t *pdly ) { if( pdly ) memset( pdly, 0, sizeof( dly_t )); }
- -void DLY_InitAll( void ) { int i; for( i = 0; i < CDLYS; i++ ) DLY_Init( &dlys[i] ); }
- -void DLY_Free( dly_t *pdly )
- -{
- - // free memory buffer
- - if( pdly )
- - {
- - FLT_Free( pdly->pflt );
- -
- - if( pdly->w )
- - {
- - GlobalUnlock( pdly->h );
- - GlobalFree( pdly->h );
- - }
- -
- - // free dly slot
- - memset( pdly, 0, sizeof( dly_t ));
- - }
- -}
- -
- -
- -void DLY_FreeAll( void ) { int i; for( i = 0; i < CDLYS; i++ ) DLY_Free( &dlys[i] ); }
- -
- -// set up 'b' gain parameter of feedback delay to
- -// compensate for gain caused by feedback.
- -void DLY_SetNormalizingGain( dly_t *pdly )
- -{
- - // compute normalized gain, set as output gain
- -
- - // calculate gain of delay line with feedback, and use it to
- - // reduce output. ie: force delay line with feedback to unity gain
- -
- - // for constant input x with feedback fb:
- -
- - // out = x + x*fb + x * fb^2 + x * fb^3...
- - // gain = out/x
- - // so gain = 1 + fb + fb^2 + fb^3...
- - // which, by the miracle of geometric series, equates to 1/1-fb
- - // thus, gain = 1/(1-fb)
- -
- - float fgain = 0;
- - float gain;
- - int b;
- -
- - // if b is 0, set b to PMAX (1)
- - b = pdly->b ? pdly->b : PMAX;
- -
- - // fgain = b * (1.0 / (1.0 - (float)pdly->a / (float)PMAX)) / (float)PMAX;
- - fgain = (1.0 / (1.0 - (float)pdly->a / (float)PMAX ));
- -
- - // compensating gain - multiply rva output by gain then >> PBITS
- - gain = (int)((1.0 / fgain) * PMAX);
- -
- - gain = gain * 4; // compensate for fact that gain calculation is for +/- 32767 amplitude wavs
- - // ie: ok to allow a bit more gain because most wavs are not at theoretical peak amplitude at all times
- -
- - gain = min( gain, PMAX ); // cap at PMAX
- - gain = ((float)b/(float)PMAX) * gain; // scale final gain by pdly->b.
- -
- - pdly->b = (int)gain;
- -}
- -
- -// allocate a new delay line
- -// D number of samples to delay
- -// a feedback value (0-PMAX normalized to 0.0-1.0)
- -// b gain value (0-PMAX normalized to 0.0-1.0)
- -// if DLY_LOWPASS:
- -// L - numerator order of filter
- -// M - denominator order of filter
- -// fb - numerator params, M+1
- -// fa - denominator params, L+1
- -
- -dly_t * DLY_AllocLP( int D, int a, int b, int type, int M, int L, int *fa, int *fb )
- -{
- - HANDLE h;
- - int cb;
- - int *w;
- - int i;
- - dly_t *pdly = NULL;
- -
- - // find open slot
- - for( i = 0; i < CDLYS; i++ )
- - {
- - if( !dlys[i].fused )
- - {
- - pdly = &dlys[i];
- - DLY_Init( pdly );
- - break;
- - }
- - }
- -
- - if( i == CDLYS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate delay line.\n" );
- - return NULL; // all delay lines in use
- - }
- -
- - cb = (D + 1) * sizeof( int ); // assume all samples are signed integers
- -
- - if( type == DLY_LOWPASS )
- - {
- - // alloc lowpass fir_filter
- - pdly->pflt = FLT_Alloc( M, L, fa, fb );
- - if( !pdly->pflt )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate filter for delay line.\n" );
- - return NULL;
- - }
- - }
- -
- - // alloc delay memory
- - h = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, cb );
- - if( !h )
- - {
- - MsgDev( D_ERROR, "Sound DSP: Out of memory.\n" );
- - FLT_Free( pdly->pflt );
- - return NULL;
- - }
- -
- - // lock delay memory
- - w = (int *)GlobalLock( h );
- -
- - if( !w )
- - {
- - MsgDev( D_ERROR, "Sound DSP: Failed to lock.\n" );
- - GlobalFree( h );
- - FLT_Free( pdly->pflt );
- - return NULL;
- - }
- -
- - // clear delay array
- - memset( w, 0, cb );
- -
- - // init values
- - pdly->type = type;
- - pdly->D = D;
- - pdly->t = D; // set delay tap to full delay
- - pdly->D0 = D;
- - pdly->p = w; // init circular pointer to head of buffer
- - pdly->w = w;
- - pdly->h = h;
- - pdly->a = min( a, PMAX ); // do not allow 100% feedback
- - pdly->b = b;
- - pdly->fused = true;
- -
- - if( type == DLY_LINEAR )
- - {
- - // linear delay has no feedback and unity gain
- - pdly->a = 0;
- - pdly->b = PMAX;
- - }
- - else
- - {
- - // adjust b to compensate for feedback gain
- - DLY_SetNormalizingGain( pdly );
- - }
- -
- - return pdly;
- -}
- -
- -// allocate lowpass or allpass delay
- -dly_t * DLY_Alloc( int D, int a, int b, int type )
- -{
- - return DLY_AllocLP( D, a, b, type, 0, 0, 0, 0 );
- -}
- -
- -
- -// Allocate new delay, convert from float params in prc preset to internal parameters
- -// Uses filter params in prc if delay is type lowpass
- -
- -// delay parameter order
- -typedef enum
- -{
- - dly_idtype, // NOTE: first 8 params must match those in mdy_e
- - dly_idelay,
- - dly_ifeedback,
- - dly_igain,
- - dly_iftype,
- - dly_icutoff,
- - dly_iqwidth,
- - dly_iquality,
- - dly_cparam
- -} dly_e;
- -
- -
- -// delay parameter ranges
- -prm_rng_t dly_rng[] =
- -{
- -{ dly_cparam, 0, 0 }, // first entry is # of parameters
- -
- -// delay params
- -{ dly_idtype, 0, DLY_MAX }, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
- -{ dly_idelay, 0.0, 1000.0 }, // delay in milliseconds
- -{ dly_ifeedback, 0.0, 0.99 }, // feedback 0-1.0
- -{ dly_igain, 0.0, 1.0 }, // final gain of output stage, 0-1.0
- -
- -// filter params if dly type DLY_LOWPASS
- -{ dly_iftype, 0, FTR_MAX },
- -{ dly_icutoff, 10.0, 22050.0 },
- -{ dly_iqwidth, 100.0, 11025.0 },
- -{ dly_iquality, 0, QUA_MAX },
- -};
- -
- -dly_t * DLY_Params( prc_t *pprc )
- -{
- - dly_t *pdly = NULL;
- - int D, a, b;
- -
- - float delay = pprc->prm[dly_idelay];
- - float feedback = pprc->prm[dly_ifeedback];
- - float gain = pprc->prm[dly_igain];
- - int type = pprc->prm[dly_idtype];
- -
- - float ftype = pprc->prm[dly_iftype];
- - float cutoff = pprc->prm[dly_icutoff];
- - float qwidth = pprc->prm[dly_iqwidth];
- - float qual = pprc->prm[dly_iquality];
- -
- - D = MSEC_TO_SAMPS( delay ); // delay samples
- - a = feedback * PMAX; // feedback
- - b = gain * PMAX; // gain
- -
- - switch( type )
- - {
- - case DLY_PLAIN:
- - case DLY_ALLPASS:
- - case DLY_LINEAR:
- - pdly = DLY_Alloc( D, a, b, type );
- - break;
- - case DLY_LOWPASS:
- - {
- - // set up dummy lowpass filter to convert params
- - prc_t prcf;
- - flt_t *pflt;
- -
- - // 0,1,2 - high, medium, low (low quality implies faster execution time)
- - prcf.prm[flt_iquality] = qual;
- - prcf.prm[flt_icutoff] = cutoff;
- - prcf.prm[flt_iftype] = ftype;
- - prcf.prm[flt_iqwidth] = qwidth;
- -
- - pflt = (flt_t *)FLT_Params( &prcf );
- -
- - if( !pflt )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate filter.\n" );
- - return NULL;
- - }
- -
- - pdly = DLY_AllocLP( D, a, b, type, pflt->M, pflt->L, pflt->a, pflt->b );
- -
- - FLT_Free( pflt );
- - break;
- - }
- - }
- - return pdly;
- -}
- -
- -_inline void *DLY_VParams( void *p )
- -{
- - PRC_CheckParams(( prc_t *)p, dly_rng );
- - return (void *) DLY_Params((prc_t *)p);
- -}
- -
- -// get next value from delay line, move x into delay line
- -int DLY_GetNext( dly_t *pdly, int x )
- -{
- - switch( pdly->type )
- - {
- - default:
- - case DLY_PLAIN:
- - return dly_plain( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
- - case DLY_ALLPASS:
- - return dly_allpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
- - case DLY_LOWPASS:
- - return dly_lowpass( pdly->D, pdly->t, pdly->w, &(pdly->p), pdly->a, pdly->b, pdly->pflt->M, pdly->pflt->a, pdly->pflt->L, pdly->pflt->b, pdly->pflt->w, x );
- - case DLY_LINEAR:
- - return dly_linear( pdly->D, pdly->t, pdly->w, &pdly->p, x );
- - }
- -}
- -
- -// batch version for performance
- -void DLY_GetNextN( dly_t *pdly, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = DLY_GetNext( pdly, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = DLY_GetNext( pdly, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = DLY_GetNext( pdly, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -// get tap on t'th sample in delay - don't update buffer pointers, this is done via DLY_GetNext
- -_inline int DLY_GetTap( dly_t *pdly, int t )
- -{
- - return tap( pdly->D, pdly->w, pdly->p, t );
- -}
- -
- -
- -// make instantaneous change to new delay value D.
- -// t tap value must be <= original D (ie: we don't do any reallocation here)
- -void DLY_ChangeVal( dly_t *pdly, int t )
- -{
- - // never set delay > original delay
- - pdly->t = min( t, pdly->D0 );
- -}
- -
- -// ignored - use MDY_ for modulatable delay
- -_inline void DLY_Mod( void *p, float v )
- -{
- -}
- -
- -///////////////////
- -// Parallel reverbs
- -///////////////////
- -
- -// Reverb A
- -// M parallel reverbs, mixed to mono output
- -
- -#define CRVAS 64 // max number of parallel series reverbs active
- -#define CRVA_DLYS 12 // max number of delays making up reverb_a
- -
- -typedef struct
- -{
- - qboolean fused;
- - int m; // number of parallel plain or lowpass delays
- - int fparallel; // true if filters in parallel with delays, otherwise single output filter
- - flt_t *pflt;
- -
- - dly_t *pdlys[CRVA_DLYS]; // array of pointers to delays
- -} rva_t;
- -
- -rva_t rvas[CRVAS];
- -
- -void RVA_Init( rva_t *prva ) { if( prva ) memset( prva, 0, sizeof( rva_t )); }
- -void RVA_InitAll( void ) { int i; for( i = 0; i < CRVAS; i++ ) RVA_Init( &rvas[i] ); }
- -
- -// free parallel series reverb
- -void RVA_Free( rva_t *prva )
- -{
- - if( prva )
- - {
- - int i;
- -
- - // free all delays
- - for( i = 0; i < CRVA_DLYS; i++)
- - DLY_Free ( prva->pdlys[i] );
- -
- - FLT_Free( prva->pflt );
- - memset( prva, 0, sizeof (rva_t) );
- - }
- -}
- -
- -
- -void RVA_FreeAll( void ) { int i; for( i = 0; i < CRVAS; i++ ) RVA_Free( &rvas[i] ); }
- -
- -// create parallel reverb - m parallel reverbs summed
- -// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
- -// a array of reverb feedback parms for parallel reverbs (CRVB_P_DLYS)
- -// b array of CRVB_P_DLYS - mix params for parallel reverbs
- -// m - number of parallel delays
- -// pflt - filter template, to be used by all parallel delays
- -// fparallel - true if filter operates in parallel with delays, otherwise filter output only
- -rva_t *RVA_Alloc( int *D, int *a, int *b, int m, flt_t *pflt, int fparallel )
- -{
- - int i;
- - rva_t *prva;
- - flt_t *pflt2 = NULL;
- -
- - // find open slot
- - for( i = 0; i < CRVAS; i++ )
- - {
- - if( !rvas[i].fused )
- - break;
- - }
- -
- - // return null if no free slots
- - if( i == CRVAS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate reverb.\n" );
- - return NULL;
- - }
- -
- - prva = &rvas[i];
- -
- - // if series filter specified, alloc
- - if( pflt && !fparallel )
- - {
- - // use filter data as template for a filter on output
- - pflt2 = FLT_Alloc( pflt->M, pflt->L, pflt->a, pflt->b );
- -
- - if( !pflt2 )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate flt for reverb.\n" );
- - return NULL;
- - }
- - }
- -
- - // alloc parallel reverbs
- - if( pflt && fparallel )
- - {
- -
- - // use this filter data as a template to alloc a filter for each parallel delay
- - for( i = 0; i < m; i++ )
- - prva->pdlys[i] = DLY_AllocLP( D[i], a[i], b[i], DLY_LOWPASS, pflt->M, pflt->L, pflt->a, pflt->b );
- - }
- - else
- - {
- - // no filter specified, use plain delays in parallel sections
- - for( i = 0; i < m; i++ )
- - prva->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_PLAIN );
- - }
- -
- -
- - // if we failed to alloc any reverb, free all, return NULL
- - for( i = 0; i < m; i++ )
- - {
- - if( !prva->pdlys[i] )
- - {
- - FLT_Free( pflt2 );
- - RVA_Free( prva );
- - MsgDev( D_WARN, "DSP: failed to allocate delay for reverb.\n" );
- - return NULL;
- - }
- - }
- -
- - prva->fused = true;
- - prva->m = m;
- - prva->fparallel = fparallel;
- - prva->pflt = pflt2;
- -
- - return prva;
- -}
- -
- -
- -// parallel reverberator
- -//
- -// for each input sample x do:
- -// x0 = plain(D0,w0,&p0,a0,x)
- -// x1 = plain(D1,w1,&p1,a1,x)
- -// x2 = plain(D2,w2,&p2,a2,x)
- -// x3 = plain(D3,w3,&p3,a3,x)
- -// y = b0*x0 + b1*x1 + b2*x2 + b3*x3
- -//
- -// rgdly - array of 6 delays:
- -// D - Delay values (typical - 29, 37, 44, 50, 27, 31)
- -// w - array of delayed values
- -// p - array of pointers to circular delay line pointers
- -// a - array of 6 feedback values (typical - all equal, like 0.75 * PMAX)
- -// b - array of 6 gain values for plain reverb outputs (1, .9, .8, .7)
- -// xin - input value
- -// if fparallel, filters are built into delays,
- -// otherwise, filter output
- -
- -_inline int RVA_GetNext( rva_t *prva, int x )
- -{
- - int m = prva->m;
- - int i, y, sum;
- -
- - sum = 0;
- -
- - for( i = 0; i < m; i++ )
- - sum += DLY_GetNext( prva->pdlys[i], x );
- -
- - // m is clamped between RVA_BASEM & CRVA_DLYS
- -
- - if( m ) y = sum/m;
- - else y = x;
- -#if 0
- - // PERFORMANCE:
- - // UNDONE: build as array
- - int mm;
- -
- - switch( m )
- - {
- - case 12: mm = (PMAX/12); break;
- - case 11: mm = (PMAX/11); break;
- - case 10: mm = (PMAX/10); break;
- - case 9: mm = (PMAX/9); break;
- - case 8: mm = (PMAX/8); break;
- - case 7: mm = (PMAX/7); break;
- - case 6: mm = (PMAX/6); break;
- - case 5: mm = (PMAX/5); break;
- - case 4: mm = (PMAX/4); break;
- - case 3: mm = (PMAX/3); break;
- - case 2: mm = (PMAX/2); break;
- - default:
- - case 1: mm = (PMAX/1); break;
- - }
- -
- - y = (sum * mm) >> PBITS;
- -
- -#endif // 0
- -
- - // run series filter if present
- - if( prva->pflt && !prva->fparallel )
- - y = FLT_GetNext( prva->pflt, y );
- -
- - return y;
- -}
- -
- -// batch version for performance
- -_inline void RVA_GetNextN( rva_t *prva, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = RVA_GetNext( prva, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = RVA_GetNext( prva, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = RVA_GetNext( prva, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -#define RVA_BASEM 3 // base number of parallel delays
- -
- -// nominal delay and feedback values
- -
- -//float rvadlys[] = { 29, 37, 44, 50, 62, 75, 96, 118, 127, 143, 164, 175 };
- -float rvadlys[] = { 18, 23, 28, 36, 47, 21, 26, 33, 40, 49, 45, 38 };
- -float rvafbs[] = { 0.7, 0.7, 0.7, 0.8, 0.8, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9 };
- -
- -// reverb parameter order
- -typedef enum
- -{
- - // parameter order
- - rva_isize,
- - rva_idensity,
- - rva_idecay,
- - rva_iftype,
- - rva_icutoff,
- - rva_iqwidth,
- - rva_ifparallel,
- - rva_cparam // # of params
- -} rva_e;
- -
- -// filter parameter ranges
- -prm_rng_t rva_rng[] =
- -{
- -{ rva_cparam, 0, 0 }, // first entry is # of parameters
- -
- -// reverb params
- -{ rva_isize, 0.0, 2.0 }, // 0-2.0 scales nominal delay parameters (starting at approx 20ms)
- -{ rva_idensity, 0.0, 2.0 }, // 0-2.0 density of reverbs (room shape) - controls # of parallel or series delays
- -{ rva_idecay, 0.0, 2.0 }, // 0-2.0 scales feedback parameters (starting at approx 0.15)
- -
- -// filter params for each parallel reverb (quality set to 0 for max execution speed)
- -{ rva_iftype, 0, FTR_MAX },
- -{ rva_icutoff, 10, 22050 },
- -{ rva_iqwidth, 100, 11025 },
- -{ rva_ifparallel, 0, 1 } // if 1, then all filters operate in parallel with delays. otherwise filter output only
- -};
- -
- -rva_t * RVA_Params( prc_t *pprc )
- -{
- - flt_t *pflt;
- - rva_t *prva;
- - float size = pprc->prm[rva_isize]; // 0-2.0 controls scale of delay parameters
- - float density = pprc->prm[rva_idensity]; // 0-2.0 density of reverbs (room shape) - controls # of parallel delays
- - float decay = pprc->prm[rva_idecay]; // 0-1.0 controls feedback parameters
- -
- - float ftype = pprc->prm[rva_iftype];
- - float cutoff = pprc->prm[rva_icutoff];
- - float qwidth = pprc->prm[rva_iqwidth];
- -
- - float fparallel = pprc->prm[rva_ifparallel];
- -
- - // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
- - // a array of reverb feedback parms for parallel delays
- - // b array of CRVB_P_DLYS - mix params for parallel reverbs
- - // m - number of parallel delays
- -
- - int D[CRVA_DLYS];
- - int a[CRVA_DLYS];
- - int b[CRVA_DLYS];
- - int m = RVA_BASEM;
- - int i;
- -
- - m = density * CRVA_DLYS / 2;
- -
- - // limit # delays 3-12
- - m = bound( RVA_BASEM, m, CRVA_DLYS );
- -
- - // average time sound takes to travel from most distant wall
- - // (cap at 1000 ft room)
- - for( i = 0; i < m; i++ )
- - {
- - // delays of parallel reverb
- - D[i] = MSEC_TO_SAMPS( rvadlys[i] * size );
- -
- - // feedback and gain of parallel reverb
- - a[i] = (int)min( 0.9 * PMAX, rvafbs[i] * (float)PMAX * decay );
- - b[i] = PMAX;
- - }
- -
- - // add filter
- - pflt = NULL;
- -
- - if( cutoff )
- - {
- - // set up dummy lowpass filter to convert params
- - prc_t prcf;
- -
- - prcf.prm[flt_iquality] = QUA_LO; // force filter to low quality for faster execution time
- - prcf.prm[flt_icutoff] = cutoff;
- - prcf.prm[flt_iftype] = ftype;
- - prcf.prm[flt_iqwidth] = qwidth;
- -
- - pflt = (flt_t *)FLT_Params( &prcf );
- - }
- -
- - prva = RVA_Alloc( D, a, b, m, pflt, fparallel );
- - FLT_Free( pflt );
- -
- - return prva;
- -}
- -
- -_inline void *RVA_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, rva_rng );
- - return (void *)RVA_Params((prc_t *)p );
- -}
- -
- -_inline void RVA_Mod( void *p, float v )
- -{
- -}
- -
- -
- -////////////
- -// Diffusor
- -///////////
- -
- -// (N series allpass reverbs)
- -#define CDFRS 64 // max number of series reverbs active
- -#define CDFR_DLYS 16 // max number of delays making up diffusor
- -
- -typedef struct
- -{
- - qboolean fused;
- - int n; // series allpass delays
- - int w[CDFR_DLYS]; // internal state array for series allpass filters
- - dly_t *pdlys[CDFR_DLYS]; // array of pointers to delays
- -} dfr_t;
- -
- -dfr_t dfrs[CDFRS];
- -
- -void DFR_Init( dfr_t *pdfr ) { if( pdfr ) memset( pdfr, 0, sizeof( dfr_t )); }
- -void DFR_InitAll( void ) { int i; for( i = 0; i < CDFRS; i++ ) DFR_Init ( &dfrs[i] ); }
- -
- -// free parallel series reverb
- -void DFR_Free( dfr_t *pdfr )
- -{
- - if( pdfr )
- - {
- - int i;
- -
- - // free all delays
- - for( i = 0; i < CDFR_DLYS; i++ )
- - DLY_Free( pdfr->pdlys[i] );
- -
- - memset( pdfr, 0, sizeof( dfr_t ));
- - }
- -}
- -
- -
- -void DFR_FreeAll( void ) { int i; for( i = 0; i < CDFRS; i++ ) DFR_Free( &dfrs[i] ); }
- -
- -// create n series allpass reverbs
- -// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
- -// a array of reverb feedback parms for series delays
- -// b array of gain params for parallel reverbs
- -// n - number of series delays
- -
- -dfr_t *DFR_Alloc( int *D, int *a, int *b, int n )
- -{
- - int i;
- - dfr_t *pdfr;
- -
- - // find open slot
- - for( i = 0; i < CDFRS; i++ )
- - {
- - if( !dfrs[i].fused )
- - break;
- - }
- -
- - // return null if no free slots
- - if( i == CDFRS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate diffusor.\n" );
- - return NULL;
- - }
- -
- - pdfr = &dfrs[i];
- -
- - DFR_Init( pdfr );
- -
- - // alloc reverbs
- - for( i = 0; i < n; i++ )
- - pdfr->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_ALLPASS );
- -
- - // if we failed to alloc any reverb, free all, return NULL
- - for( i = 0; i < n; i++ )
- - {
- - if( !pdfr->pdlys[i] )
- - {
- - DFR_Free( pdfr );
- - MsgDev( D_WARN, "DSP: failed to allocate delay for diffusor.\n" );
- - return NULL;
- - }
- - }
- -
- - pdfr->fused = true;
- - pdfr->n = n;
- -
- - return pdfr;
- -}
- -
- -// series reverberator
- -_inline int DFR_GetNext( dfr_t *pdfr, int x )
- -{
- - int i, y;
- - int n = pdfr->n;
- -
- - y = x;
- - for( i = 0; i < n; i++ )
- - y = DLY_GetNext( pdfr->pdlys[i], y );
- - return y;
- -
- -#if 0
- - // alternate method, using internal state - causes PREDELAY = sum of delay times
- -
- - int *v = pdfr->w; // intermediate results
- -
- - v[0] = x;
- -
- - // reverse evaluate series delays
- - // w[0] w[1] w[2] w[n-1] w[n]
- - // x---->D[0]--->D[1]--->D[2]...-->D[n-1]--->out
- - //
- -
- - for( i = n; i > 0; i-- )
- - v[i] = DLY_GetNext( pdfr->pdlys[i-1], v[i-1] );
- -
- - return v[n];
- -#endif
- -}
- -
- -// batch version for performance
- -_inline void DFR_GetNextN( dfr_t *pdfr, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = DFR_GetNext( pdfr, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = DFR_GetNext( pdfr, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = DFR_GetNext( pdfr, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -#define DFR_BASEN 2 // base number of series allpass delays
- -
- -// nominal diffusor delay and feedback values
- -//float dfrdlys[] = { 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95 };
- -float dfrdlys[] = { 13, 19, 26, 21, 32, 36, 38, 16, 24, 28, 41, 35, 10, 46, 50, 27 };
- -float dfrfbs[] = { 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15 };
- -
- -
- -// diffusor parameter order
- -
- -typedef enum
- -{
- - // parameter order
- - dfr_isize,
- - dfr_idensity,
- - dfr_idecay,
- - dfr_cparam // # of params
- -
- -} dfr_e;
- -
- -// diffusor parameter ranges
- -
- -prm_rng_t dfr_rng[] =
- -{
- -{ dfr_cparam, 0, 0 }, // first entry is # of parameters
- -{ dfr_isize, 0.0, 1.0 }, // 0-1.0 scales all delays
- -{ dfr_idensity, 0.0, 1.0 }, // 0-1.0 controls # of series delays
- -{ dfr_idecay, 0.0, 1.0 }, // 0-1.0 scales all feedback parameters
- -};
- -
- -dfr_t *DFR_Params( prc_t *pprc )
- -{
- - dfr_t *pdfr;
- - int i, s;
- - float size = pprc->prm[dfr_isize]; // 0-1.0 scales all delays
- - float density = pprc->prm[dfr_idensity]; // 0-1.0 controls # of series delays
- - float diffusion = pprc->prm[dfr_idecay]; // 0-1.0 scales all feedback parameters
- -
- - // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
- - // a array of reverb feedback parms for series delays (CRVB_S_DLYS)
- - // b gain of each reverb section
- - // n - number of series delays
- -
- - int D[CDFR_DLYS];
- - int a[CDFR_DLYS];
- - int b[CDFR_DLYS];
- - int n = DFR_BASEN;
- -
- - // increase # of series diffusors with increased density
- - n += density * 2;
- -
- - // limit m, n to half max number of delays
- - n = min( CDFR_DLYS / 2, n );
- -
- - // compute delays for diffusors
- - for( i = 0; i < n; i++ )
- - {
- - s = (int)( dfrdlys[i] * size );
- -
- - // delay of diffusor
- - D[i] = MSEC_TO_SAMPS( s );
- -
- - // feedback and gain of diffusor
- - a[i] = min( 0.9 * PMAX, dfrfbs[i] * PMAX * diffusion );
- - b[i] = PMAX;
- - }
- -
- - pdfr = DFR_Alloc( D, a, b, n );
- -
- - return pdfr;
- -}
- -
- -_inline void *DFR_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, dfr_rng );
- - return (void *)DFR_Params((prc_t *)p );
- -}
- -
- -_inline void DFR_Mod( void *p, float v )
- -{
- -}
- -
- -//////////////////////
- -// LFO wav definitions
- -//////////////////////
- -
- -#define CLFOSAMPS 512 // samples per wav table - single cycle only
- -#define LFOBITS 14 // bits of peak amplitude of lfo wav
- -#define LFOAMP ((1<<LFOBITS)-1) // peak amplitude of lfo wav
- -
- -//types of lfo wavs
- -
- -#define LFO_SIN 0 // sine wav
- -#define LFO_TRI 1 // triangle wav
- -#define LFO_SQR 2 // square wave, 50% duty cycle
- -#define LFO_SAW 3 // forward saw wav
- -#define LFO_RND 4 // random wav
- -#define LFO_LOG_IN 5 // logarithmic fade in
- -#define LFO_LOG_OUT 6 // logarithmic fade out
- -#define LFO_LIN_IN 7 // linear fade in
- -#define LFO_LIN_OUT 8 // linear fade out
- -#define LFO_MAX LFO_LIN_OUT
- -
- -#define CLFOWAV 9 // number of LFO wav tables
- -
- -typedef struct // lfo or envelope wave table
- -{
- - int type; // lfo type
- - dly_t *pdly; // delay holds wav values and step pointers
- -} lfowav_t;
- -
- -lfowav_t lfowavs[CLFOWAV];
- -
- -// deallocate lfo wave table. Called only when sound engine exits.
- -void LFOWAV_Free( lfowav_t *plw )
- -{
- - // free delay
- - if( plw ) DLY_Free( plw->pdly );
- -
- - memset( plw, 0, sizeof( lfowav_t ));
- -}
- -
- -// deallocate all lfo wave tables. Called only when sound engine exits.
- -void LFOWAV_FreeAll( void )
- -{
- - int i;
- -
- - for( i = 0; i < CLFOWAV; i++ )
- - LFOWAV_Free( &lfowavs[i] );
- -}
- -
- -// fill lfo array w with count samples of lfo type 'type'
- -// all lfo wavs except fade out, rnd, and log_out should start with 0 output
- -void LFOWAV_Fill( int *w, int count, int type )
- -{
- - int i,x;
- -
- - switch( type )
- - {
- - default:
- - case LFO_SIN: // sine wav, all values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - {
- - x = ( int )(( float)(LFOAMP) * sin( (M_PI2 * (float)i / (float)count ) + ( M_PI_F * 1.5 )));
- - w[i] = (x + LFOAMP)/2;
- - }
- - break;
- - case LFO_TRI: // triangle wav, all values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - {
- - w[i] = ( int ) ( (float)(2 * LFOAMP * i ) / (float)(count) );
- -
- - if( i > count / 2 )
- - w[i] = ( int )( (float) (2 * LFOAMP) - (float)( 2 * LFOAMP * i ) / (float)( count ));
- - }
- - break;
- - case LFO_SQR: // square wave, 50% duty cycle, all values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - w[i] = i > count / 2 ? 0 : LFOAMP;
- - break;
- - case LFO_SAW: // forward saw wav, aall values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - w[i] = ( int )( (float)(LFOAMP) * (float)i / (float)( count ));
- - break;
- - case LFO_RND: // random wav, all values 0 <= x <= LFOAMP
- - for( i = 0; i < count; i++ )
- - w[i] = ( int )( Com_RandomLong( 0, LFOAMP ));
- - break;
- - case LFO_LOG_IN: // logarithmic fade in, all values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - w[i] = ( int ) ( (float)(LFOAMP) * pow( (float)i / (float)count, 2 ));
- - break;
- - case LFO_LOG_OUT: // logarithmic fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
- - for( i = 0; i < count; i++ )
- - w[i] = ( int ) ( (float)(LFOAMP) * pow( 1.0 - ((float)i / (float)count), 2 ));
- - break;
- - case LFO_LIN_IN: // linear fade in, all values 0 <= x <= LFOAMP, initial value = 0
- - for( i = 0; i < count; i++ )
- - w[i] = ( int )( (float)(LFOAMP) * (float)i / (float)(count) );
- - break;
- - case LFO_LIN_OUT: // linear fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
- - for( i = 0; i < count; i++ )
- - w[i] = LFOAMP - ( int )( (float)(LFOAMP) * (float)i / (float)(count) );
- - break;
- - }
- -}
- -
- -// allocate all lfo wave tables. Called only when sound engine loads.
- -void LFOWAV_InitAll( void )
- -{
- - int i;
- - dly_t *pdly;
- -
- - memset( lfowavs, 0, sizeof( lfowavs ));
- -
- - // alloc space for each lfo wav type
- - for( i = 0; i < CLFOWAV; i++ )
- - {
- - pdly = DLY_Alloc( CLFOSAMPS, 0, 0 , DLY_PLAIN );
- -
- - lfowavs[i].pdly = pdly;
- - lfowavs[i].type = i;
- -
- - LFOWAV_Fill( pdly->w, CLFOSAMPS, i );
- - }
- -
- - // if any dlys fail to alloc, free all
- - for( i = 0; i < CLFOWAV; i++ )
- - {
- - if( !lfowavs[i].pdly )
- - LFOWAV_FreeAll();
- - }
- -}
- -
- -
- -////////////////////////////////////////
- -// LFO iterators - one shot and looping
- -////////////////////////////////////////
- -
- -#define CLFO 16 // max active lfos (this steals from active delays)
- -
- -typedef struct
- -{
- - qboolean fused; // true if slot take
- - dly_t *pdly; // delay points to lfo wav within lfowav_t (don't free this)
- - float f; // playback frequency in hz
- - pos_t pos; // current position within wav table, looping
- - pos_one_t pos1; // current position within wav table, one shot
- - int foneshot; // true - one shot only, don't repeat
- -} lfo_t;
- -
- -lfo_t lfos[CLFO];
- -
- -void LFO_Init( lfo_t *plfo ) { if( plfo ) memset( plfo, 0, sizeof( lfo_t )); }
- -void LFO_InitAll( void ) { int i; for( i = 0; i < CLFO; i++ ) LFO_Init( &lfos[i] ); }
- -void LFO_Free( lfo_t *plfo ) { if( plfo ) memset( plfo, 0, sizeof( lfo_t )); }
- -void LFO_FreeAll( void ) { int i; for( i = 0; i < CLFO; i++ ) LFO_Free( &lfos[i] ); }
- -
- -
- -// get step value given desired playback frequency
- -_inline float LFO_HzToStep( float freqHz )
- -{
- - float lfoHz;
- -
- - // calculate integer and fractional step values,
- - // assume an update rate of SOUND_DMA_SPEED samples/sec
- -
- - // 1 cycle/CLFOSAMPS * SOUND_DMA_SPEED samps/sec = cycles/sec = current lfo rate
- - //
- - // lforate * X = freqHz so X = freqHz/lforate = update rate
- - lfoHz = (float)(SOUND_DMA_SPEED) / (float)(CLFOSAMPS);
- -
- - return freqHz / lfoHz;
- -}
- -
- -// return pointer to new lfo
- -
- -lfo_t *LFO_Alloc( int wtype, float freqHz, qboolean foneshot )
- -{
- - int i, type = min( CLFOWAV - 1, wtype );
- - float lfostep;
- -
- - for( i = 0; i < CLFO; i++ )
- - {
- - if( !lfos[i].fused )
- - {
- - lfo_t *plfo = &lfos[i];
- -
- - LFO_Init( plfo );
- -
- - plfo->fused = true;
- - plfo->pdly = lfowavs[type].pdly; // pdly in lfo points to wav table data in lfowavs
- - plfo->f = freqHz;
- - plfo->foneshot = foneshot;
- -
- - lfostep = LFO_HzToStep( freqHz );
- -
- - // init positional pointer (ie: fixed point updater for controlling pitch of lfo)
- - if( !foneshot ) POS_Init(&(plfo->pos), plfo->pdly->D, lfostep );
- - else POS_ONE_Init(&(plfo->pos1), plfo->pdly->D,lfostep );
- -
- - return plfo;
- - }
- - }
- -
- - MsgDev( D_WARN, "DSP: failed to allocate LFO.\n" );
- - return NULL;
- -}
- -
- -// get next lfo value
- -// Value returned is 0..LFOAMP. can be normalized by shifting right by LFOBITS
- -// To play back at correct passed in frequency, routien should be
- -// called once for every output sample (ie: at SOUND_DMA_SPEED)
- -// x is dummy param
- -_inline int LFO_GetNext( lfo_t *plfo, int x )
- -{
- - int i;
- -
- - // get current position
- - if( !plfo->foneshot ) i = POS_GetNext( &plfo->pos );
- - else i = POS_ONE_GetNext( &plfo->pos1 );
- -
- - // return current sample
- - return plfo->pdly->w[i];
- -}
- -
- -// batch version for performance
- -_inline void LFO_GetNextN( lfo_t *plfo, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = LFO_GetNext( plfo, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = LFO_GetNext( plfo, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = LFO_GetNext( plfo, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -// uses lfowav, rate, foneshot
- -typedef enum
- -{
- - // parameter order
- - lfo_iwav,
- - lfo_irate,
- - lfo_ifoneshot,
- - lfo_cparam // # of params
- -
- -} lfo_e;
- -
- -// parameter ranges
- -
- -prm_rng_t lfo_rng[] =
- -{
- -{ lfo_cparam, 0, 0 }, // first entry is # of parameters
- -{ lfo_iwav, 0.0, LFO_MAX }, // lfo type to use (LFO_SIN, LFO_RND...)
- -{ lfo_irate, 0.0, 16000.0 }, // modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
- -{ lfo_ifoneshot, 0.0, 1.0 }, // 1.0 if lfo is oneshot
- -};
- -
- -lfo_t * LFO_Params( prc_t *pprc )
- -{
- - lfo_t *plfo;
- - qboolean foneshot = pprc->prm[lfo_ifoneshot] > 0 ? true : false;
- -
- - plfo = LFO_Alloc( pprc->prm[lfo_iwav], pprc->prm[lfo_irate], foneshot );
- -
- - return plfo;
- -}
- -
- -void LFO_ChangeVal( lfo_t *plfo, float fhz )
- -{
- - float fstep = LFO_HzToStep( fhz );
- -
- - // change lfo playback rate to new frequency fhz
- - if( plfo->foneshot ) POS_ChangeVal( &plfo->pos, fstep );
- - else POS_ChangeVal( &plfo->pos1.p, fstep );
- -}
- -
- -_inline void *LFO_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, lfo_rng );
- - return (void *)LFO_Params((prc_t *)p);
- -}
- -
- -// v is +/- 0-1.0
- -// v changes current lfo frequency up/down by +/- v%
- -_inline void LFO_Mod( lfo_t *plfo, float v )
- -{
- - float fhz;
- - float fhznew;
- -
- - fhz = plfo->f;
- - fhznew = fhz * (1.0 + v);
- -
- - LFO_ChangeVal( plfo, fhznew );
- -
- - return;
- -}
- -
- -
- -/////////////////////////////////////////////////////////////////////////////
- -// Ramp - used for varying smoothly between int parameters ie: modulation delays
- -/////////////////////////////////////////////////////////////////////////////
- -typedef struct
- -{
- - int initval; // initial ramp value
- - int target; // final ramp value
- - int sign; // increasing (1) or decreasing (-1) ramp
- - int yprev; // previous output value
- - qboolean fhitend; // true if hit end of ramp
- - pos_one_t ps; // current ramp output
- -} rmp_t;
- -
- -// ramp smoothly between initial value and target value in approx 'ramptime' seconds.
- -// (initial value may be greater or less than target value)
- -// never changes output by more than +1 or -1 (which can cause the ramp to take longer to complete than ramptime)
- -// called once per sample while ramping
- -// ramptime - duration of ramp in seconds
- -// initval - initial ramp value
- -// targetval - target ramp value
- -void RMP_Init( rmp_t *prmp, float ramptime, int initval, int targetval )
- -{
- - int rise;
- - int run;
- -
- - if( prmp ) memset( prmp, 0, sizeof( rmp_t ));
- -
- - run = (int)( ramptime * SOUND_DMA_SPEED ); // 'samples' in ramp
- - rise = (targetval - initval); // height of ramp
- -
- - // init fixed point iterator to iterate along the height of the ramp 'rise'
- - // always iterates from 0..'rise', increasing in value
- -
- - POS_ONE_Init( &prmp->ps, ABS( rise ), ABS((float) rise) / ((float) run));
- -
- - prmp->yprev = initval;
- - prmp->initval = initval;
- - prmp->target = targetval;
- - prmp->sign = SIGN( rise );
- -
- -}
- -
- -// continues from current position to new target position
- -void RMP_SetNext( rmp_t *prmp, float ramptime, int targetval )
- -{
- - RMP_Init( prmp, ramptime, prmp->yprev, targetval );
- -}
- -
- -_inline qboolean RMP_HitEnd( rmp_t *prmp )
- -{
- - return prmp->fhitend;
- -}
- -
- -_inline void RMP_SetEnd( rmp_t *prmp )
- -{
- - prmp->fhitend = true;
- -}
- -
- -// get next ramp value & update ramp, never varies by more than +1 or -1 between calls
- -// when ramp hits target value, it thereafter always returns last value
- -
- -_inline int RMP_GetNext( rmp_t *prmp )
- -{
- - int y, d;
- -
- - // if we hit ramp end, return last value
- - if( prmp->fhitend )
- - return prmp->yprev;
- -
- - // get next integer position in ramp height.
- - d = POS_ONE_GetNext( &prmp->ps );
- -
- - if( prmp->ps.fhitend )
- - prmp->fhitend = true;
- -
- - // increase or decrease from initval, depending on ramp sign
- - if( prmp->sign > 0 )
- - y = prmp->initval + d;
- - else y = prmp->initval - d;
- -
- - // only update current height by a max of +1 or -1
- - // this means that for short ramp times, we may not hit target
- - if( ABS( y - prmp->yprev ) >= 1 )
- - prmp->yprev += prmp->sign;
- -
- - return prmp->yprev;
- -}
- -
- -// get current ramp value, don't update ramp
- -_inline int RMP_GetCurrent( rmp_t *prmp )
- -{
- - return prmp->yprev;
- -}
- -
- -////////////////////////////////////////
- -// Time Compress/expand with pitch shift
- -////////////////////////////////////////
- -
- -// realtime pitch shift - ie: pitch shift without change to playback rate
- -
- -#define CPTCS 64
- -
- -typedef struct
- -{
- - qboolean fused;
- - dly_t *pdly_in; // input buffer space
- - dly_t *pdly_out; // output buffer space
- - int *pin; // input buffer (pdly_in->w)
- - int *pout; // output buffer (pdly_out->w)
- - int cin; // # samples in input buffer
- - int cout; // # samples in output buffer
- - int cxfade; // # samples in crossfade segment
- - int ccut; // # samples to cut
- - int cduplicate; // # samples to duplicate (redundant - same as ccut)
- - int iin; // current index into input buffer (reading)
- - pos_one_t psn; // stepping index through output buffer
- - qboolean fdup; // true if duplicating, false if cutting
- - float fstep; // pitch shift & time compress/expand
- -} ptc_t;
- -
- -ptc_t ptcs[CPTCS];
- -
- -void PTC_Init( ptc_t *pptc ) { if( pptc ) memset( pptc, 0, sizeof( ptc_t )); };
- -void PTC_Free( ptc_t *pptc )
- -{
- - if( pptc )
- - {
- - DLY_Free( pptc->pdly_in );
- - DLY_Free( pptc->pdly_out );
- -
- - memset( pptc, 0, sizeof( ptc_t ));
- - }
- -};
- -
- -void PTC_InitAll() { int i; for( i = 0; i < CPTCS; i++ ) PTC_Init( &ptcs[i] ); };
- -void PTC_FreeAll() { int i; for( i = 0; i < CPTCS; i++ ) PTC_Free( &ptcs[i] ); };
- -
- -// Time compressor/expander with pitch shift (ie: pitch changes, playback rate does not)
- -//
- -// Algorithm:
- -// 1) Duplicate or discard chunks of sound to provide tslice * fstep seconds of sound.
- -// (The user-selectable size of the buffer to process is tslice milliseconds in length)
- -// 2) Resample this compressed/expanded buffer at fstep to produce a pitch shifted
- -// output with the same duration as the input (ie: #samples out = # samples in, an
- -// obvious requirement for realtime _inline processing).
- -
- -// timeslice is size in milliseconds of full buffer to process.
- -// timeslice * fstep is the size of the expanded/compressed buffer
- -// timexfade is length in milliseconds of crossfade region between duplicated or cut sections
- -// fstep is % expanded/compressed sound normalized to 0.01-2.0 (1% - 200%)
- -
- -// input buffer:
- -
- -// iin-->
- -
- -// [0... tslice ...D] input samples 0...D (D is NEWEST sample)
- -// [0... ...n][m... tseg ...D] region to be cut or duplicated m...D
- -
- -// [0... [p..txf1..n][m... tseg ...D] fade in region 1 txf1 p...n
- -// [0... ...n][m..[q..txf2..D] fade out region 2 txf2 q...D
- -
- -
- -// pitch up: duplicate into output buffer: tdup = tseg
- -
- -// [0... ...n][m... tdup ...D][m... tdup ...D] output buffer size with duplicate region
- -// [0... ...n][m..[p...xf1..n][m... tdup ...D] fade in p...n while fading out q...D
- -// [0... ...n][m..[q...xf2..D][m... tdup ...D]
- -// [0... ...n][m..[.XFADE...n][m... tdup ...D] final duplicated output buffer - resample at fstep
- -
- -// pitch down: cut into output buffer: tcut = tseg
- -
- -// [0... ...n][m... tcut ...D] input samples with cut region delineated m...D
- -// [0... ...n] output buffer size after cut
- -// [0... [q..txf2...D] fade in txf1 q...D while fade out txf2 p...n
- -// [0... [.XFADE ...D] final cut output buffer - resample at fstep
- -
- -
- -ptc_t * PTC_Alloc( float timeslice, float timexfade, float fstep )
- -{
- - int i;
- - ptc_t *pptc;
- - float tout;
- - int cin, cout;
- - float tslice = timeslice;
- - float txfade = timexfade;
- - float tcutdup;
- -
- - // find time compressor slot
- - for( i = 0; i < CPTCS; i++ )
- - {
- - if( !ptcs[i].fused )
- - break;
- - }
- -
- - if( i == CPTCS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate pitch shifter.\n" );
- - return NULL;
- - }
- -
- - pptc = &ptcs[i];
- - PTC_Init( pptc );
- -
- - // get size of region to cut or duplicate
- - tcutdup = abs(( fstep - 1.0 ) * timeslice );
- -
- - // to prevent buffer overruns:
- -
- - // make sure timeslice is greater than cut/dup time
- - tslice = max ( tslice, 1.1 * tcutdup);
- -
- - // make sure xfade time smaller than cut/dup time, and smaller than (timeslice-cutdup) time
- - txfade = min( txfade, 0.9 * tcutdup );
- - txfade = min( txfade, 0.9 * ( tslice - tcutdup ));
- -
- - pptc->cxfade = MSEC_TO_SAMPS( txfade );
- - pptc->ccut = MSEC_TO_SAMPS( tcutdup );
- - pptc->cduplicate = MSEC_TO_SAMPS( tcutdup );
- -
- - // alloc delay lines (buffers)
- - tout = tslice * fstep;
- -
- - cin = MSEC_TO_SAMPS( tslice );
- - cout = MSEC_TO_SAMPS( tout );
- -
- - pptc->pdly_in = DLY_Alloc( cin, 0, 1, DLY_LINEAR ); // alloc input buffer
- - pptc->pdly_out = DLY_Alloc( cout, 0, 1, DLY_LINEAR ); // alloc output buffer
- -
- - if( !pptc->pdly_in || !pptc->pdly_out )
- - {
- - PTC_Free( pptc );
- - MsgDev( D_WARN, "DSP: failed to allocate delay for pitch shifter.\n" );
- - return NULL;
- - }
- -
- - // buffer pointers
- - pptc->pin = pptc->pdly_in->w;
- - pptc->pout = pptc->pdly_out->w;
- -
- - // input buffer index
- - pptc->iin = 0;
- -
- - // output buffer index
- - POS_ONE_Init( &pptc->psn, cout, fstep );
- -
- - // if fstep > 1.0 we're pitching shifting up, so fdup = true
- - pptc->fdup = fstep > 1.0 ? true : false;
- -
- - pptc->cin = cin;
- - pptc->cout = cout;
- -
- - pptc->fstep = fstep;
- - pptc->fused = true;
- -
- - return pptc;
- -}
- -
- -// linear crossfader
- -// yfadein - instantaneous value fading in
- -// ydafeout -instantaneous value fading out
- -// nsamples - duration in #samples of fade
- -// isample - index in to fade 0...nsamples-1
- -_inline int xfade( int yfadein, int yfadeout, int nsamples, int isample )
- -{
- - int yout;
- - int m = (isample << PBITS ) / nsamples;
- -
- - yout = ((yfadein * m) >> PBITS) + ((yfadeout * (PMAX - m)) >> PBITS);
- -
- - return yout;
- -}
- -
- -// w - pointer to start of input buffer samples
- -// v - pointer to start of output buffer samples
- -// cin - # of input buffer samples
- -// cout = # of output buffer samples
- -// cxfade = # of crossfade samples
- -// cduplicate = # of samples in duplicate/cut segment
- -void TimeExpand( int *w, int *v, int cin, int cout, int cxfade, int cduplicate )
- -{
- - int i, j;
- - int m;
- - int p;
- - int q;
- - int D;
- -
- - // input buffer
- - // xfade source duplicate
- - // [0...........][p.......n][m...........D]
- -
- - // output buffer
- - // xfade region duplicate
- - // [0.....................n][m..[q.......D][m...........D]
- -
- - // D - index of last sample in input buffer
- - // m - index of 1st sample in duplication region
- - // p - index of 1st sample of crossfade source
- - // q - index of 1st sample in crossfade region
- -
- - D = cin - 1;
- - m = cin - cduplicate;
- - p = m - cxfade;
- - q = cin - cxfade;
- -
- - // copy up to crossfade region
- - for( i = 0; i < q; i++ )
- - v[i] = w[i];
- -
- - // crossfade region
- - j = p;
- -
- - for( i = q; i <= D; i++ )
- - v[i] = xfade( w[j++], w[i], cxfade, i-q ); // fade out p..n, fade in q..D
- -
- - // duplicate region
- - j = D+1;
- -
- - for( i = m; i <= D; i++ )
- - v[j++] = w[i];
- -
- -}
- -
- -// cut ccut samples from end of input buffer, crossfade end of cut section
- -// with end of remaining section
- -
- -// w - pointer to start of input buffer samples
- -// v - pointer to start of output buffer samples
- -// cin - # of input buffer samples
- -// cout = # of output buffer samples
- -// cxfade = # of crossfade samples
- -// ccut = # of samples in cut segment
- -void TimeCompress( int *w, int *v, int cin, int cout, int cxfade, int ccut )
- -{
- - int i, j;
- - int m;
- - int p;
- - int q;
- - int D;
- -
- - // input buffer
- - // xfade source
- - // [0.....................n][m..[p.......D]
- -
- - // xfade region cut
- - // [0...........][q.......n][m...........D]
- -
- - // output buffer
- - // xfade to source
- - // [0...........][p.......D]
- -
- - // D - index of last sample in input buffer
- - // m - index of 1st sample in cut region
- - // p - index of 1st sample of crossfade source
- - // q - index of 1st sample in crossfade region
- -
- - D = cin - 1;
- - m = cin - ccut;
- - p = cin - cxfade;
- - q = m - cxfade;
- -
- - // copy up to crossfade region
- -
- - for( i = 0; i < q; i++ )
- - v[i] = w[i];
- -
- - // crossfade region
- - j = p;
- -
- - for( i = q; i < m; i++ )
- - v[i] = xfade( w[j++], w[i], cxfade, i-q ); // fade out p..n, fade in q..D
- -
- - // skip rest of input buffer
- -}
- -
- -// get next sample
- -
- -// put input sample into input (delay) buffer
- -// get output sample from output buffer, step by fstep %
- -// output buffer is time expanded or compressed version of previous input buffer
- -_inline int PTC_GetNext( ptc_t *pptc, int x )
- -{
- - int iout, xout;
- - qboolean fhitend = false;
- -
- - // write x into input buffer
- - ASSERT( pptc->iin < pptc->cin );
- -
- - pptc->pin[pptc->iin] = x;
- -
- - pptc->iin++;
- -
- - // check for end of input buffer
- - if( pptc->iin >= pptc->cin )
- - fhitend = true;
- -
- - // read sample from output buffer, resampling at fstep
- - iout = POS_ONE_GetNext( &pptc->psn );
- - ASSERT( iout < pptc->cout );
- - xout = pptc->pout[iout];
- -
- - if( fhitend )
- - {
- - // if hit end of input buffer (ie: input buffer is full)
- - // reset input buffer pointer
- - // reset output buffer pointer
- - // rebuild entire output buffer (TimeCompress/TimeExpand)
- -
- - pptc->iin = 0;
- -
- - POS_ONE_Init( &pptc->psn, pptc->cout, pptc->fstep );
- -
- - if( pptc->fdup ) TimeExpand ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->cduplicate );
- - else TimeCompress ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->ccut );
- - }
- -
- - return xout;
- -}
- -
- -// batch version for performance
- -_inline void PTC_GetNextN( ptc_t *pptc, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = PTC_GetNext( pptc, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = PTC_GetNext( pptc, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = PTC_GetNext( pptc, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -// change time compression to new value
- -// fstep is new value
- -// ramptime is how long change takes in seconds (ramps smoothly), 0 for no ramp
- -
- -void PTC_ChangeVal( ptc_t *pptc, float fstep, float ramptime )
- -{
- -// UNDONE: ignored
- -// UNDONE: just realloc time compressor with new fstep
- -}
- -
- -// uses pitch:
- -// 1.0 = playback normal rate
- -// 0.5 = cut 50% of sound (2x playback)
- -// 1.5 = add 50% sound (0.5x playback)
- -
- -typedef enum
- -{
- - // parameter order
- - ptc_ipitch,
- - ptc_itimeslice,
- - ptc_ixfade,
- - ptc_cparam // # of params
- -} ptc_e;
- -
- -// diffusor parameter ranges
- -prm_rng_t ptc_rng[] =
- -{
- -{ ptc_cparam, 0, 0 }, // first entry is # of parameters
- -{ ptc_ipitch, 0.1, 4.0 }, // 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
- -{ ptc_itimeslice, 20.0, 300.0 }, // in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
- -{ ptc_ixfade, 1.0, 200.0 }, // in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
- -};
- -
- -ptc_t *PTC_Params( prc_t *pprc )
- -{
- - ptc_t *pptc;
- -
- - float pitch = pprc->prm[ptc_ipitch];
- - float timeslice = pprc->prm[ptc_itimeslice];
- - float txfade = pprc->prm[ptc_ixfade];
- -
- - pptc = PTC_Alloc( timeslice, txfade, pitch );
- -
- - return pptc;
- -}
- -
- -_inline void *PTC_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, ptc_rng );
- - return (void *)PTC_Params((prc_t *)p);
- -}
- -
- -// change to new pitch value
- -// v is +/- 0-1.0
- -// v changes current pitch up/down by +/- v%
- -void PTC_Mod( ptc_t *pptc, float v )
- -{
- - float fstep;
- - float fstepnew;
- -
- - fstep = pptc->fstep;
- - fstepnew = fstep * (1.0 + v);
- -
- - PTC_ChangeVal( pptc, fstepnew, 0.01 );
- -}
- -
- -
- -////////////////////
- -// ADSR envelope
- -////////////////////
- -
- -#define CENVS 64 // max # of envelopes active
- -#define CENVRMPS 4 // A, D, S, R
- -
- -#define ENV_LIN 0 // linear a,d,s,r
- -#define ENV_EXP 1 // exponential a,d,s,r
- -#define ENV_MAX ENV_EXP
- -
- -#define ENV_BITS 14 // bits of resolution of ramp
- -
- -typedef struct
- -{
- - qboolean fused;
- - qboolean fhitend; // true if done
- - int ienv; // current ramp
- - rmp_t rmps[CENVRMPS]; // ramps
- -} env_t;
- -
- -env_t envs[CENVS];
- -
- -void ENV_Init( env_t *penv ) { if( penv ) memset( penv, 0, sizeof( env_t )); };
- -void ENV_Free( env_t *penv ) { if( penv ) memset( penv, 0, sizeof( env_t )); };
- -void ENV_InitAll() { int i; for( i = 0; i < CENVS; i++ ) ENV_Init( &envs[i] ); };
- -void ENV_FreeAll() { int i; for( i = 0; i < CENVS; i++ ) ENV_Free( &envs[i] ); };
- -
- -
- -// allocate ADSR envelope
- -// all times are in seconds
- -// amp1 - attack amplitude multiplier 0-1.0
- -// amp2 - sustain amplitude multiplier 0-1.0
- -// amp3 - end of sustain amplitude multiplier 0-1.0
- -env_t *ENV_Alloc( int type, float famp1, float famp2, float famp3, float attack, float decay, float sustain, float release )
- -{
- - int i;
- - env_t *penv;
- -
- - for( i = 0; i < CENVS; i++ )
- - {
- - if( !envs[i].fused )
- - {
- - int amp1 = famp1 * (1 << ENV_BITS); // ramp resolution
- - int amp2 = famp2 * (1 << ENV_BITS);
- - int amp3 = famp3 * (1 << ENV_BITS);
- -
- - penv = &envs[i];
- -
- - ENV_Init( penv );
- -
- - // UNDONE: ignoring type = ENV_EXP - use oneshot LFOS instead with sawtooth/exponential
- -
- - // set up ramps
- - RMP_Init( &penv->rmps[0], attack, 0, amp1 );
- - RMP_Init( &penv->rmps[1], decay, amp1, amp2 );
- - RMP_Init( &penv->rmps[2], sustain, amp2, amp3 );
- - RMP_Init( &penv->rmps[3], release, amp3, 0 );
- -
- - penv->ienv = 0;
- - penv->fused = true;
- - penv->fhitend = false;
- -
- - return penv;
- - }
- - }
- -
- - MsgDev( D_WARN, "DSP: failed to allocate envelope.\n" );
- - return NULL;
- -}
- -
- -_inline int ENV_GetNext( env_t *penv, int x )
- -{
- - if( !penv->fhitend )
- - {
- - int i, y;
- -
- - i = penv->ienv;
- - y = RMP_GetNext( &penv->rmps[i] );
- -
- - // check for next ramp
- - if( penv->rmps[i].fhitend )
- - i++;
- -
- - penv->ienv = i;
- -
- - // check for end of all ramps
- - if( i > 3 ) penv->fhitend = true;
- -
- - // multiply input signal by ramp
- - return (x * y) >> ENV_BITS;
- - }
- - return 0;
- -}
- -
- -// batch version for performance
- -
- -_inline void ENV_GetNextN( env_t *penv, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = ENV_GetNext( penv, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = ENV_GetNext( penv, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = ENV_GetNext( penv, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -// uses lfowav, amp1, amp2, amp3, attack, decay, sustain, release
- -// lfowav is type, currently ignored - ie: LFO_LIN_IN, LFO_LOG_IN
- -
- -// parameter order
- -typedef enum
- -{
- - env_itype,
- - env_iamp1,
- - env_iamp2,
- - env_iamp3,
- - env_iattack,
- - env_idecay,
- - env_isustain,
- - env_irelease,
- - env_cparam // # of params
- -
- -} env_e;
- -
- -// parameter ranges
- -prm_rng_t env_rng[] =
- -{
- -{ env_cparam, 0, 0 }, // first entry is # of parameters
- -{ env_itype, 0.0, ENV_MAX }, // ENV_LINEAR, ENV_LOG - currently ignored
- -{ env_iamp1, 0.0, 1.0 }, // attack peak amplitude 0-1.0
- -{ env_iamp2, 0.0, 1.0 }, // decay target amplitued 0-1.0
- -{ env_iamp3, 0.0, 1.0 }, // sustain target amplitude 0-1.0
- -{ env_iattack, 0.0, 20000.0 }, // attack time in milliseconds
- -{ env_idecay, 0.0, 20000.0 }, // envelope decay time in milliseconds
- -{ env_isustain, 0.0, 20000.0 }, // sustain time in milliseconds
- -{ env_irelease, 0.0, 20000.0 }, // release time in milliseconds
- -};
- -
- -env_t *ENV_Params( prc_t *pprc )
- -{
- - env_t *penv;
- -
- - float type = pprc->prm[env_itype];
- - float amp1 = pprc->prm[env_iamp1];
- - float amp2 = pprc->prm[env_iamp2];
- - float amp3 = pprc->prm[env_iamp3];
- - float attack = pprc->prm[env_iattack] / 1000.0f;
- - float decay = pprc->prm[env_idecay] / 1000.0f;
- - float sustain = pprc->prm[env_isustain] / 1000.0f;
- - float release = pprc->prm[env_irelease] / 1000.0f;
- -
- - penv = ENV_Alloc( type, amp1, amp2, amp3, attack, decay, sustain, release );
- - return penv;
- -}
- -
- -_inline void *ENV_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, env_rng );
- - return (void *)ENV_Params((prc_t *)p);
- -}
- -
- -_inline void ENV_Mod ( void *p, float v )
- -{
- -}
- -
- -////////////////////
- -// envelope follower
- -////////////////////
- -#define CEFOS 64 // max # of envelope followers active
- -
- -#define CEFOBITS 6 // size 2^6 = 64
- -#define CEFOWINDOW (1 << (CEFOBITS)) // size of sample window
- -
- -typedef struct
- -{
- - qboolean fused;
- - int avg; // accumulating average over sample window
- - int cavg; // count down
- - int xout; // current output value
- -
- -} efo_t;
- -
- -efo_t efos[CEFOS];
- -
- -void EFO_Init( efo_t *pefo ) { if( pefo ) memset( pefo, 0, sizeof( efo_t )); };
- -void EFO_Free( efo_t *pefo ) { if( pefo ) memset( pefo, 0, sizeof( efo_t )); };
- -void EFO_InitAll() { int i; for( i = 0; i < CEFOS; i++ ) EFO_Init( &efos[i] ); };
- -void EFO_FreeAll() { int i; for( i = 0; i < CEFOS; i++ ) EFO_Free( &efos[i] ); };
- -
- -// allocate enveloper follower
- -efo_t *EFO_Alloc( void )
- -{
- - int i;
- - efo_t *pefo;
- -
- - for( i = 0; i < CEFOS; i++ )
- - {
- - if( !efos[i].fused )
- - {
- - pefo = &efos[i];
- -
- - EFO_Init( pefo );
- -
- - pefo->xout = 0;
- - pefo->cavg = CEFOWINDOW;
- - pefo->fused = true;
- -
- - return pefo;
- - }
- - }
- -
- - MsgDev( D_WARN, "DSP: failed to allocate envelope follower.\n" );
- - return NULL;
- -}
- -
- -
- -_inline int EFO_GetNext( efo_t *pefo, int x )
- -{
- - int xa = ABS( x ); // rectify input wav
- -
- - // get running sum / 2
- - pefo->avg += xa >> 1; // divide by 2 to prevent overflow
- -
- - pefo->cavg--;
- -
- - if( !pefo->cavg )
- - {
- - // new output value - end of window
- -
- - // get average over window
- - pefo->xout = pefo->avg >> (CEFOBITS - 1); // divide by window size / 2
- - pefo->cavg = CEFOWINDOW;
- - pefo->avg = 0;
- - }
- -
- - return pefo->xout;
- -}
- -
- -// batch version for performance
- -_inline void EFO_GetNextN( efo_t *pefo, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = EFO_GetNext( pefo, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = EFO_GetNext( pefo, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = EFO_GetNext( pefo, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -
- -efo_t * EFO_Params( prc_t *pprc )
- -{
- - return EFO_Alloc();
- -}
- -
- -_inline void *EFO_VParams( void *p )
- -{
- - // PRC_CheckParams(( prc_t *)p, efo_rng ); - efo has no params
- - return (void *)EFO_Params((prc_t *)p );
- -}
- -
- -_inline void EFO_Mod( void *p, float v )
- -{
- -}
- -
- -//////////////
- -// mod delay
- -//////////////
- -
- -// modulate delay time anywhere from 0..D using MDY_ChangeVal. no output glitches (uses RMP)
- -
- -#define CMDYS 64 // max # of mod delays active (steals from delays)
- -
- -typedef struct
- -{
- - qboolean fused;
- - qboolean fchanging; // true if modulating to new delay value
- - dly_t *pdly; // delay
- - int Dcur; // current delay value
- - float ramptime; // ramp 'glide' time - time in seconds to change between values
- - int mtime; // time in samples between delay changes. 0 implies no self-modulating
- - int mtimecur; // current time in samples until next delay change
- - float depth; // modulate delay from D to D - (D*depth) depth 0-1.0
- - int xprev; // previous delay output, used to smooth transitions between delays
- - rmp_t rmp; // ramp
- -} mdy_t;
- -
- -mdy_t mdys[CMDYS];
- -
- -void MDY_Init( mdy_t *pmdy ) { if( pmdy ) memset( pmdy, 0, sizeof( mdy_t )); };
- -void MDY_Free( mdy_t *pmdy ) { if( pmdy ) { DLY_Free( pmdy->pdly ); memset( pmdy, 0, sizeof( mdy_t )); } };
- -void MDY_InitAll() { int i; for( i = 0; i < CMDYS; i++ ) MDY_Init( &mdys[i] ); };
- -void MDY_FreeAll() { int i; for( i = 0; i < CMDYS; i++ ) MDY_Free( &mdys[i] ); };
- -
- -
- -// allocate mod delay, given previously allocated dly
- -// ramptime is time in seconds for delay to change from dcur to dnew
- -// modtime is time in seconds between modulations. 0 if no self-modulation
- -// depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
- -mdy_t *MDY_Alloc( dly_t *pdly, float ramptime, float modtime, float depth )
- -{
- - int i;
- - mdy_t *pmdy;
- -
- - if( !pdly )
- - return NULL;
- -
- - for( i = 0; i < CMDYS; i++ )
- - {
- - if( !mdys[i].fused )
- - {
- - pmdy = &mdys[i];
- -
- - MDY_Init( pmdy );
- -
- - pmdy->pdly = pdly;
- -
- - if( !pmdy->pdly )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate delay for mod delay.\n" );
- - return NULL;
- - }
- -
- - pmdy->Dcur = pdly->D0;
- - pmdy->fused = true;
- - pmdy->ramptime = ramptime;
- - pmdy->mtime = SEC_TO_SAMPS( modtime );
- - pmdy->mtimecur = pmdy->mtime;
- - pmdy->depth = depth;
- -
- - return pmdy;
- - }
- - }
- -
- - MsgDev( D_WARN, "DSP: failed to allocate mod delay.\n" );
- - return NULL;
- -}
- -
- -// change to new delay tap value t samples, ramp linearly over ramptime seconds
- -void MDY_ChangeVal( mdy_t *pmdy, int t )
- -{
- - // if D > original delay value, cap at original value
- -
- - t = min( pmdy->pdly->D0, t );
- - pmdy->fchanging = true;
- -
- - RMP_Init( &pmdy->rmp, pmdy->ramptime, pmdy->Dcur, t );
- -}
- -
- -// get next value from modulating delay
- -int MDY_GetNext( mdy_t *pmdy, int x )
- -{
- - int xout;
- - int xcur;
- -
- - // get current delay output
- - xcur = DLY_GetNext( pmdy->pdly, x );
- -
- - // return right away if not modulating (not changing and not self modulating)
- - if( !pmdy->fchanging && !pmdy->mtime )
- - {
- - pmdy->xprev = xcur;
- - return xcur;
- - }
- -
- - xout = xcur;
- -
- - // if currently changing to new delay target, get next delay value
- - if( pmdy->fchanging )
- - {
- - // get next ramp value, test for done
- - int r = RMP_GetNext( &pmdy->rmp );
- -
- - if( RMP_HitEnd( &pmdy->rmp ))
- - pmdy->fchanging = false;
- -
- - // if new delay different from current delay, change delay
- - if( r != pmdy->Dcur )
- - {
- - // ramp never changes by more than + or - 1
- -
- - // change delay tap value to r
- - DLY_ChangeVal( pmdy->pdly, r );
- -
- - pmdy->Dcur = r;
- -
- - // filter delay output within transitions.
- - // note: xprev = xcur = 0 if changing delay on 1st sample
- - xout = ( xcur + pmdy->xprev ) >> 1;
- - }
- - }
- -
- - // if self-modulating and timer has expired, get next change
- - if( pmdy->mtime && !pmdy->mtimecur-- )
- - {
- - int D0 = pmdy->pdly->D0;
- - int Dnew;
- - float D1;
- -
- - pmdy->mtimecur = pmdy->mtime;
- -
- - // modulate between 0 and 100% of d0
- - D1 = (float)D0 * (1.0 - pmdy->depth);
- - Dnew = Com_RandomLong( (int)D1, D0 );
- -
- - MDY_ChangeVal( pmdy, Dnew );
- - }
- -
- - pmdy->xprev = xcur;
- -
- - return xout;
- -}
- -
- -// batch version for performance
- -_inline void MDY_GetNextN( mdy_t *pmdy, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = MDY_GetNext( pmdy, pb->left );
- - pb++;
- - }
- - return;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = MDY_GetNext( pmdy, pb->right );
- - pb++;
- - }
- - return;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = MDY_GetNext( pmdy, pb->left );
- - pb++;
- - }
- - return;
- - }
- -}
- -
- -// parameter order
- -typedef enum
- -{
- - mdy_idtype, // NOTE: first 8 params must match params in dly_e
- - mdy_idelay,
- - mdy_ifeedback,
- - mdy_igain,
- - mdy_iftype,
- - mdy_icutoff,
- - mdy_iqwidth,
- - mdy_iquality,
- - mdy_imodrate,
- - mdy_imoddepth,
- - mdy_imodglide,
- - mdy_cparam
- -} mdy_e;
- -
- -
- -// parameter ranges
- -prm_rng_t mdy_rng[] =
- -{
- -{ mdy_cparam, 0, 0 }, // first entry is # of parameters
- -
- -// delay params
- -{ mdy_idtype, 0, DLY_MAX }, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
- -{ mdy_idelay, 0.0, 1000.0 }, // delay in milliseconds
- -{ mdy_ifeedback, 0.0, 0.99 }, // feedback 0-1.0
- -{ mdy_igain, 0.0, 1.0 }, // final gain of output stage, 0-1.0
- -
- -// filter params if mdy type DLY_LOWPASS
- -{ mdy_iftype, 0, FTR_MAX },
- -{ mdy_icutoff, 10.0, 22050.0 },
- -{ mdy_iqwidth, 100.0, 11025.0 },
- -{ mdy_iquality, 0, QUA_MAX },
- -{ mdy_imodrate, 0.01, 200.0 }, // frequency at which delay values change to new random value. 0 is no self-modulation
- -{ mdy_imoddepth, 0.0, 1.0 }, // how much delay changes (decreases) from current value (0-1.0)
- -{ mdy_imodglide, 0.01, 100.0 }, // glide time between dcur and dnew in milliseconds
- -};
- -
- -// convert user parameters to internal parameters, allocate and return
- -mdy_t *MDY_Params( prc_t *pprc )
- -{
- - mdy_t *pmdy;
- - dly_t *pdly;
- -
- - float ramptime = pprc->prm[mdy_imodglide] / 1000.0; // get ramp time in seconds
- - float modtime = 1.0 / pprc->prm[mdy_imodrate]; // time between modulations in seconds
- - float depth = pprc->prm[mdy_imoddepth]; // depth of modulations 0-1.0
- -
- - // alloc plain, allpass or lowpass delay
- - pdly = DLY_Params( pprc );
- - if( !pdly ) return NULL;
- -
- - pmdy = MDY_Alloc( pdly, ramptime, modtime, depth );
- -
- - return pmdy;
- -}
- -
- -_inline void * MDY_VParams( void *p )
- -{
- - PRC_CheckParams(( prc_t *)p, mdy_rng );
- - return (void *)MDY_Params ((prc_t *)p );
- -}
- -
- -// v is +/- 0-1.0
- -// change current delay value 0..D
- -void MDY_Mod( mdy_t *pmdy, float v )
- -{
- - int D = pmdy->Dcur;
- - float v2 = -(v + 1.0)/2.0; // v2 varies -1.0-0.0
- -
- - // D varies 0..D
- - D = D + (int)((float)D * v2);
- -
- - // change delay
- - MDY_ChangeVal( pmdy, D );
- -}
- -
- -
- -///////////////////////////////////////////
- -// Chorus - lfo modulated delay
- -///////////////////////////////////////////
- -
- -
- -#define CCRSS 64 // max number chorus' active
- -
- -typedef struct
- -{
- - qboolean fused;
- - mdy_t *pmdy; // modulatable delay
- - lfo_t *plfo; // modulating lfo
- - int lfoprev; // previous modulator value from lfo
- - int mix; // mix of clean & chorus signal - 0..PMAX
- -} crs_t;
- -
- -crs_t crss[CCRSS];
- -
- -void CRS_Init( crs_t *pcrs ) { if( pcrs ) memset( pcrs, 0, sizeof( crs_t )); };
- -void CRS_Free( crs_t *pcrs )
- -{
- - if( pcrs )
- - {
- - MDY_Free( pcrs->pmdy );
- - LFO_Free( pcrs->plfo );
- - memset( pcrs, 0, sizeof( crs_t ));
- - }
- -}
- -
- -void CRS_InitAll() { int i; for( i = 0; i < CCRSS; i++ ) CRS_Init( &crss[i] ); }
- -void CRS_FreeAll() { int i; for( i = 0; i < CCRSS; i++ ) CRS_Free( &crss[i] ); }
- -
- -// fstep is base pitch shift, ie: floating point step value, where 1.0 = +1 octave, 0.5 = -1 octave
- -// lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
- -// fHz is modulation frequency in Hz
- -// depth is modulation depth, 0-1.0
- -// mix is mix of chorus and clean signal
- -
- -#define CRS_DELAYMAX 100 // max milliseconds of sweepable delay
- -#define CRS_RAMPTIME 5 // milliseconds to ramp between new delay values
- -
- -crs_t * CRS_Alloc( int lfotype, float fHz, float fdepth, float mix )
- -{
- - int i, D;
- - crs_t *pcrs;
- - dly_t *pdly;
- - mdy_t *pmdy;
- - lfo_t *plfo;
- - float ramptime;
- -
- - // find free chorus slot
- - for( i = 0; i < CCRSS; i++ )
- - {
- - if( !crss[i].fused )
- - break;
- - }
- -
- - if( i == CCRSS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate chorus.\n" );
- - return NULL;
- - }
- -
- - pcrs = &crss[i];
- - CRS_Init( pcrs );
- -
- - D = fdepth * MSEC_TO_SAMPS( CRS_DELAYMAX ); // sweep from 0 - n milliseconds
- -
- - ramptime = (float)CRS_RAMPTIME / 1000.0f; // # milliseconds to ramp between new values
- -
- - pdly = DLY_Alloc( D, 0, 1, DLY_LINEAR );
- - pmdy = MDY_Alloc( pdly, ramptime, 0.0, 0.0 );
- - plfo = LFO_Alloc( lfotype, fHz, false );
- -
- - if( !plfo || !pmdy )
- - {
- - LFO_Free( plfo );
- - MDY_Free( pmdy );
- - MsgDev( D_WARN, "DSP: failed to allocate lfo or mdy for chorus.\n" );
- - return NULL;
- - }
- -
- - pcrs->pmdy = pmdy;
- - pcrs->plfo = plfo;
- - pcrs->mix = (int)( PMAX * mix );
- - pcrs->fused = true;
- -
- - return pcrs;
- -}
- -
- -// return next chorused sample (modulated delay) mixed with input sample
- -_inline int CRS_GetNext( crs_t *pcrs, int x )
- -{
- - int l, y;
- -
- - // get current mod delay value
- - y = MDY_GetNext( pcrs->pmdy, x );
- -
- - // get next lfo value for modulation
- - // note: lfo must return 0 as first value
- - l = LFO_GetNext( pcrs->plfo, x );
- -
- - // if modulator has changed, change mdy
- - if( l != pcrs->lfoprev )
- - {
- - // calculate new tap (starts at D)
- - int D = pcrs->pmdy->pdly->D0;
- - int tap;
- -
- - // lfo should always output values 0 <= l <= LFOMAX
- -
- - if( l < 0 ) l = 0;
- -
- - tap = D - ((l * D) >> LFOBITS);
- - MDY_ChangeVal ( pcrs->pmdy, tap );
- - pcrs->lfoprev = l;
- - }
- -
- - return ((y * pcrs->mix) >> PBITS) + x;
- -}
- -
- -// batch version for performance
- -_inline void CRS_GetNextN( crs_t *pcrs, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = CRS_GetNext( pcrs, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = CRS_GetNext( pcrs, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = CRS_GetNext( pcrs, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -// parameter order
- -typedef enum
- -{
- - crs_ilfotype,
- - crs_irate,
- - crs_idepth,
- - crs_imix,
- - crs_cparam
- -} crs_e;
- -
- -
- -// parameter ranges
- -prm_rng_t crs_rng[] =
- -{
- -{ crs_cparam, 0, 0 }, // first entry is # of parameters
- -{ crs_ilfotype, 0, LFO_MAX }, // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
- -{ crs_irate, 0.0, 1000.0 }, // rate is modulation frequency in Hz
- -{ crs_idepth, 0.0, 1.0 }, // depth is modulation depth, 0-1.0
- -{ crs_imix, 0.0, 1.0 }, // mix is mix of chorus and clean signal
- -};
- -
- -// uses pitch, lfowav, rate, depth
- -crs_t *CRS_Params( prc_t *pprc )
- -{
- - crs_t *pcrs;
- -
- - pcrs = CRS_Alloc( pprc->prm[crs_ilfotype], pprc->prm[crs_irate], pprc->prm[crs_idepth], pprc->prm[crs_imix] );
- -
- - return pcrs;
- -}
- -
- -_inline void *CRS_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, crs_rng );
- - return (void *)CRS_Params((prc_t *)p );
- -}
- -
- -_inline void CRS_Mod( void *p, float v )
- -{
- -}
- -
- -////////////////////////////////////////////////////
- -// amplifier - modulatable gain, distortion
- -////////////////////////////////////////////////////
- -
- -#define CAMPS 64 // max number amps active
- -#define AMPSLEW 10 // milliseconds of slew time between gain changes
- -
- -typedef struct
- -{
- - qboolean fused;
- - float gain; // amplification 0-6.0
- - float vthresh; // clip distortion threshold 0-1.0
- - float distmix; // 0-1.0 mix of distortion with clean
- - float vfeed; // 0-1.0 feedback with distortion;
- - float gaintarget; // new gain
- - float gaindif; // incrementer
- -} amp_t;
- -
- -amp_t amps[CAMPS];
- -
- -void AMP_Init( amp_t *pamp ) { if( pamp ) memset( pamp, 0, sizeof( amp_t )); }
- -void AMP_Free( amp_t *pamp ) { if( pamp ) memset( pamp, 0, sizeof( amp_t )); }
- -void AMP_InitAll() { int i; for( i = 0; i < CAMPS; i++ ) AMP_Init( &s[i] ); }
- -void AMP_FreeAll() { int i; for( i = 0; i < CAMPS; i++ ) AMP_Free( &s[i] ); }
- -
- -amp_t *AMP_Alloc( float gain, float vthresh, float distmix, float vfeed )
- -{
- - int i;
- - amp_t *pamp;
- -
- - // find free amp slot
- - for( i = 0; i < CAMPS; i++ )
- - {
- - if ( !amps[i].fused )
- - break;
- - }
- -
- - if( i == CAMPS )
- - {
- - MsgDev( D_WARN, "DSP: failed to allocate amp.\n" );
- - return NULL;
- - }
- -
- - pamp = &s[i];
- -
- - AMP_Init ( pamp );
- -
- - pamp->gain = gain;
- - pamp->vthresh = vthresh;
- - pamp->distmix = distmix;
- - pamp->vfeed = vfeed;
- -
- - return pamp;
- -}
- -
- -// return next amplified sample
- -_inline int AMP_GetNext( amp_t *pamp, int x )
- -{
- - float y = (float)x;
- - float yin;
- - float gain = pamp->gain;
- -
- - yin = y;
- -
- - // slew between gains
- - if( gain != pamp->gaintarget )
- - {
- - float gaintarget = pamp->gaintarget;
- - float gaindif = pamp->gaindif;
- -
- - if( gain > gaintarget )
- - {
- - gain -= gaindif;
- - if( gain <= gaintarget )
- - pamp->gaintarget = gain;
- - }
- - else
- - {
- - gain += gaindif;
- - if( gain >= gaintarget )
- - pamp->gaintarget = gain;
- - }
- -
- - pamp->gain = gain;
- - }
- -
- - // if distortion is on, add distortion, feedback
- - if( pamp->vthresh < 1.0 )
- - {
- - float fclip = pamp->vthresh * 32767.0;
- -
- - if( pamp->vfeed > 0.0 )
- - {
- - // UNDONE: feedback
- - }
- -
- - // clip distort
- - y = ( y > fclip ? fclip : ( y < -fclip ? -fclip : y));
- -
- - // mix distorted with clean (1.0 = full distortion)
- - if( pamp->distmix > 0.0 )
- - y = y * pamp->distmix + yin * (1.0 - pamp->distmix);
- - }
- -
- - // amplify
- - y *= gain;
- -
- - return (int)y;
- -}
- -
- -// batch version for performance
- -_inline void AMP_GetNextN( amp_t *pamp, portable_samplepair_t *pbuffer, int SampleCount, int op )
- -{
- - int count = SampleCount;
- - portable_samplepair_t *pb = pbuffer;
- -
- - switch( op )
- - {
- - default:
- - case OP_LEFT:
- - while( count-- )
- - {
- - pb->left = AMP_GetNext( pamp, pb->left );
- - pb++;
- - }
- - break;
- - case OP_RIGHT:
- - while( count-- )
- - {
- - pb->right = AMP_GetNext( pamp, pb->right );
- - pb++;
- - }
- - break;
- - case OP_LEFT_DUPLICATE:
- - while( count-- )
- - {
- - pb->left = pb->right = AMP_GetNext( pamp, pb->left );
- - pb++;
- - }
- - break;
- - }
- -}
- -
- -_inline void AMP_Mod( amp_t *pamp, float v )
- -{
- - float vmod = bound( v, 0.0, 1.0 );
- - float samps = MSEC_TO_SAMPS( AMPSLEW ); // # samples to slew between amp values
- -
- - // ramp to new amplification value
- - pamp->gaintarget = pamp->gain * vmod;
- -
- - pamp->gaindif = fabs( pamp->gain - pamp->gaintarget ) / samps;
- -
- - if( pamp->gaindif == 0.0f )
- - pamp->gaindif = fabs( pamp->gain - pamp->gaintarget ) / 100;
- -}
- -
- -
- -// parameter order
- -typedef enum
- -{
- - amp_gain,
- - amp_vthresh,
- - amp_distmix,
- - amp_vfeed,
- - amp_cparam
- -} amp_e;
- -
- -
- -// parameter ranges
- -prm_rng_t amp_rng[] =
- -{
- -{ amp_cparam, 0, 0 }, // first entry is # of parameters
- -{ amp_gain, 0.0, 10.0 }, // amplification
- -{ amp_vthresh, 0.0, 1.0 }, // threshold for distortion (1.0 = no distortion)
- -{ amp_distmix, 0.0, 1.0 }, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
- -{ amp_vfeed, 0.0, 1.0 }, // distortion feedback
- -};
- -
- -amp_t * AMP_Params( prc_t *pprc )
- -{
- - amp_t *pamp;
- -
- - pamp = AMP_Alloc( pprc->prm[amp_gain], pprc->prm[amp_vthresh], pprc->prm[amp_distmix], pprc->prm[amp_vfeed] );
- -
- - return pamp;
- -}
- -
- -_inline void *AMP_VParams( void *p )
- -{
- - PRC_CheckParams((prc_t *)p, amp_rng );
- - return (void *)AMP_Params((prc_t *)p );
- -}
- -
- -
- -/////////////////
- -// NULL processor
- -/////////////////
- -typedef struct
- -{
- - int type;
- -} nul_t;
- -
- -nul_t nuls[] = { 0 };
- -
- -void NULL_Init( nul_t *pnul ) { }
- -void NULL_InitAll( ) { }
- -void NULL_Free( nul_t *pnul ) { }
- -void NULL_FreeAll( ) { }
- -nul_t *NULL_Alloc( ) { return &nuls[0]; }
- -
- -_inline int NULL_GetNext( void *p, int x ) { return x; }
- -_inline void NULL_GetNextN( nul_t *pnul, portable_samplepair_t *pbuffer, int SampleCount, int op ) { return; }
- -_inline void NULL_Mod( void *p, float v ) { return; }
- -_inline void * NULL_VParams( void *p ) { return (void *)(&nuls[0]); }
- -
- -//////////////////////////
- -// DSP processors presets
- -//////////////////////////
- -
- -// A dsp processor (prc) performs a single-sample function, such as pitch shift, delay, reverb, filter
- -
- -// note, this array must have CPRCPARMS entries
- -#define PRMZERO 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
- -#define PFNZERO NULL,NULL,NULL,NULL,NULL // zero pointers for pfnparam...pdata within prc_t
- -
- -//////////////////
- -// NULL processor
- -/////////////////
- -
- -#define PRC_NULL1 { PRC_NULL, PRMZERO, PFNZERO }
- -
- -#define PRC0 PRC_NULL1
- -
- -//////////////
- -// Amplifiers
- -//////////////
- -
- -// {amp_gain, 0.0, 10.0 }, // amplification
- -// {amp_vthresh, 0.0, 1.0 }, // threshold for distortion (1.0 = no distortion)
- -// {amp_distmix, 0.0, 1.0 }, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
- -// {amp_vfeed, 0.0, 1.0 }, // distortion feedback
- -
- -// prctype gain vthresh distmix vfeed
- -#define PRC_AMP1 {PRC_AMP, { 1.0, 1.0, 0.0, 0.0, }, PFNZERO } // modulatable unity gain amp
- -#define PRC_AMP2 {PRC_AMP, { 1.5, 0.75, 1.0, 0.0, }, PFNZERO } // amp with light distortion
- -#define PRC_AMP3 {PRC_AMP, { 2.0, 0.5, 1.0, 0.0, }, PFNZERO } // amp with medium distortion
- -#define PRC_AMP4 {PRC_AMP, { 4.0, 0.25, 1.0, 0.0, }, PFNZERO } // amp with heavy distortion
- -#define PRC_AMP5 {PRC_AMP, { 10.0, 0.10, 1.0, 0.0, }, PFNZERO } // mega distortion
- -
- -#define PRC_AMP6 {PRC_AMP, { 0.1, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
- -#define PRC_AMP7 {PRC_AMP, { 0.2, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
- -#define PRC_AMP8 {PRC_AMP, { 0.3, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
- -
- -#define PRC_AMP9 {PRC_AMP, { 0.75, 1.0, 0.0, 0.0, }, PFNZERO } // duck out
- -
- -
- -///////////
- -// Filters
- -///////////
- -
- -// ftype: filter type FLT_LP, FLT_HP, FLT_BP (UNDONE: FLT_BP currently ignored)
- -// cutoff: cutoff frequency in hz at -3db gain
- -// qwidth: width of BP, or steepness of LP/HP (ie: fcutoff + qwidth = -60db gain point)
- -// quality: QUA_LO, _MED, _HI 0,1,2
- -
- -// prctype ftype cutoff qwidth quality
- -#define PRC_FLT1 {PRC_FLT, { FLT_LP, 3000, 1000, QUA_MED, }, PFNZERO }
- -#define PRC_FLT2 {PRC_FLT, { FLT_LP, 2000, 2000, QUA_MED, }, PFNZERO } // lowpass for facing away
- -#define PRC_FLT3 {PRC_FLT, { FLT_LP, 1000, 1000, QUA_MED, }, PFNZERO }
- -#define PRC_FLT4 {PRC_FLT, { FLT_LP, 700, 700, QUA_LO, }, PFNZERO } // muffle filter
- -
- -#define PRC_FLT5 {PRC_FLT, { FLT_HP, 700, 200, QUA_MED, }, PFNZERO } // highpass (bandpass pair)
- -#define PRC_FLT6 {PRC_FLT, { FLT_HP, 2000, 1000, QUA_MED, }, PFNZERO } // lowpass (bandpass pair)
- -
- -//////////
- -// Delays
- -//////////
- -
- -// dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
- -// delay: delay in milliseconds
- -// feedback: feedback 0-1.0
- -// gain: final gain of output stage, 0-1.0
- -
- -// prctype dtype delay feedbk gain ftype cutoff qwidth quality
- -#define PRC_DLY1 {PRC_DLY, { DLY_PLAIN, 500.0, 0.5, 0.6, 0.0, 0.0, 0.0, 0.0, }, PFNZERO }
- -#define PRC_DLY2 {PRC_DLY, { DLY_LOWPASS, 45.0, 0.8, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO }
- -#define PRC_DLY3 {PRC_DLY, { DLY_LOWPASS, 300.0, 0.5, 0.6, FLT_LP, 2000, 2000, QUA_LO, }, PFNZERO } // outside S
- -#define PRC_DLY4 {PRC_DLY, { DLY_LOWPASS, 400.0, 0.5, 0.6, FLT_LP, 1500, 1500, QUA_LO, }, PFNZERO } // outside M
- -#define PRC_DLY5 {PRC_DLY, { DLY_LOWPASS, 750.0, 0.5, 0.6, FLT_LP, 1000, 1000, QUA_LO, }, PFNZERO } // outside L
- -#define PRC_DLY6 {PRC_DLY, { DLY_LOWPASS, 1000.0, 0.5, 0.6, FLT_LP, 800, 400, QUA_LO, }, PFNZERO } // outside VL
- -#define PRC_DLY7 {PRC_DLY, { DLY_LOWPASS, 45.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel S
- -#define PRC_DLY8 {PRC_DLY, { DLY_LOWPASS, 55.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel M
- -#define PRC_DLY9 {PRC_DLY, { DLY_LOWPASS, 65.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel L
- -#define PRC_DLY10 {PRC_DLY, { DLY_LOWPASS, 150.0, 0.5, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern S
- -#define PRC_DLY11 {PRC_DLY, { DLY_LOWPASS, 200.0, 0.7, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern M
- -#define PRC_DLY12 {PRC_DLY, { DLY_LOWPASS, 300.0, 0.7, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern L
- -#define PRC_DLY13 {PRC_DLY, { DLY_LINEAR, 300.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,}, PFNZERO } // straight delay 300ms
- -#define PRC_DLY14 {PRC_DLY, { DLY_LINEAR, 80.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,}, PFNZERO } // straight delay 80ms
- -
- -///////////
- -// Reverbs
- -///////////
- -
- -// size: 0-2.0 scales nominal delay parameters (starting at approx 20ms)
- -// density: 0-2.0 density of reverbs (room shape) - controls # of parallel or series delays
- -// decay: 0-2.0 scales feedback parameters (starting at approx 0.15)
- -
- -// prctype size density decay ftype cutoff qwidth fparallel
- -#define PRC_RVA1 {PRC_RVA, {2.0, 0.5, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO }
- -#define PRC_RVA2 {PRC_RVA, {1.0, 0.2, 1.5, 0, 0, 0, 0}, PFNZERO }
- -
- -#define PRC_RVA3 {PRC_RVA, {0.8, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic S
- -#define PRC_RVA4 {PRC_RVA, {1.0, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic M
- -#define PRC_RVA5 {PRC_RVA, {1.2, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic L
- -
- -#define PRC_RVA6 {PRC_RVA, {0.8, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel S
- -#define PRC_RVA7 {PRC_RVA, {0.9, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel M
- -#define PRC_RVA8 {PRC_RVA, {1.0, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel L
- -
- -#define PRC_RVA9 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern S
- -#define PRC_RVA10 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern M
- -#define PRC_RVA11 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern L
- -
- -#define PRC_RVA12 {PRC_RVA, {2.0, 0.5, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber S
- -#define PRC_RVA13 {PRC_RVA, {2.0, 1.0, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber M
- -#define PRC_RVA14 {PRC_RVA, {2.0, 2.0, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber L
- -
- -#define PRC_RVA15 {PRC_RVA, {1.7, 1.0, 1.2, FLT_LP, 5000, 4000, 1}, PFNZERO } // brite S
- -#define PRC_RVA16 {PRC_RVA, {1.75, 1.0, 1.5, FLT_LP, 5000, 4000, 1}, PFNZERO } // brite M
- -#define PRC_RVA17 {PRC_RVA, {1.85, 1.0, 2.0, FLT_LP, 6000, 4000, 1}, PFNZERO } // brite L
- -
- -#define PRC_RVA18 {PRC_RVA, {1.0, 1.5, 1.0, FLT_LP, 1000, 1000, 0}, PFNZERO } // generic
- -
- -#define PRC_RVA19 {PRC_RVA, {1.9, 1.8, 1.25, FLT_LP, 4000, 2000, 1}, PFNZERO } // concrete S
- -#define PRC_RVA20 {PRC_RVA, {2.0, 1.8, 1.5, FLT_LP, 3500, 2000, 1}, PFNZERO } // concrete M
- -#define PRC_RVA21 {PRC_RVA, {2.0, 1.8, 1.75, FLT_LP, 3000, 2000, 1}, PFNZERO } // concrete L
- -
- -#define PRC_RVA22 {PRC_RVA, {1.8, 1.5, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water S
- -#define PRC_RVA23 {PRC_RVA, {1.9, 1.75, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water M
- -#define PRC_RVA24 {PRC_RVA, {2.0, 2.0, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water L
- -
- -
- -/////////////
- -// Diffusors
- -/////////////
- -
- -// size: 0-1.0 scales all delays
- -// density: 0-1.0 controls # of series delays
- -// decay: 0-1.0 scales all feedback parameters
- -
- -// prctype size density decay
- -#define PRC_DFR1 {PRC_DFR, { 1.0, 0.5, 1.0 }, PFNZERO }
- -#define PRC_DFR2 {PRC_DFR, { 0.5, 0.3, 0.5 }, PFNZERO } // S
- -#define PRC_DFR3 {PRC_DFR, { 0.75, 0.5, 0.75 }, PFNZERO } // M
- -#define PRC_DFR4 {PRC_DFR, { 1.0, 0.5, 1.0 }, PFNZERO } // L
- -#define PRC_DFR5 {PRC_DFR, { 1.0, 1.0, 1.0 }, PFNZERO } // VL
- -
- -////////
- -// LFOs
- -////////
- -
- -// wavtype: lfo type to use (LFO_SIN, LFO_RND...)
- -// rate: modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
- -// foneshot: 1.0 if lfo is oneshot
- -
- -// prctype wavtype rate foneshot
- -#define PRC_LFO1 {PRC_LFO, { LFO_SIN, 440.0, 0.0, }, PFNZERO}
- -#define PRC_LFO2 {PRC_LFO, { LFO_SIN, 3000.0, 0.0, }, PFNZERO} // ear noise ring
- -#define PRC_LFO3 {PRC_LFO, { LFO_SIN, 4500.0, 0.0, }, PFNZERO} // ear noise ring
- -#define PRC_LFO4 {PRC_LFO, { LFO_SIN, 6000.0, 0.0, }, PFNZERO} // ear noise ring
- -#define PRC_LFO5 {PRC_LFO, { LFO_SAW, 100.0, 0.0, }, PFNZERO} // sub bass
- -
- -/////////
- -// Pitch
- -/////////
- -
- -// pitch: 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
- -// timeslice: in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
- -// xfade: in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
- -
- -// prctype pitch timeslice xfade
- -#define PRC_PTC1 {PRC_PTC, { 1.1, 100.0, 20.0 }, PFNZERO} // pitch up 10%
- -#define PRC_PTC2 {PRC_PTC, { 0.9, 100.0, 20.0 }, PFNZERO} // pitch down 10%
- -#define PRC_PTC3 {PRC_PTC, { 0.95, 100.0, 20.0 }, PFNZERO} // pitch down 5%
- -#define PRC_PTC4 {PRC_PTC, { 1.01, 100.0, 20.0 }, PFNZERO} // pitch up 1%
- -#define PRC_PTC5 {PRC_PTC, { 0.5, 100.0, 20.0 }, PFNZERO} // pitch down 50%
- -
- -/////////////
- -// Envelopes
- -/////////////
- -
- -// etype: ENV_LINEAR, ENV_LOG - currently ignored
- -// amp1: attack peak amplitude 0-1.0
- -// amp2: decay target amplitued 0-1.0
- -// amp3: sustain target amplitude 0-1.0
- -// attack time in milliseconds
- -// envelope decay time in milliseconds
- -// sustain time in milliseconds
- -// release time in milliseconds
- -
- -// prctype etype amp1 amp2 amp3 attack decay sustain release
- -#define PRC_ENV1 {PRC_ENV, {ENV_LIN, 1.0, 0.5, 0.4, 500, 500, 3000, 6000 }, PFNZERO}
- -
- -
- -//////////////
- -// Mod delays
- -//////////////
- -
- -// dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
- -// delay: delay in milliseconds
- -// feedback: feedback 0-1.0
- -// gain: final gain of output stage, 0-1.0
- -
- -// modrate: frequency at which delay values change to new random value. 0 is no self-modulation
- -// moddepth: how much delay changes (decreases) from current value (0-1.0)
- -// modglide: glide time between dcur and dnew in milliseconds
- -
- -// prctype dtype delay feedback gain ftype cutoff qwidth qual modrate moddepth modglide
- -#define PRC_MDY1 {PRC_MDY, {DLY_PLAIN, 500.0, 0.5, 1.0, 0, 0, 0, 0, 10, 0.8, 5,}, PFNZERO}
- -#define PRC_MDY2 {PRC_MDY, {DLY_PLAIN, 50.0, 0.8, 1.0, 0, 0, 0, 0, 5, 0.8, 5,}, PFNZERO}
- -
- -#define PRC_MDY3 {PRC_MDY, {DLY_PLAIN, 300.0, 0.2, 1.0, 0, 0, 0, 0, 30, 0.01, 15,}, PFNZERO } // weird 1
- -#define PRC_MDY4 {PRC_MDY, {DLY_PLAIN, 400.0, 0.3, 1.0, 0, 0, 0, 0, 0.25, 0.01, 15,}, PFNZERO } // weird 2
- -#define PRC_MDY5 {PRC_MDY, {DLY_PLAIN, 500.0, 0.4, 1.0, 0, 0, 0, 0, 0.25, 0.01, 15,}, PFNZERO } // weird 3
- -
- -//////////
- -// Chorus
- -//////////
- -
- -// lfowav: lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
- -// rate: rate is modulation frequency in Hz
- -// depth: depth is modulation depth, 0-1.0
- -// mix: mix is mix of chorus and clean signal
- -
- -// prctype lfowav rate depth mix
- -#define PRC_CRS1 {PRC_CRS, { LFO_SIN, 10, 1.0, 0.5, }, PFNZERO }
- -
- -/////////////////////
- -// Envelope follower
- -/////////////////////
- -
- -// takes no parameters
- -#define PRC_EFO1 {PRC_EFO, { PRMZERO }, PFNZERO }
- -
- -// init array of processors - first store pfnParam, pfnGetNext and pfnFree functions for type,
- -// then call the pfnParam function to initialize each processor
- -
- -// prcs - an array of prc structures, all with initialized params
- -// count - number of elements in the array
- -// returns false if failed to init one or more processors
- -
- -qboolean PRC_InitAll( prc_t *prcs, int count )
- -{
- - int i;
- - prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
- - prc_GetNext_t pfnGetNext; // get next function
- - prc_GetNextN_t pfnGetNextN; // get next function, batch version
- - prc_Free_t pfnFree;
- - prc_Mod_t pfnMod;
- - qboolean fok = true;
- -
- - // set up pointers to XXX_Free, XXX_GetNext and XXX_Params functions
- -
- - for( i = 0; i < count; i++ )
- - {
- - switch (prcs[i].type)
- - {
- - case PRC_DLY:
- - pfnFree = &(prc_Free_t)DLY_Free;
- - pfnGetNext = &(prc_GetNext_t)DLY_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)DLY_GetNextN;
- - pfnParam = &DLY_VParams;
- - pfnMod = &(prc_Mod_t)DLY_Mod;
- - break;
- - case PRC_RVA:
- - pfnFree = &(prc_Free_t)RVA_Free;
- - pfnGetNext = &(prc_GetNext_t)RVA_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)RVA_GetNextN;
- - pfnParam = &RVA_VParams;
- - pfnMod = &(prc_Mod_t)RVA_Mod;
- - break;
- - case PRC_FLT:
- - pfnFree = &(prc_Free_t)FLT_Free;
- - pfnGetNext = &(prc_GetNext_t)FLT_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)FLT_GetNextN;
- - pfnParam = &FLT_VParams;
- - pfnMod = &(prc_Mod_t)FLT_Mod;
- - break;
- - case PRC_CRS:
- - pfnFree = &(prc_Free_t)CRS_Free;
- - pfnGetNext = &(prc_GetNext_t)CRS_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)CRS_GetNextN;
- - pfnParam = &CRS_VParams;
- - pfnMod = &(prc_Mod_t)CRS_Mod;
- - break;
- - case PRC_PTC:
- - pfnFree = &(prc_Free_t)PTC_Free;
- - pfnGetNext = &(prc_GetNext_t)PTC_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)PTC_GetNextN;
- - pfnParam = &PTC_VParams;
- - pfnMod = &(prc_Mod_t)PTC_Mod;
- - break;
- - case PRC_ENV:
- - pfnFree = &(prc_Free_t)ENV_Free;
- - pfnGetNext = &(prc_GetNext_t)ENV_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)ENV_GetNextN;
- - pfnParam = &ENV_VParams;
- - pfnMod = &(prc_Mod_t)ENV_Mod;
- - break;
- - case PRC_LFO:
- - pfnFree = &(prc_Free_t)LFO_Free;
- - pfnGetNext = &(prc_GetNext_t)LFO_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)LFO_GetNextN;
- - pfnParam = &LFO_VParams;
- - pfnMod = &(prc_Mod_t)LFO_Mod;
- - break;
- - case PRC_EFO:
- - pfnFree = &(prc_Free_t)EFO_Free;
- - pfnGetNext = &(prc_GetNext_t)EFO_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)EFO_GetNextN;
- - pfnParam = &EFO_VParams;
- - pfnMod = &(prc_Mod_t)EFO_Mod;
- - break;
- - case PRC_MDY:
- - pfnFree = &(prc_Free_t)MDY_Free;
- - pfnGetNext = &(prc_GetNext_t)MDY_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)MDY_GetNextN;
- - pfnParam = &MDY_VParams;
- - pfnMod = &(prc_Mod_t)MDY_Mod;
- - break;
- - case PRC_DFR:
- - pfnFree = &(prc_Free_t)DFR_Free;
- - pfnGetNext = &(prc_GetNext_t)DFR_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)DFR_GetNextN;
- - pfnParam = &DFR_VParams;
- - pfnMod = &(prc_Mod_t)DFR_Mod;
- - break;
- - case PRC_AMP:
- - pfnFree = &(prc_Free_t)AMP_Free;
- - pfnGetNext = &(prc_GetNext_t)AMP_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)AMP_GetNextN;
- - pfnParam = &_VParams;
- - pfnMod = &(prc_Mod_t)AMP_Mod;
- - break;
- - case PRC_NULL:
- - default:
- - pfnFree = &(prc_Free_t)NULL_Free;
- - pfnGetNext = &(prc_GetNext_t)NULL_GetNext;
- - pfnGetNextN = &(prc_GetNextN_t)NULL_GetNextN;
- - pfnParam = &NULL_VParams;
- - pfnMod = &(prc_Mod_t)NULL_Mod;
- - break;
- - }
- -
- - // set up function pointers
- - prcs[i].pfnParam = pfnParam;
- - prcs[i].pfnGetNext = pfnGetNext;
- - prcs[i].pfnGetNextN = pfnGetNextN;
- - prcs[i].pfnFree = pfnFree;
- -
- - // call param function, store pdata for the processor type
- - prcs[i].pdata = pfnParam((void *)( &prcs[i] ));
- -
- - if( !prcs[i].pdata )
- - fok = false;
- - }
- - return fok;
- -}
- -
- -// free individual processor's data
- -void PRC_Free( prc_t *pprc )
- -{
- - if( pprc->pfnFree && pprc->pdata )
- - pprc->pfnFree( pprc->pdata );
- -}
- -
- -// free all processors for supplied array
- -// prcs - array of processors
- -// count - elements in array
- -void PRC_FreeAll( prc_t *prcs, int count )
- -{
- - int i;
- -
- - for( i = 0; i < count; i++ )
- - PRC_Free( &prcs[i] );
- -}
- -
- -// get next value for processor - (usually called directly by PSET_GetNext)
- -_inline int PRC_GetNext( prc_t *pprc, int x )
- -{
- - return pprc->pfnGetNext( pprc->pdata, x );
- -}
- -
- -// automatic parameter range limiting
- -// force parameters between specified min/max in param_rng
- -void PRC_CheckParams( prc_t *pprc, prm_rng_t *prng )
- -{
- - // first entry in param_rng is # of parameters
- - int cprm = prng[0].iprm;
- - int i;
- -
- - for( i = 0; i < cprm; i++)
- - {
- - // if parameter is 0.0f, always allow it (this is 'off' for most params)
- - if( pprc->prm[i] != 0.0f && ( pprc->prm[i] > prng[i+1].hi || pprc->prm[i] < prng[i+1].lo ))
- - {
- - MsgDev( D_WARN, "DSP: clamping out of range parameter.\n" );
- - pprc->prm[i] = bound( prng[i+1].lo, pprc->prm[i], prng[i+1].hi );
- - }
- - }
- -}
- -
- -// DSP presets
- -// A dsp preset comprises one or more dsp processors in linear, parallel or feedback configuration
- -// preset configurations
- -//
- -#define PSET_SIMPLE 0
- -
- -// x(n)--->P(0)--->y(n)
- -#define PSET_LINEAR 1
- -
- -// x(n)--->P(0)-->P(1)-->...P(m)--->y(n)
- -#define PSET_PARALLEL6 4
- -
- -// x(n)-P(0)-->P(1)-->P(2)-->(+)-P(5)->y(n)
- -// | ^
- -// | |
- -// -->P(3)-->P(4)---->
- -
- -
- -#define PSET_PARALLEL2 5
- -
- -// x(n)--->P(0)-->(+)-->y(n)
- -// ^
- -// |
- -// x(n)--->P(1)-----
- -
- -#define PSET_PARALLEL4 6
- -
- -// x(n)--->P(0)-->P(1)-->(+)-->y(n)
- -// ^
- -// |
- -// x(n)--->P(2)-->P(3)-----
- -
- -#define PSET_PARALLEL5 7
- -
- -// x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
- -// ^
- -// |
- -// x(n)--->P(2)-->P(3)-----
- -
- -#define PSET_FEEDBACK 8
- -
- -// x(n)-P(0)--(+)-->P(1)-->P(2)-->P(5)->y(n)
- -// ^ |
- -// | v
- -// -----P(4)<--P(3)--
- -
- -#define PSET_FEEDBACK3 9
- -
- -// x(n)---(+)-->P(0)--------->y(n)
- -// ^ |
- -// | v
- -// -----P(2)<--P(1)--
- -
- -#define PSET_FEEDBACK4 10
- -
- -// x(n)---(+)-->P(0)-------->P(3)--->y(n)
- -// ^ |
- -// | v
- -// ---P(2)<--P(1)--
- -
- -#define PSET_MOD 11
- -
- -//
- -// x(n)------>P(1)--P(2)--P(3)--->y(n)
- -// ^
- -// x(n)------>P(0)....:
- -
- -#define PSET_MOD2 12
- -
- -//
- -// x(n)-------P(1)-->y(n)
- -// ^
- -// x(n)-->P(0)..:
- -
- -
- -#define PSET_MOD3 13
- -
- -//
- -// x(n)-------P(1)-->P(2)-->y(n)
- -// ^
- -// x(n)-->P(0)..:
- -
- -
- -#define CPSETS 64 // max number of presets simultaneously active
- -
- -#define CPSET_PRCS 6 // max # of processors per dsp preset
- -#define CPSET_STATES (CPSET_PRCS+3) // # of internal states
- -
- -// NOTE: do not reorder members of pset_t - psettemplates relies on it!!!
- -typedef struct
- -{
- - int type; // preset configuration type
- - int cprcs; // number of processors for this preset
- - prc_t prcs[CPSET_PRCS]; // processor preset data
- - float gain; // preset gain 0.1->2.0
- - int w[CPSET_STATES]; // internal states
- - int fused;
- -} pset_t;
- -
- -pset_t psets[CPSETS];
- -
- -// array of dsp presets, each with up to 6 processors per preset
- -
- -#define WZERO {0,0,0,0,0,0,0,0,0}, 0
- -
- -pset_t psettemplates[] =
- -{
- -// presets 0-29 map to legacy room_type 0-29
- -
- -// type # proc P0 P1 P2 P3 P4 P5 GAIN
- -{PSET_SIMPLE, 1, { PRC_NULL1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // OFF 0
- -{PSET_SIMPLE, 1, { PRC_RVA18, PRC0, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // GENERIC 1 // general, low reflective, diffuse room
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA3, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_S 2 // highly reflective, parallel surfaces
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA4, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_M 3
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA5, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_L 4
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA6, PRC0, PRC0, PRC0, PRC0 },2.0, WZERO }, // TUNNEL_S 5 // resonant reflective, long surfaces
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA7, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // TUNNEL_M 6
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA8, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // TUNNEL_L 7
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA12,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CHAMBER_S 8 // diffuse, moderately reflective surfaces
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA13,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CHAMBER_M 9
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA14,PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // CHAMBER_L 10
- -{PSET_SIMPLE, 1, { PRC_RVA15, PRC0, PRC0, PRC0, PRC0, PRC0 },1.5, WZERO }, // BRITE_S 11 // diffuse, highly reflective
- -{PSET_SIMPLE, 1, { PRC_RVA16, PRC0, PRC0, PRC0, PRC0, PRC0 },1.6, WZERO }, // BRITE_M 12
- -{PSET_SIMPLE, 1, { PRC_RVA17, PRC0, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // BRITE_L 13
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA22,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER1 14 // underwater fx
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA23,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER2 15
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_RVA24,PRC_MDY5, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER3 16
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA19,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CONCRTE_S 17 // bare, reflective, parallel surfaces
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA20,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // CONCRTE_M 18
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA21,PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // CONCRTE_L 19
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_DLY3, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // OUTSIDE1 20 // echoing, moderately reflective
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_DLY4, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // OUTSIDE2 21 // echoing, dull
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_DLY5, PRC0, PRC0, PRC0 },1.6, WZERO }, // OUTSIDE3 22 // echoing, very dull
- -{PSET_LINEAR, 2, { PRC_DLY10, PRC_RVA10,PRC0, PRC0, PRC0, PRC0 },2.8, WZERO }, // CAVERN_S 23 // large, echoing area
- -{PSET_LINEAR, 2, { PRC_DLY11, PRC_RVA10,PRC0, PRC0, PRC0, PRC0 },2.6, WZERO }, // CAVERN_M 24
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DLY12,PRC_RVA11,PRC0, PRC0, PRC0 },2.6, WZERO }, // CAVERN_L 25
- -{PSET_LINEAR, 2, { PRC_DLY7, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },2.0, WZERO }, // WEIRDO1 26
- -{PSET_LINEAR, 2, { PRC_DLY8, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // WEIRDO2 27
- -{PSET_LINEAR, 2, { PRC_DLY9, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WEIRDO3 28
- -{PSET_LINEAR, 2, { PRC_DLY9, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WEIRDO4 29
- -
- -// presets 30-40 are new presets
- -{PSET_SIMPLE, 1, { PRC_FLT2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 30 lowpass - facing away
- -{PSET_LINEAR, 2, { PRC_FLT3, PRC_DLY14,PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 31 lowpass - facing away+80ms delay
- -//{PSET_PARALLEL2,2, { PRC_AMP6, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 32 explosion ring 1
- -//{PSET_PARALLEL2,2, { PRC_AMP7, PRC_LFO3, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 33 explosion ring 2
- -//{PSET_PARALLEL2,2, { PRC_AMP8, PRC_LFO4, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 34 explosion ring 3
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 32 explosion ring
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 33 explosion ring 2
- -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 34 explosion ring 3
- -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 35 shock muffle 1
- -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 36 shock muffle 2
- -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 37 shock muffle 3
- -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 35 shock muffle 1
- -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 36 shock muffle 2
- -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 37 shock muffle 3
- -{PSET_FEEDBACK3,3, { PRC_DLY13, PRC_PTC4, PRC_FLT2, PRC0, PRC0, PRC0 },0.25, WZERO }, // 38 fade pitchdown 1
- -{PSET_LINEAR, 3, { PRC_AMP3, PRC_FLT5, PRC_FLT6, PRC0, PRC0, PRC0 },2.0, WZERO }, // 39 distorted speaker 1
- -
- -// fade out fade in
- -
- -// presets 40+ are test presets
- -{PSET_SIMPLE, 1, { PRC_NULL1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 39 null
- -{PSET_SIMPLE, 1, { PRC_DLY1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 40 delay
- -{PSET_SIMPLE, 1, { PRC_RVA1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 41 parallel reverb
- -{PSET_SIMPLE, 1, { PRC_DFR1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 42 series diffusor
- -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA1, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 43 diff & reverb
- -{PSET_SIMPLE, 1, { PRC_DLY2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 44 lowpass delay
- -{PSET_SIMPLE, 1, { PRC_MDY2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 45 modulating delay
- -{PSET_SIMPLE, 1, { PRC_PTC1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 46 pitch shift
- -{PSET_SIMPLE, 1, { PRC_PTC2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 47 pitch shift
- -{PSET_SIMPLE, 1, { PRC_FLT1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 48 filter
- -{PSET_SIMPLE, 1, { PRC_CRS1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 49 chorus
- -{PSET_SIMPLE, 1, { PRC_ENV1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 50
- -{PSET_SIMPLE, 1, { PRC_LFO1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 51 lfo
- -{PSET_SIMPLE, 1, { PRC_EFO1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 52
- -{PSET_SIMPLE, 1, { PRC_MDY1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 53 modulating delay
- -{PSET_SIMPLE, 1, { PRC_FLT2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 54 lowpass - facing away
- -{PSET_PARALLEL2, 2, { PRC_PTC2, PRC_PTC1, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 55 ptc1/ptc2
- -{PSET_FEEDBACK, 6, { PRC_DLY1, PRC0, PRC0, PRC_PTC1, PRC_FLT1, PRC0 },1.0, WZERO }, // 56 dly/ptc1
- -{PSET_MOD, 4, { PRC_EFO1, PRC0, PRC_PTC1, PRC0, PRC0, PRC0 },1.0, WZERO }, // 57 efo mod ptc
- -{PSET_LINEAR, 3, { PRC_DLY1, PRC_RVA1, PRC_CRS1, PRC0, PRC0, PRC0 },1.0, WZERO } // 58 dly/rvb/crs
- -};
- -
- -
- -// number of presets currently defined above
- -
- -#define CPSETTEMPLATES 60 //(sizeof( psets ) / sizeof( pset_t ))
- -
- -// init a preset - just clear state array
- -void PSET_Init( pset_t *ppset )
- -{
- - // clear state array
- - if( ppset ) memset( ppset->w, 0, sizeof( int ) * ( CPSET_STATES ));
- -}
- -
- -// clear runtime slots
- -void PSET_InitAll( void )
- -{
- - int i;
- -
- - for( i = 0; i < CPSETS; i++ )
- - memset( &psets[i], 0, sizeof( pset_t ));
- -}
- -
- -// free the preset - free all processors
- -
- -void PSET_Free( pset_t *ppset )
- -{
- - if( ppset )
- - {
- - // free processors
- - PRC_FreeAll( ppset->prcs, ppset->cprcs );
- -
- - // clear
- - memset( ppset, 0, sizeof( pset_t ));
- - }
- -}
- -
- -void PSET_FreeAll() { int i; for( i = 0; i < CPSETS; i++ ) PSET_Free( &psets[i] ); };
- -
- -// return preset struct, given index into preset template array
- -// NOTE: should not ever be more than 2 or 3 of these active simultaneously
- -pset_t *PSET_Alloc( int ipsettemplate )
- -{
- - pset_t *ppset;
- - qboolean fok;
- - int i;
- -
- - // don't excede array bounds
- - if( ipsettemplate >= CPSETTEMPLATES )
- - ipsettemplate = 0;
- -
- - // find free slot
- - for( i = 0; i < CPSETS; i++)
- - {
- - if( !psets[i].fused )
- - break;
- - }
- -
- - if( i == CPSETS )
- - return NULL;
- -
- - ppset = &psets[i];
- -
- - // copy template into preset
- - *ppset = psettemplates[ipsettemplate];
- -
- - ppset->fused = true;
- -
- - // clear state array
- - PSET_Init( ppset );
- -
- - // init all processors, set up processor function pointers
- - fok = PRC_InitAll( ppset->prcs, ppset->cprcs );
- -
- - if( !fok )
- - {
- - // failed to init one or more processors
- - MsgDev( D_ERROR, "Sound DSP: preset failed to init.\n");
- - PRC_FreeAll( ppset->prcs, ppset->cprcs );
- - return NULL;
- - }
- - return ppset;
- -}
- -
- -// batch version of PSET_GetNext for linear array of processors. For performance.
- -
- -// ppset - preset array
- -// pbuffer - input sample data
- -// SampleCount - size of input buffer
- -// OP: OP_LEFT - process left channel in place
- -// OP_RIGHT - process right channel in place
- -// OP_LEFT_DUPLICATe - process left channel, duplicate into right
- -
- -_inline void PSET_GetNextN( pset_t *ppset, portable_samplepair_t *pbf, int SampleCount, int op )
- -{
- - prc_t *pprc;
- - int i, count = ppset->cprcs;
- -
- - switch( ppset->type )
- - {
- - default:
- - case PSET_SIMPLE:
- - {
- - // x(n)--->P(0)--->y(n)
- - ppset->prcs[0].pfnGetNextN( ppset->prcs[0].pdata, pbf, SampleCount, op );
- - break;
- - }
- - case PSET_LINEAR:
- - {
- -
- - // w0 w1 w2
- - // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
- -
- - // w0 w1 w2 w3 w4 w5
- - // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
- -
- - // call batch processors in sequence - no internal state for batch processing
- - // point to first processor
- -
- - pprc = &ppset->prcs[0];
- -
- - for( i = 0; i < count; i++ )
- - {
- - pprc->pfnGetNextN( pprc->pdata, pbf, SampleCount, op );
- - pprc++;
- - }
- - break;
- - }
- - }
- -}
- -
- -
- -// Get next sample from this preset. called once for every sample in buffer
- -// ppset is pointer to preset
- -// x is input sample
- -_inline int PSET_GetNext( pset_t *ppset, int x )
- -{
- - int *w = ppset->w;
- - prc_t *pprc;
- - int count = ppset->cprcs;
- -
- - // initialized 0'th element of state array
- -
- - w[0] = x;
- -
- - switch( ppset->type )
- - {
- - default:
- - case PSET_SIMPLE:
- - {
- - // x(n)--->P(0)--->y(n)
- - return ppset->prcs[0].pfnGetNext (ppset->prcs[0].pdata, x);
- - }
- - case PSET_LINEAR:
- - {
- - // w0 w1 w2
- - // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
- -
- - // w0 w1 w2 w3 w4 w5
- - // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
- -
- - // call processors in reverse order, from count to 1
- -
- - // point to last processor
- -
- - pprc = &ppset->prcs[count-1];
- -
- - switch( count )
- - {
- - default:
- - case 5:
- - w[5] = pprc->pfnGetNext (pprc->pdata, w[4]);
- - pprc--;
- - case 4:
- - w[4] = pprc->pfnGetNext (pprc->pdata, w[3]);
- - pprc--;
- - case 3:
- - w[3] = pprc->pfnGetNext (pprc->pdata, w[2]);
- - pprc--;
- - case 2:
- - w[2] = pprc->pfnGetNext (pprc->pdata, w[1]);
- - pprc--;
- - case 1:
- - w[1] = pprc->pfnGetNext (pprc->pdata, w[0]);
- - }
- - return w[count];
- - }
- -
- - case PSET_PARALLEL6:
- - {
- - // w0 w1 w2 w3 w6 w7
- - // x(n)-P(0)-->P(1)-->P(2)-->(+)---P(5)--->y(n)
- - // | ^
- - // | w4 w5 |
- - // -->P(3)-->P(4)---->
- -
- - pprc = &ppset->prcs[0];
- -
- - // start with all adders
- -
- - w[6] = w[3] + w[5];
- -
- - // top branch - evaluate in reverse order
- -
- - w[7] = pprc[5].pfnGetNext( pprc[5].pdata, w[6] );
- - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
- - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
- -
- - // bottom branch - evaluate in reverse order
- -
- - w[5] = pprc[4].pfnGetNext( pprc[4].pdata, w[4] );
- - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[1] );
- -
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- -
- - return w[7];
- - }
- - case PSET_PARALLEL2:
- - { // w0 w1 w3
- - // x(n)--->P(0)-->(+)-->y(n)
- - // ^
- - // w0 w2 |
- - // x(n)--->P(1)-----
- -
- - pprc = &ppset->prcs[0];
- -
- - w[3] = w[1] + w[2];
- -
- - w[1] = pprc->pfnGetNext( pprc->pdata, w[0] );
- - pprc++;
- - w[2] = pprc->pfnGetNext( pprc->pdata, w[0] );
- -
- - return w[3];
- - }
- -
- - case PSET_PARALLEL4:
- - {
- - // w0 w1 w2 w5
- - // x(n)--->P(0)-->P(1)-->(+)-->y(n)
- - // ^
- - // w0 w3 w4 |
- - // x(n)--->P(2)-->P(3)-----
- +typedef struct sx_preset_s
- +{
- + float room_lp; // lowpass
- + float room_mod; // modulation
- - pprc = &ppset->prcs[0];
- + // reverb
- + float room_size;
- + float room_refl;
- + float room_rvblp;
- - w[5] = w[2] + w[4];
- + // delay
- + float room_delay;
- + float room_feedback;
- + float room_dlylp;
- + float room_left;
- +} sx_preset_t;
- - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
- - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
- +typedef struct dly_s
- +{
- + size_t cdelaysamplesmax; // delay line array size
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
- + // delay line pointers
- + size_t idelayinput;
- + size_t idelayoutput;
- - return w[5];
- - }
- + // crossfade
- + size_t idelayoutputxf; // output pointer
- + int xfade; // value
- - case PSET_PARALLEL5:
- - {
- - // w0 w1 w2 w5 w6
- - // x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
- - // ^
- - // w0 w3 w4 |
- - // x(n)--->P(2)-->P(3)-----
- + int delaysamples; // delay setting
- + int delayfeedback; // feedback setting
- - pprc = &ppset->prcs[0];
- + // lowpass
- + int lp; // is lowpass enabled
- + int lp0, lp1, lp2; // lowpass buffer
- - w[5] = w[2] + w[4];
- + // modulation
- + int mod;
- + int modcur;
- - w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
- + // delay line
- + int *lpdelayline;
- +} dly_t;
- - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
- - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
- +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
- +};
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
- +// 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
- - return w[6];
- - }
- +// underwater/special fx modulations
- +convar_t *sxmod_mod;
- +convar_t *sxmod_lowpass;
- - case PSET_FEEDBACK:
- - {
- - // w0 w1 w2 w3 w4 w7
- - // x(n)-P(0)--(+)-->P(1)-->P(2)-->P(5)->y(n)
- - // ^ |
- - // | w6 w5 v
- - // -----P(4)<--P(3)--
- -
- - pprc = &ppset->prcs[0];
- -
- - // start with adders
- -
- - w[2] = w[1] + w[6];
- -
- - // evaluate in reverse order
- -
- - w[7] = pprc[5].pfnGetNext( pprc[5].pdata, w[4] );
- - w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
- - w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[4] );
- - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
- - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- -
- - return w[7];
- - }
- - case PSET_FEEDBACK3:
- - {
- - // w0 w1 w2
- - // x(n)---(+)-->P(0)--------->y(n)
- - // ^ |
- - // | w4 w3 v
- - // -----P(2)<--P(1)--
- -
- - pprc = &ppset->prcs[0];
- -
- - // start with adders
- -
- - w[1] = w[0] + w[4];
- -
- - // evaluate in reverse order
- -
- - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
- - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
- - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
- -
- - return w[2];
- - }
- - case PSET_FEEDBACK4:
- - {
- - // w0 w1 w2 w5
- - // x(n)---(+)-->P(0)-------->P(3)--->y(n)
- - // ^ |
- - // | w4 w3 v
- - // ---P(2)<--P(1)--
- -
- - pprc = &ppset->prcs[0];
- -
- - // start with adders
- -
- - w[1] = w[0] + w[4];
- -
- - // evaluate in reverse order
- -
- - w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[2] );
- - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
- - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
- - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
- -
- - return w[2];
- - }
- - case PSET_MOD:
- - {
- - // w0 w1 w3 w4
- - // x(n)------>P(1)--P(2)--P(3)--->y(n)
- - // w0 w2 ^
- - // x(n)------>P(0)....:
- +// stereo delay(no feedback)
- +convar_t *sxste_delay; // straight left delay
- - pprc = &ppset->prcs[0];
- +// mono reverb
- +convar_t *sxrvb_lp; // lowpass
- +convar_t *sxrvb_feedback; // reverb decay. Higher -- longer
- +convar_t *sxrvb_size; // room size. Higher -- larger
- - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
- +// mono delay
- +convar_t *sxdly_lp; // lowpass
- +convar_t *sxdly_feedback; // cycles
- +convar_t *sxdly_delay; // current delay in seconds
- - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[1] );
- +convar_t *dsp_room; // for compability
- +int idsp_dma_speed;
- +int idsp_room;
- +int room_typeprev;
- - // modulate processor 2
- +// routines
- +int sxamodl, sxamodr; // amplitude modulation values
- +int sxamodlt, sxamodrt; // modulation targets
- +int sxmod1cur, sxmod2cur;
- +int sxmod1, sxmod2;
- +int sxhires;
- - pprc[2].pfnMod( pprc[2].pdata, ((float)w[2] / (float)PMAX));
- +portable_samplepair_t *paintto = NULL;
- - // get modulator output
- +dly_t rgsxdly[MAXDLY]; // stereo is last
- +int rgsxlp[MAXLP];
- - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- +void SX_Profiling_f( void );
- - w[1] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
- +/*
- +============
- +SX_ReloadRoomFX
- - return w[4];
- - }
- - case PSET_MOD2:
- - {
- - // w0 w2
- - // x(n)---------P(1)-->y(n)
- - // w0 w1 ^
- - // x(n)-->P(0)....:
- +============
- +*/
- +void SX_ReloadRoomFX( void )
- +{
- + if( !dsp_room ) return; // not initialized
- - pprc = &ppset->prcs[0];
- + sxste_delay->modified = true;
- + sxrvb_feedback->modified = true;
- + sxdly_delay->modified = true;
- + room_type->modified = true;
- +}
- - // modulate processor 1
- +/*
- +============
- +SX_Init()
- - pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
- +Starts sound crackling system
- +============
- +*/
- +void SX_Init( void )
- +{
- + memset( rgsxdly, 0, sizeof( rgsxdly ));
- + memset( rgsxlp, 0, sizeof( rgsxlp ));
- - // get modulator output
- + sxamodr = sxamodl = sxamodrt = sxamodlt = 255;
- + idsp_dma_speed = SOUND_11k;
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- + hisound = Cvar_Get( "room_hires", "2", CVAR_ARCHIVE, "dsp quality. 1 for 22k, 2 for 44k(recommended) and 3 for 96k" );
- + sxhires = 2;
- - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
- + sxmod1cur = sxmod1 = 350 * ( idsp_dma_speed / SOUND_11k );
- + sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
- - return w[2];
- + 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" );
- - }
- - case PSET_MOD3:
- - {
- - // w0 w2 w3
- - // x(n)----------P(1)-->P(2)-->y(n)
- - // w0 w1 ^
- - // x(n)-->P(0).....:
- + 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" );
- - pprc = &ppset->prcs[0];
- + 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" );
- - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
- + 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" );
- - // modulate processor 1
- + sxste_delay = Cvar_Get( "room_left", "0", 0, "left channel delay time" );
- - pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
- + Cmd_AddCommand( "dsp_profile", SX_Profiling_f, "dsp stress-test, first argument is room_type" );
- - // get modulator output
- + // for compability
- + dsp_room = room_type;
- + SX_ReloadRoomFX();
- +}
- - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
- +/*
- +===========
- +DLY_Free
- - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
- +Free memory allocated for DSP
- +===========
- +*/
- +void DLY_Free( int idelay )
- +{
- + Assert( idelay >= 0 && idelay < MAXDLY );
- - return w[2];
- - }
- + if( rgsxdly[idelay].lpdelayline )
- + {
- + Z_Free( rgsxdly[idelay].lpdelayline );
- + rgsxdly[idelay].lpdelayline = NULL;
- }
- }
- +/*
- +==========
- +SX_Shutdown
- -/////////////
- -// DSP system
- -/////////////
- -
- -// Main interface
- -
- -// Whenever the preset # changes on any of these processors, the old processor is faded out, new is faded in.
- -// dsp_chan is optionally set when a sound is played - a preset is sent with the start_static/dynamic sound.
- -//
- -// sound1---->dsp_chan--> -------------(+)---->dsp_water--->dsp_player--->out
- -// sound2---->dsp_chan--> | |
- -// sound3---------------> ----dsp_room---
- -// | |
- -// --dsp_indirect-
- -
- -// dsp_room - set this cvar to a preset # to change the room dsp. room fx are more prevalent farther from player.
- -// use: when player moves into a new room, all sounds played in room take on its reverberant character
- -// dsp_water - set this cvar (once) to a preset # for serial underwater sound.
- -// use: when player goes under water, all sounds pass through this dsp (such as low pass filter)
- -// dsp_player - set this cvar to a preset # to cause all sounds to run through the effect (serial, in-line).
- -// use: player is deafened, player fires special weapon, player is hit by special weapon.
- -// dsp_facingaway- set this cvar to a preset # appropriate for sounds which are played facing away from player (weapon,voice)
- -
- -// Dsp presets
- +Stop DSP processor
- +==========
- +*/
- +void SX_Free( void )
- +{
- + int i;
- -convar_t *dsp_room; // room dsp preset - sounds more distant from player (1ch)
- + for( i = 0; i <= 3; i++ )
- + DLY_Free( i );
- -int ipset_room_prev;
- + Cmd_RemoveCommand( "dsp_profile" );
- +}
- -// legacy room_type support
- -convar_t *dsp_room_type;
- -int ipset_room_typeprev;
- +/*
- +===========
- +DLY_Init
- -// DSP processors
- +Initialize dly
- +===========
- +*/
- +int DLY_Init( int idelay, float delay )
- +{
- + dly_t *cur;
- -int idsp_room;
- -convar_t *dsp_stereo; // set to 1 for true stereo processing. 2x perf hit.
- + // 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 );
- -// DSP preset executor
- -#define CDSPS 32 // max number dsp executors active
- -#define DSPCHANMAX 4 // max number of channels dsp can process (allocs a separte processor for each chan)
- + DLY_Free( idelay ); // free dly if it's allocated
- -typedef struct
- -{
- - qboolean fused;
- - int cchan; // 1-4 channels, ie: mono, FrontLeft, FrontRight, RearLeft, RearRight
- - pset_t *ppset[DSPCHANMAX]; // current preset (1-4 channels)
- - int ipset; // current ipreset
- - pset_t *ppsetprev[DSPCHANMAX]; // previous preset (1-4 channels)
- - int ipsetprev; // previous ipreset
- - float xfade; // crossfade time between previous preset and new
- - rmp_t xramp; // crossfade ramp
- -} dsp_t;
- -
- -dsp_t dsps[CDSPS];
- -
- -void DSP_Init( int idsp )
- -{
- - dsp_t *pdsp;
- -
- - if( idsp < 0 || idsp > CDSPS )
- - return;
- -
- - pdsp = &dsps[idsp];
- - memset( pdsp, 0, sizeof( dsp_t ));
- -}
- + cur = &rgsxdly[idelay];
- + cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
- + cur->lpdelayline = (int *)Z_Malloc( cur->cdelaysamplesmax * sizeof( int ));
- + cur->xfade = 0;
- -void DSP_Free( int idsp )
- -{
- - dsp_t *pdsp;
- - int i;
- + // init modulation
- + cur->mod = cur->modcur = 0;
- - if( idsp < 0 || idsp > CDSPS )
- - return;
- -
- - pdsp = &dsps[idsp];
- + // init lowpass
- + cur->lp = 1;
- + cur->lp0 = cur->lp1 = cur->lp2 = 0;
- - for( i = 0; i < pdsp->cchan; i++ )
- - {
- - if( pdsp->ppset[i] )
- - PSET_Free( pdsp->ppset[i] );
- -
- - if( pdsp->ppsetprev[i] )
- - PSET_Free( pdsp->ppsetprev[i] );
- - }
- + cur->idelayinput = 0;
- + cur->idelayoutput = cur->cdelaysamplesmax - cur->delaysamples; // NOTE: delaysamples must be set!!!
- - memset( pdsp, 0, sizeof( dsp_t ));
- -}
- -// Init all dsp processors - called once, during engine startup
- -void DSP_InitAll( void )
- -{
- - int idsp;
- -
- - // order is important, don't rearange.
- - FLT_InitAll();
- - DLY_InitAll();
- - RVA_InitAll();
- - LFOWAV_InitAll();
- - LFO_InitAll();
- -
- - CRS_InitAll();
- - PTC_InitAll();
- - ENV_InitAll();
- - EFO_InitAll();
- - MDY_InitAll();
- - AMP_InitAll();
- -
- - PSET_InitAll();
- -
- - for( idsp = 0; idsp < CDSPS; idsp++ )
- - DSP_Init( idsp );
- + return 1;
- }
- -// free all resources associated with dsp - called once, during engine shutdown
- +/*
- +============
- +DLY_MovePointer
- -void DSP_FreeAll( void )
- +Checks overflow and moves pointer
- +============
- +*/
- +_inline void DLY_MovePointer( dly_t *dly )
- {
- - int idsp;
- -
- - // order is important, don't rearange.
- - for( idsp = 0; idsp < CDSPS; idsp++ )
- - DSP_Free( idsp );
- -
- - AMP_FreeAll();
- - MDY_FreeAll();
- - EFO_FreeAll();
- - ENV_FreeAll();
- - PTC_FreeAll();
- - CRS_FreeAll();
- -
- - LFO_FreeAll();
- - LFOWAV_FreeAll();
- - RVA_FreeAll();
- - DLY_FreeAll();
- - FLT_FreeAll();
- + if( ++dly->idelayinput >= dly->cdelaysamplesmax )
- + dly->idelayinput = 0;
- +
- + if( ++dly->idelayoutput >= dly->cdelaysamplesmax )
- + dly->idelayoutput = 0;
- }
- +/*
- +=============
- +DLY_CheckNewStereoDelayVal
- -// allocate a new dsp processor chain, kill the old processor. Called by DSP_CheckNewPreset()
- -// ipset is new preset
- -// xfade is crossfade time when switching between presets (milliseconds)
- -// cchan is how many simultaneous preset channels to allocate (1-4)
- -// return index to new dsp
- -int DSP_Alloc( int ipset, float xfade, int cchan )
- +Update stereo processor settings if we are in new room
- +=============
- +*/
- +void DLY_CheckNewStereoDelayVal( void )
- {
- - dsp_t *pdsp;
- - int i, idsp;
- - int cchans = bound( 1, cchan, DSPCHANMAX);
- + dly_t *const dly = &rgsxdly[STEREODLY];
- + float delay = sxste_delay->value;
- +
- + if( !sxste_delay->modified )
- + return;
- - // find free slot
- - for( idsp = 0; idsp < CDSPS; idsp++ )
- + if( delay == 0 )
- {
- - if( !dsps[idsp].fused )
- - break;
- + DLY_Free( STEREODLY );
- }
- + else
- + {
- + int samples;
- - if( idsp == CDSPS )
- - return -1;
- + delay = Q_min( delay, MAX_STEREO_DELAY );
- + samples = (int)(delay * idsp_dma_speed) << sxhires;
- - pdsp = &dsps[idsp];
- + // re-init dly
- + if( !dly->lpdelayline )
- + {
- + dly->delaysamples = samples;
- + DLY_Init( STEREODLY, MAX_STEREO_DELAY );
- + }
- - DSP_Init( idsp );
- + if( dly->delaysamples != samples )
- + {
- + dly->xfade = 128;
- + dly->idelayoutputxf = dly->idelayinput - samples;
- + if( dly->idelayoutputxf < 0 )
- + dly->idelayoutputxf += dly->cdelaysamplesmax;
- + }
- - pdsp->fused = true;
- - pdsp->cchan = cchans;
- + dly->modcur = dly->mod = 0;
- - // allocate a preset processor for each channel
- - pdsp->ipset = ipset;
- - pdsp->ipsetprev = 0;
- -
- - for( i = 0; i < pdsp->cchan; i++ )
- - {
- - pdsp->ppset[i] = PSET_Alloc( ipset );
- - pdsp->ppsetprev[i] = NULL;
- + if( dly->delaysamples == 0 )
- + DLY_Free( STEREODLY );
- }
- - // set up crossfade time in seconds
- - pdsp->xfade = xfade / 1000.0f;
- -
- - RMP_SetEnd( &pdsp->xramp );
- -
- - return idsp;
- + sxste_delay->modified = false;
- }
- -// return gain for current preset associated with dsp
- -// get crossfade to new gain if switching from previous preset (from preset crossfader value)
- -// Returns 1.0 gain if no preset (preset 0)
- -float DSP_GetGain( int idsp )
- +/*
- +=============
- +DLY_DoStereoDelay
- +
- +Do stereo processing
- +=============
- +*/
- +void DLY_DoStereoDelay( int count )
- {
- - float gain_target = 0.0;
- - float gain_prev = 0.0;
- - float gain;
- - dsp_t *pdsp;
- - int r;
- -
- - if( idsp < 0 || idsp > CDSPS )
- - return 1.0f;
- -
- - pdsp = &dsps[idsp];
- -
- - // get current preset's gain
- - if( pdsp->ppset[0] )
- - gain_target = pdsp->ppset[0]->gain;
- - else gain_target = 1.0f;
- -
- - // if not crossfading, return current preset gain
- - if( RMP_HitEnd( &pdsp->xramp ))
- - {
- - // return current preset's gain
- - return gain_target;
- - }
- -
- - // get previous preset gain
- + int delay, samplexf;
- + dly_t *const dly = &rgsxdly[STEREODLY];
- + portable_samplepair_t *paint = paintto;
- - if( pdsp->ppsetprev[0] )
- - gain_prev = pdsp->ppsetprev[0]->gain;
- - else gain_prev = 1.0;
- + if( !dly->lpdelayline )
- + return; // inactive
- - // if current gain = target preset gain, return
- - if( gain_target == gain_prev )
- + for( ; count; count--, paint++ )
- {
- - if( gain_target == 0.0f )
- - return 1.0f;
- - return gain_target;
- - }
- + if( dly->mod && --dly->modcur < 0 )
- + dly->modcur = dly->mod;
- - // get crossfade ramp value (updated elsewhere, when actually crossfading preset data)
- - r = RMP_GetCurrent( &pdsp->xramp );
- + delay = dly->lpdelayline[dly->idelayoutput];
- - // crossfade from previous to current preset gain
- - if( gain_target > gain_prev )
- - {
- - // ramping gain up - ramp up gain to target in last 10% of ramp
- - float rf = (float)r;
- - float pmax = (float)PMAX;
- + // 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 );
- - rf = rf / pmax; // rf 0->1.0
- + dly->xfade = 128;
- + }
- - if( rf < 0.9 ) rf = 0.0;
- - else rf = (rf - 0.9) / (1.0 - 0.9); // 0->1.0 after rf > 0.9
- + dly->idelayoutputxf %= dly->cdelaysamplesmax;
- - // crossfade gain from prev to target over rf
- - gain = gain_prev + (gain_target - gain_prev) * rf;
- + // modify delay, if crossfading
- + if( dly->xfade )
- + {
- + samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7;
- + delay = samplexf + ((delay * dly->xfade) >> 7);
- - return gain;
- - }
- - else
- - {
- - // ramping gain down - drop gain to target in first 10% of ramp
- - float rf = (float) r;
- - float pmax = (float)PMAX;
- + if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
- + dly->idelayoutputxf = 0;
- - rf = rf / pmax; // rf 0.0->1.0
- + if( --dly->xfade == 0 )
- + dly->idelayoutput = dly->idelayoutputxf;
- + }
- - if( rf < 0.1 ) rf = (rf - 0.1) / (0.0 - 0.1); // 1.0->0.0 if rf < 0.1
- - else rf = 0.0;
- + // save left value to delay line
- + dly->lpdelayline[dly->idelayinput] = CLIP( paint->left );
- - // crossfade gain from prev to target over rf
- - gain = gain_prev + (gain_target - gain_prev) * (1.0 - rf);
- + // paint new delay value
- + paint->left = delay;
- + }
- + else
- + {
- + // clear delay line
- + dly->lpdelayline[dly->idelayinput] = 0;
- + }
- - return gain;
- + DLY_MovePointer( dly );
- }
- }
- -// free previous preset if not 0
- -_inline void DSP_FreePrevPreset( dsp_t *pdsp )
- +/*
- +=============
- +DLY_CheckNewDelayVal
- +
- +Update delay processor settings if we are in new room
- +=============
- +*/
- +void DLY_CheckNewDelayVal( void )
- {
- - // free previous presets if non-null - ie: rapid change of preset just kills old without xfade
- - if( pdsp->ipsetprev )
- - {
- - int i;
- + float delay = sxdly_delay->value;
- + dly_t *const dly = &rgsxdly[MONODLY];
- - for( i = 0; i < pdsp->cchan; i++ )
- + if( sxdly_delay->modified )
- + {
- + if( delay == 0 )
- {
- - if( pdsp->ppsetprev[i] )
- + 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 )
- {
- - PSET_Free( pdsp->ppsetprev[i] );
- - pdsp->ppsetprev[i] = NULL;
- + 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 );
- +
- }
- - pdsp->ipsetprev = 0;
- }
- + sxdly_delay->modified = false;
- + dly->lp = sxdly_lp->integer;
- + dly->delayfeedback = 255 * sxdly_feedback->value;
- }
- -// alloc new preset if different from current
- -// xfade from prev to new preset
- -// free previous preset, copy current into previous, set up xfade from previous to new
- -void DSP_SetPreset( int idsp, int ipsetnew )
- +/*
- +=============
- +DLY_DoDelay
- +
- +Do delay processing
- +=============
- +*/
- +void DLY_DoDelay( int count )
- {
- - dsp_t *pdsp;
- - pset_t *ppsetnew[DSPCHANMAX];
- - int i;
- + dly_t *const dly = &rgsxdly[MONODLY];
- + portable_samplepair_t *paint = paintto;
- + int delay;
- - ASSERT( idsp >= 0 && idsp < CDSPS );
- + if( !dly->lpdelayline || !count )
- + return; // inactive
- - pdsp = &dsps[idsp];
- + for( ; count; count--, paint++ )
- + {
- + delay = dly->lpdelayline[dly->idelayoutput];
- - // validate new preset range
- - if( ipsetnew >= CPSETTEMPLATES || ipsetnew < 0 )
- - return;
- + // 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 );
- - // ignore if new preset is same as current preset
- - if( ipsetnew == pdsp->ipset )
- - return;
- + if( dly->lp ) // lowpass
- + {
- + dly->lp0 = dly->lp1;
- + dly->lp1 = val;
- + val = ( dly->lp0 + dly->lp1 + (val << 1) ) >> 2;
- + }
- - // alloc new presets (each channel is a duplicate preset)
- - ASSERT( pdsp->cchan <= DSPCHANMAX );
- + dly->lpdelayline[dly->idelayinput] = val;
- - for( i = 0; i < pdsp->cchan; i++ )
- - {
- - ppsetnew[i] = PSET_Alloc( ipsetnew );
- + val >>= 2;
- - if( !ppsetnew[i] )
- + paint->left = CLIP( paint->left + val );
- + paint->right = CLIP( paint->right + val );
- + }
- + else
- {
- - MsgDev( D_NOTE, "DSP preset failed to allocate.\n" );
- - return;
- + dly->lpdelayline[dly->idelayinput] = 0;
- + dly->lp0 = dly->lp1 = 0;
- }
- +
- + DLY_MovePointer( dly );
- }
- +}
- +
- +/*
- +===========
- +RVB_SetUpDly
- - ASSERT( pdsp );
- +Set up dly for reverb
- +===========
- +*/
- +void RVB_SetUpDly( int pos, float delay, int kmod )
- +{
- + int samples;
- - // free PREVIOUS previous preset if not 0
- - DSP_FreePrevPreset( pdsp );
- + delay = Q_min( delay, MAX_REVERB_DELAY );
- + samples = (int)(delay * idsp_dma_speed) << sxhires;
- - for( i = 0; i < pdsp->cchan; i++ )
- + if( !rgsxdly[pos].lpdelayline )
- {
- - // current becomes previous
- - pdsp->ppsetprev[i] = pdsp->ppset[i];
- -
- - // new becomes current
- - pdsp->ppset[i] = ppsetnew[i];
- + rgsxdly[pos].delaysamples = samples;
- + DLY_Init( pos, MAX_REVERB_DELAY );
- }
- -
- - pdsp->ipsetprev = pdsp->ipset;
- - pdsp->ipset = ipsetnew;
- - // clear ramp
- - RMP_SetEnd( &pdsp->xramp );
- -
- - // make sure previous dsp preset has data
- - ASSERT( pdsp->ppsetprev[0] );
- + 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;
- + }
- - // shouldn't be crossfading if current dsp preset == previous dsp preset
- - ASSERT( pdsp->ipset != pdsp->ipsetprev );
- + if( !rgsxdly[pos].delaysamples )
- + DLY_Free( pos );
- - RMP_Init( &pdsp->xramp, pdsp->xfade, 0, PMAX );
- }
- -///////////////////////////////////////
- -// Helpers: called only from DSP_Process
- -///////////////////////////////////////
- +/*
- +===========
- +RVB_CheckNewReverbVal
- -// return true if batch processing version of preset exists
- -_inline qboolean FBatchPreset( pset_t *ppset )
- +Update reverb settings if we are in new room
- +===========
- +*/
- +void RVB_CheckNewReverbVal( void )
- {
- - switch( ppset->type )
- + dly_t *const dly1 = &rgsxdly[REVERBPOS];
- + dly_t *const dly2 = &rgsxdly[REVERBPOS + 1];
- + float delay = sxrvb_size->value;
- +
- + if( sxrvb_size->modified )
- {
- - case PSET_LINEAR:
- - return true;
- - case PSET_SIMPLE:
- - return true;
- - default:
- - return false;
- + 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 );
- + }
- }
- +
- + sxrvb_size->modified = false;
- + dly1->lp = dly2->lp = sxrvb_lp->integer;
- + dly1->delayfeedback = dly2->delayfeedback = (int)(255 * sxrvb_feedback->value);
- }
- -// Helper: called only from DSP_Process
- -// mix front stereo buffer to mono buffer, apply dsp fx
- -_inline void DSP_ProcessStereoToMono( dsp_t *pdsp, portable_samplepair_t *pbfront, int sampleCount, qboolean bcrossfading )
- +/*
- +===========
- +RVB_DoReverbForOneDly
- +
- +Do reverberation for one dly
- +===========
- +*/
- +int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair )
- {
- - portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
- - int count = sampleCount;
- - int av, x;
- + int delay;
- + int samplexf;
- + int val, valt;
- + int voutm = 0;
- +
- + if( --dly->modcur < 0 )
- + dly->modcur = dly->mod;
- +
- + delay = dly->lpdelayline[dly->idelayoutput];
- - if( !bcrossfading )
- + if( dly->xfade || delay || samplepair->left || samplepair->right )
- {
- - if( FBatchPreset( pdsp->ppset[0] ))
- + // modulate delay rate
- + if( !dly->mod )
- {
- - // convert Stereo to Mono in place, then batch process fx: perf KDB
- + dly->idelayoutputxf = dly->idelayoutput + ((Com_RandomLong( 0, 255 ) * delay) >> 9 );
- - // front->left + front->right / 2 into front->left, front->right duplicated.
- - while( count-- )
- - {
- - pbf->left = (pbf->left + pbf->right) >> 1;
- - pbf++;
- - }
- -
- - // process left (mono), duplicate output into right
- - PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
- + if( dly->idelayoutputxf >= dly->cdelaysamplesmax )
- + dly->idelayoutputxf -= dly->cdelaysamplesmax;
- +
- + dly->xfade = REVERB_XFADE;
- }
- - else
- +
- + if( dly->xfade )
- {
- - // avg left and right -> mono fx -> duplcate out left and right
- - while( count-- )
- - {
- - av = ( ( pbf->left + pbf->right ) >> 1 );
- - x = PSET_GetNext( pdsp->ppset[0], av );
- - x = CLIP_DSP( x );
- - pbf->left = pbf->right = x;
- - pbf++;
- - }
- + 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;
- }
- - return;
- - }
- - // crossfading to current preset from previous preset
- - if( bcrossfading )
- - {
- - int r = -1;
- - int fl, flp;
- - int xf_fl;
- -
- - while( count-- )
- +
- + if( delay )
- {
- - av = ( ( pbf->left + pbf->right ) >> 1 );
- -
- - // get current preset values
- - fl = PSET_GetNext( pdsp->ppset[0], av );
- -
- - // get previous preset values
- - flp = PSET_GetNext( pdsp->ppsetprev[0], av );
- -
- - fl = CLIP_DSP(fl);
- - flp = CLIP_DSP(flp);
- -
- - // get current ramp value
- - r = RMP_GetNext( &pdsp->xramp );
- -
- - // crossfade from previous to current preset
- - xf_fl = XFADE( fl, flp, r ); // crossfade front left previous to front left
- -
- - pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
- - pbf->right = xf_fl;
- -
- - pbf++;
- + 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;
- +
- }
- -// Helper: called only from DSP_Process
- -// DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
- -_inline void DSP_ProcessStereoToStereo( dsp_t *pdsp, portable_samplepair_t *pbfront, int sampleCount, qboolean bcrossfading )
- +/*
- +===========
- +RVB_DoReverb
- +
- +Do reverberation processing
- +===========
- +*/
- +void RVB_DoReverb( int count )
- {
- - portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
- - int count = sampleCount;
- - int fl, fr;
- + 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;
- - if( !bcrossfading )
- + for( ; count; count--, paint++ )
- {
- + vlr = ( paint->left + paint->right ) >> 1;
- - if( FBatchPreset( pdsp->ppset[0] ) && FBatchPreset( pdsp->ppset[1] ))
- - {
- - // process left & right
- - PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT );
- - PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
- - }
- - else
- - {
- - // left -> left fx, right -> right fx
- - while( count-- )
- - {
- - fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
- - fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
- + voutm = RVB_DoReverbForOneDly( dly1, vlr, paint );
- + voutm += RVB_DoReverbForOneDly( dly2, vlr, paint );
- - fl = CLIP_DSP( fl );
- - fr = CLIP_DSP( fr );
- + voutm = (11 * voutm) >> 6;
- - pbf->left = fl;
- - pbf->right = fr;
- - pbf++;
- - }
- - }
- - return;
- + 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->integer && !sxmod_mod->integer )
- + return;
- - // crossfading to current preset from previous preset
- - if( bcrossfading )
- + for( ; count; count--, paint++ )
- {
- - int r, flp, frp;
- - int xf_fl, xf_fr;
- + portable_samplepair_t res = *paint;
- - while( count-- )
- + if( sxmod_lowpass->value )
- {
- - // get current preset values
- - fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
- - fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
- -
- - // get previous preset values
- - flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
- - frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
- -
- - // get current ramp value
- - r = RMP_GetNext( &pdsp->xramp );
- -
- - fl = CLIP_DSP( fl );
- - fr = CLIP_DSP( fr );
- - flp = CLIP_DSP( flp );
- - frp = CLIP_DSP( frp );
- -
- - // crossfade from previous to current preset
- - xf_fl = XFADE( fl, flp, r ); // crossfade front left previous to front left
- - xf_fr = XFADE( fr, frp, r );
- -
- - pbf->left = xf_fl; // crossfaded front left
- - pbf->right = xf_fr;
- -
- - pbf++;
- - }
- - }
- -}
- + 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;
- -void DSP_ClearState( void )
- -{
- - if( !dsp_room ) return; // not init
- + res.left >>= 2;
- + res.right >>= 2;
- - Cvar_SetFloat( "dsp_room", 0.0f );
- - Cvar_SetFloat( "room_type", 0.0f );
- + rgsxlp[0] = rgsxlp[1];
- + rgsxlp[1] = rgsxlp[2];
- + rgsxlp[2] = rgsxlp[3];
- + rgsxlp[3] = rgsxlp[4];
- + rgsxlp[4] = paint->left;
- - CheckNewDspPresets();
- + rgsxlp[5] = rgsxlp[6];
- + rgsxlp[6] = rgsxlp[7];
- + rgsxlp[7] = rgsxlp[8];
- + rgsxlp[8] = rgsxlp[9];
- + rgsxlp[9] = paint->right;
- + }
- - // don't crossfade
- - dsps[0].xramp.fhitend = true;
- -}
- + if( sxmod_mod->integer )
- + {
- + if( --sxmod1cur < 0 )
- + sxmod1cur = sxmod1;
- -// Main DSP processing routine:
- -// process samples in buffers using pdsp processor
- -// continue crossfade between 2 dsp processors if crossfading on switch
- -// pfront - front stereo buffer to process
- -// prear - rear stereo buffer to process (may be NULL)
- -// sampleCount - number of samples in pbuf to process
- -// This routine also maps the # processing channels in the pdsp to the number of channels
- -// supplied. ie: if the pdsp has 4 channels and pbfront and pbrear are both non-null, the channels
- -// map 1:1 through the processors.
- + if( !sxmod1 )
- + sxamodlt = Com_RandomLong( 32, 255 );
- -void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
- -{
- - qboolean bcrossfading;
- - int cprocs; // output cannels (1, 2 or 4)
- - dsp_t *pdsp;
- + if( --sxmod2cur < 0 )
- + sxmod2cur = sxmod2;
- - if( idsp < 0 || idsp >= CDSPS )
- - return;
- + if( !sxmod2 )
- + sxamodrt = Com_RandomLong( 32, 255 );
- - ASSERT ( idsp < CDSPS ); // make sure idsp is valid
- + res.left = (sxamodl * res.left) >> 8;
- + res.right = (sxamodr * res.right) >> 8;
- - pdsp = &dsps[idsp];
- + if( sxamodl < sxamodlt )
- + sxamodl++;
- + else if( sxamodl > sxamodlt )
- + sxamodl--;
- - // if current and previous preset 0, return - preset 0 is 'off'
- - if( !pdsp->ipset && !pdsp->ipsetprev )
- - return;
- + if( sxamodr < sxamodrt )
- + sxamodr++;
- + else if( sxamodr > sxamodrt )
- + sxamodr--;
- + }
- +
- + paint->left = CLIP(res.left);
- + paint->right = CLIP(res.right);
- + }
- +}
- - ASSERT( pbfront );
- +/*
- +===========
- +DSP_Process
- - // return right away if fx processing is turned off
- +(xash dsp interface)
- +===========
- +*/
- +void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
- +{
- if( dsp_off->integer )
- return;
- - if( sampleCount < 0 )
- + // HACKHACK: don't process while in menu
- + if( cls.key_dest == key_menu || !sampleCount )
- return;
- -
- - bcrossfading = !RMP_HitEnd( &pdsp->xramp );
- - // if not crossfading, and previous channel is not null, free previous
- - if( !bcrossfading ) DSP_FreePrevPreset( pdsp );
- + // preset is already installed by CheckNewDspPresets
- + paintto = pbfront;
- - cprocs = pdsp->cchan;
- -
- - // NOTE: when mixing between different channel sizes,
- - // always AVERAGE down to fewer channels and DUPLICATE up more channels.
- - // The following routines always process cchan_in channels.
- - // ie: QuadToMono still updates 4 values in buffer
- + RVB_DoAMod( sampleCount );
- + RVB_DoReverb( sampleCount );
- + DLY_DoDelay( sampleCount );
- + DLY_DoStereoDelay( sampleCount );
- +}
- - // DSP_Process stereo in to mono out (ie: left and right are averaged)
- - if( cprocs == 1 )
- - {
- - DSP_ProcessStereoToMono( pdsp, pbfront, sampleCount, bcrossfading );
- - return;
- - }
- +/*
- +===========
- +DSP_ClearState
- - // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
- - if( cprocs >= 2 )
- - {
- - DSP_ProcessStereoToStereo( pdsp, pbfront, sampleCount, bcrossfading );
- - return;
- - }
- +(xash dsp interface)
- +===========
- +*/
- +void DSP_ClearState( void )
- +{
- + Cvar_SetFloat( "room_type", 0.0f );
- + SX_ReloadRoomFX();
- }
- -// DSP helpers
- +/*
- +===========
- +AllocDsps
- -// free all dsp processors
- -void FreeDsps( void )
- +(xash dsp interface)
- +===========
- +*/
- +qboolean AllocDsps( void )
- {
- - DSP_Free( idsp_room );
- - idsp_room = 0;
- -
- - DSP_FreeAll();
- + SX_Init();
- +
- + return 1;
- }
- -// alloc dsp processors
- -qboolean AllocDsps( void )
- +/*
- +===========
- +FreeDsps
- +
- +(xash dsp interface)
- +===========
- +*/
- +void FreeDsps( void )
- {
- - DSP_InitAll();
- + SX_Free();
- +}
- - idsp_room = -1.0;
- +/*
- +===========
- +CheckNewDspPresets
- +
- +(xash dsp interface)
- +===========
- +*/
- +void CheckNewDspPresets( void )
- +{
- + if( dsp_off->value != 0.0f )
- + return;
- - // initialize DSP cvars
- - dsp_room = Cvar_Get( "dsp_room", "0", 0, "room dsp preset - sounds more distant from player (1ch)" );
- - dsp_room_type = Cvar_Get( "room_type", "0", 0, "duplicate for dsp_room cvar for backward compatibility" );
- - dsp_stereo = Cvar_Get( "dsp_stereo", "0", 0, "set to 1 for true stereo processing. 2x perf hits" );
- + if( s_listener.waterlevel > 2 )
- + idsp_room = roomwater_type->value;
- + else idsp_room = room_type->value;
- - // alloc dsp room channel (mono, stereo if dsp_stereo is 1)
- + if( hisound->modified )
- + {
- + sxhires = hisound->integer;
- + hisound->modified = false;
- + }
- - // dsp room is mono, 300ms fade time
- - idsp_room = DSP_Alloc( dsp_room->integer, 300, dsp_stereo->integer * 2 );
- + if( idsp_room == room_typeprev && idsp_room == 0 )
- + return;
- - // init prev values
- - ipset_room_prev = dsp_room->integer;
- - ipset_room_typeprev = dsp_room_type->integer;
- + if( idsp_room > MAX_ROOM_TYPES )
- + return;
- - if( idsp_room < 0 )
- + if( idsp_room != room_typeprev )
- {
- - MsgDev( D_WARN, "DSP processor failed to initialize! \n" );
- + const sx_preset_t *cur = rgsxpre + idsp_room;
- - FreeDsps();
- - return false;
- + Cvar_SetFloat( "room_lp", cur->room_lp );
- + Cvar_SetFloat( "room_mod", cur->room_mod );
- + Cvar_SetFloat( "room_size", cur->room_size );
- + Cvar_SetFloat( "room_refl", cur->room_refl );
- + Cvar_SetFloat( "room_rvblp", cur->room_rvblp );
- + Cvar_SetFloat( "room_delay", cur->room_delay );
- + Cvar_SetFloat( "room_feedback", cur->room_feedback );
- + Cvar_SetFloat( "room_dlylp", cur->room_dlylp );
- + Cvar_SetFloat( "room_left", cur->room_left );
- }
- - return true;
- +
- + room_typeprev = idsp_room;
- +
- + RVB_CheckNewReverbVal( );
- + DLY_CheckNewDelayVal( );
- + DLY_CheckNewStereoDelayVal();
- }
- +/*
- +===========
- +DSP_GetGain
- -// Helper to check for change in preset of any of 4 processors
- -// if switching to a new preset, alloc new preset, simulate both presets in DSP_Process & xfade,
- -void CheckNewDspPresets( void )
- +(xash dsp interface)
- +===========
- +*/
- +float DSP_GetGain( int idsp )
- {
- - int iroomtype = dsp_room_type->integer;
- - int iroom;
- + return 1.0f;
- +}
- - if( dsp_off->integer )
- - return;
- +void SX_Profiling_f( void )
- +{
- + portable_samplepair_t testbuffer[512];
- + int i, calls = 10000;
- + double start, end;
- + float oldroom = room_type->value;
- - if( s_listener.waterlevel > 2 )
- - iroom = 15;
- - else if( s_listener.inmenu )
- - iroom = 0;
- - else iroom = dsp_room->integer;
- + for( i = 0; i < 512; i++ )
- + {
- + testbuffer[i].left = Com_RandomLong( 0, 3000 );
- + testbuffer[i].right = Com_RandomLong( 0, 3000 );
- + }
- - // legacy code support for "room_type" Cvar
- - if( iroomtype != ipset_room_typeprev )
- + if( Cmd_Argc() > 1 )
- {
- - // force dsp_room = room_type
- - ipset_room_typeprev = iroomtype;
- - Cvar_SetFloat( "dsp_room", iroomtype );
- + Cvar_SetFloat( "room_type", Q_atof( Cmd_Argv( 1 )));
- + SX_ReloadRoomFX();
- + CheckNewDspPresets(); // we just need idsp_room immediately, for message below
- }
- - if( iroom != ipset_room_prev )
- + MsgDev( D_INFO, "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room );
- +
- + start = Sys_DoubleTime();
- + for( ; calls; calls-- )
- {
- - DSP_SetPreset( idsp_room, iroom );
- - ipset_room_prev = iroom;
- + DSP_Process( idsp_room, testbuffer, 512 );
- + }
- + end = Sys_DoubleTime();
- - // force room_type = dsp_room
- - Cvar_SetFloat( "room_type", iroom );
- - ipset_room_typeprev = iroom;
- + MsgDev( D_INFO, "----------\nTook %g seconds.\n", end - start );
- +
- + if( Cmd_Argc() > 1 )
- + {
- + Cvar_SetFloat( "room_type", oldroom );
- + SX_ReloadRoomFX();
- + CheckNewDspPresets();
- }
- }
- \ No newline at end of file
- diff --git b/engine/client/s_load.c a/engine/client/s_load.c
- index e9e90ac..0a0ed45 100644
- --- b/engine/client/s_load.c
- +++ a/engine/client/s_load.c
- @@ -68,8 +68,8 @@ void S_SoundList_f( void )
- // return true if char 'c' is one of 1st 2 characters in pch
- qboolean S_TestSoundChar( const char *pch, char c )
- {
- - int i;
- char *pcht = (char *)pch;
- + int i;
- if( !pch || !*pch )
- return false;
- @@ -141,15 +141,11 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
- if( sc->rate < SOUND_11k ) // some bad sounds
- Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
- -#if SOUND_DMA_SPEED > SOUND_11k
- else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
- Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
- -#endif
- -
- -#if SOUND_DMA_SPEED > SOUND_32k
- else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
- Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
- -#endif
- +
- sfx->cache = sc;
- return sfx->cache;
- @@ -201,9 +197,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
- // 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 )
- {
- diff --git b/engine/client/s_main.c a/engine/client/s_main.c
- index ab9386c..85c71d8 100644
- --- b/engine/client/s_main.c
- +++ a/engine/client/s_main.c
- @@ -20,7 +20,6 @@ GNU General Public License for more details.
- #include "ref_params.h"
- #include "pm_local.h"
- -#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
- #define SND_CLIP_DISTANCE (float)(GI->soundclip_dist)
- dma_t dma;
- @@ -28,6 +27,7 @@ byte *sndpool;
- static soundfade_t soundfade;
- channel_t channels[MAX_CHANNELS];
- sound_t ambient_sfx[NUM_AMBIENTS];
- +rawchan_t *raw_channels[MAX_RAW_CHANNELS];
- qboolean snd_ambient = false;
- listener_t s_listener;
- int total_channels;
- @@ -35,6 +35,7 @@ int soundtime; // sample PAIRS
- int paintedtime; // sample PAIRS
- static int trace_count = 0;
- static int last_trace_chan = 0;
- +static byte s_fatphs[MAX_MAP_LEAFS/8]; // PHS array for snd module
- convar_t *s_volume;
- convar_t *s_musicvolume;
- @@ -51,7 +52,6 @@ convar_t *snd_gain_max;
- convar_t *snd_gain_min;
- convar_t *s_refdist;
- convar_t *s_refdb;
- -convar_t *dsp_off; // set to 1 to disable all dsp processing
- convar_t *s_cull; // cull sounds by geometry
- convar_t *s_test; // cvar for testing new effects
- convar_t *s_phs;
- @@ -356,21 +356,8 @@ already playing.
- channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
- {
- channel_t *ch = NULL;
- - int i, dupe = 0;
- -
- -#if 1
- - // TODO: remove this code when predicting is will be done
- - // check for duplicate sounds
- - for( i = 0; i < total_channels; i++ )
- - {
- - if( channels[i].sfx == sfx && VectorCompare( channels[i].origin, pos ))
- - dupe++;
- - }
- + int i;
- - // check for duplicated static channels (same origin and same sfx)
- - if( dupe > MAX_DUPLICATED_CHANNELS )
- - return NULL;
- -#endif
- // check for replacement sound, or find the best one to replace
- for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ )
- {
- @@ -703,27 +690,26 @@ float SND_GetGain( channel_t *ch, qboolean fplayersound, qboolean flooping, floa
- return gain;
- }
- +/*
- +=================
- +SND_CheckPHS
- +
- +using a 'fat' radius
- +=================
- +*/
- qboolean SND_CheckPHS( channel_t *ch )
- {
- mleaf_t *leaf;
- - int leafnum;
- - byte *mask = NULL;
- - // cull sounds by PHS
- - if( !s_phs->integer )
- - return true;
- + if( !ch->dist_mult || !s_phs->integer )
- + return true; // no attenuation
- leaf = Mod_PointInLeaf( ch->origin, cl.worldmodel->nodes );
- - mask = Mod_LeafPHS( leaf, cl.worldmodel );
- - if( mask )
- - {
- - leafnum = Mod_PointLeafnum( s_listener.origin ) - 1;
- + if( CHECKVISBIT( s_listener.pasbytes, leaf->cluster ))
- + return true;
- - if( leafnum != -1 && (!(mask[leafnum>>3] & (1<<( leafnum & 7 )))))
- - return false;
- - }
- - return true;
- + return false;
- }
- /*
- @@ -1369,7 +1355,7 @@ void S_UpdateAmbientSounds( void )
- if( !chan->sfx ) continue;
- vol = s_ambient_level->value * leaf->ambient_sound_level[ambient_channel];
- - if( vol < 8 ) vol = 0;
- + if( vol < 0 ) vol = 0;
- // don't adjust volume too fast
- if( chan->master_vol < vol )
- @@ -1388,13 +1374,369 @@ void S_UpdateAmbientSounds( void )
- }
- /*
- +=============================================================================
- +
- + SOUND STREAM RAW SAMPLES
- +
- +=============================================================================
- +*/
- +/*
- +===================
- +S_FindRawChannel
- +===================
- +*/
- +rawchan_t *S_FindRawChannel( int entnum, qboolean create )
- +{
- + int i, free;
- + int best, best_time;
- + size_t raw_samples = 0;
- + rawchan_t *ch;
- +
- + if( !entnum ) return NULL; // world is unused
- +
- + // check for replacement sound, or find the best one to replace
- + best_time = 0x7fffffff;
- + best = free = -1;
- +
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + ch = raw_channels[i];
- +
- + if( free < 0 && !ch )
- + {
- + free = i;
- + }
- + else if( ch )
- + {
- + int time;
- +
- + // exact match
- + if( ch->entnum == entnum )
- + return ch;
- +
- + time = ch->s_rawend - paintedtime;
- + if( time < best_time )
- + {
- + best = i;
- + best_time = time;
- + }
- + }
- + }
- +
- + if( !create ) return NULL;
- +
- + if( free >= 0 ) best = free;
- + if( best < 0 ) return NULL; // no free slots
- +
- + if( !raw_channels[best] )
- + {
- + raw_samples = MAX_RAW_SAMPLES;
- + raw_channels[best] = Mem_Alloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * ( raw_samples - 1 ));
- + }
- +
- + ch = raw_channels[best];
- + ch->max_samples = raw_samples;
- + ch->entnum = entnum;
- + ch->s_rawend = 0;
- +
- + return ch;
- +}
- +
- +/*
- +===================
- +S_RawSamplesStereo
- +===================
- +*/
- +static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
- +{
- + uint fracstep, samplefrac;
- + uint src, dst;
- +
- + if( rawend < paintedtime )
- + rawend = paintedtime;
- +
- + fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS);
- + samplefrac = 0;
- +
- + if( width == 2 )
- + {
- + const short *in = (const short *)data;
- +
- + if( channels == 2 )
- + {
- + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
- + {
- + dst = rawend++ & ( max_samples - 1 );
- + rawsamples[dst].left = in[src*2+0];
- + rawsamples[dst].right = in[src*2+1];
- + }
- + }
- + else
- + {
- + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
- + {
- + dst = rawend++ & ( max_samples - 1 );
- + rawsamples[dst].left = in[src];
- + rawsamples[dst].right = in[src];
- + }
- + }
- + }
- + else
- + {
- + if( channels == 2 )
- + {
- + const char *in = (const char *)data;
- +
- + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
- + {
- + dst = rawend++ & ( max_samples - 1 );
- + rawsamples[dst].left = in[src*2+0] << 8;
- + rawsamples[dst].right = in[src*2+1] << 8;
- + }
- + }
- + else
- + {
- + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
- + {
- + dst = rawend++ & ( max_samples - 1 );
- + rawsamples[dst].left = ( data[src] - 128 ) << 8;
- + rawsamples[dst].right = ( data[src] - 128 ) << 8;
- + }
- + }
- + }
- +
- + return rawend;
- +}
- +
- +/*
- +===================
- +S_RawEntSamples
- +===================
- +*/
- +static void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
- +{
- + rawchan_t *ch;
- +
- + if( snd_vol < 0 )
- + snd_vol = 0;
- +
- + if( !( ch = S_FindRawChannel( entnum, true )))
- + return;
- +
- + ch->master_vol = snd_vol;
- + ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE);
- + ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
- + ch->leftvol = ch->rightvol = snd_vol;
- +}
- +
- +/*
- +===================
- +S_RawSamples
- +===================
- +*/
- +void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum )
- +{
- + int snd_vol;
- +
- + if( entnum < 0 ) snd_vol = 128; // bg track or movie track
- + if( snd_vol < 0 ) snd_vol = 0; // fixup negative values
- +
- + S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
- +}
- +
- +/*
- +===================
- +S_PositionedRawSamples
- +===================
- +*/
- +static void S_PositionedRawSamples( int entnum, float fvol, float attn, uint samples, uint rate, word width, word channels, const byte *data )
- +{
- + rawchan_t *ch;
- +
- + if( entnum < 0 || entnum >= GI->max_edicts )
- + return;
- +
- + if( !( ch = S_FindRawChannel( entnum, true )))
- + return;
- +
- + ch->master_vol = bound( 0, fvol * 255, 255 );
- + ch->dist_mult = (attn / SND_CLIP_DISTANCE);
- + ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
- +}
- +
- +/*
- +===================
- +S_GetRawSamplesLength
- +===================
- +*/
- +uint S_GetRawSamplesLength( int entnum )
- +{
- + rawchan_t *ch;
- +
- + if( !( ch = S_FindRawChannel( entnum, false )))
- + return 0;
- +
- + return ch->s_rawend <= paintedtime ? 0 : (float)(ch->s_rawend - paintedtime) * DMA_MSEC_PER_SAMPLE;
- +}
- +
- +/*
- +===================
- +S_ClearRawChannel
- +===================
- +*/
- +void S_ClearRawChannel( int entnum )
- +{
- + rawchan_t *ch;
- +
- + if( !( ch = S_FindRawChannel( entnum, false )))
- + return;
- +
- + ch->s_rawend = 0;
- +}
- +
- +/*
- +===================
- +S_FreeIdleRawChannels
- +
- +Free raw channel that have been idling for too long.
- +===================
- +*/
- +static void S_FreeIdleRawChannels( void )
- +{
- + int i;
- +
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + rawchan_t *ch = raw_channels[i];
- +
- + if( !ch ) continue;
- +
- + if( ch->s_rawend >= paintedtime )
- + continue;
- +
- + if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
- + {
- + raw_channels[i] = NULL;
- + Mem_Free( ch );
- + }
- + }
- +}
- +
- +/*
- +===================
- +S_ClearRawChannels
- +===================
- +*/
- +static void S_ClearRawChannels( void )
- +{
- + int i;
- +
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + rawchan_t *ch = raw_channels[i];
- +
- + if( !ch ) continue;
- + ch->s_rawend = 0;
- + }
- +}
- +
- +/*
- +===================
- +S_SpatializeRawChannels
- +===================
- +*/
- +static void S_SpatializeRawChannels( void )
- +{
- + int i;
- +
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + rawchan_t *ch = raw_channels[i];
- + vec3_t source_vec;
- + float dist, dot;
- +
- + if( !ch ) continue;
- +
- + if( ch->s_rawend < paintedtime )
- + {
- + ch->leftvol = ch->rightvol = 0;
- + continue;
- + }
- +
- + // spatialization
- + if( !S_IsClient( ch->entnum ) && ch->dist_mult && ch->entnum >= 0 && ch->entnum < GI->max_edicts )
- + {
- + if( !CL_GetEntitySpatialization( ch->entnum, ch->origin, &ch->radius ))
- + {
- + // origin is null and entity not exist on client
- + ch->leftvol = ch->rightvol = 0;
- + }
- + else
- + {
- + VectorSubtract( ch->origin, s_listener.origin, source_vec );
- +
- + // normalize source_vec and get distance from listener to source
- + dist = VectorNormalizeLength( source_vec );
- + dot = DotProduct( s_listener.right, source_vec );
- +
- + // for sounds with a radius, spatialize left/right evenly within the radius
- + if( ch->radius > 0 && dist < ch->radius )
- + {
- + float interval = ch->radius * 0.5f;
- + float blend = dist - interval;
- +
- + if( blend < 0 ) blend = 0;
- + blend /= interval;
- +
- + // blend is 0.0 - 1.0, from 50% radius -> 100% radius
- + // at radius * 0.5, dot is 0 (ie: sound centered left/right)
- + // at radius dot == dot
- + dot *= blend;
- + }
- +
- + // don't pan sounds with no attenuation
- + if( ch->dist_mult <= 0.0f ) dot = 0.0f;
- +
- + // fill out channel volumes for single location
- + S_SpatializeChannel( &ch->leftvol, &ch->rightvol, ch->master_vol, 1.0f, dot, dist * ch->dist_mult );
- + }
- + }
- + else
- + {
- + ch->leftvol = ch->rightvol = ch->master_vol;
- + }
- + }
- +}
- +
- +/*
- +===================
- +S_FreeRawChannels
- +===================
- +*/
- +static void S_FreeRawChannels( void )
- +{
- + int i;
- +
- + // free raw samples
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + if( raw_channels[i] )
- + Mem_Free( raw_channels[i] );
- + }
- +
- + memset( raw_channels, 0, sizeof( raw_channels ));
- +}
- +
- +//=============================================================================
- +
- +/*
- ==================
- S_ClearBuffer
- ==================
- */
- void S_ClearBuffer( void )
- {
- - s_rawend = 0;
- + S_ClearRawChannels();
- SNDDMA_BeginPainting ();
- if( dma.buffer ) memset( dma.buffer, 0, dma.samples * 2 );
- @@ -1520,6 +1862,9 @@ void S_RenderFrame( ref_params_t *fd )
- // update any client side sound fade
- S_UpdateSoundFade();
- + // release raw-channels that no longer used more than 10 secs
- + S_FreeIdleRawChannels();
- +
- s_listener.entnum = fd->viewentity; // can be camera entity too
- s_listener.frametime = fd->frametime;
- s_listener.waterlevel = fd->waterlevel;
- @@ -1531,6 +1876,9 @@ void S_RenderFrame( ref_params_t *fd )
- VectorCopy( fd->simvel, s_listener.velocity );
- AngleVectors( fd->viewangles, s_listener.forward, s_listener.right, s_listener.up );
- + if( cl.worldmodel != NULL )
- + Mod_FatPVS( s_listener.origin, FATPHS_RADIUS, s_listener.pasbytes, world.visbytes, false, !s_phs->integer );
- +
- // update general area ambient sound sources
- S_UpdateAmbientSounds();
- @@ -1585,6 +1933,8 @@ void S_RenderFrame( ref_params_t *fd )
- }
- }
- + S_SpatializeRawChannels();
- +
- // debugging output
- if( s_show->value )
- {
- @@ -1605,11 +1955,16 @@ void S_RenderFrame( ref_params_t *fd )
- }
- // to differentiate modes
- - if( s_cull->integer ) VectorSet( info.color, 0.0f, 1.0f, 0.0f );
- + if( s_cull->integer && s_phs->integer )
- + VectorSet( info.color, 0.0f, 1.0f, 0.0f );
- + else if( s_phs->integer )
- + VectorSet( info.color, 1.0f, 1.0f, 0.0f );
- + else if( s_cull->integer )
- + VectorSet( info.color, 1.0f, 0.0f, 0.0f );
- else VectorSet( info.color, 1.0f, 1.0f, 1.0f );
- info.index = 0;
- - Con_NXPrintf( &info, "----(%i)---- painted: %i\n", total - 1, paintedtime );
- + Con_NXPrintf( &info, "room_type: %i ----(%i)---- painted: %i\n", idsp_room, total - 1, paintedtime );
- }
- S_StreamBackgroundTrack ();
- @@ -1773,9 +2128,8 @@ qboolean S_Init( void )
- s_mixahead = Cvar_Get( "_snd_mixahead", "0.12", 0, "how much sound to mix ahead of time" );
- s_show = Cvar_Get( "s_show", "0", CVAR_ARCHIVE, "show playing sounds" );
- s_lerping = Cvar_Get( "s_lerping", "0", CVAR_ARCHIVE, "apply interpolation to sound output" );
- - dsp_off = Cvar_Get( "dsp_off", "0", CVAR_ARCHIVE, "set to 1 to disable all dsp processing" );
- - s_ambient_level = Cvar_Get( "ambient_level", "0.3", 0, "volume of environment noises (water and wind)" );
- - s_ambient_fade = Cvar_Get( "ambient_fade", "100", 0, "rate of volume fading when client is moving" );
- + s_ambient_level = Cvar_Get( "ambient_level", "0.3", CVAR_ARCHIVE, "volume of environment noises (water and wind)" );
- + s_ambient_fade = Cvar_Get( "ambient_fade", "1000", CVAR_ARCHIVE, "rate of volume fading when client is moving" );
- s_combine_sounds = Cvar_Get( "s_combine_channels", "1", CVAR_ARCHIVE, "combine channels with same sounds" );
- snd_foliage_db_loss = Cvar_Get( "snd_foliage_db_loss", "4", 0, "foliage loss factor" );
- snd_gain_max = Cvar_Get( "snd_gain_max", "1", 0, "gain maximal threshold" );
- @@ -1836,10 +2190,11 @@ void S_Shutdown( void )
- Cmd_RemoveCommand( "s_info" );
- Cmd_RemoveCommand( "+voicerecord" );
- Cmd_RemoveCommand( "-voicerecord" );
- - Cmd_RemoveCommand( "spk" );
- Cmd_RemoveCommand( "speak" );
- + Cmd_RemoveCommand( "spk" );
- S_StopAllSounds ();
- + S_FreeRawChannels ();
- S_FreeSounds ();
- VOX_Shutdown ();
- FreeDsps ();
- diff --git b/engine/client/s_mix.c a/engine/client/s_mix.c
- index 9a4a899..a902fcc 100644
- --- b/engine/client/s_mix.c
- +++ a/engine/client/s_mix.c
- @@ -216,8 +216,8 @@ CHANNEL MIXING
- */
- void S_PaintMonoFrom8( portable_samplepair_t *pbuf, int *volume, byte *pData, int outCount )
- {
- - int i, data;
- int *lscale, *rscale;
- + int i, data;
- lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
- rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
- @@ -252,8 +252,8 @@ void S_PaintStereoFrom8( portable_samplepair_t *pbuf, int *volume, byte *pData,
- void S_PaintMonoFrom16( portable_samplepair_t *pbuf, int *volume, short *pData, int outCount )
- {
- - int i, data;
- int left, right;
- + int i, data;
- for( i = 0; i < outCount; i++ )
- {
- @@ -473,20 +473,13 @@ int S_MixDataToDevice( channel_t *pChannel, int sampleCount, int outputRate, int
- for( i = 0; i < CPAINTBUFFERS; i++ )
- {
- - if( paintbuffers[i].factive )
- - {
- - // mix chan into all active paintbuffers
- - MIX_SetCurrentPaintbuffer( i );
- -
- - S_MixChannel(
- - pChannel, // Channel.
- - pData, // Input buffer.
- - outputOffset, // Output position.
- - FIX_FLOAT( sampleFraction ), // Iterators.
- - FIX_FLOAT( rate ),
- - outputSampleCount
- - );
- - }
- + if( !paintbuffers[i].factive )
- + continue;
- +
- + // mix chan into all active paintbuffers
- + MIX_SetCurrentPaintbuffer( i );
- +
- + S_MixChannel( pChannel, pData, outputOffset, FIX_FLOAT( sampleFraction ), FIX_FLOAT( rate ), outputSampleCount );
- }
- MIX_SetCurrentPaintbuffer( j );
- @@ -692,7 +685,7 @@ void S_Interpolate2xCubic( portable_samplepair_t *pbuffer, portable_samplepair_t
- {
- // get source sample pointer
- psamp0 = S_GetNextpFilter( i-1, pbuffer, pfiltermem );
- - psamp1 = S_GetNextpFilter( i, pbuffer, pfiltermem );
- + psamp1 = S_GetNextpFilter( i+0, pbuffer, pfiltermem );
- psamp2 = S_GetNextpFilter( i+1, pbuffer, pfiltermem );
- psamp3 = S_GetNextpFilter( i+2, pbuffer, pfiltermem );
- @@ -778,9 +771,9 @@ void S_Interpolate2xLinear( portable_samplepair_t *pbuffer, portable_samplepair_
- // filtertype: FILTERTYPE_NONE, _LINEAR, _CUBIC etc. Must match prevfilter.
- void S_MixBufferUpsample2x( int count, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem, int filtertype )
- {
- - int i, j;
- int upCount = count<<1;
- -
- + int i, j;
- +
- // reverse through buffer, duplicating contents for 'count' samples
- for( i = upCount - 1, j = count - 1; j >= 0; i-=2, j-- )
- {
- @@ -893,57 +886,16 @@ void S_MixUpsample( int sampleCount, int filtertype )
- ppaint->ifilter++;
- }
- -// mix and upsample channels to 44khz 'ipaintbuffer'
- -// mix channels matching 'flags' (SOUND_MIX_DRY or SOUND_MIX_WET) into specified paintbuffer
- -// upsamples 11khz, 22khz channels to 44khz.
- -
- -// NOTE: only call this on channels that will be mixed into only 1 paintbuffer
- -// and that will not be mixed until the next mix pass! otherwise, MIX_MixChannelsToPaintbuffer
- -// will advance any internal pointers on mixed channels; subsequent calls will be at
- -// incorrect offset.
- -void MIX_MixUpsampleBuffer( int ipaintbuffer, int end, int count )
- -{
- - int ipaintcur = MIX_GetCurrentPaintbufferIndex(); // save current paintbuffer
- -
- - // reset paintbuffer upsampling filter index
- - MIX_ResetPaintbufferFilterCounter( ipaintbuffer );
- -
- - // prevent other paintbuffers from being mixed
- - MIX_DeactivateAllPaintbuffers();
- -
- - MIX_ActivatePaintbuffer( ipaintbuffer ); // operates on MIX_MixChannelsToPaintbuffer
- - MIX_SetCurrentPaintbuffer( ipaintbuffer ); // operates on MixUpSample
- -
- - // mix 11khz channels to buffer
- - MIX_MixChannelsToPaintbuffer( end, SOUND_11k, SOUND_11k );
- -
- - // upsample 11khz buffer by 2x
- - S_MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
- -
- - // mix 22khz channels to buffer
- - MIX_MixChannelsToPaintbuffer( end, SOUND_22k, SOUND_22k );
- -
- - // upsample 22khz buffer by 2x
- -#if (SOUND_DMA_SPEED > SOUND_22k)
- - S_MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
- -#endif
- - // mix 44khz channels to buffer
- - MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED );
- -
- - MIX_DeactivateAllPaintbuffers();
- -
- - // restore previous paintbuffer
- - MIX_SetCurrentPaintbuffer( ipaintcur );
- -}
- -
- void MIX_MixStreamBuffer( int end )
- {
- portable_samplepair_t *pbuf;
- + rawchan_t *ch;
- pbuf = MIX_GetPFrontFromIPaint( ISTREAMBUFFER );
- + ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, false );
- // clear the paint buffer
- - if( s_listener.paused || s_rawend < paintedtime )
- + if( s_listener.paused || !ch || ch->s_rawend < paintedtime )
- {
- memset( pbuf, 0, (end - paintedtime) * sizeof( portable_samplepair_t ));
- }
- @@ -952,18 +904,54 @@ void MIX_MixStreamBuffer( int end )
- int i, stop;
- // copy from the streaming sound source
- - stop = (end < s_rawend) ? end : s_rawend;
- + stop = (end < ch->s_rawend) ? end : ch->s_rawend;
- for( i = paintedtime; i < stop; i++ )
- - pbuf[i - paintedtime] = s_rawsamples[i & (MAX_RAW_SAMPLES - 1)];
- -
- + {
- + pbuf[i-paintedtime].left = ( ch->rawsamples[i & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
- + pbuf[i-paintedtime].right = ( ch->rawsamples[i & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
- + }
- +
- for( ; i < end; i++ )
- pbuf[i-paintedtime].left = pbuf[i-paintedtime].right = 0;
- }
- }
- +void MIX_MixRawSamplesBuffer( int end )
- +{
- + portable_samplepair_t *pbuf;
- + uint i, j, stop;
- +
- + pbuf = MIX_GetCurrentPaintbufferPtr()->pbuf;
- +
- + if( s_listener.paused ) return;
- +
- + // paint in the raw channels
- + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
- + {
- + // copy from the streaming sound source
- + rawchan_t *ch = raw_channels[i];
- +
- + // background track should be mixing into another buffer
- + if( !ch || ch->entnum == S_RAW_SOUND_BACKGROUNDTRACK )
- + continue;
- +
- + // not audible
- + if( !ch->leftvol && !ch->rightvol )
- + continue;
- +
- + stop = (end < ch->s_rawend) ? end : ch->s_rawend;
- +
- + for( j = paintedtime; j < stop; j++ )
- + {
- + pbuf[j-paintedtime].left += ( ch->rawsamples[j & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
- + pbuf[j-paintedtime].right += ( ch->rawsamples[j & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
- + }
- + }
- +}
- +
- // upsample and mix sounds into final 44khz versions of:
- -// IROOMBUFFER, IFACINGBUFFER, IFACINGAWAY, IDRYBUFFER
- +// IROOMBUFFER, IFACINGBUFFER, IFACINGAWAY
- // dsp fx are then applied to these buffers by the caller.
- // caller also remixes all into final IPAINTBUFFER output.
- void MIX_UpsampleAllPaintbuffers( int end, int count )
- @@ -1000,14 +988,17 @@ void MIX_UpsampleAllPaintbuffers( int end, int count )
- MIX_MixChannelsToPaintbuffer( end, SOUND_22k, SOUND_22k );
- // upsample all 22khz buffers by 2x
- -#if (SOUND_DMA_SPEED > SOUND_22k)
- // only upsample roombuffer if dsp fx are on KDB: perf
- MIX_SetCurrentPaintbuffer( IROOMBUFFER );
- S_MixUpsample( count / ( SOUND_DMA_SPEED / SOUND_22k ), FILTERTYPE_LINEAR );
- -#endif
- +
- // mix all 44khz sounds to all active paintbuffers
- MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED );
- + // mix raw samples from the video streams
- + MIX_SetCurrentPaintbuffer( IROOMBUFFER );
- + MIX_MixRawSamplesBuffer( end );
- +
- MIX_DeactivateAllPaintbuffers();
- MIX_SetCurrentPaintbuffer( IPAINTBUFFER );
- }
- diff --git b/engine/client/s_mouth.c a/engine/client/s_mouth.c
- index 41b88ea..c242f8b 100644
- --- b/engine/client/s_mouth.c
- +++ a/engine/client/s_mouth.c
- @@ -32,8 +32,8 @@ void SND_InitMouth( int entnum, int entchannel )
- if( clientEntity )
- {
- clientEntity->mouth.mouthopen = 0;
- - clientEntity->mouth.sndavg = 0;
- clientEntity->mouth.sndcount = 0;
- + clientEntity->mouth.sndavg = 0;
- }
- }
- }
- @@ -59,8 +59,8 @@ void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count )
- cl_entity_t *clientEntity;
- char *pdata = NULL;
- mouth_t *pMouth = NULL;
- - int savg, data;
- int scount, pos = 0;
- + int savg, data;
- uint i;
- clientEntity = CL_GetEntityByIndex( ch->entnum );
- diff --git b/engine/client/s_stream.c a/engine/client/s_stream.c
- index 2be6e30..84886d8 100644
- --- b/engine/client/s_stream.c
- +++ a/engine/client/s_stream.c
- @@ -17,11 +17,14 @@ GNU General Public License for more details.
- #include "sound.h"
- #include "client.h"
- -portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
- static bg_track_t s_bgTrack;
- static musicfade_t musicfade; // controlled by game dlls
- -int s_rawend;
- +/*
- +=================
- +S_PrintBackgroundTrackState
- +=================
- +*/
- void S_PrintBackgroundTrackState( void )
- {
- if( s_bgTrack.current[0] && s_bgTrack.loopName[0] )
- @@ -32,18 +35,6 @@ void S_PrintBackgroundTrackState( void )
- Msg( "BackgroundTrack: %s [loop]\n", s_bgTrack.loopName );
- }
- -void S_CheckLerpingState( void )
- -{
- - wavdata_t *info;
- -
- - s_listener.lerping = false;
- - if( !s_bgTrack.stream ) return;
- - info = FS_StreamInfo( s_bgTrack.stream );
- -
- - if( info && ((float)info->rate / SOUND_DMA_SPEED ) >= 1.0f )
- - s_listener.lerping = s_lerping->integer;
- -}
- -
- /*
- =================
- S_FadeMusicVolume
- @@ -68,6 +59,7 @@ float S_GetMusicVolume( void )
- scale = bound( 0.0f, musicfade.percent / 100.0f, 1.0f );
- scale = 1.0f - scale;
- }
- +
- return s_musicvolume->value * scale;
- }
- @@ -109,10 +101,13 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long
- // restore message, update song position
- FS_SetStreamPos( s_bgTrack.stream, position );
- }
- -
- - S_CheckLerpingState();
- }
- +/*
- +=================
- +S_StopBackgroundTrack
- +=================
- +*/
- void S_StopBackgroundTrack( void )
- {
- s_listener.stream_paused = false;
- @@ -123,10 +118,13 @@ void S_StopBackgroundTrack( void )
- FS_FreeStream( s_bgTrack.stream );
- memset( &s_bgTrack, 0, sizeof( bg_track_t ));
- memset( &musicfade, 0, sizeof( musicfade ));
- - s_listener.lerping = false;
- - s_rawend = 0;
- }
- +/*
- +=================
- +S_StreamSetPause
- +=================
- +*/
- void S_StreamSetPause( int pause )
- {
- s_listener.stream_paused = pause;
- @@ -175,10 +173,10 @@ void S_StreamBackgroundTrack( void )
- int fileSamples;
- byte raw[MAX_RAW_SAMPLES];
- int r, fileBytes;
- + rawchan_t *ch = NULL;
- - if( !dma.initialized ) return;
- - if( !s_bgTrack.stream ) return;
- - if( s_listener.streaming ) return; // we are playing movie or somewhat
- + 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 )
- @@ -193,15 +191,19 @@ void S_StreamBackgroundTrack( void )
- 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( s_rawend < soundtime )
- - s_rawend = soundtime;
- + if( ch->s_rawend < soundtime )
- + ch->s_rawend = soundtime;
- - while( s_rawend < soundtime + MAX_RAW_SAMPLES )
- + while( ch->s_rawend < soundtime + ch->max_samples )
- {
- wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
- - bufferSamples = MAX_RAW_SAMPLES - (s_rawend - soundtime);
- + 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 );
- @@ -228,7 +230,7 @@ void S_StreamBackgroundTrack( void )
- if( r > 0 )
- {
- // add to raw buffer
- - S_StreamRawSamples( fileSamples, info->rate, info->width, info->channels, raw );
- + S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_BACKGROUNDTRACK );
- }
- else
- {
- @@ -240,7 +242,6 @@ void S_StreamBackgroundTrack( void )
- Q_strncpy( s_bgTrack.current, s_bgTrack.loopName, sizeof( s_bgTrack.current ));
- if( !s_bgTrack.stream ) return;
- - S_CheckLerpingState();
- }
- else
- {
- @@ -262,7 +263,6 @@ void S_StartStreaming( void )
- if( !dma.initialized ) return;
- // begin streaming movie soundtrack
- s_listener.streaming = true;
- - s_listener.lerping = false;
- }
- /*
- @@ -274,8 +274,6 @@ void S_StopStreaming( void )
- {
- if( !dma.initialized ) return;
- s_listener.streaming = false;
- - s_listener.lerping = false;
- - s_rawend = 0;
- }
- /*
- @@ -289,19 +287,26 @@ void S_StreamSoundTrack( void )
- int fileSamples;
- byte raw[MAX_RAW_SAMPLES];
- int r, fileBytes;
- + rawchan_t *ch = NULL;
- - if( !dma.initialized ) return;
- - if( !s_listener.streaming || s_listener.paused ) return;
- + 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( s_rawend < soundtime )
- - s_rawend = soundtime;
- + if( ch->s_rawend < soundtime )
- + ch->s_rawend = soundtime;
- - while( s_rawend < soundtime + MAX_RAW_SAMPLES )
- + while( ch->s_rawend < soundtime + ch->max_samples )
- {
- wavdata_t *info = SCR_GetMovieInfo();
- - bufferSamples = MAX_RAW_SAMPLES - (s_rawend - soundtime);
- + 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 );
- @@ -328,68 +333,8 @@ void S_StreamSoundTrack( void )
- if( r > 0 )
- {
- // add to raw buffer
- - S_StreamRawSamples( fileSamples, info->rate, info->width, info->channels, raw );
- + S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_SOUNDTRACK );
- }
- else break; // no more samples for this frame
- }
- -}
- -
- -/*
- -============
- -S_StreamRawSamples
- -
- -Cinematic streaming and voice over network
- -============
- -*/
- -void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data )
- -{
- - int i, a, b, src, dst;
- - int fracstep, samplefrac;
- - int incount, outcount;
- -
- - src = 0;
- - samplefrac = 0;
- - fracstep = (((double)rate) / (double)SOUND_DMA_SPEED) * 256.0;
- - outcount = (double)samples * (double)SOUND_DMA_SPEED / (double)rate;
- - incount = samples * channels;
- -
- -#define TAKE_SAMPLE( s ) (sizeof(*in) == 1 ? (a = (in[src+(s)]-128)<<8,\
- - b = (src < incount - channels) ? (in[src+channels+(s)]-128)<<8 : 128) : \
- - (a = in[src+(s)],\
- - b = (src < incount - channels) ? (in[src+channels+(s)]) : 0))
- -
- - // NOTE: disable lerping for cinematic sountracks
- -#define LERP_SAMPLE s_listener.lerping ? (((((b - a) * (samplefrac & 255)) >> 8) + a)) : a
- -
- -#define RESAMPLE_RAW \
- - if( channels == 2 ) { \
- - for( i = 0; i < outcount; i++, samplefrac += fracstep, src = (samplefrac >> 8) << 1 ) { \
- - dst = s_rawend++ & (MAX_RAW_SAMPLES - 1); \
- - TAKE_SAMPLE(0); \
- - s_rawsamples[dst].left = LERP_SAMPLE; \
- - TAKE_SAMPLE(1); \
- - s_rawsamples[dst].right = LERP_SAMPLE; \
- - } \
- - } else { \
- - for( i = 0; i < outcount; i++, samplefrac += fracstep, src = (samplefrac >> 8) << 0 ) { \
- - dst = s_rawend++ & (MAX_RAW_SAMPLES - 1); \
- - TAKE_SAMPLE(0); \
- - s_rawsamples[dst].left = LERP_SAMPLE; \
- - s_rawsamples[dst].right = s_rawsamples[dst].left; \
- - } \
- - }
- -
- - if( s_rawend < paintedtime )
- - s_rawend = paintedtime;
- -
- - if( width == 2 )
- - {
- - short *in = (short *)data;
- - RESAMPLE_RAW
- - }
- - else
- - {
- - byte *in = (unsigned char *)data;
- - RESAMPLE_RAW
- - }
- }
- \ No newline at end of file
- diff --git b/engine/client/s_utils.c a/engine/client/s_utils.c
- index 8e065cb..24c046c 100644
- --- b/engine/client/s_utils.c
- +++ a/engine/client/s_utils.c
- @@ -35,7 +35,7 @@ float S_SimpleSpline( float value )
- float valueSquared = value * value;
- // nice little ease-in, ease-out spline-like curve
- - return (3 * valueSquared - 2 * valueSquared * value);
- + return (3.0f * valueSquared - 2.0f * valueSquared * value);
- }
- //-----------------------------------------------------------------------------
- diff --git b/engine/client/s_vox.c a/engine/client/s_vox.c
- index 2601301..8889d45 100644
- --- b/engine/client/s_vox.c
- +++ a/engine/client/s_vox.c
- @@ -383,17 +383,17 @@ void VOX_FreeWord( channel_t *pchan )
- pchan->currentWord = NULL; // sentence is finished
- memset( &pchan->pMixer, 0, sizeof( pchan->pMixer ));
- -#if 0 // release unused sounds ?
- + // 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 )
- {
- - S_FreeSound( pchan->words[pchan->wordIndex].sfx );
- + FS_FreeSound( pchan->words[pchan->wordIndex].sfx->cache );
- + pchan->words[pchan->wordIndex].sfx->cache = NULL;
- pchan->words[pchan->wordIndex].sfx = NULL;
- }
- }
- -#endif
- }
- void VOX_LoadFirstWord( channel_t *pchan, voxword_t *pwords )
- diff --git b/engine/client/sound.h a/engine/client/sound.h
- index e69f736..23479f9 100644
- --- b/engine/client/sound.h
- +++ a/engine/client/sound.h
- @@ -20,17 +20,14 @@ extern byte *sndpool;
- #include "mathlib.h"
- -// local flags (never sending acorss the net)
- -#define SND_LOCALSOUND (1<<9) // not paused, not looped, for internal use
- -#define SND_STOP_LOOPING (1<<10) // stop all looping sounds on the entity.
- -
- // 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 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
- @@ -50,14 +47,14 @@ extern byte *sndpool;
- #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 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 )
- @@ -66,26 +63,30 @@ extern byte *sndpool;
- (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
- +#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 )
- -typedef struct
- -{
- - int left;
- - int right;
- -} portable_samplepair_t;
- +#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
- @@ -104,7 +105,6 @@ typedef struct sfx_s
- struct sfx_s *hashNext;
- } sfx_t;
- -extern portable_samplepair_t drybuffer[];
- extern portable_samplepair_t paintbuffer[];
- extern portable_samplepair_t roombuffer[];
- extern portable_samplepair_t temppaintbuffer[];
- @@ -146,6 +146,20 @@ typedef struct
- qboolean finished;
- } mixer_t;
- +typedef struct
- +{
- + 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
- @@ -196,8 +210,9 @@ typedef struct
- qboolean inmenu; // listener in-menu ?
- qboolean paused;
- qboolean streaming; // playing AVI-file
- - qboolean lerping; // lerp stream ?
- qboolean stream_paused; // pause only background track
- +
- + byte pasbytes[(MAX_MAP_LEAFS+7)/8];// actual PHS for current frame
- } listener_t;
- typedef struct
- @@ -226,18 +241,19 @@ void SNDDMA_Submit( void );
- #define MAX_DYNAMIC_CHANNELS (28 + NUM_AMBIENTS)
- #define MAX_CHANNELS (128 + 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 s_rawend;
- extern int soundtime;
- -extern dma_t dma;
- extern listener_t s_listener;
- extern int idsp_room;
- +extern dma_t dma;
- extern convar_t *s_volume;
- extern convar_t *s_musicvolume;
- @@ -245,10 +261,7 @@ 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;
- -extern convar_t *s_phs;
- -
- -extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
- +extern convar_t *s_test; // cvar to testify new effects
- void S_InitScaletable( void );
- wavdata_t *S_LoadSound( sfx_t *sfx );
- @@ -296,7 +309,11 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos );
- 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( void );
- void S_FreeSounds( void );
- diff --git b/engine/client/vgui/utlvector.h a/engine/client/vgui/utlvector.h
- index 86554e3..4bbaac5 100644
- --- b/engine/client/vgui/utlvector.h
- +++ a/engine/client/vgui/utlvector.h
- @@ -332,7 +332,7 @@ void CUtlVector<T>::ShiftElementsLeft( int elem, int num )
- memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
- #ifdef _DEBUG
- - Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
- + memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
- #endif
- }
- }
- diff --git b/engine/client/vgui/vgui_draw.c a/engine/client/vgui/vgui_draw.c
- index 2afaa8d..3eca12e 100644
- --- b/engine/client/vgui/vgui_draw.c
- +++ a/engine/client/vgui/vgui_draw.c
- @@ -32,7 +32,7 @@ Startup VGUI backend
- */
- void VGUI_DrawInit( void )
- {
- - Q_memset( g_textures, 0, sizeof( g_textures ));
- + memset( g_textures, 0, sizeof( g_textures ));
- g_textureId = g_iBoundTexture = 0;
- vgui_colorstrings = Cvar_Get( "vgui_colorstrings", "0", CVAR_ARCHIVE, "allow colorstrings in VGUI texts" );
- @@ -65,7 +65,7 @@ generate unique texture number
- int VGUI_GenerateTexture( void )
- {
- if( ++g_textureId >= VGUI_MAX_TEXTURES )
- - Sys_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
- + Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
- return g_textureId;
- }
- @@ -88,7 +88,7 @@ void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
- }
- Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
- - Q_memset( &r_image, 0, sizeof( r_image ));
- + memset( &r_image, 0, sizeof( r_image ));
- r_image.width = width;
- r_image.height = height;
- @@ -98,7 +98,6 @@ void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
- r_image.buffer = (byte *)buffer;
- g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE, false );
- - GL_SetTextureType( g_textures[id], TEX_VGUI );
- g_iBoundTexture = id;
- }
- @@ -121,7 +120,7 @@ void VGUI_CreateTexture( int id, int width, int height )
- }
- Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
- - Q_memset( &r_image, 0, sizeof( r_image ));
- + memset( &r_image, 0, sizeof( r_image ));
- r_image.width = width;
- r_image.height = height;
- @@ -131,7 +130,6 @@ void VGUI_CreateTexture( int id, int width, int height )
- r_image.buffer = NULL;
- g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST, false );
- - GL_SetTextureType( g_textures[id], TEX_VGUI );
- g_iBoundTexture = id;
- }
- @@ -233,7 +231,8 @@ generic method to fill rectangle
- */
- void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
- {
- - ASSERT( ul != NULL && lr != NULL );
- + Assert( ul != NULL );
- + Assert( lr != NULL );
- pglBegin( GL_QUADS );
- pglTexCoord2f( ul->coord[0], ul->coord[1] );
- diff --git b/engine/client/vgui/vgui_draw.h a/engine/client/vgui/vgui_draw.h
- index fa1da80..a40225e 100644
- --- b/engine/client/vgui/vgui_draw.h
- +++ a/engine/client/vgui/vgui_draw.h
- @@ -46,7 +46,7 @@ void VGUI_EnableTexture( qboolean enable );
- void VGUI_CreateTexture( int id, int width, int height );
- void VGUI_UploadTexture( int id, const char *buffer, int width, int height );
- void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight );
- -long VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
- +LONG VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
- void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
- void VGUI_GetTextureSizes( int *width, int *height );
- int VGUI_GenerateTexture( void );
- diff --git b/engine/client/vgui/vgui_input.cpp a/engine/client/vgui/vgui_input.cpp
- index f05ee2f..1ac8e2f 100644
- --- b/engine/client/vgui/vgui_input.cpp
- +++ a/engine/client/vgui/vgui_input.cpp
- @@ -106,7 +106,7 @@ void VGUI_InitKeyTranslationTable( void )
- bInitted = true;
- // set virtual key translation table
- - Q_memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ));
- + memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ));
- s_pVirtualKeyTrans['0'] = KEY_0;
- s_pVirtualKeyTrans['1'] = KEY_1;
- @@ -217,9 +217,9 @@ KeyCode VGUI_MapKey( int keyCode )
- {
- VGUI_InitKeyTranslationTable();
- - if( keyCode < 0 || keyCode >= sizeof( s_pVirtualKeyTrans ) / sizeof( s_pVirtualKeyTrans[0] ))
- + if( keyCode < 0 || keyCode >= ARRAYSIZE( s_pVirtualKeyTrans ))
- {
- - Assert( false );
- + Assert( 0 );
- return (KeyCode)-1;
- }
- else
- @@ -228,7 +228,7 @@ KeyCode VGUI_MapKey( int keyCode )
- }
- }
- -long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- +LONG VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- {
- SurfaceBase *surface = NULL;
- CEnginePanel *panel = NULL;
- @@ -238,11 +238,13 @@ long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- return 0;
- panel = (CEnginePanel *)VGui_GetPanel();
- + ASSERT( panel != NULL );
- +
- surface = panel->getSurfaceBase();
- - pApp = panel->getApp();
- + ASSERT( surface != NULL );
- + pApp = panel->getApp();
- ASSERT( pApp != NULL );
- - ASSERT( surface != NULL );
- switch( uMsg )
- {
- @@ -284,7 +286,7 @@ long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- break;
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- - if(!( lParam & ( 1 << 30 )))
- + if( !FBitSet( lParam, BIT( 30 )))
- pApp->internalKeyPressed( VGUI_MapKey( wParam ), surface );
- pApp->internalKeyTyped( VGUI_MapKey( wParam ), surface );
- break;
- diff --git b/engine/client/vgui/vgui_int.cpp a/engine/client/vgui/vgui_int.cpp
- index a461670..bb30f94 100644
- --- b/engine/client/vgui/vgui_int.cpp
- +++ a/engine/client/vgui/vgui_int.cpp
- @@ -68,7 +68,7 @@ void VGui_Startup( void )
- {
- if( rootpanel )
- {
- - rootpanel->setSize( menu.globals->scrWidth, menu.globals->scrHeight );
- + rootpanel->setSize( gameui.globals->scrWidth, gameui.globals->scrHeight );
- return;
- }
- diff --git b/engine/client/vgui/vgui_main.h a/engine/client/vgui/vgui_main.h
- index 8c354d8..788010b 100644
- --- b/engine/client/vgui/vgui_main.h
- +++ a/engine/client/vgui/vgui_main.h
- @@ -19,6 +19,8 @@ GNU General Public License for more details.
- #include "utlvector.h"
- #include "utlrbtree.h"
- +//#define NEW_VGUI_DLL
- +
- #include<VGUI.h>
- #include<VGUI_App.h>
- #include<VGUI_Font.h>
- @@ -127,6 +129,9 @@ public:
- virtual void setTitle( const char *title ) { }
- virtual void createPopup( Panel* embeddedPanel ) { }
- virtual bool isWithin( int x, int y ) { return true; }
- +#ifdef NEW_VGUI_DLL
- + virtual void GetMousePos( int &x, int &y );
- +#endif
- virtual bool hasFocus( void );
- protected:
- virtual int createNewTextureID( void );
- diff --git b/engine/client/vgui/vgui_surf.cpp a/engine/client/vgui/vgui_surf.cpp
- index d240012..1a73772 100644
- --- b/engine/client/vgui/vgui_surf.cpp
- +++ a/engine/client/vgui/vgui_surf.cpp
- @@ -27,8 +27,8 @@ CEngineSurface :: CEngineSurface( Panel *embeddedPanel ):SurfaceBase( embeddedPa
- _drawTextColor[0] = _drawTextColor[1] = _drawTextColor[2] = _drawTextColor[3] = 255;
- _surfaceExtents[0] = _surfaceExtents[1] = 0;
- - _surfaceExtents[2] = menu.globals->scrWidth;
- - _surfaceExtents[3] = menu.globals->scrHeight;
- + _surfaceExtents[2] = gameui.globals->scrWidth;
- + _surfaceExtents[3] = gameui.globals->scrHeight;
- _drawTextPos[0] = _drawTextPos[1] = 0;
- _hCurrentFont = null;
- @@ -56,6 +56,19 @@ void CEngineSurface :: setCursor( Cursor *cursor )
- VGUI_CursorSelect( cursor );
- }
- +#ifdef NEW_VGUI_DLL
- +void CEngineSurface :: GetMousePos( int &x, int &y )
- +{
- + POINT curpos;
- +
- + GetCursorPos( &curpos );
- + ScreenToClient( host.hWnd, &curpos );
- +
- + x = curpos.x;
- + y = curpos.y;
- +}
- +#endif
- +
- void CEngineSurface :: SetupPaintState( const paintState_t &paintState )
- {
- _translateX = paintState.iTranslateX;
- diff --git b/engine/common/avikit.c a/engine/common/avikit.c
- index 44976c4..c3fc08d 100644
- --- b/engine/common/avikit.c
- +++ a/engine/common/avikit.c
- @@ -139,8 +139,6 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
- dword dest_length;
- short bits;
- - ASSERT( Avi != NULL );
- -
- // WMA codecs, both versions - they simply don't work.
- if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
- {
- @@ -249,8 +247,6 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
- qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration )
- {
- - ASSERT( Avi != NULL );
- -
- if( !Avi->active )
- return false;
- @@ -269,8 +265,6 @@ qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *du
- // returns a unique frame identifier
- long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
- {
- - ASSERT( Avi != NULL );
- -
- if( !Avi->active )
- return 0;
- @@ -284,8 +278,6 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
- byte *frame_raw, *tmp;
- int i;
- - ASSERT( Avi != NULL );
- -
- if( !Avi->active ) return NULL;
- if( frame >= Avi->video_frames )
- @@ -310,8 +302,6 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
- qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
- {
- - ASSERT( Avi != NULL );
- -
- if( !Avi->active || Avi->audio_stream == NULL || snd_info == NULL )
- {
- return false;
- @@ -335,8 +325,6 @@ qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
- {
- int breaker;
- - ASSERT( Avi != NULL );
- -
- if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
- {
- if( Avi->cpa_blockoffset - offset < 500000 )
- @@ -382,12 +370,10 @@ qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
- }
- // get a chunk of audio from the stream (in bytes)
- -fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length )
- +long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length )
- {
- - int i;
- long result = 0;
- -
- - ASSERT( Avi != NULL );
- + int i;
- // zero data past the end of the file
- if( offset + length > Avi->audio_length )
- @@ -457,8 +443,6 @@ fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset,
- void AVI_CloseVideo( movie_state_t *Avi )
- {
- - ASSERT( Avi != NULL );
- -
- if( Avi->active )
- {
- pAVIStreamGetFrameClose( Avi->video_getframe );
- @@ -494,8 +478,6 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
- long opened_streams = 0;
- LONG hr;
- - ASSERT( Avi != NULL );
- -
- // default state: non-working.
- Avi->active = false;
- Avi->quiet = quiet;
- diff --git b/engine/common/build.c a/engine/common/build.c
- index b34aa6a..d227ac7 100644
- --- b/engine/common/build.c
- +++ a/engine/common/build.c
- @@ -48,6 +48,6 @@ int Q_buildnum( void )
- return b;
- #else
- - return 3366;
- + return 3598;
- #endif
- }
- \ No newline at end of file
- diff --git b/engine/common/cmd.c a/engine/common/cmd.c
- index 4ad5be6..c6236e8 100644
- --- b/engine/common/cmd.c
- +++ a/engine/common/cmd.c
- @@ -17,8 +17,8 @@ GNU General Public License for more details.
- #include "client.h"
- #include "server.h"
- -#define MAX_CMD_BUFFER 16384
- -#define MAX_CMD_LINE 1024
- +#define MAX_CMD_BUFFER 32768
- +#define MAX_CMD_LINE 2048
- typedef struct
- {
- @@ -31,6 +31,8 @@ qboolean cmd_wait;
- cmdbuf_t cmd_text;
- byte cmd_text_buf[MAX_CMD_BUFFER];
- cmdalias_t *cmd_alias;
- +uint cmd_condition;
- +int cmd_condlevel;
- /*
- =============================================================================
- @@ -92,17 +94,16 @@ Adds command text at the end of the buffer
- */
- void Cbuf_AddText( const char *text )
- {
- - int l;
- -
- - l = Q_strlen( text );
- + int l = Q_strlen( text );
- if( cmd_text.cursize + l >= cmd_text.maxsize )
- {
- MsgDev( D_WARN, "Cbuf_AddText: overflow\n" );
- - return;
- }
- -
- - memcpy( Cbuf_GetSpace( &cmd_text, l ), text, l );
- + else
- + {
- + memcpy( Cbuf_GetSpace( &cmd_text, l ), text, l );
- + }
- }
- /*
- @@ -115,28 +116,17 @@ Adds a \n to the text
- */
- void Cbuf_InsertText( const char *text )
- {
- - char *temp;
- - int templen;
- -
- - // copy off any commands still remaining in the exec buffer
- - templen = cmd_text.cursize;
- + int l = Q_strlen( text );
- - if( templen )
- + if( cmd_text.cursize + l >= cmd_text.maxsize )
- {
- - temp = Z_Malloc( templen );
- - memcpy( temp, cmd_text.data, templen );
- - cmd_text.cursize = 0;
- + MsgDev( D_WARN, "Cbuf_InsertText: overflow\n" );
- }
- - else temp = NULL;
- -
- - // add the entire text of the file
- - Cbuf_AddText( text );
- -
- - // add the copied off data
- - if( templen )
- + else
- {
- - memcpy( Cbuf_GetSpace( &cmd_text, templen ), temp, templen );
- - Z_Free( temp );
- + memmove( cmd_text.data + l, cmd_text.data, cmd_text.cursize );
- + memcpy( cmd_text.data, text, l );
- + cmd_text.cursize += l;
- }
- }
- @@ -150,28 +140,50 @@ void Cbuf_Execute( void )
- char *text;
- char line[MAX_CMD_LINE];
- int i, quotes;
- + char *comment;
- while( cmd_text.cursize )
- {
- // find a \n or ; line break
- text = (char *)cmd_text.data;
- - quotes = 0;
- + quotes = false;
- + comment = NULL;
- for( i = 0; i < cmd_text.cursize; i++ )
- {
- - if( text[i] == '"' ) quotes++;
- - if(!( quotes & 1 ) && text[i] == ';' )
- - break; // don't break if inside a quoted string
- + if( !comment )
- + {
- + if( text[i] == '"' ) quotes = !quotes;
- +
- + if( quotes )
- + {
- + // make sure i doesn't get > cursize which causes a negative size in memmove, which is fatal --blub
- + if( i < ( cmd_text.cursize - 1 ) && ( text[i+0] == '\\' && (text[i+1] == '"' || text[i+1] == '\\')))
- + i++;
- + }
- + else
- + {
- + if( text[i+0] == '/' && text[i+1] == '/' && ( i == 0 || (byte)text[i - 1] <= ' ' ))
- + comment = &text[i];
- + if( text[i] == ';' ) break; // don't break if inside a quoted string or comment
- + }
- + }
- +
- if( text[i] == '\n' || text[i] == '\r' )
- break;
- }
- if( i >= ( MAX_CMD_LINE - 1 ))
- - Sys_Error( "Cbuf_Execute: command string owerflow\n" );
- -
- - memcpy( line, text, i );
- - line[i] = 0;
- + {
- + MsgDev( D_ERROR, "Cbuf_Execute: command string owerflow\n" );
- + line[0] = 0;
- + }
- + else
- + {
- + memcpy( line, text, comment ? (comment - text) : i );
- + line[comment ? (comment - text) : i] = 0;
- + }
- // delete the text from the command buffer and move remaining commands down
- // this is necessary because commands (exec) can insert data at the
- @@ -184,11 +196,11 @@ void Cbuf_Execute( void )
- {
- i++;
- cmd_text.cursize -= i;
- - memcpy( text, text + i, cmd_text.cursize );
- + memmove( cmd_text.data, text + i, cmd_text.cursize );
- }
- // execute the command line
- - Cmd_ExecuteString( line, src_command );
- + Cmd_ExecuteString( line );
- if( cmd_wait )
- {
- @@ -332,7 +344,7 @@ void Cmd_Alias_f( void )
- return;
- }
- - // if the alias allready exists, reuse it
- + // if the alias already exists, reuse it
- for( a = cmd_alias; a; a = a->next )
- {
- if( !Q_strcmp( s, a->name ))
- @@ -344,12 +356,19 @@ void Cmd_Alias_f( void )
- if( !a )
- {
- + cmdalias_t *cur, *prev;
- +
- a = Z_Malloc( sizeof( cmdalias_t ));
- - a->next = cmd_alias;
- - cmd_alias = a;
- - }
- - Q_strncpy( a->name, s, sizeof( a->name ));
- + Q_strncpy( a->name, s, sizeof( a->name ));
- +
- + // insert it at the right alphanumeric position
- + for( prev = NULL, cur = cmd_alias; cur && Q_strcmp( cur->name, a->name ) < 0; prev = cur, cur = cur->next );
- +
- + if( prev ) prev->next = a;
- + else cmd_alias = a;
- + a->next = cur;
- + }
- // copy the rest of the command line
- cmd[0] = 0; // start out with a null string
- @@ -358,15 +377,56 @@ void Cmd_Alias_f( void )
- for( i = 2; i < c; i++ )
- {
- - Q_strcat( cmd, Cmd_Argv( i ));
- - if( i != c ) Q_strcat( cmd, " " );
- + if( i != 2 ) Q_strncat( cmd, " ", sizeof( cmd ));
- + Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd ));
- }
- - Q_strcat( cmd, "\n" );
- + Q_strncat( cmd, "\n", sizeof( cmd ));
- a->value = copystring( cmd );
- }
- /*
- +===============
- +Cmd_UnAlias_f
- +
- +Remove existing aliases.
- +===============
- +*/
- +static void Cmd_UnAlias_f ( void )
- +{
- + cmdalias_t *a, *p;
- + const char *s;
- + int i;
- +
- + if( Cmd_Argc() == 1 )
- + {
- + Msg( "Usage: unalias alias1 [alias2 ...]\n" );
- + return;
- + }
- +
- + for( i = 1; i < Cmd_Argc(); i++ )
- + {
- + s = Cmd_Argv( i );
- + p = NULL;
- +
- + for( a = cmd_alias; a; p = a, a = a->next )
- + {
- + if( !Q_strcmp( s, a->name ))
- + {
- + if( a == cmd_alias )
- + cmd_alias = a->next;
- + if( p ) p->next = a->next;
- + Mem_Free( a->value );
- + Mem_Free( a );
- + break;
- + }
- + }
- +
- + if( !a ) Msg( "unalias: %s alias not found\n", s );
- + }
- +}
- +
- +/*
- =============================================================================
- COMMAND EXECUTION
- @@ -387,7 +447,6 @@ static char *cmd_args = NULL;
- static char *cmd_argv[MAX_CMD_TOKENS];
- static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted
- static cmd_t *cmd_functions; // possible commands to execute
- -cmd_source_t cmd_source;
- /*
- ============
- @@ -489,12 +548,14 @@ void Cmd_TokenizeString( char *text )
- while( 1 )
- {
- // skip whitespace up to a /n
- - while( *text && ((byte)*text) <= ' ' && *text != '\n' )
- + while( *text && ((byte)*text) <= ' ' && *text != '\r' && *text != '\n' )
- text++;
- -
- - if( *text == '\n' )
- - {
- +
- + if( *text == '\n' || *text == '\r' )
- + {
- // a newline seperates commands in the buffer
- + if( *text == '\r' && text[1] == '\n' )
- + text++;
- text++;
- break;
- }
- @@ -516,7 +577,6 @@ void Cmd_TokenizeString( char *text )
- }
- }
- -
- /*
- ============
- Cmd_AddCommand
- @@ -524,7 +584,7 @@ Cmd_AddCommand
- */
- void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
- {
- - cmd_t *cmd;
- + cmd_t *cmd, *cur, *prev;
- // fail if the command is a variable name
- if( Cvar_FindVar( cmd_name ))
- @@ -545,41 +605,57 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_
- cmd->name = copystring( cmd_name );
- cmd->desc = copystring( cmd_desc );
- cmd->function = function;
- - cmd->next = cmd_functions;
- - cmd_functions = cmd;
- +
- + // insert it at the right alphanumeric position
- + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
- +
- + if( prev ) prev->next = cmd;
- + else cmd_functions = cmd;
- + cmd->next = cur;
- }
- /*
- ============
- -Cmd_AddGameCommand
- +Cmd_AddServerCommand
- ============
- */
- -void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function )
- +void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
- {
- - cmd_t *cmd;
- + cmd_t *cmd, *cur, *prev;
- +
- + if( !cmd_name || !*cmd_name )
- + {
- + MsgDev( D_INFO, "Cmd_AddServerCommand: NULL name\n" );
- + return;
- + }
- // fail if the command is a variable name
- if( Cvar_FindVar( cmd_name ))
- {
- - MsgDev( D_INFO, "Cmd_AddCommand: %s already defined as a var\n", cmd_name );
- + MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined as a var\n", cmd_name );
- return;
- }
- // fail if the command already exists
- if( Cmd_Exists( cmd_name ))
- {
- - MsgDev(D_INFO, "Cmd_AddCommand: %s already defined\n", cmd_name);
- + MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined\n", cmd_name );
- return;
- }
- // use a small malloc to avoid zone fragmentation
- cmd = Z_Malloc( sizeof( cmd_t ));
- cmd->name = copystring( cmd_name );
- - cmd->desc = copystring( "game command" );
- + cmd->desc = copystring( "server command" );
- cmd->function = function;
- - cmd->flags = CMD_EXTDLL;
- - cmd->next = cmd_functions;
- - cmd_functions = cmd;
- + cmd->flags = CMD_SERVERDLL;
- +
- + // insert it at the right alphanumeric position
- + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
- +
- + if( prev ) prev->next = cmd;
- + else cmd_functions = cmd;
- + cmd->next = cur;
- }
- /*
- @@ -587,22 +663,28 @@ void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function )
- Cmd_AddClientCommand
- ============
- */
- -void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
- +int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
- {
- - cmd_t *cmd;
- + cmd_t *cmd, *cur, *prev;
- +
- + if( !cmd_name || !*cmd_name )
- + {
- + MsgDev( D_INFO, "Cmd_AddClientCommand: NULL name\n" );
- + return 0;
- + }
- // fail if the command is a variable name
- if( Cvar_FindVar( cmd_name ))
- {
- - MsgDev( D_INFO, "Cmd_AddCommand: %s already defined as a var\n", cmd_name );
- - return;
- + MsgDev( D_INFO, "Cmd_AddClientCommand: %s already defined as a var\n", cmd_name );
- + return 0;
- }
- // fail if the command already exists
- if( Cmd_Exists( cmd_name ))
- {
- - MsgDev(D_INFO, "Cmd_AddCommand: %s already defined\n", cmd_name);
- - return;
- + MsgDev(D_INFO, "Cmd_AddClientCommand: %s already defined\n", cmd_name );
- + return 0;
- }
- // use a small malloc to avoid zone fragmentation
- @@ -611,8 +693,61 @@ void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
- cmd->desc = copystring( "client command" );
- cmd->function = function;
- cmd->flags = CMD_CLIENTDLL;
- - cmd->next = cmd_functions;
- - cmd_functions = cmd;
- +
- + // insert it at the right alphanumeric position
- + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
- +
- + if( prev ) prev->next = cmd;
- + else cmd_functions = cmd;
- + cmd->next = cur;
- +
- + return 1;
- +}
- +
- +/*
- +============
- +Cmd_AddGameUICommand
- +============
- +*/
- +int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
- +{
- + cmd_t *cmd, *cur, *prev;
- +
- + if( !cmd_name || !*cmd_name )
- + {
- + MsgDev( D_INFO, "Cmd_AddGameUICommand: NULL name\n" );
- + return 0;
- + }
- +
- + // fail if the command is a variable name
- + if( Cvar_FindVar( cmd_name ))
- + {
- + MsgDev( D_INFO, "Cmd_AddGameUICommand: %s already defined as a var\n", cmd_name );
- + return 0;
- + }
- +
- + // fail if the command already exists
- + if( Cmd_Exists( cmd_name ))
- + {
- + MsgDev(D_INFO, "Cmd_AddGameUICommand: %s already defined\n", cmd_name );
- + return 0;
- + }
- +
- + // use a small malloc to avoid zone fragmentation
- + cmd = Z_Malloc( sizeof( cmd_t ));
- + cmd->name = copystring( cmd_name );
- + cmd->desc = copystring( "GameUI command" );
- + cmd->function = function;
- + cmd->flags = CMD_GAMEUIDLL;
- +
- + // insert it at the right alphanumeric position
- + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
- +
- + if( prev ) prev->next = cmd;
- + else cmd_functions = cmd;
- + cmd->next = cur;
- +
- + return 1;
- }
- /*
- @@ -693,25 +828,143 @@ qboolean Cmd_Exists( const char *cmd_name )
- /*
- ============
- +Cmd_If_f
- +
- +Compare and et condition bit if true
- +============
- +*/
- +void Cmd_If_f( void )
- +{
- + // reset bit first
- + cmd_condition &= ~BIT( cmd_condlevel );
- +
- + // usage
- + if( cmd_argc == 1 )
- + {
- + Msg( "Usage: if <op1> [ <operator> <op2> ]\n");
- + Msg( ":<action1>\n" );
- + Msg( ":<action2>\n" );
- + Msg( "else\n" );
- + Msg( ":<action3>\n" );
- + Msg( "operands are string or float values\n" );
- + Msg( "and substituted cvars like '$cl_lw'\n" );
- + Msg( "operator is '='', '==', '>', '<', '>=', '<=' or '!='\n" );
- + return;
- + }
- +
- + // one argument - check if nonzero
- + if( cmd_argc == 2 )
- + {
- + if( Q_atof( cmd_argv[1] ))
- + cmd_condition |= BIT( cmd_condlevel );
- + }
- + else if( cmd_argc == 4 )
- + {
- + // simple compare
- + float f1 = Q_atof( cmd_argv[1] );
- + float f2 = Q_atof( cmd_argv[3] );
- +
- + if( !cmd_argv[2][0] ) // this is wrong
- + return;
- +
- + if(( cmd_argv[2][0] == '=' ) || ( cmd_argv[2][1] == '=' )) // =, ==, >=, <=
- + {
- + if( !Q_strcmp( cmd_argv[1], cmd_argv[3] ) || (( f1 || f2 ) && ( f1 == f2 )))
- + cmd_condition |= BIT( cmd_condlevel );
- + }
- +
- + if( cmd_argv[2][0] == '!' ) // !=
- + {
- + cmd_condition ^= BIT( cmd_condlevel );
- + return;
- + }
- +
- + if(( cmd_argv[2][0] == '>' ) && ( f1 > f2 )) // >, >=
- + cmd_condition |= BIT( cmd_condlevel );
- +
- + if(( cmd_argv[2][0] == '<' ) && ( f1 < f2 )) // <, <=
- + cmd_condition |= BIT( cmd_condlevel );
- + }
- +}
- +
- +/*
- +============
- +Cmd_Else_f
- +
- +Invert condition bit
- +============
- +*/
- +void Cmd_Else_f( void )
- +{
- + cmd_condition ^= BIT( cmd_condlevel );
- +}
- +
- +/*
- +============
- Cmd_ExecuteString
- A complete command line has been parsed, so try to execute it
- ============
- */
- -void Cmd_ExecuteString( char *text, cmd_source_t src )
- +void Cmd_ExecuteString( char *text )
- {
- - cmd_t *cmd;
- + cmd_t *cmd;
- cmdalias_t *a;
- + char command[MAX_CMD_LINE];
- + char *pcmd = command;
- + int len = 0;
- +
- + cmd_condlevel = 0;
- +
- + // cvar value substitution
- + if( cmd_scripting && cmd_scripting->integer )
- + {
- + while( *text )
- + {
- + // check for escape
- + if(( *text == '\\' || *text == '$' ) && (*( text + 1 ) == '$' ))
- + {
- + text ++;
- + }
- + else if( *text == '$' )
- + {
- + char token[MAX_CMD_LINE];
- + char *ptoken = token;
- +
- + // check for correct cvar name
- + text++;
- + while(( *text >= '0' && *text <= '9' ) || ( *text >= 'A' && *text <= 'Z' ) || ( *text >= 'a' && *text <= 'z' ) || ( *text == '_' ))
- + *ptoken++ = *text++;
- + *ptoken = 0;
- +
- + len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len );
- + pcmd = command + len;
- +
- + if( !*text ) break;
- + }
- +
- + *pcmd++ = *text++;
- + len++;
- + }
- +
- + *pcmd = 0;
- + text = command;
- +
- + while( *text == ':' )
- + {
- + if( !FBitSet( cmd_condition, BIT( cmd_condlevel )))
- + return;
- + cmd_condlevel++;
- + text++;
- + }
- + }
- - // set cmd source
- - cmd_source = src;
- -
- // execute the command line
- Cmd_TokenizeString( text );
- if( !Cmd_Argc()) return; // no tokens
- - // check alias
- + // check aliases
- for( a = cmd_alias; a; a = a->next )
- {
- if( !Q_stricmp( cmd_argv[0], a->name ))
- @@ -735,13 +988,10 @@ void Cmd_ExecuteString( char *text, cmd_source_t src )
- if( Cvar_Command( )) return;
- // forward the command line to the server, so the entity DLL can parse it
- - if( cmd_source == src_command && host.type == HOST_NORMAL )
- + if( host.type == HOST_NORMAL )
- {
- if( cls.state >= ca_connected )
- - {
- Cmd_ForwardToServer();
- - return;
- - }
- }
- else if( text[0] != '@' && host.type == HOST_NORMAL )
- {
- @@ -808,11 +1058,16 @@ void Cmd_List_f( void )
- for( cmd = cmd_functions; cmd; cmd = cmd->next )
- {
- + if( cmd->name[0] == '@' )
- + continue; // never show system cmds
- +
- if( match && !Q_stricmpext( match, cmd->name ))
- continue;
- - Msg( "%10s %s\n", cmd->name, cmd->desc );
- +
- + Msg( " %-*s ^3%s^7\n", 32, cmd->name, cmd->desc );
- i++;
- }
- +
- Msg( "%i commands\n", i );
- }
- @@ -820,7 +1075,7 @@ void Cmd_List_f( void )
- ============
- Cmd_Unlink
- -unlink all commands with flag CVAR_EXTDLL
- +unlink all commands with specified flag
- ============
- */
- void Cmd_Unlink( int group )
- @@ -829,15 +1084,21 @@ void Cmd_Unlink( int group )
- cmd_t **prev;
- int count = 0;
- - if( Cvar_VariableInteger( "host_gameloaded" ) && ( group & CMD_EXTDLL ))
- + if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, CMD_SERVERDLL ))
- + {
- + MsgDev( D_INFO, "can't unlink commands while server is loaded\n" );
- + return;
- + }
- +
- + if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, CMD_CLIENTDLL ))
- {
- - Msg( "can't unlink cvars while game is loaded\n" );
- + MsgDev( D_INFO, "can't unlink commands while client is loaded\n" );
- return;
- }
- - if( Cvar_VariableInteger( "host_clientloaded" ) && ( group & CMD_CLIENTDLL ))
- + if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, CMD_GAMEUIDLL ))
- {
- - Msg( "can't unlink cvars while client is loaded\n" );
- + MsgDev( D_INFO, "can't unlink commands while GameUI is loaded\n" );
- return;
- }
- @@ -847,7 +1108,8 @@ void Cmd_Unlink( int group )
- cmd = *prev;
- if( !cmd ) break;
- - if( group && !( cmd->flags & group ))
- + // do filter by specified group
- + if( group && !FBitSet( cmd->flags, group ))
- {
- prev = &cmd->next;
- continue;
- @@ -855,11 +1117,8 @@ void Cmd_Unlink( int group )
- *prev = cmd->next;
- - if( cmd->name )
- - Mem_Free( cmd->name );
- -
- - if( cmd->desc )
- - Mem_Free( cmd->desc );
- + if( cmd->name ) Mem_Free( cmd->name );
- + if( cmd->desc ) Mem_Free( cmd->desc );
- Mem_Free( cmd );
- count++;
- @@ -885,13 +1144,21 @@ Cmd_Init
- void Cmd_Init( void )
- {
- Cbuf_Init();
- +
- cmd_functions = NULL;
- + cmd_condition = 0;
- + cmd_alias = NULL;
- + cmd_args = NULL;
- + cmd_argc = 0;
- // register our commands
- - Cmd_AddCommand ("echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" );
- - Cmd_AddCommand ("wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
- - Cmd_AddCommand ("cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
- - Cmd_AddCommand ("stuffcmds", Cmd_StuffCmds_f, va( "execute commandline parameters (must be present in %s.rc script)", SI.ModuleName ));
- - Cmd_AddCommand ("cmd", Cmd_ForwardToServer, "send a console commandline to the server" );
- - Cmd_AddCommand ("alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
- + Cmd_AddCommand( "echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" );
- + Cmd_AddCommand( "wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
- + Cmd_AddCommand( "cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
- + Cmd_AddCommand( "stuffcmds", Cmd_StuffCmds_f, va( "execute commandline parameters (must be present in %s.rc script)", SI.ModuleName ));
- + Cmd_AddCommand( "cmd", Cmd_ForwardToServer, "send a console commandline to the server" );
- + Cmd_AddCommand( "alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
- + Cmd_AddCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
- + Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" );
- + Cmd_AddCommand( "else", Cmd_Else_f, "invert condition bit" );
- }
- \ No newline at end of file
- diff --git b/engine/common/common.c a/engine/common/common.c
- index a15e971..559aba6 100644
- --- b/engine/common/common.c
- +++ a/engine/common/common.c
- @@ -22,6 +22,39 @@ GNU General Public License for more details.
- /*
- ==============
- +COM_IsSingleChar
- +
- +interpert this character as single
- +==============
- +*/
- +static int COM_IsSingleChar( char c )
- +{
- + if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
- + return true;
- +
- + if( host.com_handlecolon && c == ':' )
- + return true;
- +
- + return false;
- +}
- +
- +/*
- +==============
- +COM_IsWhiteSpace
- +
- +interpret symbol as whitespace
- +==============
- +*/
- +
- +static int COM_IsWhiteSpace( char space )
- +{
- + if( space == ' ' || space == '\t' || space == '\r' || space == '\n' )
- + return 1;
- + return 0;
- +}
- +
- +/*
- +==============
- COM_ParseFile
- text parser
- @@ -74,7 +107,7 @@ skipwhite:
- }
- // parse single characters
- - if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
- + if( COM_IsSingleChar( c ))
- {
- token[len] = c;
- len++;
- @@ -90,7 +123,7 @@ skipwhite:
- len++;
- c = ((byte)*data);
- - if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
- + if( COM_IsSingleChar( c ))
- break;
- } while( c > 32 );
- @@ -100,6 +133,56 @@ skipwhite:
- }
- /*
- +================
- +COM_ParseVector
- +
- +================
- +*/
- +qboolean COM_ParseVector( char **pfile, float *v, size_t size )
- +{
- + string token;
- + qboolean bracket = false;
- + char *saved;
- + uint i;
- +
- + if( v == NULL || size == 0 )
- + return false;
- +
- + memset( v, 0, sizeof( *v ) * size );
- +
- + if( size == 1 )
- + {
- + *pfile = COM_ParseFile( *pfile, token );
- + v[0] = Q_atof( token );
- + return true;
- + }
- +
- + saved = *pfile;
- +
- + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
- + return false;
- +
- + if( token[0] == '(' )
- + bracket = true;
- + else *pfile = saved; // restore token to right get it again
- +
- + for( i = 0; i < size; i++ )
- + {
- + *pfile = COM_ParseFile( *pfile, token );
- + v[i] = Q_atof( token );
- + }
- +
- + if( !bracket ) return true; // done
- +
- + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
- + return false;
- +
- + if( token[0] == ')' )
- + return true;
- + return false;
- +}
- +
- +/*
- =============
- COM_FileSize
- @@ -164,6 +247,39 @@ int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBu
- }
- /*
- +=============
- +COM_TrimSpace
- +
- +trims all whitespace from the front
- +and end of a string
- +=============
- +*/
- +void COM_TrimSpace( const char *source, char *dest )
- +{
- + int start, end, length;
- +
- + start = 0;
- + end = Q_strlen( source );
- +
- + while( source[start] && COM_IsWhiteSpace( source[start] ))
- + start++;
- + end--;
- +
- + while( end > 0 && COM_IsWhiteSpace( source[end] ))
- + end--;
- + end++;
- +
- + length = end - start;
- +
- + if( length > 0 )
- + memcpy( dest, source + start, length );
- + else length = 0;
- +
- + // terminate the dest string
- + dest[length] = 0;
- +}
- +
- +/*
- ============
- COM_FixSlashes
- @@ -213,7 +329,6 @@ char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, i
- i++;
- }
- -
- // if we actually advanced the pointer, copy it over
- if( i != *filePos )
- {
- @@ -266,7 +381,8 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
- if( !filename || !*filename )
- {
- - if( pLength ) *pLength = 0;
- + if( pLength )
- + *pLength = 0;
- return NULL;
- }
- @@ -279,8 +395,11 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
- if( pfile )
- {
- file = malloc( iLength + 1 );
- - memcpy( file, pfile, iLength );
- - file[iLength] = '\0';
- + if( file != NULL )
- + {
- + memcpy( file, pfile, iLength );
- + file[iLength] = '\0';
- + }
- Mem_Free( pfile );
- pfile = file;
- }
- @@ -296,34 +415,26 @@ COM_LoadFile
- */
- byte *COM_LoadFile( const char *filename, int usehunk, int *pLength )
- {
- - string name;
- - byte *file, *pfile;
- - int iLength;
- + return COM_LoadFileForMe( filename, pLength );
- +}
- - ASSERT( usehunk == 5 );
- +/*
- +=============
- +COM_LoadFile
- +=============
- +*/
- +int COM_SaveFile( const char *filename, const void *data, long len )
- +{
- + // check for empty filename
- if( !filename || !*filename )
- - {
- - if( pLength ) *pLength = 0;
- - return NULL;
- - }
- -
- - Q_strncpy( name, filename, sizeof( name ));
- - COM_FixSlashes( name );
- + return false;
- - pfile = FS_LoadFile( name, &iLength, false );
- - if( pLength ) *pLength = iLength;
- -
- - if( pfile )
- - {
- - file = malloc( iLength + 1 );
- - memcpy( file, pfile, iLength );
- - file[iLength] = '\0';
- - Mem_Free( pfile );
- - pfile = file;
- - }
- + // check for null data
- + if( !data || len <= 0 )
- + return false;
- - return pfile;
- + return FS_WriteFile( filename, data, len );
- }
- /*
- @@ -339,6 +450,25 @@ void COM_FreeFile( void *buffer )
- /*
- =============
- +COM_NormalizeAngles
- +
- +=============
- +*/
- +void COM_NormalizeAngles( vec3_t angles )
- +{
- + int i;
- +
- + for( i = 0; i < 3; i++ )
- + {
- + if( angles[i] > 180.0f )
- + angles[i] -= 360.0f;
- + else if( angles[i] < -180.0f )
- + angles[i] += 360.0f;
- + }
- +}
- +
- +/*
- +=============
- pfnGetModelType
- =============
- @@ -376,42 +506,36 @@ pfnCvar_RegisterVariable
- =============
- */
- -cvar_t *pfnCvar_RegisterVariable( const char *szName, const char *szValue, int flags )
- +cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
- {
- + if( FBitSet( flags, FCVAR_GLCONFIG ))
- + return (cvar_t *)Cvar_Get( szName, szValue, flags, va( "enable or disable %s", szName ));
- return (cvar_t *)Cvar_Get( szName, szValue, flags|CVAR_CLIENTDLL, "client cvar" );
- }
- /*
- =============
- -pfnCVarGetPointer
- +pfnCvar_RegisterVariable
- -can return NULL
- =============
- */
- -cvar_t *pfnCVarGetPointer( const char *szVarName )
- +cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
- {
- - cvar_t *cvPtr;
- -
- - cvPtr = (cvar_t *)Cvar_FindVar( szVarName );
- -
- - return cvPtr;
- + if( FBitSet( flags, FCVAR_GLCONFIG ))
- + return (cvar_t *)Cvar_Get( szName, szValue, flags, va( "enable or disable %s", szName ));
- + return (cvar_t *)Cvar_Get( szName, szValue, flags|CVAR_GAMEUIDLL, "GameUI cvar" );
- }
- /*
- =============
- -pfnAddClientCommand
- +pfnCVarGetPointer
- +can return NULL
- =============
- */
- -int pfnAddClientCommand( const char *cmd_name, xcommand_t func )
- +cvar_t *pfnCVarGetPointer( const char *szVarName )
- {
- - if( !cmd_name || !*cmd_name )
- - return 0;
- -
- - // NOTE: if( func == NULL ) cmd will be forwarded to a server
- - Cmd_AddClientCommand( cmd_name, func );
- -
- - return 1;
- + return (cvar_t *)Cvar_FindVar( szVarName );
- }
- /*
- @@ -429,7 +553,7 @@ void Con_Printf( char *szFmt, ... )
- return;
- va_start( args, szFmt );
- - Q_vsnprintf( buffer, 16384, szFmt, args );
- + Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
- va_end( args );
- Sys_Print( buffer );
- @@ -450,7 +574,7 @@ void Con_DPrintf( char *szFmt, ... )
- return;
- va_start( args, szFmt );
- - Q_vsnprintf( buffer, 16384, szFmt, args );
- + Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
- va_end( args );
- Sys_Print( buffer );
- diff --git b/engine/common/common.h a/engine/common/common.h
- index 7fcf37f..6149c0b 100644
- --- b/engine/common/common.h
- +++ a/engine/common/common.h
- @@ -36,9 +36,15 @@ extern "C" {
- #define MAX_STRING 256 // generic string
- #define MAX_INFO_STRING 256 // infostrings are transmitted across network
- #define MAX_SYSPATH 1024 // system filepath
- +#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Msg or MsgDev
- #define MAX_MODS 512 // environment games that engine can keep visible
- #define EXPORT __declspec( dllexport )
- #define BIT( n ) (1<<( n ))
- +#define GAMMA ( 2.2 ) // Valve Software gamma
- +#define INVGAMMA ( 1.0 / 2.2 ) // back to 1.0
- +#define SetBits( iBitVector, bits ) ((iBitVector) = (iBitVector) | (bits))
- +#define ClearBits( iBitVector, bits ) ((iBitVector) = (iBitVector) & ~(bits))
- +#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
- #ifndef __cplusplus
- #define NULL ((void *)0)
- @@ -53,7 +59,6 @@ extern "C" {
- typedef unsigned long dword;
- typedef unsigned int uint;
- typedef char string[MAX_STRING];
- -typedef long fs_offset_t;
- typedef struct file_s file_t; // normal file
- typedef struct wfile_s wfile_t; // wad file
- typedef struct stream_s stream_t; // sound stream for background music playing
- @@ -70,7 +75,7 @@ enum
- D_INFO = 1, // "-dev 1", shows various system messages
- D_WARN, // "-dev 2", shows not critical system warnings
- D_ERROR, // "-dev 3", shows critical warnings
- - D_AICONSOLE, // "-dev 4", special case for game aiconsole
- + D_REPORT, // "-dev 4", special case for game reports
- D_NOTE // "-dev 5", show system notifications for engine developers
- };
- @@ -88,12 +93,19 @@ typedef enum
- #define XASH_VERSION 0.98f // engine current version
- // PERFORMANCE INFO
- -#define MIN_FPS 15.0 // host minimum fps value for maxfps.
- +#define MIN_FPS 20.0 // host minimum fps value for maxfps.
- #define MAX_FPS 500.0 // upper limit for maxfps.
- #define MAX_FRAMETIME 0.1
- #define MIN_FRAMETIME 0.000001
- +// HOST_FIXED_FRAMERATE stuff
- +#define HOST_MINFPS 20.0
- +#define HOST_MAXFPS 72.0
- +#define GAME_FPS 20.0
- +#define HOST_FPS 60.0 // client and the server clamped at 60.0 fps max. Render clamped at fps_max cvar
- +#define HOST_FRAMETIME ( 1.0 / HOST_FPS )
- +
- #define MAX_CMD_TOKENS 80 // cmd tokens
- #define MAX_ENTNUMBER 99999 // for server and client parsing
- #define MAX_HEARTBEAT -99999 // connection time
- @@ -133,6 +145,7 @@ extern convar_t *scr_width;
- extern convar_t *scr_height;
- extern convar_t *scr_loading;
- extern convar_t *scr_download;
- +extern convar_t *cmd_scripting;
- extern convar_t *cl_allow_levelshots;
- extern convar_t *mod_allow_materials;
- extern convar_t *host_limitlocal;
- @@ -214,7 +227,6 @@ typedef enum
- HOST_ERR_FATAL, // sys error
- HOST_SLEEP, // sleeped by different reason, e.g. minimize window
- HOST_NOFOCUS, // same as HOST_FRAME, but disable mouse
- - HOST_RESTART, // during the changes video mode
- HOST_CRASHED // an exception handler called
- } host_state;
- @@ -267,6 +279,11 @@ typedef struct host_redirect_s
- void (*flush)( netadr_t adr, rdtype_t target, char *buffer );
- } host_redirect_t;
- +// local flags (never sending acorss the net)
- +#define SND_LOCALSOUND (1<<9) // not paused, not looped, for internal use
- +#define SND_STOP_LOOPING (1<<10) // stop all looping sounds on the entity.
- +#define SND_FILTER_CLIENT (1<<11) // don't send sound from local player if prediction was enabled
- +
- typedef struct
- {
- char name[64];
- @@ -315,6 +332,7 @@ typedef struct host_parm_s
- qboolean key_overstrike; // key overstrike mode
- qboolean stuffcmdsrun; // execute stuff commands
- qboolean con_showalways; // show console always (developer and dedicated)
- + qboolean com_handlecolon; // allow COM_ParseFile to handle colon as single char
- qboolean change_game; // initialize when game is changed
- qboolean mouse_visible; // vgui override cursor control
- qboolean input_enabled; // vgui override mouse & keyboard input
- @@ -338,9 +356,6 @@ typedef struct host_parm_s
- struct decallist_s *decalList; // used for keep decals, when renderer is restarted or changed
- int numdecals;
- -
- - soundlist_t *soundList; // used for keep ambient sounds, when renderer or sound is restarted
- - int numsounds;
- } host_parm_t;
- extern host_parm_t host;
- @@ -361,43 +376,45 @@ void FS_LoadGameInfo( const char *rootfolder );
- void FS_FileBase( const char *in, char *out );
- const char *FS_FileExtension( const char *in );
- void FS_DefaultExtension( char *path, const char *extension );
- -void FS_ExtractFilePath( const char* const path, char* dest );
- +void FS_ExtractFilePath( const char *path, char *dest );
- const char *FS_GetDiskPath( const char *name, qboolean gamedironly );
- const char *FS_FileWithoutPath( const char *in );
- -wfile_t *W_Open( const char *filename, const char *mode );
- +wfile_t *W_Open( const char *filename, const char *mode, int *errorcode );
- byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type );
- void W_Close( wfile_t *wad );
- -file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
- -byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
- -qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
- +file_t *FS_OpenFile( const char *path, long *filesizeptr, qboolean gamedironly );
- +byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
- +qboolean FS_WriteFile( const char *filename, const void *data, long len );
- +qboolean COM_ParseVector( char **pfile, float *v, size_t size );
- +void COM_NormalizeAngles( vec3_t angles );
- int COM_FileSize( const char *filename );
- void COM_FixSlashes( char *pname );
- void COM_FreeFile( void *buffer );
- int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
- search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
- file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
- -fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
- -fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
- +long FS_Write( file_t *file, const void *data, size_t datasize );
- +long FS_Read( file_t *file, void *buffer, size_t buffersize );
- int FS_VPrintf( file_t *file, const char *format, va_list ap );
- -int FS_Seek( file_t *file, fs_offset_t offset, int whence );
- +int FS_Seek( file_t *file, long offset, int whence );
- int FS_Gets( file_t *file, byte *string, size_t bufsize );
- int FS_Printf( file_t *file, const char *format, ... );
- -fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly );
- -fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly );
- +long FS_FileSize( const char *filename, qboolean gamedironly );
- +long FS_FileTime( const char *filename, qboolean gamedironly );
- int FS_Print( file_t *file, const char *msg );
- qboolean FS_Rename( const char *oldname, const char *newname );
- qboolean FS_FileExists( const char *filename, qboolean gamedironly );
- -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
- +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
- qboolean FS_Delete( const char *path );
- int FS_UnGetc( file_t *file, byte c );
- void FS_StripExtension( char *path );
- -fs_offset_t FS_Tell( file_t *file );
- +long FS_Tell( file_t *file );
- qboolean FS_Eof( file_t *file );
- void FS_Purge( file_t *file );
- int FS_Close( file_t *file );
- int FS_Getc( file_t *file );
- qboolean FS_Eof( file_t *file );
- -fs_offset_t FS_FileLength( file_t *f );
- +long FS_FileLength( file_t *f );
- //
- // network.c
- @@ -424,6 +441,7 @@ typically expanded to rgba buffer
- NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == PF_RGB_888
- ========================================================================
- */
- +#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24)
- #define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5)
- typedef enum
- @@ -435,9 +453,9 @@ typedef enum
- PF_BGRA_32, // big endian RGBA (MacOS)
- PF_RGB_24, // uncompressed dds or another 24-bit image
- PF_BGR_24, // big-endian RGB (MacOS)
- - PF_DXT1, // nvidia DXT1 format
- - PF_DXT3, // nvidia DXT3 format
- - PF_DXT5, // nvidia DXT5 format
- + PF_DXT1, // s3tc DXT1 format
- + PF_DXT3, // s3tc DXT3 format
- + PF_DXT5, // s3tc DXT5 format
- PF_TOTALCOUNT, // must be last
- } pixformat_t;
- @@ -483,6 +501,7 @@ typedef enum
- IMAGE_SKYBOX = BIT(5), // only used by FS_SaveImage - for write right suffixes
- IMAGE_QUAKESKY = BIT(6), // it's a quake sky double layered clouds (so keep it as 8 bit)
- IMAGE_DDS_FORMAT = BIT(7), // a hint for GL loader
- + IMAGE_MULTILAYER = BIT(8), // to differentiate from 3D texture
- // Image_Process manipulation flags
- IMAGE_FLIP_X = BIT(16), // flip the image by width
- @@ -679,15 +698,17 @@ qboolean SV_Active( void );
- ==============================================================
- */
- -cvar_t *pfnCvar_RegisterVariable( const char *szName, const char *szValue, int flags );
- +cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags );
- +cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags );
- char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
- +int COM_SaveFile( const char *filename, const void *data, long len );
- byte* COM_LoadFileForMe( const char *filename, int *pLength );
- cvar_t *pfnCVarGetPointer( const char *szVarName );
- int pfnDrawConsoleString( int x, int y, char *string );
- void pfnDrawSetTextColor( float r, float g, float b );
- void pfnDrawConsoleStringLen( const char *pText, int *length, int *height );
- -int pfnAddClientCommand( const char *cmd_name, xcommand_t func );
- void *Cache_Check( byte *mempool, struct cache_user_s *c );
- +void COM_TrimSpace( const char *source, char *dest );
- edict_t* pfnPEntityOfEntIndex( int iEntIndex );
- void pfnGetModelBounds( model_t *mod, float *mins, float *maxs );
- void pfnGetGameDir( char *szGetGameDir );
- @@ -773,7 +794,7 @@ long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
- byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame );
- qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration );
- qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info );
- -fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length );
- +long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length );
- void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, qboolean ignore_hwgamma, int quiet );
- movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio, qboolean ignore_hwgamma );
- movie_state_t *AVI_LoadVideoNoSound( const char *filename, qboolean ignore_hwgamma );
- @@ -803,12 +824,13 @@ void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appNam
- int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBufferSize );
- struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe );
- void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
- -void SV_StartMusic( const char *curtrack, const char *looptrack, fs_offset_t position );
- +void SV_StartMusic( const char *curtrack, const char *looptrack, long position );
- void SV_CreateDecal( struct sizebuf_s *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
- void SV_CreateStudioDecal( struct sizebuf_s *msg, const float *origin, const float *start, int decalIndex, int entityIndex, int modelIndex,
- int flags, struct modelstate_s *state );
- struct sizebuf_s *SV_GetReliableDatagram( void );
- qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
- +void SV_BroadcastPrintf( struct sv_client_s *ignore, int level, char *fmt, ... );
- int R_CreateDecalList( struct decallist_s *pList, qboolean changelevel );
- void R_ClearAllDecals( void );
- void R_ClearStaticEntities( void );
- diff --git b/engine/common/con_utils.c a/engine/common/con_utils.c
- index 115ebae..2ce6ef3 100644
- --- b/engine/common/con_utils.c
- +++ a/engine/common/con_utils.c
- @@ -67,7 +67,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
- int ver = -1, mapver = -1, lumpofs = 0, lumplen = 0;
- const char *ext = FS_FileExtension( t->filenames[i] );
- char *ents = NULL, *pfile;
- - qboolean paranoia = false;
- + int version = 0;
- qboolean gearbox = false;
- if( Q_stricmp( ext, "bsp" )) continue;
- @@ -108,8 +108,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
- hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader31_t ));
- else hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t ));
- - if( hdrext->id == IDEXTRAHEADER && hdrext->version == EXTRA_VERSION )
- - paranoia = true;
- + if( hdrext->id == IDEXTRAHEADER ) version = hdrext->version;
- Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
- FS_StripExtension( entfilename );
- @@ -163,11 +162,17 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
- break;
- case HLBSP_VERSION:
- if( gearbox ) Q_strncpy( buf, "Blue-Shift", sizeof( buf ));
- - else if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf ));
- + else if( version == 1 ) Q_strncpy( buf, "XashXT old format", sizeof( buf ));
- + else if( version == 2 ) Q_strncpy( buf, "Paranoia 2: Savior", sizeof( buf ));
- + else if( version == 3 ) Q_strncpy( buf, "not supported", sizeof( buf ));
- + else if( version == 4 ) Q_strncpy( buf, "Half-Life extended", sizeof( buf ));
- else Q_strncpy( buf, "Half-Life", sizeof( buf ));
- break;
- case XTBSP_VERSION:
- - if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf ));
- + if( version == 1 ) Q_strncpy( buf, "XashXT old format", sizeof( buf ));
- + else if( version == 2 ) Q_strncpy( buf, "Paranoia 2: Savior", sizeof( buf ));
- + else if( version == 3 ) Q_strncpy( buf, "not supported", sizeof( buf ));
- + else if( version == 4 ) Q_strncpy( buf, "Xash3D extended", sizeof( buf ));
- else Q_strncpy( buf, "Xash3D", sizeof( buf ));
- break;
- default: Q_strncpy( buf, "??", sizeof( buf )); break;
- @@ -304,8 +309,8 @@ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length )
- {
- const char *ext = FS_FileExtension( t->filenames[i] );
- - if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" ));
- - else continue;
- + if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
- + continue;
- FS_FileBase( t->filenames[i], matchbuf );
- Msg( "%16s\n", matchbuf );
- @@ -563,46 +568,40 @@ qboolean Cmd_GetCustomList( const char *s, char *completedname, int length )
- /*
- =====================================
- -Cmd_GetTexturemodes
- +Cmd_GetGameList
- -Prints or complete sound filename
- +Prints or complete gamedir name
- =====================================
- */
- -qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
- +qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
- {
- - int i, numtexturemodes;
- - string texturemodes[6]; // keep an actual ( sizeof( gl_texturemode) / sizeof( gl_texturemode[0] ))
- + int i, numgamedirs;
- + string gamedirs[MAX_MODS];
- string matchbuf;
- - const char *gl_texturemode[] =
- - {
- - "GL_LINEAR",
- - "GL_LINEAR_MIPMAP_LINEAR",
- - "GL_LINEAR_MIPMAP_NEAREST",
- - "GL_NEAREST",
- - "GL_NEAREST_MIPMAP_LINEAR",
- - "GL_NEAREST_MIPMAP_NEAREST",
- - };
- + // stand-alone games doesn't have cmd "game"
- + if( !Cmd_Exists( "game" ))
- + return false;
- // compare gamelist with current keyword
- - for( i = 0, numtexturemodes = 0; i < 6; i++ )
- + for( i = 0, numgamedirs = 0; i < SI.numgames; i++ )
- {
- - if(( *s == '*' ) || !Q_strnicmp( gl_texturemode[i], s, Q_strlen( s )))
- - Q_strcpy( texturemodes[numtexturemodes++], gl_texturemode[i] );
- + if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, Q_strlen( s )))
- + Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder );
- }
- - if( !numtexturemodes ) return false;
- - Q_strncpy( matchbuf, gl_texturemode[0], MAX_STRING );
- + if( !numgamedirs ) return false;
- + Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
- if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
- - if( numtexturemodes == 1 ) return true;
- + if( numgamedirs == 1 ) return true;
- - for( i = 0; i < numtexturemodes; i++ )
- + for( i = 0; i < numgamedirs; i++ )
- {
- - Q_strncpy( matchbuf, texturemodes[i], MAX_STRING );
- + Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
- Msg( "%16s\n", matchbuf );
- }
- - Msg( "\n^3 %i filters found.\n", numtexturemodes );
- + Msg( "\n^3 %i games found.\n", numgamedirs );
- // cut shortestMatch to the amount common with s
- if( completedname && length )
- @@ -618,40 +617,48 @@ qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
- /*
- =====================================
- -Cmd_GetGameList
- +Cmd_GetCDList
- -Prints or complete gamedir name
- +Prints or complete CD command name
- =====================================
- */
- -qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
- +qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
- {
- - int i, numgamedirs;
- - string gamedirs[MAX_MODS];
- + int i, numcdcommands;
- + string cdcommands[8];
- string matchbuf;
- - // stand-alone games doesn't have cmd "game"
- - if( !Cmd_Exists( "game" ))
- - return false;
- + const char *cd_command[] =
- + {
- + "info",
- + "loop",
- + "off",
- + "on",
- + "pause",
- + "play",
- + "resume",
- + "stop",
- + };
- - // compare gamelist with current keyword
- - for( i = 0, numgamedirs = 0; i < SI.numgames; i++ )
- + // compare CD command list with current keyword
- + for( i = 0, numcdcommands = 0; i < 8; i++ )
- {
- - if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, Q_strlen( s )))
- - Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder );
- + if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, Q_strlen( s )))
- + Q_strcpy( cdcommands[numcdcommands++], cd_command[i] );
- }
- - if( !numgamedirs ) return false;
- - Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
- + if( !numcdcommands ) return false;
- + Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
- if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
- - if( numgamedirs == 1 ) return true;
- + if( numcdcommands == 1 ) return true;
- - for( i = 0; i < numgamedirs; i++ )
- + for( i = 0; i < numcdcommands; i++ )
- {
- - Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
- + Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
- Msg( "%16s\n", matchbuf );
- }
- - Msg( "\n^3 %i games found.\n", numgamedirs );
- + Msg( "\n^3 %i commands found.\n", numcdcommands );
- // cut shortestMatch to the amount common with s
- if( completedname && length )
- @@ -815,7 +822,6 @@ qboolean Cmd_CheckMapsList( qboolean fRefresh )
- autocomplete_list_t cmd_list[] =
- {
- -{ "gl_texturemode", Cmd_GetTexturemodes },
- { "map_background", Cmd_GetMapList },
- { "changelevel", Cmd_GetMapList },
- { "playdemo", Cmd_GetDemoList, },
- @@ -832,6 +838,7 @@ autocomplete_list_t cmd_list[] =
- { "load", Cmd_GetSavesList },
- { "play", Cmd_GetSoundList },
- { "map", Cmd_GetMapList },
- +{ "cd", Cmd_GetCDList },
- { NULL }, // termiantor
- };
- diff --git b/engine/common/console.c a/engine/common/console.c
- index c4fa2e6..d7e1e9a 100644
- --- b/engine/common/console.c
- +++ a/engine/common/console.c
- @@ -25,26 +25,31 @@ convar_t *con_notifytime;
- convar_t *scr_conspeed;
- convar_t *con_fontsize;
- -#define CON_TIMES 5 // need for 4 lines
- +#define CON_TIMES 4 // notify lines
- #define COLOR_DEFAULT '7'
- #define CON_HISTORY 64
- #define MAX_DBG_NOTIFY 128
- #define CON_MAXCMDS 4096 // auto-complete intermediate list
- #define CON_NUMFONTS 3 // maxfonts
- -#define CON_TEXTSIZE 131072 // 128 kb buffer
- +#define CON_LINES( i ) (con.lines[(con.lines_first + (i)) % con.maxlines])
- +#define CON_LINES_COUNT con.lines_count
- +#define CON_LINES_LAST() CON_LINES( CON_LINES_COUNT - 1 )
- +
- +#define CON_TEXTSIZE 1048576 // max scrollback buffer characters in console (1 Mb)
- +#define CON_MAXLINES 16384 // max scrollback buffer lines in console
- // console color typeing
- rgba_t g_color_table[8] =
- {
- -{ 0, 0, 0, 255}, // black
- -{255, 0, 0, 255}, // red
- -{ 0, 255, 0, 255}, // green
- -{255, 255, 0, 255}, // yellow
- -{ 0, 0, 255, 255}, // blue
- -{ 0, 255, 255, 255}, // cyan
- -{255, 0, 255, 255}, // magenta
- -{240, 180, 24, 255}, // default color (can be changed by user)
- +{ 0, 0, 0, 255 }, // black
- +{ 255, 0, 0, 255 }, // red
- +{ 0, 255, 0, 255 }, // green
- +{ 255, 255, 0, 255 }, // yellow
- +{ 0, 0, 255, 255 }, // blue
- +{ 0, 255, 255, 255 }, // cyan
- +{ 255, 0, 255, 255 }, // magenta
- +{ 240, 180, 24, 255 }, // default color (can be changed by user)
- };
- typedef struct
- @@ -63,29 +68,38 @@ typedef struct
- int key_dest;
- } notify_t;
- +typedef struct con_lineinfo_s
- +{
- + char *start;
- + size_t length;
- + double addtime; // notify stuff
- +} con_lineinfo_t;
- +
- typedef struct
- {
- qboolean initialized;
- - short text[CON_TEXTSIZE];
- - int current; // line where next message will be printed
- - int display; // bottom of console displays this line
- - int x; // offset in current line for next print
- + // conbuffer
- + char *buffer; // common buffer for all console lines
- + int bufsize; // CON_TEXSIZE
- + con_lineinfo_t *lines; // console lines
- + int maxlines; // CON_MAXLINES
- - int linewidth; // characters across screen
- - int totallines; // total lines in console scrollback
- + int lines_first; // cyclic buffer
- + int lines_count;
- - float displayFrac; // aproaches finalFrac at scr_conspeed
- - float finalFrac; // 0.0 to 1.0 lines of console to display
- + // console scroll
- + int backscroll; // lines up from bottom to display
- + int linewidth; // characters across screen
- + // console animation
- + int showlines; // how many lines we should display
- int vislines; // in scanlines
- - double times[CON_TIMES]; // host.realtime the line was generated for transparent notify lines
- - rgba_t color;
- // console images
- int background; // console background
- - // conchars
- + // console fonts
- cl_font_t chars[CON_NUMFONTS];// fonts.wad/font1.fnt
- cl_font_t *curFont, *lastUsedFont;
- @@ -108,6 +122,7 @@ typedef struct
- string shortestMatch;
- field_t *completionField; // con.input or dedicated server fake field-line
- char *completionString;
- + char *completionBuffer;
- char *cmds[CON_MAXCMDS];
- int matchCount;
- } console_t;
- @@ -123,11 +138,8 @@ Con_Clear_f
- */
- void Con_Clear_f( void )
- {
- - int i;
- -
- - for( i = 0; i < CON_TEXTSIZE; i++ )
- - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
- - con.display = con.current; // go to end
- + con.lines_count = 0;
- + con.backscroll = 0; // go to end
- }
- /*
- @@ -168,8 +180,8 @@ void Con_ClearNotify( void )
- {
- int i;
- - for( i = 0; i < CON_TIMES; i++ )
- - con.times[i] = 0;
- + for( i = 0; i < CON_LINES_COUNT; i++ )
- + CON_LINES( i ).addtime = 0.0;
- }
- /*
- @@ -272,9 +284,8 @@ Con_ToggleConsole_f
- */
- void Con_ToggleConsole_f( void )
- {
- - if( !host.developer ) return; // disabled
- -
- - if( UI_CreditsActive( )) return; // disabled by final credits
- + if( !host.developer || UI_CreditsActive( ))
- + return; // disabled
- // show console only in game or by special call from menu
- if( cls.state != ca_active || cls.key_dest == key_menu )
- @@ -298,69 +309,157 @@ void Con_ToggleConsole_f( void )
- /*
- ================
- -Con_CheckResize
- +Con_FixTimes
- -If the line width has changed, reformat the buffer.
- +Notifies the console code about the current time
- +(and shifts back times of other entries when the time
- +went backwards)
- ================
- */
- -void Con_CheckResize( void )
- +void Con_FixTimes( void )
- {
- - int i, j, width, numlines, numchars;
- - int oldwidth, oldtotallines;
- - short tbuf[CON_TEXTSIZE];
- - int charWidth = 8;
- + double diff;
- + int i;
- - if( con.curFont && con.curFont->hFontTexture )
- - charWidth = con.curFont->charWidths['M'] - 1;
- + if( con.lines_count <= 0 ) return;
- - width = ( scr_width->integer / charWidth );
- + diff = cl.time - CON_LINES_LAST().addtime;
- + if( diff >= 0.0 ) return; // nothing to fix
- - if( width == con.linewidth )
- + for( i = 0; i < con.lines_count; i++ )
- + CON_LINES( i ).addtime += diff;
- +}
- +
- +/*
- +================
- +Con_DeleteLine
- +
- +Deletes the first line from the console history.
- +================
- +*/
- +void Con_DeleteLine( void )
- +{
- + if( con.lines_count == 0 )
- return;
- + con.lines_count--;
- + con.lines_first = (con.lines_first + 1) % con.maxlines;
- +}
- - if( !glw_state.initialized )
- - {
- - // video hasn't been initialized yet
- - con.linewidth = width;
- - con.totallines = CON_TEXTSIZE / con.linewidth;
- +/*
- +================
- +Con_DeleteLastLine
- +
- +Deletes the last line from the console history.
- +================
- +*/
- +void Con_DeleteLastLine( void )
- +{
- + if( con.lines_count == 0 )
- + return;
- + con.lines_count--;
- +}
- - for( i = 0; i < CON_TEXTSIZE; i++ )
- - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
- +/*
- +================
- +Con_BytesLeft
- +
- +Checks if there is space for a line of the given length, and if yes, returns a
- +pointer to the start of such a space, and NULL otherwise.
- +================
- +*/
- +static char *Con_BytesLeft( int length )
- +{
- + if( length > con.bufsize )
- + return NULL;
- +
- + if( con.lines_count == 0 )
- + {
- + return con.buffer;
- }
- else
- {
- - oldwidth = con.linewidth;
- - con.linewidth = width;
- - oldtotallines = con.totallines;
- - con.totallines = CON_TEXTSIZE / con.linewidth;
- - numlines = oldtotallines;
- + char *firstline_start = con.lines[con.lines_first].start;
- + char *lastline_onepastend = CON_LINES_LAST().start + CON_LINES_LAST().length;
- - if( con.totallines < numlines )
- - numlines = con.totallines;
- + // the buffer is cyclic, so we first have two cases...
- + if( firstline_start < lastline_onepastend ) // buffer is contiguous
- + {
- + // put at end?
- + if( length <= con.buffer + con.bufsize - lastline_onepastend )
- + return lastline_onepastend;
- + // put at beginning?
- + else if( length <= firstline_start - con.buffer )
- + return con.buffer;
- +
- + return NULL;
- + }
- + else
- + {
- + // buffer has a contiguous hole
- + if( length <= firstline_start - lastline_onepastend )
- + return lastline_onepastend;
- - numchars = oldwidth;
- -
- - if( con.linewidth < numchars )
- - numchars = con.linewidth;
- + return NULL;
- + }
- + }
- +}
- - memcpy( tbuf, con.text, CON_TEXTSIZE * sizeof( short ));
- +/*
- +================
- +Con_AddLine
- - for( i = 0; i < CON_TEXTSIZE; i++ )
- - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
- +Appends a given string as a new line to the console.
- +================
- +*/
- +void Con_AddLine( const char *line, int length )
- +{
- + byte *putpos;
- + con_lineinfo_t *p;
- - for( i = 0; i < numlines; i++ )
- - {
- - for( j = 0; j < numchars; j++ )
- - {
- - con.text[(con.totallines - 1 - i) * con.linewidth + j] =
- - tbuf[((con.current - i + oldtotallines) % oldtotallines) * oldwidth + j + con.x];
- - }
- - }
- - Con_ClearNotify ();
- - }
- + if( !con.initialized ) return;
- +
- + Con_FixTimes();
- + length++; // reserve space for term
- +
- + ASSERT( length < CON_TEXTSIZE );
- +
- + while( !( putpos = Con_BytesLeft( length )) || con.lines_count >= con.maxlines )
- + Con_DeleteLine();
- - con.current = con.totallines - 1;
- - con.display = con.current;
- + memcpy( putpos, line, length );
- + putpos[length - 1] = '\0';
- + con.lines_count++;
- +
- + p = &CON_LINES_LAST();
- + p->start = putpos;
- + p->length = length;
- + p->addtime = cl.time;
- +}
- +
- +/*
- +================
- +Con_CheckResize
- +
- +If the line width has changed, reformat the buffer.
- +================
- +*/
- +void Con_CheckResize( void )
- +{
- + int charWidth = 8;
- + int i, width;
- +
- + if( con.curFont && con.curFont->hFontTexture )
- + charWidth = con.curFont->charWidths['M'] - 1;
- +
- + width = ( scr_width->integer / charWidth ) - 2;
- + if( !glw_state.initialized ) width = 78;
- +
- + if( width == con.linewidth )
- + return;
- +
- + Con_ClearNotify();
- + con.linewidth = width;
- + con.backscroll = 0;
- con.input.widthInChars = con.linewidth;
- @@ -375,10 +474,7 @@ Con_PageUp
- */
- void Con_PageUp( int lines )
- {
- - con.display -= abs( lines );
- -
- - if( con.current - con.display >= con.totallines )
- - con.display = con.current - con.totallines + 1;
- + con.backscroll += abs( lines );
- }
- /*
- @@ -388,10 +484,7 @@ Con_PageDown
- */
- void Con_PageDown( int lines )
- {
- - con.display += abs( lines );
- -
- - if( con.display > con.current )
- - con.display = con.current;
- + con.backscroll -= abs( lines );
- }
- /*
- @@ -401,10 +494,7 @@ Con_Top
- */
- void Con_Top( void )
- {
- - con.display = con.totallines;
- -
- - if( con.current - con.display >= con.totallines )
- - con.display = con.current - con.totallines + 1;
- + con.backscroll = CON_MAXLINES;
- }
- /*
- @@ -414,7 +504,7 @@ Con_Bottom
- */
- void Con_Bottom( void )
- {
- - con.display = con.current;
- + con.backscroll = 0;
- }
- /*
- @@ -424,7 +514,7 @@ Con_Visible
- */
- qboolean Con_Visible( void )
- {
- - return (con.displayFrac != 0.0f);
- + return (con.vislines > 0);
- }
- /*
- @@ -436,8 +526,6 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
- {
- int fontWidth;
- - ASSERT( font != NULL );
- -
- if( font->valid ) return; // already loaded
- // loading conchars
- @@ -501,6 +589,36 @@ static void Con_LoadConchars( void )
- }
- +/*
- +====================
- +Con_TextAdjustSize
- +
- +draw charcters routine
- +====================
- +*/
- +static void Con_TextAdjustSize( int *x, int *y, int *w, int *h )
- +{
- + float xscale, yscale;
- +
- + if( !x && !y && !w && !h ) return;
- +
- + // scale for screen sizes
- + xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
- + yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
- +
- + if( x ) *x *= xscale;
- + if( y ) *y *= yscale;
- + if( w ) *w *= xscale;
- + if( h ) *h *= yscale;
- +}
- +
- +/*
- +====================
- +Con_DrawGenericChar
- +
- +draw console single character
- +====================
- +*/
- static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
- {
- int width, height;
- @@ -529,36 +647,73 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
- width = rc->right - rc->left;
- height = rc->bottom - rc->top;
- - TextAdjustSize( &x, &y, &width, &height );
- + if( clgame.ds.adjust_size )
- + Con_TextAdjustSize( &x, &y, &width, &height );
- R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, con.curFont->hFontTexture );
- pglColor4ub( 255, 255, 255, 255 ); // don't forget reset color
- return con.curFont->charWidths[number];
- }
- +/*
- +====================
- +Con_SetFont
- +
- +choose font size
- +====================
- +*/
- void Con_SetFont( int fontNum )
- {
- fontNum = bound( 0, fontNum, 2 );
- con.curFont = &con.chars[fontNum];
- }
- +/*
- +====================
- +Con_RestoreFont
- +
- +restore auto-selected console font
- +(that based on screen resolution)
- +====================
- +*/
- void Con_RestoreFont( void )
- {
- con.curFont = con.lastUsedFont;
- }
- +/*
- +====================
- +Con_DrawCharacter
- +
- +client version of routine
- +====================
- +*/
- int Con_DrawCharacter( int x, int y, int number, rgba_t color )
- {
- GL_SetRenderMode( kRenderTransTexture );
- return Con_DrawGenericChar( x, y, number, color );
- }
- +/*
- +====================
- +Con_DrawCharacterLen
- +
- +returns character sizes in screen pixels
- +====================
- +*/
- void Con_DrawCharacterLen( int number, int *width, int *height )
- {
- if( width && con.curFont ) *width = con.curFont->charWidths[number];
- if( height && con.curFont ) *height = con.curFont->charHeight;
- }
- +/*
- +====================
- +Con_DrawStringLen
- +
- +compute string width and height in screen pixels
- +====================
- +*/
- void Con_DrawStringLen( const char *pText, int *length, int *height )
- {
- int curLength = 0;
- @@ -613,10 +768,10 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb
- if( !con.curFont ) return 0; // no font set
- // draw the colored text
- - s = string;
- *(uint *)color = *(uint *)setColor;
- + s = string;
- - while ( *s )
- + while( *s )
- {
- if( *s == '\n' )
- {
- @@ -652,6 +807,13 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb
- return drawLen;
- }
- +/*
- +====================
- +Con_DrawString
- +
- +client version of routine
- +====================
- +*/
- int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
- {
- return Con_DrawGenericString( x, y, string, setColor, false, -1 );
- @@ -669,10 +831,17 @@ void Con_Init( void )
- // must be init before startup video subsystem
- scr_width = Cvar_Get( "width", "640", 0, "screen width" );
- scr_height = Cvar_Get( "height", "480", 0, "screen height" );
- - scr_conspeed = Cvar_Get( "scr_conspeed", "600", 0, "console moving speed" );
- - con_notifytime = Cvar_Get( "con_notifytime", "3", 0, "notify time to live" );
- + scr_conspeed = Cvar_Get( "scr_conspeed", "600", CVAR_ARCHIVE, "console moving speed" );
- + con_notifytime = Cvar_Get( "con_notifytime", "3", CVAR_ARCHIVE, "notify time to live" );
- con_fontsize = Cvar_Get( "con_fontsize", "1", CVAR_ARCHIVE, "console font number (0, 1 or 2)" );
- + // init the console buffer
- + con.bufsize = CON_TEXTSIZE;
- + con.buffer = (char *)Z_Malloc( con.bufsize );
- + con.maxlines = CON_MAXLINES;
- + con.lines = (con_lineinfo_t *)Z_Malloc( con.maxlines * sizeof( *con.lines ));
- + con.lines_first = con.lines_count = 0;
- +
- Con_CheckResize();
- Con_ClearField( &con.input );
- @@ -697,28 +866,23 @@ void Con_Init( void )
- con.initialized = true;
- }
- -
- /*
- -===============
- -Con_Linefeed
- -===============
- +================
- +Con_Shutdown
- +================
- */
- -void Con_Linefeed( void )
- +void Con_Shutdown( void )
- {
- - int i;
- + con.initialized = false;
- - // mark time for transparent overlay
- - if( con.current >= 0 )
- - con.times[con.current % CON_TIMES] = host.realtime;
- + if( con.buffer )
- + Mem_Free( con.buffer );
- - con.x = 0;
- - if( con.display == con.current )
- - con.display++;
- + if( con.lines )
- + Mem_Free( con.lines );
- - con.current++;
- -
- - for( i = 0; i < con.linewidth; i++ )
- - con.text[(con.current % con.totallines) * con.linewidth+i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
- + con.buffer = NULL;
- + con.lines = NULL;
- }
- /*
- @@ -726,63 +890,52 @@ void Con_Linefeed( void )
- Con_Print
- Handles cursor positioning, line wrapping, etc
- -All console printing must go through this in order to be logged to disk
- -If no console is visible, the text will appear at the top of the game window
- +All console printing must go through this in order to be displayed
- +If no console is visible, the notify window will pop up.
- ================
- */
- void Con_Print( const char *txt )
- {
- - int y, c, l, color;
- + static int cr_pending = 0;
- + static char buf[MAX_PRINT_MSG];
- + static int bufpos = 0;
- // client not running
- - if( host.type == HOST_DEDICATED ) return;
- - if( !con.initialized ) return;
- -
- - color = ColorIndex( COLOR_DEFAULT );
- + if( !con.initialized || !con.buffer || host.type == HOST_DEDICATED )
- + return;
- - while(( c = *txt ) != 0 )
- + for( ; *txt; txt++ )
- {
- - if( IsColorString( txt ))
- + if( cr_pending )
- {
- - color = ColorIndex( *( txt + 1 ));
- - txt += 2;
- - continue;
- + Con_DeleteLastLine();
- + cr_pending = 0;
- }
- - // count word length
- - for( l = 0; l < con.linewidth; l++ )
- - {
- - if( txt[l] <= ' ')
- - break;
- - }
- -#if 0
- - // g-cont. experiment from SDLash3D
- - // word wrap
- - if( l != con.linewidth && ( con.x + l >= con.linewidth ))
- - Con_Linefeed();
- -#endif
- - txt++;
- -
- - switch( c )
- + switch( *txt )
- {
- - case '\n':
- - Con_Linefeed();
- + case '\0':
- break;
- case '\r':
- - con.x = 0;
- + Con_AddLine( buf, bufpos );
- + cr_pending = 1;
- + bufpos = 0;
- break;
- - default: // display character and advance
- - y = con.current % con.totallines;
- - con.text[y*con.linewidth+con.x] = (color << 8) | c;
- - con.x++;
- - if( con.x >= con.linewidth )
- + case '\n':
- + Con_AddLine( buf, bufpos );
- + bufpos = 0;
- + break;
- + default:
- + buf[bufpos++] = *txt;
- + if(( bufpos >= sizeof( buf ) - 1 ) || bufpos >= ( con.linewidth - 1 ))
- {
- - Con_Linefeed();
- - con.x = 0;
- + Con_AddLine( buf, bufpos );
- + bufpos = 0;
- }
- break;
- }
- }
- +
- }
- /*
- @@ -949,7 +1102,7 @@ static int Con_SortCmds( const char **arg1, const char **arg2 )
- /*
- ===============
- -pfnPrintMatches
- +Con_PrintMatches
- ===============
- */
- static void Con_PrintMatches( const char *s, const char *unused1, const char *m, void *unused2 )
- @@ -961,7 +1114,12 @@ static void Con_PrintMatches( const char *s, const char *unused1, const char *m,
- }
- }
- -static void ConcatRemaining( const char *src, const char *start )
- +/*
- +===============
- +Con_ConcatRemaining
- +===============
- +*/
- +static void Con_ConcatRemaining( const char *src, const char *start )
- {
- char *arg;
- int i;
- @@ -1018,11 +1176,16 @@ void Con_CompleteCommand( field_t *field )
- nextcmd = ( con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ' ) ? true : false;
- con.completionString = Cmd_Argv( 0 );
- + con.completionBuffer = Cmd_Argv( 1 );
- // skip backslash
- while( *con.completionString && ( *con.completionString == '\\' || *con.completionString == '/' ))
- con.completionString++;
- + // skip backslash
- + while( *con.completionBuffer && ( *con.completionBuffer == '\\' || *con.completionBuffer == '/' ))
- + con.completionBuffer++;
- +
- if( !Q_strlen( con.completionString ))
- return;
- @@ -1051,12 +1214,15 @@ void Con_CompleteCommand( field_t *field )
- {
- qboolean result = false;
- + if( !Q_strlen( con.completionBuffer ))
- + return;
- +
- // autocomplete second arg
- for( list = cmd_list; list->name; list++ )
- {
- if( Cmd_CheckName( list->name ))
- {
- - result = list->func( Cmd_Argv( 1 ), filename, MAX_STRING );
- + result = list->func( con.completionBuffer, filename, MAX_STRING );
- break;
- }
- }
- @@ -1080,7 +1246,7 @@ void Con_CompleteCommand( field_t *field )
- {
- Q_sprintf( con.completionField->buffer, "\\%s", con.cmds[0] );
- if( Cmd_Argc() == 1 ) Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
- - else ConcatRemaining( temp.buffer, con.completionString );
- + else Con_ConcatRemaining( temp.buffer, con.completionString );
- con.completionField->cursor = Q_strlen( con.completionField->buffer );
- }
- else
- @@ -1108,7 +1274,7 @@ void Con_CompleteCommand( field_t *field )
- // multiple matches, complete to shortest
- Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
- con.completionField->cursor = Q_strlen( con.completionField->buffer );
- - ConcatRemaining( temp.buffer, con.completionString );
- + Con_ConcatRemaining( temp.buffer, con.completionString );
- Msg( "]%s\n", con.completionField->buffer );
- @@ -1135,7 +1301,6 @@ void Field_Paste( field_t *edit )
- pasteLen = Q_strlen( cbd );
- for( i = 0; i < pasteLen; i++ )
- Field_CharEvent( edit, cbd[i] );
- - Mem_Free( cbd );
- }
- /*
- @@ -1313,7 +1478,7 @@ void Field_DrawInputLine( int x, int y, field_t *edit )
- drawLen = len - prestep;
- // extract <drawLen> characters from the field at <prestep>
- - ASSERT( drawLen < MAX_SYSPATH );
- + drawLen = Q_min( drawLen, MAX_SYSPATH - 1 );
- memcpy( str, edit->buffer + prestep, drawLen );
- str[drawLen] = 0;
- @@ -1370,7 +1535,7 @@ void Key_Console( int key )
- }
- // enter finishes the line
- - if ( key == K_ENTER || key == K_KP_ENTER )
- + if( key == K_ENTER || key == K_KP_ENTER )
- {
- // if not in the game explicitly prepent a slash if needed
- if( cls.state != ca_active && con.input.buffer[0] != '\\' && con.input.buffer[0] != '/' )
- @@ -1418,9 +1583,7 @@ void Key_Console( int key )
- if(( key == K_MWHEELUP && Key_IsDown( K_SHIFT )) || ( key == K_UPARROW ) || (( Q_tolower(key) == 'p' ) && Key_IsDown( K_CTRL )))
- {
- if( con.nextHistoryLine - con.historyLine < CON_HISTORY && con.historyLine > 0 )
- - {
- con.historyLine--;
- - }
- con.input = con.historyLines[con.historyLine % CON_HISTORY];
- return;
- }
- @@ -1436,13 +1599,13 @@ void Key_Console( int key )
- // console scrolling
- if( key == K_PGUP )
- {
- - Con_PageUp( 2 );
- + Con_PageUp( 1 );
- return;
- }
- if( key == K_PGDN )
- {
- - Con_PageDown( 2 );
- + Con_PageDown( 1 );
- return;
- }
- @@ -1528,21 +1691,17 @@ Con_DrawInput
- The input line scrolls horizontally if typing goes beyond the right edge
- ================
- */
- -void Con_DrawInput( void )
- +void Con_DrawInput( int lines )
- {
- - byte *colorDefault;
- - int x, y;
- + int y;
- // don't draw anything (always draw if not active)
- - if( cls.key_dest != key_console ) return;
- - if( !con.curFont ) return;
- -
- - x = QCHAR_WIDTH; // room for ']'
- - y = con.vislines - ( con.curFont->charHeight * 2 );
- - colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
- + if( cls.key_dest != key_console || !con.curFont )
- + return;
- - Con_DrawCharacter( QCHAR_WIDTH >> 1, y, ']', colorDefault );
- - Field_DrawInputLine( x, y, &con.input );
- + y = lines - ( con.curFont->charHeight * 2 );
- + Con_DrawCharacter( 8, y, ']', g_color_table[7] );
- + Field_DrawInputLine( 16, y, &con.input );
- }
- /*
- @@ -1555,8 +1714,8 @@ Custom debug messages
- int Con_DrawDebugLines( void )
- {
- int i, count = 0;
- - int y = 20;
- int defaultX;
- + int y = 20;
- defaultX = glState.width / 4;
- @@ -1568,7 +1727,7 @@ int Con_DrawDebugLines( void )
- int fontTall;
- Con_DrawStringLen( con.notify[i].szNotify, &len, &fontTall );
- - x = scr_width->integer - max( defaultX, len ) - 10;
- + x = scr_width->integer - Q_max( defaultX, len ) - 10;
- fontTall += 1;
- if( y + fontTall > (int)scr_height->integer - 20 )
- @@ -1611,38 +1770,24 @@ Draws the last few lines of output transparently over the game top
- */
- void Con_DrawNotify( void )
- {
- - int i, x, v = 0;
- - int start, currentColor;
- - short *text;
- - float time;
- + double time = cl.time;
- + int i, x, y = 0;
- if( !con.curFont ) return;
- + x = con.curFont->charWidths[' ']; // offset one space at left screen side
- +
- if( host.developer && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
- {
- - currentColor = 7;
- - pglColor4ubv( g_color_table[currentColor] );
- -
- - for( i = con.current - CON_TIMES + 1; i <= con.current; i++ )
- + for( i = CON_LINES_COUNT - CON_TIMES; i < CON_LINES_COUNT; i++ )
- {
- - if( i < 0 ) continue;
- - time = con.times[i % CON_TIMES];
- - if( time == 0 ) continue;
- - time = host.realtime - time;
- + con_lineinfo_t *l = &CON_LINES( i );
- - if( time > con_notifytime->value )
- - continue; // expired
- + if( l->addtime < ( time - con_notifytime->value ))
- + continue;
- - text = con.text + (i % con.totallines) * con.linewidth;
- - start = con.curFont->charWidths[' ']; // offset one space at left screen side
- -
- - for( x = 0; x < con.linewidth; x++ )
- - {
- - if((( text[x] >> 8 ) & 7 ) != currentColor )
- - currentColor = ( text[x] >> 8 ) & 7;
- - start += Con_DrawCharacter( start, v, text[x] & 0xFF, g_color_table[currentColor] );
- - }
- - v += con.curFont->charHeight;
- + Con_DrawString( x, y, l->start, g_color_table[7] );
- + y += con.curFont->charHeight;
- }
- }
- @@ -1651,21 +1796,16 @@ void Con_DrawNotify( void )
- string buf;
- int len;
- - currentColor = 7;
- - pglColor4ubv( g_color_table[currentColor] );
- -
- - start = con.curFont->charWidths[' ']; // offset one space at left screen side
- -
- // update chatline position from client.dll
- if( clgame.dllFuncs.pfnChatInputPosition )
- - clgame.dllFuncs.pfnChatInputPosition( &start, &v );
- + clgame.dllFuncs.pfnChatInputPosition( &x, &y );
- Q_snprintf( buf, sizeof( buf ), "%s: ", con.chat_cmd );
- Con_DrawStringLen( buf, &len, NULL );
- - Con_DrawString( start, v, buf, g_color_table[7] );
- + Con_DrawString( x, y, buf, g_color_table[7] );
- - Field_DrawInputLine( start + len, v, &con.chat );
- + Field_DrawInputLine( x + len, y, &con.chat );
- }
- pglColor4ub( 255, 255, 255, 255 );
- @@ -1673,98 +1813,135 @@ void Con_DrawNotify( void )
- /*
- ================
- +Con_DrawConsoleLine
- +
- +Draws a line of the console; returns its height in lines.
- +If alpha is 0, the line is not drawn, but still wrapped and its height
- +returned.
- +================
- +*/
- +int Con_DrawConsoleLine( int y, int lineno )
- +{
- + con_lineinfo_t *li = &CON_LINES( lineno );
- +
- + if( y >= con.curFont->charHeight )
- + Con_DrawGenericString( con.curFont->charWidths[' '], y, li->start, g_color_table[7], false, -1 );
- +
- + return con.curFont->charHeight;
- +}
- +
- +/*
- +================
- +Con_LastVisibleLine
- +
- +Calculates the last visible line index and how much to show
- +of it based on con.backscroll.
- +================
- +*/
- +static void Con_LastVisibleLine( int *lastline )
- +{
- + int i, lines_seen = 0;
- +
- + con.backscroll = Q_max( 0, con.backscroll );
- + *lastline = 0;
- +
- + // now count until we saw con_backscroll actual lines
- + for( i = CON_LINES_COUNT - 1; i >= 0; i-- )
- + {
- + // line is the last visible line?
- + *lastline = i;
- +
- + if( lines_seen + 1 > con.backscroll && lines_seen <= con.backscroll )
- + return;
- +
- + lines_seen += 1;
- + }
- +
- + // if we get here, no line was on screen - scroll so that one line is visible then.
- + con.backscroll = lines_seen - 1;
- +}
- +
- +/*
- +================
- Con_DrawConsole
- Draws the console with the solid background
- ================
- */
- -void Con_DrawSolidConsole( float frac )
- +void Con_DrawSolidConsole( int lines )
- {
- int i, x, y;
- - int rows;
- - short *text;
- - int row;
- - int lines, start;
- - int currentColor;
- - string curbuild;
- + float fraction;
- + int start;
- - lines = scr_height->integer * frac;
- if( lines <= 0 ) return;
- - if( lines > scr_height->integer )
- - lines = scr_height->integer;
- // draw the background
- - y = frac * scr_height->integer;
- + GL_SetRenderMode( kRenderNormal );
- + pglColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade
- + R_DrawStretchPic( 0, lines - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background );
- - if( y >= 1 )
- - {
- - GL_SetRenderMode( kRenderNormal );
- - R_DrawStretchPic( 0, y - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background );
- - }
- - else y = 0;
- + if( !con.curFont || host.developer <= 0 )
- + return; // nothing to draw
- - if( !con.curFont ) return; // nothing to draw
- -
- - if( host.developer )
- + if( host.developer > 0 )
- {
- // draw current version
- - byte *color = g_color_table[7];
- int stringLen, width = 0, charH;
- + string curbuild;
- + byte color[4];
- +
- + memcpy( color, g_color_table[7], sizeof( color ));
- Q_snprintf( curbuild, MAX_STRING, "Xash3D %i/%g (hw build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
- Con_DrawStringLen( curbuild, &stringLen, &charH );
- start = scr_width->integer - stringLen;
- stringLen = Con_StringLength( curbuild );
- + fraction = lines / (float)scr_height->integer;
- + color[3] = Q_min( fraction * 2.0f, 1.0f ) * 255; // fadeout version number
- +
- for( i = 0; i < stringLen; i++ )
- width += Con_DrawCharacter( start + width, 0, curbuild[i], color );
- }
- // draw the text
- - con.vislines = lines;
- - rows = ( lines - QCHAR_WIDTH ) / QCHAR_WIDTH; // rows of text to draw
- - y = lines - ( con.curFont->charHeight * 3 );
- -
- - // draw from the bottom up
- - if( con.display != con.current )
- + if( CON_LINES_COUNT > 0 )
- {
- - start = con.curFont->charWidths[' ']; // offset one space at left screen side
- -
- - // draw red arrows to show the buffer is backscrolled
- - for( x = 0; x < con.linewidth; x += 4 )
- - Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] );
- - y -= con.curFont->charHeight;
- - rows--;
- - }
- -
- - row = con.display;
- - if( con.x == 0 ) row--;
- + int ymax = lines - (con.curFont->charHeight * 2.0f);
- + int lastline;
- - currentColor = 7;
- - pglColor4ubv( g_color_table[currentColor] );
- + Con_LastVisibleLine( &lastline );
- + y = ymax - con.curFont->charHeight;
- - for( i = 0; i < rows; i++, y -= con.curFont->charHeight, row-- )
- - {
- - if( row < 0 ) break;
- - if( con.current - row >= con.totallines )
- + if( con.backscroll )
- {
- - // past scrollback wrap point
- - continue;
- - }
- + start = con.curFont->charWidths[' ']; // offset one space at left screen side
- - text = con.text + ( row % con.totallines ) * con.linewidth;
- - start = con.curFont->charWidths[' ']; // offset one space at left screen side
- + // draw red arrows to show the buffer is backscrolled
- + for( x = 0; x < con.linewidth; x += 4 )
- + Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] );
- + y -= con.curFont->charHeight;
- + }
- + x = lastline;
- - for( x = 0; x < con.linewidth; x++ )
- + while( 1 )
- {
- - if((( text[x] >> 8 ) & 7 ) != currentColor )
- - currentColor = ( text[x] >> 8 ) & 7;
- - start += Con_DrawCharacter( start, y, text[x] & 0xFF, g_color_table[currentColor] );
- + y -= Con_DrawConsoleLine( y, x );
- +
- + // top of console buffer or console window
- + if( x == 0 || y < con.curFont->charHeight )
- + break;
- + x--;
- }
- }
- // draw the input prompt, user text, and cursor if desired
- - Con_DrawInput();
- + Con_DrawInput( lines );
- +
- + y = lines - ( con.curFont->charHeight * 1.2f );
- + SCR_DrawFPS( max( y, 4 )); // to avoid to hide fps counter
- +
- pglColor4ub( 255, 255, 255, 255 );
- }
- @@ -1787,18 +1964,18 @@ void Con_DrawConsole( void )
- if( !cl_allow_levelshots->integer )
- {
- if(( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" )) && cls.key_dest != key_console )
- - con.displayFrac = con.finalFrac = 0.0f;
- - else con.displayFrac = con.finalFrac = 1.0f;
- + con.vislines = con.showlines = 0;
- + else con.vislines = con.showlines = scr_height->integer;
- }
- else
- {
- if( host.developer >= 4 )
- {
- - con.displayFrac = 0.5f; // keep console open
- + con.vislines = (scr_height->integer >> 1); // keep console open
- }
- else
- {
- - con.finalFrac = 0.0f;
- + con.showlines = 0;
- Con_RunConsole();
- if( host.developer >= 2 )
- @@ -1815,31 +1992,37 @@ void Con_DrawConsole( void )
- case ca_disconnected:
- if( cls.key_dest != key_menu && host.developer )
- {
- - Con_DrawSolidConsole( 1.0f );
- + Con_DrawSolidConsole( scr_height->integer );
- Key_SetKeyDest( key_console );
- }
- break;
- case ca_connected:
- case ca_connecting:
- // force to show console always for -dev 3 and higher
- - if( con.displayFrac ) Con_DrawSolidConsole( con.displayFrac );
- + if( con.vislines )
- + {
- + GL_CleanupAllTextureUnits(); // ugly hack to remove blinking voiceicon.spr during loading
- + Con_DrawSolidConsole( con.vislines );
- + }
- break;
- case ca_active:
- case ca_cinematic:
- if( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
- {
- if( cls.key_dest == key_console )
- - Con_DrawSolidConsole( 1.0f );
- + Con_DrawSolidConsole( scr_height->integer );
- }
- else
- {
- - if( con.displayFrac )
- - Con_DrawSolidConsole( con.displayFrac );
- + if( con.vislines )
- + Con_DrawSolidConsole( con.vislines );
- else if( cls.state == ca_active && ( cls.key_dest == key_game || cls.key_dest == key_message ))
- Con_DrawNotify(); // draw notify lines
- }
- break;
- }
- +
- + if( !Con_Visible( )) SCR_DrawFPS( 4 );
- }
- /*
- @@ -1893,30 +2076,38 @@ Scroll it up or down
- */
- void Con_RunConsole( void )
- {
- + int lines_per_frame;
- +
- // decide on the destination height of the console
- if( host.developer && cls.key_dest == key_console )
- {
- if( cls.state == ca_disconnected )
- - con.finalFrac = 1.0f;// full screen
- - else con.finalFrac = 0.5f; // half screen
- + con.showlines = scr_height->integer; // full screen
- + else con.showlines = (scr_height->integer >> 1); // half screen
- }
- - else con.finalFrac = 0; // none visible
- + else con.showlines = 0; // none visible
- // when level is loading frametime may be is wrong
- if( cls.state == ca_connecting || cls.state == ca_connected )
- - host.realframetime = ( MAX_FPS / host_maxfps->value ) * MIN_FRAMETIME;
- + {
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + host.realframetime = ( MAX_FPS / host_maxfps->value ) * MIN_FRAMETIME;
- + else host.realframetime = HOST_FRAMETIME;
- + }
- +
- + lines_per_frame = bound( 1, fabs( scr_conspeed->value ) * host.realframetime, scr_height->integer );
- - if( con.finalFrac < con.displayFrac )
- + if( con.showlines < con.vislines )
- {
- - con.displayFrac -= fabs( scr_conspeed->value ) * 0.002f * host.realframetime;
- - if( con.finalFrac > con.displayFrac )
- - con.displayFrac = con.finalFrac;
- + con.vislines -= lines_per_frame;
- + if( con.showlines > con.vislines )
- + con.vislines = con.showlines;
- }
- - else if( con.finalFrac > con.displayFrac )
- + else if( con.showlines > con.vislines )
- {
- - con.displayFrac += fabs( scr_conspeed->value ) * 0.002f * host.realframetime;
- - if( con.finalFrac < con.displayFrac )
- - con.displayFrac = con.finalFrac;
- + con.vislines += lines_per_frame;
- + if( con.showlines < con.vislines )
- + con.vislines = con.showlines;
- }
- }
- @@ -1947,6 +2138,14 @@ void Con_CharEvent( int key )
- }
- }
- +/*
- +=========
- +Con_VidInit
- +
- +reload background
- +resize console
- +=========
- +*/
- void Con_VidInit( void )
- {
- Con_CheckResize();
- @@ -1954,42 +2153,62 @@ void Con_VidInit( void )
- // loading console image
- if( host.developer )
- {
- - if( scr_width->integer < 640 )
- - {
- - if( FS_FileExists( "cached/conback400", false ))
- - con.background = GL_LoadTexture( "cached/conback400", NULL, 0, TF_IMAGE, NULL );
- - else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
- - }
- - else
- + // trying to load truecolor image first
- + if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
- + con.background = GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE, NULL );
- +
- + if( !con.background )
- {
- - if( FS_FileExists( "cached/conback640", false ))
- - con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE, NULL );
- - else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
- + if( scr_width->integer < 640 )
- + {
- + if( FS_FileExists( "cached/conback400", false ))
- + con.background = GL_LoadTexture( "cached/conback400", NULL, 0, TF_IMAGE, NULL );
- + else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
- + }
- + else
- + {
- + if( FS_FileExists( "cached/conback640", false ))
- + con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE, NULL );
- + else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
- + }
- }
- }
- else
- {
- - if( scr_width->integer < 640 )
- - {
- - if( FS_FileExists( "cached/loading400", false ))
- - con.background = GL_LoadTexture( "cached/loading400", NULL, 0, TF_IMAGE, NULL );
- - else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
- - }
- - else
- + // trying to load truecolor image first
- + if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
- + con.background = GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE, NULL );
- +
- + if( !con.background )
- {
- - if( FS_FileExists( "cached/loading640", false ))
- - con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE, NULL );
- - else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
- + if( scr_width->integer < 640 )
- + {
- + if( FS_FileExists( "cached/loading400", false ))
- + con.background = GL_LoadTexture( "cached/loading400", NULL, 0, TF_IMAGE, NULL );
- + else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
- + }
- + else
- + {
- + if( FS_FileExists( "cached/loading640", false ))
- + con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE, NULL );
- + else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
- + }
- }
- }
- - // missed console image will be replaced as white (GoldSrc rules)
- + // missed console image will be replaced as gray background like X-Ray or Crysis
- if( con.background == tr.defaultTexture || con.background == 0 )
- - con.background = tr.whiteTexture;
- + con.background = tr.grayTexture;
- Con_LoadConchars();
- }
- +/*
- +=========
- +Con_InvalidateFonts
- +
- +=========
- +*/
- void Con_InvalidateFonts( void )
- {
- memset( con.chars, 0, sizeof( con.chars ));
- @@ -2022,12 +2241,19 @@ void Cmd_AutoComplete( char *complete_string )
- else Q_strncpy( complete_string, input.buffer, sizeof( input.buffer ));
- }
- -void Con_Close( void )
- +/*
- +=========
- +Con_FastClose
- +
- +immediately close the console
- +=========
- +*/
- +void Con_FastClose( void )
- {
- Con_ClearField( &con.input );
- Con_ClearNotify();
- - con.finalFrac = 0.0f; // none visible
- - con.displayFrac = 0.0f;
- + con.showlines = 0;
- + con.vislines = 0;
- }
- /*
- diff --git b/engine/common/crtlib.c a/engine/common/crtlib.c
- index 9a3c348..8a44b25 100644
- --- b/engine/common/crtlib.c
- +++ a/engine/common/crtlib.c
- @@ -71,6 +71,29 @@ int Q_strlen( const char *string )
- return len;
- }
- +int Q_colorstr( const char *string )
- +{
- + int len;
- + const char *p;
- +
- + if( !string ) return 0;
- +
- + len = 0;
- + p = string;
- + while( *p )
- + {
- + if( IsColorString( p ))
- + {
- + len += 2;
- + p += 2;
- + continue;
- + }
- + p++;
- + }
- +
- + return len;
- +}
- +
- char Q_toupper( const char in )
- {
- char out;
- @@ -572,6 +595,26 @@ int Q_sprintf( char *buffer, const char *format, ... )
- return result;
- }
- +uint Q_hashkey( const char *string, uint hashSize, qboolean caseinsensitive )
- +{
- + uint i, hashKey = 0;
- +
- + if( caseinsensitive )
- + {
- + for( i = 0; string[i]; i++)
- + hashKey += (i * 119) * Q_tolower( string[i] );
- + }
- + else
- + {
- + for( i = 0; string[i]; i++ )
- + hashKey += (i + 119) * (int)string[i];
- + }
- +
- + hashKey = ((hashKey ^ (hashKey >> 10)) ^ (hashKey >> 20)) & (hashSize - 1);
- +
- + return hashKey;
- +}
- +
- char *Q_pretifymem( float value, int digitsafterdecimal )
- {
- static char output[8][32];
- @@ -666,36 +709,4 @@ char *va( const char *format, ... )
- va_end( argptr );
- return s;
- -}
- -
- -void _memcpy( void *dest, const void *src, size_t count, const char *filename, int fileline )
- -{
- - if( src == NULL || count <= 0 ) return; // nothing to copy
- - if( dest == NULL ) Sys_Error( "memcpy: dest == NULL (called at %s:%i)\n", filename, fileline );
- - memcpy( dest, src, count );
- -}
- -
- -void _memset( void *dest, int set, size_t count, const char *filename, int fileline )
- -{
- - if( dest == NULL ) Sys_Error( "memset: dest == NULL (called at %s:%i)\n", filename, fileline );
- - memset( dest, set, count );
- -}
- -
- -int _memcmp( const void *src0, const void *src1, size_t count, const char *filename, int fileline )
- -{
- - if( src0 == NULL ) Sys_Error( "memcmp: src1 == NULL (called at %s:%i)\n", filename, fileline );
- - if( src1 == NULL ) Sys_Error( "memcmp: src2 == NULL (called at %s:%i)\n", filename, fileline );
- - return memcmp( src0, src1, count );
- -}
- -
- -void _memmove( void *dest, const void *src, size_t count, const char *filename, int fileline )
- -{
- - if( src == NULL || count <= 0 ) return; // nothing to move
- - if( dest == NULL ) Sys_Error( "memmove: dest == NULL (called at %s:%i)\n", filename, fileline );
- - memmove( dest, src, count );
- -}
- -
- -void CRT_Init( void )
- -{
- - Memory_Init();
- }
- \ No newline at end of file
- diff --git b/engine/common/crtlib.h a/engine/common/crtlib.h
- index 012d4e0..d4c994e 100644
- --- b/engine/common/crtlib.h
- +++ a/engine/common/crtlib.h
- @@ -27,21 +27,13 @@ enum
- TIME_FILENAME,
- };
- -#define CMD_EXTDLL BIT( 0 ) // added by game.dll
- +#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
- #define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
- +#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
- typedef void (*setpair_t)( const char *key, const char *value, void *buffer, void *numpairs );
- typedef void (*xcommand_t)( void );
- -typedef enum
- -{
- - src_client, // came in over a net connection as a clc_stringcmd
- - // host_client will be valid during this state.
- - src_command // from the command buffer
- -} cmd_source_t;
- -
- -extern cmd_source_t cmd_source;
- -
- // NOTE: if this is changed, it must be changed in cvardef.h too
- typedef struct convar_s
- {
- @@ -63,25 +55,26 @@ typedef struct convar_s
- // cvar flags
- typedef enum
- {
- - CVAR_ARCHIVE = BIT(0), // set to cause it to be saved to config.cfg
- - CVAR_USERINFO = BIT(1), // added to userinfo when changed
- - CVAR_SERVERNOTIFY = BIT(2), // notifies players when changed
- - CVAR_EXTDLL = BIT(3), // defined by external DLL
- - CVAR_CLIENTDLL = BIT(4), // defined by the client dll
- - CVAR_PROTECTED = BIT(5), // it's a server cvar, but we don't send the data since it's a password, etc.
- - CVAR_SPONLY = BIT(6), // this cvar cannot be changed by clients connected to a multiplayer server.
- - CVAR_PRINTABLEONLY = BIT(7), // this cvar's string cannot contain unprintable characters ( player name )
- - CVAR_UNLOGGED = BIT(8), // if this is a FCVAR_SERVER, don't log changes to the log file / console
- - CVAR_SERVERINFO = BIT(9), // added to serverinfo when changed
- - CVAR_PHYSICINFO = BIT(10),// added to physinfo when changed
- - CVAR_RENDERINFO = BIT(11),// save to a seperate config called opengl.cfg
- - CVAR_CHEAT = BIT(12),// can not be changed if cheats are disabled
- - CVAR_INIT = BIT(13),// don't allow change from console at all, but can be set from the command line
- - CVAR_LATCH = BIT(14),// save changes until server restart
- - CVAR_READ_ONLY = BIT(15),// display only, cannot be set by user at all
- - CVAR_LATCH_VIDEO = BIT(16),// save changes until render restart
- - CVAR_USER_CREATED = BIT(17),// created by a set command (dll's used)
- - CVAR_GLCONFIG = BIT(18),// set to cause it to be saved to opengl.cfg
- + CVAR_ARCHIVE = BIT( 0 ), // set to cause it to be saved to config.cfg
- + CVAR_USERINFO = BIT( 1 ), // added to userinfo when changed
- + CVAR_SERVERNOTIFY = BIT( 2 ), // notifies players when changed
- + CVAR_SERVERDLL = BIT( 3 ), // defined by the server DLL
- + CVAR_CLIENTDLL = BIT( 4 ), // defined by the client dll
- + CVAR_PROTECTED = BIT( 5 ), // it's a server cvar, but we don't send the data since it's a password, etc.
- + CVAR_SPONLY = BIT( 6 ), // this cvar cannot be changed by clients connected to a multiplayer server.
- + CVAR_PRINTABLEONLY = BIT( 7 ), // this cvar's string cannot contain unprintable characters ( player name )
- + CVAR_UNLOGGED = BIT( 8 ), // if this is a FCVAR_SERVER, don't log changes to the log file / console
- + CVAR_NOWHITEPACE = BIT( 9 ), // strip trailing/leading white space from this cvar
- + CVAR_SERVERINFO = BIT( 10 ), // added to serverinfo when changed
- + CVAR_PHYSICINFO = BIT( 11 ), // added to physinfo when changed
- + CVAR_RENDERINFO = BIT( 12 ), // save to a seperate config called opengl.cfg
- + CVAR_CHEAT = BIT( 13 ), // can not be changed if cheats are disabled
- + CVAR_INIT = BIT( 14 ), // don't allow change from console at all, but can be set from the command line
- + CVAR_LATCH = BIT( 15 ), // save changes until server restart
- + CVAR_READ_ONLY = BIT( 16 ), // display only, cannot be set by user at all
- + CVAR_GAMEUIDLL = BIT( 17 ), // defined by the GameUI DLL
- + CVAR_GLCONFIG = BIT( 18 ), // set to cause it to be saved to opengl.cfg
- + CVAR_USER_CREATED = BIT( 19 ), // created by a set command (dll's used)
- } cvar_flags_t;
- #include "cvardef.h"
- @@ -109,7 +102,7 @@ void Cvar_WriteVariables( file_t *f );
- void Cvar_Init( void );
- char *Cvar_Userinfo( void );
- char *Cvar_Serverinfo( void );
- -void Cvar_Unlink( void );
- +void Cvar_Unlink( int group );
- //
- // cmd.c
- @@ -125,8 +118,9 @@ char *Cmd_Argv( int arg );
- void Cmd_Init( void );
- void Cmd_Unlink( int group );
- void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
- -void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function );
- -void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
- +void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
- +int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
- +int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
- void Cmd_RemoveCommand( const char *cmd_name );
- qboolean Cmd_Exists( const char *cmd_name );
- void Cmd_LookupCmds( char *buffer, void *ptr, setpair_t callback );
- @@ -134,7 +128,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length );
- qboolean Cmd_GetDemoList( const char *s, char *completedname, int length );
- qboolean Cmd_GetMovieList( const char *s, char *completedname, int length );
- void Cmd_TokenizeString( char *text );
- -void Cmd_ExecuteString( char *text, cmd_source_t src );
- +void Cmd_ExecuteString( char *text );
- void Cmd_ForwardToServer( void );
- //
- @@ -145,6 +139,7 @@ void Q_strnupr( const char *in, char *out, size_t size_out );
- #define Q_strlwr( int, out ) Q_strnlwr( in, out, 99999 )
- void Q_strnlwr( const char *in, char *out, size_t size_out );
- int Q_strlen( const char *string );
- +int Q_colorstr( const char *string );
- char Q_toupper( const char in );
- char Q_tolower( const char in );
- #define Q_strcat( dst, src ) Q_strncat( dst, src, 99999 )
- @@ -153,6 +148,7 @@ size_t Q_strncat( char *dst, const char *src, size_t siz );
- size_t Q_strncpy( char *dst, const char *src, size_t siz );
- #define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ )
- char *_copystring( byte *mempool, const char *s, const char *filename, int fileline );
- +uint Q_hashkey( const char *string, uint hashSize, qboolean caseinsensitive );
- qboolean Q_isdigit( const char *str );
- int Q_atoi( const char *str );
- float Q_atof( const char *str );
- @@ -174,14 +170,6 @@ int Q_sprintf( char *buffer, const char *format, ... );
- #define Q_memprint( val ) Q_pretifymem( val, 2 )
- char *Q_pretifymem( float value, int digitsafterdecimal );
- char *va( const char *format, ... );
- -#define Q_memcpy( dest, src, size ) _Q_memcpy( dest, src, size, __FILE__, __LINE__ )
- -#define Q_memset( dest, val, size ) _Q_memset( dest, val, size, __FILE__, __LINE__ )
- -#define Q_memcmp( src0, src1, siz ) _Q_memcmp( src0, src1, siz, __FILE__, __LINE__ )
- -#define Q_memmove( dest, src, size ) _Q_memmove( dest, src, size, __FILE__, __LINE__ )
- -void _Q_memset( void *dest, int set, size_t count, const char *filename, int fileline );
- -void _Q_memcpy( void *dest, const void *src, size_t count, const char *filename, int fileline );
- -int _Q_memcmp( const void *src0, const void *src1, size_t count, const char *filename, int fileline );
- -void _Q_memmove( void *dest, const void *src, size_t count, const char *filename, int fileline );
- //
- // zone.c
- @@ -206,7 +194,5 @@ void Mem_PrintStats( void );
- #define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
- #define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
- #define Mem_Check() _Mem_Check( __FILE__, __LINE__ )
- -
- -void CRT_Init( void ); // must be call first
- #endif//STDLIB_H
- \ No newline at end of file
- diff --git b/engine/common/cvar.c a/engine/common/cvar.c
- index cb7f6b6..6b93895 100644
- --- b/engine/common/cvar.c
- +++ a/engine/common/cvar.c
- @@ -17,6 +17,7 @@ GNU General Public License for more details.
- convar_t *cvar_vars; // head of list
- convar_t *userinfo, *physinfo, *serverinfo, *renderinfo;
- +convar_t *cmd_scripting;
- /*
- ============
- @@ -139,7 +140,7 @@ void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback
- else
- {
- // NOTE: dlls cvars doesn't have description
- - if( cvar->flags & CVAR_EXTDLL )
- + if( FBitSet( cvar->flags, CVAR_SERVERDLL ))
- callback( cvar->name, cvar->string, "game cvar", ptr );
- else callback( cvar->name, cvar->string, cvar->description, ptr );
- }
- @@ -156,18 +157,25 @@ The flags will be or'ed in if the variable exists.
- */
- convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, const char *var_desc )
- {
- - convar_t *var;
- + convar_t *cur, *find, *var;
- if( !var_name )
- {
- - Sys_Error( "Cvar_Get: passed NULL name\n" );
- + MsgDev( D_ERROR, "Cvar_Get: passed NULL name\n" );
- + return NULL;
- + }
- +
- + // check for command coexisting
- + if( Cmd_Exists( var_name ))
- + {
- + MsgDev( D_ERROR, "Cvar_Get: %s is a command\n", var_name );
- return NULL;
- }
- if( !var_value ) var_value = "0"; // just apply default value
- // all broadcast cvars must be passed this check
- - if( flags & ( CVAR_USERINFO|CVAR_SERVERINFO|CVAR_PHYSICINFO ))
- + if( FBitSet( flags, CVAR_USERINFO|CVAR_SERVERINFO|CVAR_PHYSICINFO ))
- {
- if( !Cvar_ValidateString( var_name, false ))
- {
- @@ -182,37 +190,30 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
- }
- }
- - // check for command coexisting
- - if( Cmd_Exists( var_name ))
- - {
- - MsgDev( D_ERROR, "Cvar_Get: %s is a command\n", var_name );
- - return NULL;
- - }
- -
- var = Cvar_FindVar( var_name );
- if( var )
- {
- // fast check for short cvars
- - if( var->flags & CVAR_EXTDLL )
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- {
- - var->flags |= flags;
- + SetBits( var->flags, flags );
- return var;
- }
- // if the C code is now specifying a variable that the user already
- // set a value for, take the new value as the reset value
- - if(( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED ) && var_value[0] )
- + if( FBitSet( var->flags, CVAR_USER_CREATED ) && !FBitSet( flags, CVAR_USER_CREATED ) && var_value[0] )
- {
- - var->flags &= ~CVAR_USER_CREATED;
- Mem_Free( var->reset_string );
- var->reset_string = copystring( var_value );
- + ClearBits( var->flags, CVAR_USER_CREATED );
- }
- - var->flags |= flags;
- + SetBits( var->flags, flags );
- // only allow one non-empty reset string without a warning
- - if( !var->reset_string[0] )
- + if( var->reset_string != NULL && !var->reset_string[0] )
- {
- // we don't have a reset string yet
- Mem_Free( var->reset_string );
- @@ -220,7 +221,7 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
- }
- // if we have a latched string, take that value now
- - if( var->latched_string )
- + if( var->latched_string != NULL )
- {
- char *s = var->latched_string;
- var->latched_string = NULL; // otherwise cvar_set2 would free it
- @@ -228,12 +229,13 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
- Mem_Free( s );
- }
- - if( var_desc )
- + if( var_desc != NULL )
- {
- // update description if needs
- if( var->description ) Mem_Free( var->description );
- var->description = copystring( var_desc );
- }
- +
- return var;
- }
- @@ -248,9 +250,24 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
- var->modified = true;
- var->flags = flags;
- - // link the variable in
- - var->next = cvar_vars;
- - cvar_vars = var;
- + // link the variable in alphanumerical order
- + for( cur = NULL, find = cvar_vars; find && Q_strcmp( find->name, var->name ) < 0; cur = find, find = find->next );
- +
- + if( cur ) cur->next = var;
- + else cvar_vars = var;
- + var->next = find;
- +
- + if( var->flags & CVAR_USERINFO )
- + userinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_PHYSICINFO )
- + physinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_SERVERINFO )
- + serverinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_RENDERINFO )
- + renderinfo->modified = true; // transmit at next oportunity
- return var;
- }
- @@ -264,7 +281,7 @@ Adds a freestanding variable to the variable list.
- */
- void Cvar_RegisterVariable( cvar_t *var )
- {
- - convar_t **prev, *cur = NULL;
- + convar_t *cur = NULL;
- convar_t *find;
- ASSERT( var != NULL );
- @@ -281,65 +298,67 @@ void Cvar_RegisterVariable( cvar_t *var )
- {
- // this cvar is already registered with Cvar_RegisterVariable
- // so we can't replace it
- - if( cur->flags & CVAR_EXTDLL )
- + if( FBitSet( cur->flags, CVAR_SERVERDLL ))
- {
- MsgDev( D_ERROR, "can't register variable %s, allready defined\n", var->name );
- return;
- }
- - }
- -
- - if( cur )
- - {
- - prev = &cvar_vars;
- -
- - while( 1 )
- + else
- {
- - find = *prev;
- + var->string = cur->string; // we already have right string
- + var->value = Q_atof( var->string );
- + SetBits( var->flags, CVAR_SERVERDLL ); // all cvars passed this function are game cvars
- + var->next = (cvar_t *)cur->next;
- - ASSERT( find != NULL );
- -
- - if( cur == cvar_vars )
- + if( cvar_vars == cur )
- {
- // relink at tail
- cvar_vars = (convar_t *)var;
- - break;
- }
- -
- - // search for previous cvar
- - if( cur != find->next )
- + else
- {
- - prev = &find->next;
- - continue;
- + // otherwise find it somewhere in the list
- + for( find = cvar_vars; find->next != cur; find = find->next );
- +
- + ASSERT( find != NULL );
- +
- + find->next = (convar_t *)var;
- }
- - // link new variable
- - find->next = (convar_t *)var;
- - break;
- + // release current cvar (but keep string)
- + if( cur->name ) Mem_Free( cur->name );
- + if( cur->latched_string ) Mem_Free( cur->latched_string );
- + if( cur->reset_string ) Mem_Free( cur->reset_string );
- + if( cur->description ) Mem_Free( cur->description );
- + Mem_Free( cur );
- }
- -
- - var->string = cur->string; // we already have right string
- - var->value = Q_atof( var->string );
- - var->flags |= CVAR_EXTDLL; // all cvars passed this function are game cvars
- - var->next = (cvar_t *)cur->next;
- -
- - // release current cvar (but keep string)
- - if( cur->name ) Mem_Free( cur->name );
- - if( cur->latched_string ) Mem_Free( cur->latched_string );
- - if( cur->reset_string ) Mem_Free( cur->reset_string );
- - if( cur->description ) Mem_Free( cur->description );
- - Mem_Free( cur );
- }
- else
- {
- // copy the value off, because future sets will Z_Free it
- var->string = copystring( var->string );
- var->value = Q_atof( var->string );
- - var->flags |= CVAR_EXTDLL; // all cvars passed this function are game cvars
- + SetBits( var->flags, CVAR_SERVERDLL ); // all cvars passed this function are game cvars
- +
- + // link the variable in alphanumerical order
- + for( cur = NULL, find = cvar_vars; find && Q_strcmp( find->name, var->name ) < 0; cur = find, find = find->next );
- - // link the variable in
- - var->next = (cvar_t *)cvar_vars;
- - cvar_vars = (convar_t *)var;
- + if( cur ) cur->next = (convar_t *)var;
- + else cvar_vars = (convar_t *)var;
- + var->next = (cvar_t *)find;
- }
- +
- + if( var->flags & CVAR_USERINFO )
- + userinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_PHYSICINFO )
- + physinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_SERVERINFO )
- + serverinfo->modified = true; // transmit at next oportunity
- +
- + if( var->flags & CVAR_RENDERINFO )
- + renderinfo->modified = true; // transmit at next oportunity
- }
- /*
- @@ -352,7 +371,6 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- convar_t *var;
- const char *pszValue;
- char szNew[MAX_SYSPATH];
- - qboolean dll_variable = false;
- if( !Cvar_ValidateString( var_name, false ))
- {
- @@ -361,6 +379,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- }
- var = Cvar_FindVar( var_name );
- +
- if( !var )
- {
- // create it
- @@ -369,14 +388,10 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- }
- - // use this check to prevent acessing for unexisting fields
- - // for cvar_t: latched_string, description, etc
- - if( var->flags & CVAR_EXTDLL )
- - dll_variable = true;
- -
- if( !value )
- {
- - if( dll_variable ) value = "0";
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + value = "0";
- else value = var->reset_string;
- }
- @@ -384,23 +399,24 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- return var;
- // any latched values not allowed for game cvars
- - if( dll_variable ) force = true;
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + force = true;
- if( !force )
- {
- - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG ))
- + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG ))
- {
- MsgDev( D_INFO, "%s is read only.\n", var_name );
- return var;
- }
- - if( var->flags & CVAR_INIT )
- + if( FBitSet( var->flags, CVAR_INIT ))
- {
- MsgDev( D_INFO, "%s is write protected.\n", var_name );
- return var;
- }
- - if( var->flags & ( CVAR_LATCH|CVAR_LATCH_VIDEO ))
- + if( FBitSet( var->flags, CVAR_LATCH ))
- {
- if( var->latched_string )
- {
- @@ -414,16 +430,11 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- return var;
- }
- - if( var->flags & CVAR_LATCH && Cvar_VariableInteger( "host_serverstate" ))
- + if( FBitSet( var->flags, CVAR_LATCH ) && Cvar_VariableInteger( "host_serverstate" ))
- {
- MsgDev( D_INFO, "%s will be changed upon restarting.\n", var->name );
- var->latched_string = copystring( value );
- }
- - else if( var->flags & CVAR_LATCH_VIDEO )
- - {
- - MsgDev( D_INFO, "%s will be changed upon restarting video.\n", var->name );
- - var->latched_string = copystring( value );
- - }
- else
- {
- Mem_Free( var->string ); // free the old value string
- @@ -436,7 +447,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- return var;
- }
- - if(( var->flags & CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
- + if( FBitSet( var->flags, CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
- {
- MsgDev( D_INFO, "%s is cheat protected.\n", var_name );
- return var;
- @@ -444,7 +455,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- }
- else
- {
- - if( !dll_variable && var->latched_string )
- + if( !FBitSet( var->flags, CVAR_SERVERDLL ) && var->latched_string )
- {
- Mem_Free( var->latched_string );
- var->latched_string = NULL;
- @@ -453,39 +464,32 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- pszValue = value;
- - // This cvar's string must only contain printable characters.
- - // Strip out any other crap.
- - // We'll fill in "empty" if nothing is left
- - if( var->flags & CVAR_PRINTABLEONLY )
- + // this cvar's string must only contain printable characters.
- + // strip out any other crap.
- + // we'll fill in "empty" if nothing is left
- + if( FBitSet( var->flags, CVAR_PRINTABLEONLY ))
- {
- - const char *pS;
- - char *pD;
- + const char *s;
- + char *d;
- - // clear out new string
- szNew[0] = '\0';
- -
- - pS = pszValue;
- - pD = szNew;
- + s = pszValue;
- + d = szNew;
- // step through the string, only copying back in characters that are printable
- - while( *pS )
- + while( *s )
- {
- - if( ((byte)*pS) < 32 || ((byte)*pS) > 255 )
- + if( ((byte)*s) < 32 )
- {
- - pS++;
- + s++;
- continue;
- }
- - *pD++ = *pS++;
- + *d++ = *s++;
- }
- + *d = '\0';
- - // terminate the new string
- - *pD = '\0';
- -
- - // if it's empty, then insert a marker string
- if( !Q_strlen( szNew ))
- - {
- - Q_strcpy( szNew, "default" );
- - }
- + Q_strncpy( szNew, "default", sizeof( szNew ));
- // point the value here.
- pszValue = szNew;
- @@ -495,24 +499,39 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
- if( !Q_strcmp( pszValue, var->string ))
- return var;
- - if( var->flags & CVAR_USERINFO )
- - userinfo->modified = true; // transmit at next oportunity
- + if( FBitSet( var->flags, CVAR_SERVERNOTIFY ))
- + {
- + if( !FBitSet( var->flags, CVAR_UNLOGGED ))
- + {
- + if( FBitSet( var->flags, CVAR_PROTECTED ))
- + {
- + SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, "***PROTECTED***" );
- + }
- + else
- + {
- + SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, pszValue );
- + }
- + }
- + }
- - if( var->flags & CVAR_PHYSICINFO )
- - physinfo->modified = true; // transmit at next oportunity
- + if( FBitSet( var->flags, CVAR_USERINFO ))
- + userinfo->modified = true; // transmit at next oportunity
- - if( var->flags & CVAR_SERVERINFO )
- - serverinfo->modified = true; // transmit at next oportunity
- + if( FBitSet( var->flags, CVAR_PHYSICINFO ))
- + physinfo->modified = true; // transmit at next oportunity
- - if( var->flags & CVAR_RENDERINFO )
- - renderinfo->modified = true; // transmit at next oportunity
- + if( FBitSet( var->flags, CVAR_SERVERINFO ))
- + serverinfo->modified = true; // transmit at next oportunity
- +
- + if( FBitSet( var->flags, CVAR_RENDERINFO ))
- + renderinfo->modified = true; // transmit at next oportunity
- // free the old value string
- Mem_Free( var->string );
- var->string = copystring( pszValue );
- var->value = Q_atof( var->string );
- - if( !dll_variable )
- + if( !FBitSet( var->flags, CVAR_SERVERDLL ))
- {
- var->integer = Q_atoi( var->string );
- var->modified = true;
- @@ -549,53 +568,33 @@ Cvar_FullSet
- void Cvar_FullSet( const char *var_name, const char *value, int flags )
- {
- convar_t *var;
- - qboolean dll_variable = false;
- - var = Cvar_FindVar( var_name );
- - if( !var )
- + if(( var = Cvar_FindVar( var_name )) == NULL )
- {
- // create it
- Cvar_Get( var_name, value, flags, "" );
- return;
- }
- - // use this check to prevent acessing for unexisting fields
- - // for cvar_t: latechd_string, description, etc
- - if( var->flags & CVAR_EXTDLL )
- - {
- - dll_variable = true;
- - }
- + if( FBitSet( var->flags, CVAR_USERINFO ))
- + userinfo->modified = true; // transmit at next oportunity
- - if( var->flags & CVAR_USERINFO )
- - {
- - // transmit at next oportunity
- - userinfo->modified = true;
- - }
- + if( FBitSet( var->flags, CVAR_PHYSICINFO ))
- + physinfo->modified = true; // transmit at next oportunity
- - if( var->flags & CVAR_PHYSICINFO )
- - {
- - // transmit at next oportunity
- - physinfo->modified = true;
- - }
- + if( FBitSet( var->flags, CVAR_SERVERINFO ))
- + serverinfo->modified = true; // transmit at next oportunity
- - if( var->flags & CVAR_SERVERINFO )
- - {
- - // transmit at next oportunity
- - serverinfo->modified = true;
- - }
- -
- - if( var->flags & CVAR_RENDERINFO )
- - {
- - // transmit at next oportunity
- - renderinfo->modified = true;
- - }
- + if( FBitSet( var->flags, CVAR_RENDERINFO ))
- + renderinfo->modified = true; // transmit at next oportunity
- Mem_Free( var->string ); // free the old value string
- var->string = copystring( value );
- var->value = Q_atof( var->string );
- var->flags = flags;
- - if( dll_variable ) return; // below fields doesn't exist in cvar_t
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + return; // below fields doesn't exist in cvar_t
- var->integer = Q_atoi( var->string );
- var->modified = true;
- @@ -608,15 +607,17 @@ Cvar_DirectSet
- */
- void Cvar_DirectSet( cvar_t *var, const char *value )
- {
- - cvar_t *test;
- const char *pszValue;
- char szNew[MAX_SYSPATH];
- if( !var ) return; // GET_CVAR_POINTER is failed ?
- // make sure what is really pointer to the cvar
- - test = (cvar_t *)Cvar_FindVar( var->name );
- - ASSERT( var == test );
- + if( var != (cvar_t *)Cvar_FindVar( var->name ))
- + {
- + MsgDev( D_ERROR, "Cvar_DirectSet: invalid pointer to cvar\n" );
- + return;
- + }
- if( value && !Cvar_ValidateString( value, true ))
- {
- @@ -624,60 +625,59 @@ void Cvar_DirectSet( cvar_t *var, const char *value )
- value = "0";
- }
- - if( !value ) value = "0";
- + if( !value )
- + {
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + value = "0";
- + else value = ((convar_t *)var)->reset_string;
- + }
- - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_LATCH|CVAR_LATCH_VIDEO ))
- + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_LATCH ))
- {
- // Cvar_DirectSet cannot change these cvars at all
- return;
- }
- - if(( var->flags & CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
- + if( FBitSet( var->flags, CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
- {
- - // cheats are disabled
- + MsgDev( D_INFO, "%s is cheat protected.\n", var->name );
- return;
- }
- pszValue = value;
- - // This cvar's string must only contain printable characters.
- - // Strip out any other crap.
- - // We'll fill in "empty" if nothing is left
- - if( var->flags & CVAR_PRINTABLEONLY )
- + // this cvar's string must only contain printable characters.
- + // strip out any other crap.
- + // we'll fill in "empty" if nothing is left
- + if( FBitSet( var->flags, CVAR_PRINTABLEONLY ))
- {
- - const char *pS;
- - char *pD;
- + const char *s;
- + char *d;
- - // clear out new string
- szNew[0] = '\0';
- -
- - pS = pszValue;
- - pD = szNew;
- + s = pszValue;
- + d = szNew;
- // step through the string, only copying back in characters that are printable
- - while( *pS )
- + while( *s )
- {
- - if( *pS < 32 || *pS > 255 )
- + if( ((byte)*s) < 32 )
- {
- - pS++;
- + s++;
- continue;
- }
- - *pD++ = *pS++;
- + *d++ = *s++;
- }
- + *d = '\0';
- - // terminate the new string
- - *pD = '\0';
- -
- - // if it's empty, then insert a marker string
- if( !Q_strlen( szNew ))
- - {
- - Q_strcpy( szNew, "default" );
- - }
- + Q_strncpy( szNew, "default", sizeof( szNew ));
- // point the value here.
- pszValue = szNew;
- }
- + // nothing to change
- if( !Q_strcmp( pszValue, var->string ))
- return;
- @@ -697,6 +697,12 @@ void Cvar_DirectSet( cvar_t *var, const char *value )
- Mem_Free( var->string );
- var->string = copystring( pszValue );
- var->value = Q_atof( var->string );
- +
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + return; // below fields doesn't exist in cvar_t
- +
- + ((convar_t *)var)->integer = Q_atoi( var->string );
- + ((convar_t *)var)->modified = true;
- }
- /*
- @@ -739,10 +745,10 @@ void Cvar_SetCheatState( void )
- for( var = cvar_vars; var; var = var->next )
- {
- // can't process dll cvars - missed latched_string, reset_string
- - if( var->flags & CVAR_EXTDLL )
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- continue;
- - if( var->flags & CVAR_CHEAT )
- + if( FBitSet( var->flags, CVAR_CHEAT ))
- {
- // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
- // because of a different var->latched_string
- @@ -753,9 +759,7 @@ void Cvar_SetCheatState( void )
- }
- if( Q_strcmp( var->reset_string, var->string ))
- - {
- Cvar_Set( var->name, var->reset_string );
- - }
- }
- }
- }
- @@ -778,7 +782,8 @@ qboolean Cvar_Command( void )
- // perform a variable print or set
- if( Cmd_Argc() == 1 )
- {
- - if( v->flags & ( CVAR_INIT|CVAR_EXTDLL )) Msg( "%s: %s\n", v->name, v->string );
- + if( FBitSet( v->flags, CVAR_INIT|CVAR_SERVERDLL ))
- + Msg( "%s: %s\n", v->name, v->string );
- else Msg( "%s: %s ( ^3%s^7 )\n", v->name, v->string, v->reset_string );
- return true;
- }
- @@ -805,8 +810,7 @@ void Cvar_Toggle_f( void )
- return;
- }
- - v = Cvar_VariableValue( Cmd_Argv( 1 ));
- - v = !v;
- + v = !Cvar_VariableInteger( Cmd_Argv( 1 ));
- Cvar_Set2( Cmd_Argv( 1 ), va( "%i", v ), false );
- }
- @@ -825,16 +829,18 @@ void Cvar_Set_f( void )
- char combined[MAX_CMD_TOKENS];
- c = Cmd_Argc();
- +
- if( c < 3 )
- {
- Msg( "Usage: set <variable> <value>\n" );
- return;
- }
- - combined[0] = 0;
- +
- + combined[0] = '\0';
- for( i = 2; i < c; i++ )
- {
- - len = Q_strlen( Cmd_Argv(i) + 1 );
- + len = Q_strlen( Cmd_Argv( i ) + 1 );
- if( l + len >= MAX_CMD_TOKENS - 2 )
- break;
- Q_strcat( combined, Cmd_Argv( i ));
- @@ -866,7 +872,7 @@ void Cvar_SetU_f( void )
- v = Cvar_FindVar( Cmd_Argv( 1 ));
- if( !v ) return;
- - v->flags |= CVAR_USERINFO;
- + SetBits( v->flags, CVAR_USERINFO );
- }
- /*
- @@ -890,7 +896,7 @@ void Cvar_SetP_f( void )
- v = Cvar_FindVar( Cmd_Argv( 1 ));
- if( !v ) return;
- - v->flags |= CVAR_PHYSICINFO;
- + SetBits( v->flags, CVAR_PHYSICINFO );
- }
- /*
- @@ -909,11 +915,12 @@ void Cvar_SetS_f( void )
- Msg( "Usage: sets <variable> <value>\n" );
- return;
- }
- +
- Cvar_Set_f();
- v = Cvar_FindVar( Cmd_Argv( 1 ));
- if( !v ) return;
- - v->flags |= CVAR_SERVERINFO;
- + SetBits( v->flags, CVAR_SERVERINFO );
- }
- /*
- @@ -937,7 +944,7 @@ void Cvar_SetA_f( void )
- v = Cvar_FindVar( Cmd_Argv( 1 ));
- if( !v ) return;
- - v->flags |= CVAR_ARCHIVE;
- + SetBits( v->flags, CVAR_ARCHIVE );
- }
- /*
- @@ -988,6 +995,7 @@ void Cvar_Reset_f( void )
- Msg( "Usage: reset <variable>\n" );
- return;
- }
- +
- Cvar_Reset( Cmd_Argv( 1 ));
- }
- @@ -1000,12 +1008,13 @@ void Cvar_List_f( void )
- {
- convar_t *var;
- char *match = NULL;
- - int i = 0, j = 0;
- + char *value;
- + int i = 0;
- if( Cmd_Argc() > 1 )
- match = Cmd_Argv( 1 );
- - for( var = cvar_vars; var; var = var->next, i++ )
- + for( var = cvar_vars; var; var = var->next )
- {
- if( var->name[0] == '@' )
- continue; // never shows system cvars
- @@ -1013,44 +1022,17 @@ void Cvar_List_f( void )
- if( match && !Q_stricmpext( match, var->name ))
- continue;
- - if( var->flags & CVAR_SERVERINFO ) Msg( "SV " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_USERINFO ) Msg( "USER " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_PHYSICINFO ) Msg( "PHYS " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_READ_ONLY ) Msg( "READ " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_INIT ) Msg( "INIT " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_ARCHIVE ) Msg( "ARCH " );
- - else Msg( " " );
- + if( Q_colorstr( var->string ))
- + value = va( "\"%s\"", var->string );
- + else value = va( "\"^2%s^7\"", var->string );
- - if( var->flags & CVAR_LATCH ) Msg( "LATCH " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_LATCH_VIDEO ) Msg( "VIDEO " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_GLCONFIG ) Msg( "OPENGL" );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_CHEAT ) Msg( "CHEAT " );
- - else Msg( " " );
- -
- - if( var->flags & CVAR_EXTDLL )
- - Msg(" %s \"%s\" %s\n", var->name, var->string, "game cvar" );
- - else Msg(" %s \"%s\" %s\n", var->name, var->string, var->description );
- - j++;
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- + Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, "server cvar" );
- + else Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, var->description );
- + i++;
- }
- - Msg( "\n%i cvars\n", j );
- - Msg( "%i total cvars\n", i );
- + Msg( "\n%i cvars\n", i );
- }
- /*
- @@ -1072,16 +1054,15 @@ void Cvar_Restart_f( void )
- var = *prev;
- if( !var ) break;
- - // don't mess with rom values, or some inter-module
- - // communication will get broken (cl.active, etc)
- - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_EXTDLL ))
- + // don't mess with rom values, or some inter-module communication will get broken (cl.active, etc)
- + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_SERVERDLL ))
- {
- prev = &var->next;
- continue;
- }
- // throw out any variables the user created
- - if( var->flags & CVAR_USER_CREATED )
- + if( FBitSet( var->flags, CVAR_USER_CREATED ))
- {
- *prev = var->next;
- if( var->name ) Mem_Free( var->name );
- @@ -1118,113 +1099,51 @@ void Cvar_Latched_f( void )
- var = *prev;
- if( !var ) break;
- - if( var->flags & CVAR_EXTDLL )
- + if( FBitSet( var->flags, CVAR_SERVERDLL ))
- {
- prev = &var->next;
- continue;
- }
- - if( var->flags & CVAR_LATCH && var->latched_string )
- + if( FBitSet( var->flags, CVAR_LATCH ) && var->latched_string )
- {
- Cvar_FullSet( var->name, var->latched_string, var->flags );
- Mem_Free( var->latched_string );
- var->latched_string = NULL;
- }
- - prev = &var->next;
- - }
- -}
- -
- -/*
- -============
- -Cvar_LatchedVideo_f
- -
- -Now all latched video strings is valid
- -============
- -*/
- -void Cvar_LatchedVideo_f( void )
- -{
- - convar_t *var;
- - convar_t **prev;
- -
- - prev = &cvar_vars;
- -
- - while ( 1 )
- - {
- - var = *prev;
- - if( !var ) break;
- -
- - if( var->flags & CVAR_EXTDLL )
- - {
- - prev = &var->next;
- - continue;
- - }
- - if( var->flags & CVAR_LATCH_VIDEO && var->latched_string )
- - {
- - Cvar_FullSet( var->name, var->latched_string, var->flags );
- - Mem_Free( var->latched_string );
- - var->latched_string = NULL;
- - }
- prev = &var->next;
- }
- }
- /*
- ============
- -Cvar_Unlink_f
- +Cvar_Unlink
- -unlink all cvars with flag CVAR_EXTDLL
- +unlink all cvars with specified flag
- ============
- */
- -void Cvar_Unlink_f( void )
- +void Cvar_Unlink( int group )
- {
- convar_t *var;
- convar_t **prev;
- int count = 0;
- - if( Cvar_VariableInteger( "host_gameloaded" ))
- + if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, CVAR_SERVERDLL ))
- {
- - MsgDev( D_NOTE, "can't unlink cvars while game is loaded\n" );
- + MsgDev( D_INFO, "can't unlink variables while server is loaded\n" );
- return;
- }
- - prev = &cvar_vars;
- -
- - while( 1 )
- + if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, CVAR_CLIENTDLL ))
- {
- - var = *prev;
- - if( !var ) break;
- -
- - // ignore all non-game cvars
- - if( !( var->flags & CVAR_EXTDLL ))
- - {
- - prev = &var->next;
- - continue;
- - }
- -
- - // throw out any variables the game created
- - *prev = var->next;
- - if( var->string ) Mem_Free( var->string );
- - count++;
- + MsgDev( D_INFO, "can't unlink variables while client is loaded\n" );
- + return;
- }
- -}
- -
- -/*
- -============
- -Cvar_Unlink
- -
- -unlink all cvars with flag CVAR_CLIENTDLL
- -============
- -*/
- -void Cvar_Unlink( void )
- -{
- - convar_t *var;
- - convar_t **prev;
- - int count = 0;
- - if( Cvar_VariableInteger( "host_clientloaded" ))
- + if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, CVAR_GAMEUIDLL ))
- {
- - MsgDev( D_NOTE, "can't unlink cvars while client is loaded\n" );
- + MsgDev( D_INFO, "can't unlink variables while GameUI is loaded\n" );
- return;
- }
- @@ -1235,8 +1154,8 @@ void Cvar_Unlink( void )
- var = *prev;
- if( !var ) break;
- - // ignore all non-client cvars
- - if(!( var->flags & CVAR_CLIENTDLL ))
- + // do filter by specified group
- + if( group && !FBitSet( var->flags, group ))
- {
- prev = &var->next;
- continue;
- @@ -1244,12 +1163,17 @@ void Cvar_Unlink( void )
- // throw out any variables the game created
- *prev = var->next;
- - if( var->name ) Mem_Free( var->name );
- if( var->string ) Mem_Free( var->string );
- - if( var->latched_string ) Mem_Free( var->latched_string );
- - if( var->reset_string ) Mem_Free( var->reset_string );
- - if( var->description ) Mem_Free( var->description );
- - Mem_Free( var );
- +
- + if( !FBitSet( var->flags, CVAR_SERVERDLL ))
- + {
- + if( var->name ) Mem_Free( var->name );
- + if( var->latched_string ) Mem_Free( var->latched_string );
- + if( var->reset_string ) Mem_Free( var->reset_string );
- + if( var->description ) Mem_Free( var->description );
- + Mem_Free( var );
- + }
- +
- count++;
- }
- }
- @@ -1268,19 +1192,18 @@ void Cvar_Init( void )
- physinfo = Cvar_Get( "@physinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
- serverinfo = Cvar_Get( "@serverinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
- renderinfo = Cvar_Get( "@renderinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
- -
- - Cmd_AddCommand ("toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
- - Cmd_AddCommand ("set", Cvar_Set_f, "create or change the value of a console variable" );
- - Cmd_AddCommand ("sets", Cvar_SetS_f, "create or change the value of a serverinfo variable" );
- - Cmd_AddCommand ("setu", Cvar_SetU_f, "create or change the value of a userinfo variable" );
- - Cmd_AddCommand ("setp", Cvar_SetP_f, "create or change the value of a physicinfo variable" );
- - Cmd_AddCommand ("setr", Cvar_SetR_f, "create or change the value of a renderinfo variable" );
- - Cmd_AddCommand ("setgl", Cvar_SetGL_f, "create or change the value of a opengl variable" );
- - Cmd_AddCommand ("seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg" );
- - Cmd_AddCommand ("reset", Cvar_Reset_f, "reset any type variable to initial value" );
- - Cmd_AddCommand ("latch", Cvar_Latched_f, "apply latched values" );
- - Cmd_AddCommand ("vidlatch", Cvar_LatchedVideo_f, "apply latched values for video subsystem" );
- - Cmd_AddCommand ("cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
- - Cmd_AddCommand ("unsetall", Cvar_Restart_f, "reset all console variables to their default values" );
- - Cmd_AddCommand ("@unlink", Cvar_Unlink_f, "unlink static cvars defined in gamedll" );
- -}
- + cmd_scripting = Cvar_Get( "cmd_scripting", "0", CVAR_ARCHIVE, "enable simple condition checking and variable operations" );
- +
- + Cmd_AddCommand( "toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
- + Cmd_AddCommand( "set", Cvar_Set_f, "create or change the value of a console variable" );
- + Cmd_AddCommand( "sets", Cvar_SetS_f, "create or change the value of a serverinfo variable" );
- + Cmd_AddCommand( "setu", Cvar_SetU_f, "create or change the value of a userinfo variable" );
- + Cmd_AddCommand( "setp", Cvar_SetP_f, "create or change the value of a physicinfo variable" );
- + Cmd_AddCommand( "setr", Cvar_SetR_f, "create or change the value of a renderinfo variable" );
- + Cmd_AddCommand( "setgl", Cvar_SetGL_f, "create or change the value of a opengl variable" );
- + Cmd_AddCommand( "seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg" );
- + Cmd_AddCommand( "reset", Cvar_Reset_f, "reset any type variable to initial value" );
- + Cmd_AddCommand( "latch", Cvar_Latched_f, "apply latched values" );
- + Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
- + Cmd_AddCommand( "unsetall", Cvar_Restart_f, "reset all console variables to their default values" );
- +}
- \ No newline at end of file
- diff --git b/engine/common/filesystem.c a/engine/common/filesystem.c
- index a32fa7c..0a184ab 100644
- --- b/engine/common/filesystem.c
- +++ a/engine/common/filesystem.c
- @@ -24,14 +24,26 @@ GNU General Public License for more details.
- #include "library.h"
- #include "mathlib.h"
- -#define FILE_BUFF_SIZE 2048
- +#define FILE_COPY_SIZE (1024 * 1024)
- +#define FILE_BUFF_SIZE (65535)
- +
- +// PAK errors
- #define PAK_LOAD_OK 0
- #define PAK_LOAD_COULDNT_OPEN 1
- #define PAK_LOAD_BAD_HEADER 2
- #define PAK_LOAD_BAD_FOLDERS 3
- #define PAK_LOAD_TOO_MANY_FILES 4
- #define PAK_LOAD_NO_FILES 5
- -#define PAK_LOAD_CORRUPTED 6
- +#define PAK_LOAD_CORRUPTED 6
- +
- +// WAD errors
- +#define WAD_LOAD_OK 0
- +#define WAD_LOAD_COULDNT_OPEN 1
- +#define WAD_LOAD_BAD_HEADER 2
- +#define WAD_LOAD_BAD_FOLDERS 3
- +#define WAD_LOAD_TOO_MANY_FILES 4
- +#define WAD_LOAD_NO_FILES 5
- +#define WAD_LOAD_CORRUPTED 6
- typedef struct stringlist_s
- {
- @@ -50,19 +62,19 @@ typedef struct wadtype_s
- typedef struct file_s
- {
- int handle; // file descriptor
- - fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
- - fs_offset_t position; // current position in the file
- - fs_offset_t offset; // offset into the package (0 if external file)
- + long real_length; // uncompressed file size (for files opened in "read" mode)
- + long position; // current position in the file
- + long offset; // offset into the package (0 if external file)
- int ungetc; // single stored character from ungetc, cleared to EOF when read
- time_t filetime; // pak, wad or real filetime
- - // Contents buffer
- - fs_offset_t buff_ind, buff_len; // buffer current index and length
- + // contents buffer
- + long buff_ind, buff_len; // buffer current index and length
- byte buff[FILE_BUFF_SIZE]; // intermediate buffer
- };
- typedef struct wfile_s
- {
- - char filename[MAX_SYSPATH];
- + string filename;
- int infotableofs;
- byte *mempool; // W_ReadLump temp buffers
- int numlumps;
- @@ -72,47 +84,41 @@ typedef struct wfile_s
- time_t filetime;
- };
- -typedef struct packfile_s
- -{
- - char name[56];
- - fs_offset_t offset;
- - fs_offset_t realsize; // real file size (uncompressed)
- -} packfile_t;
- -
- typedef struct pack_s
- {
- - char filename[MAX_SYSPATH];
- + string filename;
- int handle;
- int numfiles;
- time_t filetime; // common for all packed files
- - packfile_t *files;
- + dpackfile_t *files;
- } pack_t;
- typedef struct searchpath_s
- {
- - char filename[MAX_SYSPATH];
- + string filename;
- pack_t *pack;
- wfile_t *wad;
- int flags;
- struct searchpath_s *next;
- } searchpath_t;
- -byte *fs_mempool;
- -searchpath_t *fs_searchpaths = NULL;
- -searchpath_t fs_directpath; // static direct path
- -char fs_rootdir[MAX_SYSPATH]; // engine root directory
- -char fs_basedir[MAX_SYSPATH]; // base directory of game
- -char fs_falldir[MAX_SYSPATH]; // game falling directory
- -char fs_gamedir[MAX_SYSPATH]; // game current directory
- -char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too)
- -qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
- +byte *fs_mempool;
- +searchpath_t *fs_searchpaths = NULL; // chain
- +searchpath_t fs_directpath; // static direct path
- +char fs_rootdir[MAX_SYSPATH]; // engine root directory
- +char fs_basedir[MAX_SYSPATH]; // base directory of game
- +char fs_falldir[MAX_SYSPATH]; // game falling directory
- +char fs_gamedir[MAX_SYSPATH]; // game current directory
- +char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too)
- +qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
- +static const wadtype_t wad_hints[10];
- static void FS_InitMemory( void );
- const char *FS_FileExtension( const char *in );
- static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
- static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype );
- -static packfile_t* FS_AddFileToPack( const char* name, pack_t *pack, fs_offset_t offset, fs_offset_t size );
- -static byte *W_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
- +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size );
- +static byte *W_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
- static qboolean FS_SysFileExists( const char *path );
- static qboolean FS_SysFolderExists( const char *path );
- static long FS_SysFileTime( const char *filename );
- @@ -126,56 +132,53 @@ FILEMATCH COMMON SYSTEM
- =============================================================================
- */
- -int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive )
- +int matchpattern( const char *str, const char *cmp, qboolean caseinsensitive )
- {
- int c1, c2;
- - while( *pattern )
- + while( *cmp )
- {
- - switch( *pattern )
- + switch( *cmp )
- {
- case 0: return 1; // end of pattern
- case '?': // match any single character
- - if( *in == 0 || *in == '/' || *in == '\\' || *in == ':' )
- + if( *str == 0 || *str == '/' || *str == '\\' || *str == ':' )
- return 0; // no match
- - in++;
- - pattern++;
- + str++;
- + cmp++;
- break;
- case '*': // match anything until following string
- - if( !*in ) return 1; // match
- - pattern++;
- - while( *in )
- + if( !*str ) return 1; // match
- + cmp++;
- + while( *str )
- {
- - if( *in == '/' || *in == '\\' || *in == ':' )
- + if( *str == '/' || *str == '\\' || *str == ':' )
- break;
- // see if pattern matches at this offset
- - if( matchpattern( in, pattern, caseinsensitive ))
- + if( matchpattern( str, cmp, caseinsensitive ))
- return 1;
- // nope, advance to next offset
- - in++;
- + str++;
- }
- break;
- default:
- - if( *in != *pattern )
- + if( *str != *cmp )
- {
- if( !caseinsensitive )
- return 0; // no match
- - c1 = *in;
- - if( c1 >= 'A' && c1 <= 'Z' )
- - c1 += 'a' - 'A';
- - c2 = *pattern;
- - if( c2 >= 'A' && c2 <= 'Z' )
- - c2 += 'a' - 'A';
- - if( c1 != c2) return 0; // no match
- + c1 = Q_tolower( *str );
- + c2 = Q_tolower( *cmp );
- + if( c1 != c2 ) return 0; // no match
- }
- - in++;
- - pattern++;
- +
- + str++;
- + cmp++;
- break;
- }
- }
- - if( *in ) return 0; // reached end of pattern but not end of input
- - return 1; // success
- + // reached end of pattern but not end of input?
- + return (*str) ? 0 : 1;
- }
- void stringlistinit( stringlist_t *list )
- @@ -194,23 +197,25 @@ void stringlistfreecontents( stringlist_t *list )
- list->strings[i] = NULL;
- }
- + if( list->strings )
- + Mem_Free( list->strings );
- +
- list->numstrings = 0;
- list->maxstrings = 0;
- - if( list->strings ) Mem_Free( list->strings );
- + list->strings = NULL;
- }
- void stringlistappend( stringlist_t *list, char *text )
- {
- size_t textlen;
- - char **oldstrings;
- +
- + if( !Q_stricmp( text, "." ) || !Q_stricmp( text, ".." ))
- + return; // ignore the virtual directories
- if( list->numstrings >= list->maxstrings )
- {
- - oldstrings = list->strings;
- list->maxstrings += 4096;
- - list->strings = Mem_Alloc( fs_mempool, list->maxstrings * sizeof( *list->strings ));
- - if( list->numstrings ) memcpy( list->strings, oldstrings, list->numstrings * sizeof( *list->strings ));
- - if( oldstrings ) Mem_Free( oldstrings );
- + list->strings = Mem_Realloc( fs_mempool, list->strings, list->maxstrings * sizeof( *list->strings ));
- }
- textlen = Q_strlen( text ) + 1;
- @@ -221,8 +226,8 @@ void stringlistappend( stringlist_t *list, char *text )
- void stringlistsort( stringlist_t *list )
- {
- - int i, j;
- char *temp;
- + int i, j;
- // this is a selection sort (finds the best entry for each slot)
- for( i = 0; i < list->numstrings - 1; i++ )
- @@ -241,10 +246,11 @@ void stringlistsort( stringlist_t *list )
- void listdirectory( stringlist_t *list, const char *path )
- {
- - int i;
- - char pattern[4096], *c;
- + char pattern[4096];
- struct _finddata_t n_file;
- long hFile;
- + char *c;
- + int i;
- Q_strncpy( pattern, path, sizeof( pattern ));
- Q_strncat( pattern, "*", sizeof( pattern ));
- @@ -264,10 +270,7 @@ void listdirectory( stringlist_t *list, const char *path )
- for( i = 0; i < list->numstrings; i++ )
- {
- for( c = list->strings[i]; *c; c++ )
- - {
- - if( *c >= 'A' && *c <= 'Z' )
- - *c += 'a' - 'A';
- - }
- + *c = Q_tolower( *c );
- }
- }
- @@ -285,10 +288,10 @@ FS_AddFileToPack
- Add a file to the list of files contained into a package
- ====================
- */
- -static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t size )
- +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset, long size )
- {
- int left, right, middle;
- - packfile_t *pfile;
- + dpackfile_t *pfile;
- // look for the slot we should put that file into (binary search)
- left = 0;
- @@ -301,7 +304,7 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t
- diff = Q_stricmp( pack->files[middle].name, name );
- // If we found the file, there's a problem
- - if( !diff ) MsgDev( D_NOTE, "Package %s contains the file %s several times\n", pack->filename, name );
- + if( !diff ) MsgDev( D_WARN, "Package %s contains the file %s several times\n", pack->filename, name );
- // If we're too far in the list
- if( diff > 0 ) right = middle - 1;
- @@ -314,8 +317,8 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t
- pack->numfiles++;
- Q_strncpy( pfile->name, name, sizeof( pfile->name ));
- - pfile->offset = offset;
- - pfile->realsize = size;
- + pfile->filepos = offset;
- + pfile->filelen = size;
- return pfile;
- }
- @@ -363,7 +366,8 @@ void FS_Path_f( void )
- else if( s->wad ) Msg( "%s (%i files)", s->wad->filename, s->wad->numlumps );
- else Msg( "%s", s->filename );
- - if( s->flags & FS_GAMEDIR_PATH ) Msg( " ^2gamedir^7\n" );
- + if( FBitSet( s->flags, FS_GAMEDIR_PATH ))
- + Msg( " ^2gamedir^7\n" );
- else Msg( "\n" );
- }
- }
- @@ -436,8 +440,8 @@ of the list so they override previous pack files.
- pack_t *FS_LoadPackPAK( const char *packfile, int *error )
- {
- dpackheader_t header;
- - int i, numpackfiles;
- int packhandle;
- + int i, numpackfiles;
- pack_t *pack;
- dpackfile_t *info;
- @@ -500,16 +504,14 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
- pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t ));
- Q_strncpy( pack->filename, packfile, sizeof( pack->filename ));
- + pack->files = (dpackfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( dpackfile_t ));
- + pack->filetime = FS_SysFileTime( packfile );
- pack->handle = packhandle;
- pack->numfiles = 0;
- - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t ));
- - pack->filetime = FS_SysFileTime( packfile );
- // parse the directory
- for( i = 0; i < numpackfiles; i++ )
- - {
- FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen );
- - }
- MsgDev( D_NOTE, "Adding packfile: %s (%i files)\n", packfile, numpackfiles );
- if( error ) *error = PAK_LOAD_OK;
- @@ -520,7 +522,7 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
- /*
- ================
- -FS_AddPack_Fullpath
- +FS_AddPak_Fullpath
- Adds the given pack to the search path.
- The pack type is autodetected by the file extension.
- @@ -532,7 +534,7 @@ If keep_plain_dirs is set, the pack will be added AFTER the first sequence of
- plain directories.
- ================
- */
- -static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
- +static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
- {
- searchpath_t *search;
- pack_t *pak = NULL;
- @@ -558,7 +560,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
- if( keep_plain_dirs )
- {
- // find the first item whose next one is a pack or NULL
- - searchpath_t *insertion_point = 0;
- + searchpath_t *insertion_point = NULL;
- if( fs_searchpaths && !fs_searchpaths->pack )
- {
- insertion_point = fs_searchpaths;
- @@ -603,7 +605,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
- else
- {
- if( errorcode != PAK_LOAD_NO_FILES )
- - MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile );
- + MsgDev( D_ERROR, "FS_AddPak_Fullpath: unable to load pak \"%s\"\n", pakfile );
- return false;
- }
- }
- @@ -613,11 +615,12 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
- FS_AddWad_Fullpath
- ====================
- */
- -static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs )
- +static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
- {
- searchpath_t *search;
- wfile_t *wad = NULL;
- const char *ext = FS_FileExtension( wadfile );
- + int errorcode = WAD_LOAD_COULDNT_OPEN;
- for( search = fs_searchpaths; search; search = search->next )
- {
- @@ -629,7 +632,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
- }
- if( already_loaded ) *already_loaded = false;
- - if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb" );
- + if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb", &errorcode );
- else MsgDev( D_ERROR, "\"%s\" doesn't have a wad extension\n", wadfile );
- if( wad )
- @@ -656,6 +659,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
- search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
- search->wad = wad;
- search->next = fs_searchpaths;
- + search->flags |= flags;
- fs_searchpaths = search;
- }
- else // otherwise we want to append directly after insertion_point.
- @@ -663,6 +667,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
- search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
- search->wad = wad;
- search->next = insertion_point->next;
- + search->flags |= flags;
- insertion_point->next = search;
- }
- }
- @@ -671,6 +676,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
- search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
- search->wad = wad;
- search->next = fs_searchpaths;
- + search->flags |= flags;
- fs_searchpaths = search;
- }
- @@ -679,7 +685,8 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
- }
- else
- {
- - MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
- + if( errorcode != WAD_LOAD_NO_FILES )
- + MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
- return false;
- }
- }
- @@ -699,7 +706,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
- string fullpath;
- int i;
- - if(!( flags & FS_NOWRITE_PATH ))
- + if( !FBitSet( flags, FS_NOWRITE_PATH ))
- Q_strncpy( fs_gamedir, dir, sizeof( fs_gamedir ));
- stringlistinit( &list );
- @@ -712,7 +719,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
- if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "pak" ))
- {
- Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
- - FS_AddPack_Fullpath( fullpath, NULL, false, flags );
- + FS_AddPak_Fullpath( fullpath, NULL, false, flags );
- }
- }
- @@ -722,7 +729,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
- if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "wad" ))
- {
- Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
- - FS_AddWad_Fullpath( fullpath, NULL, false );
- + FS_AddWad_Fullpath( fullpath, NULL, false, flags );
- }
- }
- @@ -761,13 +768,20 @@ const char *FS_FileExtension( const char *in )
- separator = Q_strrchr( in, '/' );
- backslash = Q_strrchr( in, '\\' );
- - if( !separator || separator < backslash ) separator = backslash;
- +
- + if( !separator || separator < backslash )
- + separator = backslash;
- +
- colon = Q_strrchr( in, ':' );
- - if( !separator || separator < colon ) separator = colon;
- +
- + if( !separator || separator < colon )
- + separator = colon;
- dot = Q_strrchr( in, '.' );
- +
- if( dot == NULL || ( separator && ( dot < separator )))
- return "";
- +
- return dot + 1;
- }
- @@ -782,9 +796,15 @@ const char *FS_FileWithoutPath( const char *in )
- separator = Q_strrchr( in, '/' );
- backslash = Q_strrchr( in, '\\' );
- - if( !separator || separator < backslash ) separator = backslash;
- +
- + if( !separator || separator < backslash )
- + separator = backslash;
- +
- colon = Q_strrchr( in, ':' );
- - if( !separator || separator < colon ) separator = colon;
- +
- + if( !separator || separator < colon )
- + separator = colon;
- +
- return separator ? separator + 1 : in;
- }
- @@ -793,10 +813,9 @@ const char *FS_FileWithoutPath( const char *in )
- FS_ExtractFilePath
- ============
- */
- -void FS_ExtractFilePath( const char* const path, char* dest )
- +void FS_ExtractFilePath( const char *path, char *dest )
- {
- - const char *src;
- - src = path + Q_strlen( path ) - 1;
- + const char *src = path + Q_strlen( path ) - 1;
- // back up until a \ or the start
- while( src != path && !(*(src - 1) == '\\' || *(src - 1) == '/' ))
- @@ -821,7 +840,9 @@ void FS_ClearSearchPath( void )
- {
- searchpath_t *search = fs_searchpaths;
- - if( search->flags & FS_STATIC_PATH )
- + if( !search ) break;
- +
- + if( FBitSet( search->flags, FS_STATIC_PATH ))
- {
- // skip read-only pathes
- if( search->next )
- @@ -841,7 +862,7 @@ void FS_ClearSearchPath( void )
- W_Close( search->wad );
- }
- - if( search ) Mem_Free( search );
- + Mem_Free( search );
- }
- }
- @@ -874,15 +895,7 @@ int FS_CheckNastyPath( const char *path, qboolean isgamedir )
- // Windows and UNIXes: don't allow absolute paths
- if( path[0] == '/' && !fs_ext_path ) return 2; // attempt to go outside the game directory
- -#if 0
- - // all: don't allow . characters before the last slash (it should only be used in filenames, not path elements),
- - // this catches all imaginable cases of ./, ../, .../, etc
- - if( Q_strchr( path, '.' ) && !fs_ext_path )
- - {
- - if( isgamedir ) return 2; // gamedir is entirely path elements, so simply forbid . entirely
- - if( Q_strchr( path, '.' ) < Q_strrchr( path, '/' )) return 2; // possible attempt to go outside the game directory
- - }
- -#endif
- +
- // all: forbid trailing slash on gamedir
- if( isgamedir && !fs_ext_path && path[Q_strlen( path )-1] == '/' ) return 2;
- @@ -912,55 +925,16 @@ void FS_Rescan( void )
- FS_AddGameHierarchy( GI->gamedir, FS_GAMEDIR_PATH );
- }
- +/*
- +================
- +FS_Rescan_f
- +================
- +*/
- void FS_Rescan_f( void )
- {
- FS_Rescan();
- }
- -static qboolean FS_ParseVector( char **pfile, float *v, size_t size )
- -{
- - string token;
- - qboolean bracket = false;
- - char *saved;
- - uint i;
- -
- - if( v == NULL || size == 0 )
- - return false;
- -
- - memset( v, 0, sizeof( *v ) * size );
- -
- - if( size == 1 )
- - {
- - *pfile = COM_ParseFile( *pfile, token );
- - v[0] = Q_atof( token );
- - return true;
- - }
- -
- - saved = *pfile;
- -
- - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
- - return false;
- -
- - if( token[0] == '(' )
- - bracket = true;
- - else *pfile = saved; // restore token to right get it again
- -
- - for( i = 0; i < size; i++ )
- - {
- - *pfile = COM_ParseFile( *pfile, token );
- - v[i] = Q_atof( token );
- - }
- -
- - if( !bracket ) return true; // done
- -
- - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
- - return false;
- -
- - if( token[0] == ')' )
- - return true;
- - return false;
- -}
- -
- /*
- ================
- FS_WriteGameInfo
- @@ -1113,6 +1087,11 @@ void FS_CreateDefaultGameInfo( const char *filename )
- FS_WriteGameInfo( filename, &defGI );
- }
- +/*
- +================
- +FS_ParseLiblistGam
- +================
- +*/
- static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo )
- {
- char *afile, *pfile;
- @@ -1461,8 +1440,8 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo )
- }
- else
- {
- - FS_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 );
- - FS_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 );
- + COM_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 );
- + COM_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 );
- }
- }
- else if( !Q_strnicmp( token, "ambient", 7 ))
- @@ -1657,18 +1636,22 @@ static file_t* FS_SysOpen( const char* filepath, const char* mode )
- // Parse the mode string
- switch( mode[0] )
- {
- - case 'r':
- + case 'r': // read
- mod = O_RDONLY;
- opt = 0;
- break;
- - case 'w':
- + case 'w': // write
- mod = O_WRONLY;
- opt = O_CREAT | O_TRUNC;
- break;
- - case 'a':
- + case 'a': // append
- mod = O_WRONLY;
- opt = O_CREAT | O_APPEND;
- break;
- + case 'e': // edit
- + mod = O_WRONLY;
- + opt = O_CREAT;
- + break;
- default:
- MsgDev( D_ERROR, "FS_SysOpen(%s, %s): invalid mode\n", filepath, mode );
- return NULL;
- @@ -1720,13 +1703,13 @@ Open a packed file using its package file descriptor
- */
- file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
- {
- - packfile_t *pfile;
- + dpackfile_t *pfile;
- int dup_handle;
- file_t *file;
- pfile = &pack->files[pack_ind];
- - if( lseek( pack->handle, pfile->offset, SEEK_SET ) == -1 )
- + if( lseek( pack->handle, pfile->filepos, SEEK_SET ) == -1 )
- return NULL;
- dup_handle = dup( pack->handle );
- @@ -1735,10 +1718,9 @@ file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
- return NULL;
- file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file ));
- - memset( file, 0, sizeof( *file ));
- file->handle = dup_handle;
- - file->real_length = pfile->realsize;
- - file->offset = pfile->offset;
- + file->real_length = pfile->filelen;
- + file->offset = pfile->filepos;
- file->position = 0;
- file->ungetc = EOF;
- @@ -1755,10 +1737,10 @@ Look for a file in the filesystem only
- qboolean FS_SysFileExists( const char *path )
- {
- int desc;
- -
- - desc = open( path, O_RDONLY|O_BINARY );
- - if( desc < 0 ) return false;
- + if(( desc = open( path, O_RDONLY|O_BINARY )) < 0 )
- + return false;
- +
- close( desc );
- return true;
- }
- @@ -1774,7 +1756,7 @@ qboolean FS_SysFolderExists( const char *path )
- {
- DWORD dwFlags = GetFileAttributes( path );
- - return ( dwFlags != -1 ) && ( dwFlags & FILE_ATTRIBUTE_DIRECTORY );
- + return ( dwFlags != -1 ) && FBitSet( dwFlags, FILE_ATTRIBUTE_DIRECTORY );
- }
- /*
- @@ -1796,7 +1778,7 @@ static searchpath_t *FS_FindFile( const char *name, int* index, qboolean gamedir
- // search through the path, one element at a time
- for( search = fs_searchpaths; search; search = search->next )
- {
- - if( gamedironly & !( search->flags & FS_GAMEDIR_PATH ))
- + if( gamedironly & !FBitSet( search->flags, FS_GAMEDIR_PATH ))
- continue;
- // is the element a pak file?
- @@ -1987,7 +1969,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
- return NULL;
- // if the file is opened in "write", "append", or "read/write" mode
- - if( mode[0] == 'w' || mode[0] == 'a' || Q_strchr( mode, '+' ))
- + if( mode[0] == 'w' || mode[0] == 'a'|| mode[0] == 'e' || Q_strchr( mode, '+' ))
- {
- char real_path[MAX_SYSPATH];
- @@ -2024,9 +2006,9 @@ FS_Write
- Write "datasize" bytes into a file
- ====================
- */
- -fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize )
- +long FS_Write( file_t *file, const void *data, size_t datasize )
- {
- - fs_offset_t result;
- + long result;
- if( !file ) return 0;
- @@ -2038,7 +2020,7 @@ fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize )
- FS_Purge( file );
- // write the buffer and update the position
- - result = write( file->handle, data, (fs_offset_t)datasize );
- + result = write( file->handle, data, (long)datasize );
- file->position = lseek( file->handle, 0, SEEK_CUR );
- if( file->real_length < file->position )
- file->real_length = file->position;
- @@ -2055,10 +2037,10 @@ FS_Read
- Read up to "buffersize" bytes from a file
- ====================
- */
- -fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
- +long FS_Read( file_t *file, void *buffer, size_t buffersize )
- {
- - fs_offset_t count, done;
- - fs_offset_t nb;
- + long count, done;
- + long nb;
- // nothing to copy
- if( buffersize == 0 ) return 1;
- @@ -2078,7 +2060,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
- {
- count = file->buff_len - file->buff_ind;
- - done += ((fs_offset_t)buffersize > count ) ? count : (fs_offset_t)buffersize;
- + done += ((long)buffersize > count ) ? count : (long)buffersize;
- memcpy( buffer, &file->buff[file->buff_ind], done );
- file->buff_ind += done;
- @@ -2095,8 +2077,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
- // if we have a lot of data to get, put them directly into "buffer"
- if( buffersize > sizeof( file->buff ) / 2 )
- {
- - if( count > (fs_offset_t)buffersize )
- - count = (fs_offset_t)buffersize;
- + if( count > (long)buffersize )
- + count = (long)buffersize;
- lseek( file->handle, file->offset + file->position, SEEK_SET );
- nb = read (file->handle, &((byte *)buffer)[done], count );
- @@ -2104,14 +2086,14 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
- {
- done += nb;
- file->position += nb;
- - // Purge cached data
- + // purge cached data
- FS_Purge( file );
- }
- }
- else
- {
- - if( count > (fs_offset_t)sizeof( file->buff ))
- - count = (fs_offset_t)sizeof( file->buff );
- + if( count > (long)sizeof( file->buff ))
- + count = (long)sizeof( file->buff );
- lseek( file->handle, file->offset + file->position, SEEK_SET );
- nb = read( file->handle, file->buff, count );
- @@ -2121,7 +2103,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
- file->position += nb;
- // copy the requested data in "buffer" (as much as we can)
- - count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize;
- + count = (long)buffersize > file->buff_len ? file->buff_len : (long)buffersize;
- memcpy( &((byte *)buffer)[done], file->buff, count );
- file->buff_ind = count;
- done += count;
- @@ -2171,9 +2153,9 @@ Print a string into a file
- */
- int FS_VPrintf( file_t *file, const char* format, va_list ap )
- {
- - int len;
- - fs_offset_t buff_size = MAX_SYSPATH;
- - char *tempbuff;
- + int len;
- + long buff_size = MAX_SYSPATH;
- + char *tempbuff;
- if( !file ) return 0;
- @@ -2181,7 +2163,10 @@ int FS_VPrintf( file_t *file, const char* format, va_list ap )
- {
- tempbuff = (char *)Mem_Alloc( fs_mempool, buff_size );
- len = Q_vsprintf( tempbuff, format, ap );
- - if( len >= 0 && len < buff_size ) break;
- +
- + if( len >= 0 && len < buff_size )
- + break;
- +
- Mem_Free( tempbuff );
- buff_size *= 2;
- }
- @@ -2251,7 +2236,8 @@ int FS_Gets( file_t *file, byte *string, size_t bufsize )
- if( c == '\r' )
- {
- c = FS_Getc( file );
- - if( c != '\n' ) FS_UnGetc( file, (byte)c );
- + if( c != '\n' )
- + FS_UnGetc( file, (byte)c );
- }
- return c;
- @@ -2264,7 +2250,7 @@ FS_Seek
- Move the position index in a file
- ====================
- */
- -int FS_Seek( file_t *file, fs_offset_t offset, int whence )
- +int FS_Seek( file_t *file, long offset, int whence )
- {
- // compute the file offset
- switch( whence )
- @@ -2281,7 +2267,7 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
- return -1;
- }
- - if( offset < 0 || offset > (long)file->real_length )
- + if( offset < 0 || offset > file->real_length )
- return -1;
- // if we have the data in our read buffer, we don't need to actually seek
- @@ -2308,7 +2294,7 @@ FS_Tell
- Give the current position in a file
- ====================
- */
- -fs_offset_t FS_Tell( file_t* file )
- +long FS_Tell( file_t* file )
- {
- if( !file ) return 0;
- return file->position - file->buff_len + file->buff_ind;
- @@ -2349,11 +2335,11 @@ Filename are relative to the xash directory.
- Always appends a 0 byte.
- ============
- */
- -byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
- +byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly )
- {
- - file_t *file;
- - byte *buf = NULL;
- - fs_offset_t filesize = 0;
- + file_t *file;
- + byte *buf = NULL;
- + long filesize = 0;
- file = FS_Open( path, "rb", gamedironly );
- @@ -2383,7 +2369,7 @@ FS_OpenFile
- Simply version of FS_Open
- ============
- */
- -file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
- +file_t *FS_OpenFile( const char *path, long *filesizeptr, qboolean gamedironly )
- {
- file_t *file = FS_Open( path, "rb", gamedironly );
- @@ -2402,7 +2388,7 @@ FS_WriteFile
- The filename will be prefixed by the current game directory
- ============
- */
- -qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len )
- +qboolean FS_WriteFile( const char *filename, const void *data, long len )
- {
- file_t *file;
- @@ -2414,8 +2400,9 @@ qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len )
- return false;
- }
- - FS_Write (file, data, len);
- - FS_Close (file);
- + FS_Write( file, data, len );
- + FS_Close( file );
- +
- return true;
- }
- @@ -2493,18 +2480,16 @@ const char *FS_GetDiskPath( const char *name, qboolean gamedironly )
- {
- int index;
- searchpath_t *search;
- -
- +
- search = FS_FindFile( name, &index, gamedironly );
- if( search )
- {
- - if( index != -1 )
- - {
- - // file in pack or wad
- + if( index != -1 ) // file in pack or wad
- return NULL;
- - }
- return va( "%s%s", search->filename, name );
- }
- +
- return NULL;
- }
- @@ -2611,7 +2596,7 @@ FS_FileSize
- return size of file in bytes
- ==================
- */
- -fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly )
- +long FS_FileSize( const char *filename, qboolean gamedironly )
- {
- file_t *fp;
- int length = 0;
- @@ -2635,7 +2620,7 @@ FS_FileLength
- return size of file in bytes
- ==================
- */
- -fs_offset_t FS_FileLength( file_t *f )
- +long FS_FileLength( file_t *f )
- {
- if( !f ) return 0;
- return f->real_length;
- @@ -2648,7 +2633,7 @@ FS_FileTime
- return time of creation file in seconds
- ==================
- */
- -fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly )
- +long FS_FileTime( const char *filename, qboolean gamedironly )
- {
- searchpath_t *search;
- int pack_ind;
- @@ -2725,22 +2710,32 @@ FS_FileCopy
- ==================
- */
- -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
- +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
- {
- - char buf[MAX_SYSPATH]; // A small buffer for the copy
- - int size;
- + char *buf = Mem_Alloc( fs_mempool, FILE_COPY_SIZE );
- + int size, readSize;
- + qboolean done = true;
- while( fileSize > 0 )
- {
- - if( fileSize > MAX_SYSPATH )
- - size = MAX_SYSPATH;
- + if( fileSize > FILE_COPY_SIZE )
- + size = FILE_COPY_SIZE;
- else size = fileSize;
- - FS_Read( pInput, buf, size );
- - FS_Write( pOutput, buf, size );
- -
- + if(( readSize = FS_Read( pInput, buf, size )) < size )
- + {
- + MsgDev( D_ERROR, "FS_FileCopy: unexpected end of input file\n" );
- + fileSize = 0;
- + done = false;
- + break;
- + }
- +
- + FS_Write( pOutput, buf, readSize );
- fileSize -= size;
- }
- +
- + Mem_Free( buf );
- + return done;
- }
- /*
- @@ -2787,7 +2782,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
- // search through the path, one element at a time
- for( searchpath = fs_searchpaths; searchpath; searchpath = searchpath->next )
- {
- - if( gamedironly && !( searchpath->flags & FS_GAMEDIR_PATH ))
- + if( gamedironly && !FBitSet( searchpath->flags, FS_GAMEDIR_PATH ))
- continue;
- // is the element a pak file?
- @@ -2809,9 +2804,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
- }
- if( resultlistindex == resultlist.numstrings )
- - {
- stringlistappend( &resultlist, temp );
- - }
- }
- // strip off one path element at a time until empty
- // this way directories are added to the listing if they match the pattern
- @@ -2866,7 +2859,9 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
- if( type != TYP_ANY && wad->lumps[i].type != type )
- continue;
- - Q_strncpy( temp, wad->lumps[i].name, sizeof( temp ));
- + // build the lumpname with image suffix (if present)
- + Q_snprintf( temp, sizeof( temp ), "%s%s", wad->lumps[i].name, wad_hints[wad->lumps[i].img_type].ext );
- +
- while( temp[0] )
- {
- if( matchpattern( temp, wadpattern, true ))
- @@ -2920,11 +2915,10 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
- }
- if( resultlistindex == resultlist.numstrings )
- - {
- stringlistappend( &resultlist, temp );
- - }
- }
- }
- +
- stringlistfreecontents( &dirlist );
- }
- }
- @@ -3006,6 +3000,13 @@ static const wadtype_t wad_hints[10] =
- { NULL, 0 } // terminator
- };
- +/*
- +===========
- +W_TypeFromExt
- +
- +Extracts file type from extension
- +===========
- +*/
- static char W_TypeFromExt( const char *lumpname )
- {
- const char *ext = FS_FileExtension( lumpname );
- @@ -3057,11 +3058,17 @@ char W_HintFromSuf( const char *lumpname )
- {
- char barename[64];
- char suffix[8];
- + size_t namelen;
- const wadtype_t *hint;
- // trying to extract hint from the name
- FS_FileBase( lumpname, barename );
- - Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix ));
- + namelen = Q_strlen( barename );
- +
- + if( namelen <= HINT_NAMELEN )
- + return IMG_DIFFUSE;
- +
- + Q_strncpy( suffix, barename + namelen - HINT_NAMELEN, sizeof( suffix ));
- // we not known about filetype, so match only by filename
- for( hint = wad_hints; hint->ext; hint++ )
- @@ -3074,11 +3081,19 @@ char W_HintFromSuf( const char *lumpname )
- return IMG_DIFFUSE;
- }
- +/*
- +===========
- +W_FindLump
- +
- +Serach for already existed lump
- +===========
- +*/
- static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype )
- {
- char img_type = IMG_DIFFUSE;
- char barename[64], suffix[8];
- int left, right;
- + size_t namelen;
- const wadtype_t *hint;
- if( !wad || !wad->lumps || matchtype == TYP_NONE )
- @@ -3086,20 +3101,25 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match
- // trying to extract hint from the name
- FS_FileBase( name, barename );
- - Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix ));
- + namelen = Q_strlen( barename );
- - // we not known about filetype, so match only by filename
- - for( hint = wad_hints; hint->ext; hint++ )
- + if( namelen > HINT_NAMELEN )
- {
- - if( !Q_stricmp( suffix, hint->ext ))
- + Q_strncpy( suffix, barename + namelen - HINT_NAMELEN, sizeof( suffix ));
- +
- + // we not known about filetype, so match only by filename
- + for( hint = wad_hints; hint->ext; hint++ )
- {
- - img_type = hint->type;
- - break;
- + if( !Q_stricmp( suffix, hint->ext ))
- + {
- + img_type = hint->type;
- + break;
- + }
- }
- - }
- - if( img_type != IMG_DIFFUSE )
- - barename[Q_strlen( barename ) - HINT_NAMELEN] = '\0'; // kill the suffix
- + if( img_type != IMG_DIFFUSE )
- + barename[namelen - HINT_NAMELEN] = '\0'; // kill the suffix
- + }
- // look for the file (binary search)
- left = 0;
- @@ -3135,9 +3155,10 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match
- /*
- ====================
- -FS_AddFileToWad
- +W_AddFileToWad
- Add a file to the list of files contained into a package
- +and sort LAT in alpha-bethical order
- ====================
- */
- static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t *newlump )
- @@ -3145,14 +3166,6 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
- int left, right;
- dlumpinfo_t *plump;
- - // convert all qmip types to miptex
- - if( newlump->type == TYP_RAWDATA )
- - newlump->type = TYP_MIPTEX;
- -
- - // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic)
- - if( !Q_stricmp( newlump->name, "conchars" ) && newlump->type == TYP_RAWDATA )
- - newlump->type = TYP_GFXPIC;
- -
- // look for the slot we should put that file into (binary search)
- left = 0;
- right = wad->numlumps - 1;
- @@ -3172,7 +3185,7 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
- diff = 1;
- else if( wad->lumps[middle].type > newlump->type )
- diff = -1;
- - else MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name );
- + else MsgDev( D_WARN, "Wad %s contains the file %s several times\n", wad->filename, name );
- }
- // If we're too far in the list
- @@ -3191,53 +3204,17 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
- return plump;
- }
- -static qboolean W_ReadLumpTable( wfile_t *wad )
- -{
- - size_t lat_size;
- - dlumpinfo_t *srclumps;
- - int i, k, numlumps;
- -
- - // nothing to convert ?
- - if( !wad || !wad->numlumps )
- - return false;
- -
- - lat_size = wad->numlumps * sizeof( dlumpinfo_t );
- - srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
- - numlumps = wad->numlumps;
- - wad->numlumps = 0; // reset it
- -
- - if( read( wad->handle, srclumps, lat_size ) != lat_size )
- - {
- - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
- - W_Close( wad );
- - return false;
- - }
- -
- - // swap everything
- - for( i = 0; i < numlumps; i++ )
- - {
- - char name[16];
- -
- - // cleanup lumpname
- - Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name ));
- -
- - // check for '*' symbol issues
- - k = Q_strlen( Q_strrchr( name, '*' ));
- - if( k ) name[Q_strlen( name ) - k] = '!'; // quake1 issues (can't save images that contain '*' symbol)
- -
- - W_AddFileToWad( name, wad, &srclumps[i] );
- - }
- -
- - // release source lumps
- - Mem_Free( srclumps );
- -
- - return true;
- -}
- +/*
- +===========
- +W_ReadLump
- -byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
- +reading lump into temp buffer
- +===========
- +*/
- +byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, long *lumpsizeptr )
- {
- + size_t oldpos, size = 0;
- byte *buf;
- - size_t size = 0;
- // assume error
- if( lumpsizeptr ) *lumpsizeptr = 0;
- @@ -3245,9 +3222,12 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
- // no wads loaded
- if( !wad || !lump ) return NULL;
- + oldpos = tell( wad->handle ); // don't forget restore original position
- +
- if( lseek( wad->handle, lump->filepos, SEEK_SET ) == -1 )
- {
- MsgDev( D_ERROR, "W_ReadLump: %s is corrupted\n", lump->name );
- + lseek( wad->handle, oldpos, SEEK_SET );
- return NULL;
- }
- @@ -3256,47 +3236,129 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
- if( size < lump->disksize )
- {
- MsgDev( D_WARN, "W_ReadLump: %s is probably corrupted\n", lump->name );
- + lseek( wad->handle, oldpos, SEEK_SET );
- Mem_Free( buf );
- return NULL;
- }
- +
- if( lumpsizeptr ) *lumpsizeptr = lump->size;
- + lseek( wad->handle, oldpos, SEEK_SET );
- +
- return buf;
- }
- /*
- +===========
- +W_WriteLump
- +
- +compress and write lump
- +===========
- +*/
- +qboolean W_WriteLump( wfile_t *wad, dlumpinfo_t *lump, const void *data, size_t datasize )
- +{
- + if( !wad || !lump ) return false;
- +
- + if( !data || !datasize )
- + {
- + MsgDev( D_WARN, "W_WriteLump: ignore blank lump %s - nothing to save\n", lump->name );
- + return false;
- + }
- +
- + if( wad->mode == O_RDONLY )
- + {
- + MsgDev( D_ERROR, "W_WriteLump: %s opened in readonly mode\n", wad->filename );
- + return false;
- + }
- +
- + lump->size = lump->disksize = datasize;
- +
- + if( write( wad->handle, data, datasize ) == datasize )
- + return true;
- + return false;
- +}
- +
- +/*
- =============================================================================
- WADSYSTEM PUBLIC BASE FUNCTIONS
- =============================================================================
- */
- -wfile_t *W_Open( const char *filename, const char *mode )
- +/*
- +===========
- +W_Open
- +
- +open the wad for reading & writing
- +===========
- +*/
- +wfile_t *W_Open( const char *filename, const char *mode, int *error )
- {
- dwadinfo_t header;
- wfile_t *wad = (wfile_t *)Mem_Alloc( fs_mempool, sizeof( wfile_t ));
- - const char *comment = "Generated by Xash WadLib. ";
- + const char *comment = "Created by Xash3D Engine.\0";
- + int i, ind, mod, opt, lumpcount;
- + size_t wadsize, lat_size;
- + dlumpinfo_t *srclumps;
- - if( mode[0] == 'a' ) wad->handle = open( filename, O_RDWR|O_BINARY, 0x666 );
- - else if( mode[0] == 'w' ) wad->handle = open( filename, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0x666 );
- - else if( mode[0] == 'r' ) wad->handle = open( filename, O_RDONLY|O_BINARY, 0x666 );
- + // parse the mode string
- + switch( mode[0] )
- + {
- + case 'r':
- + mod = O_RDONLY;
- + opt = 0;
- + break;
- + case 'w':
- + mod = O_WRONLY;
- + opt = O_CREAT|O_TRUNC;
- + break;
- + case 'a':
- + mod = O_WRONLY;
- + opt = O_CREAT;
- + break;
- + default:
- + MsgDev( D_ERROR, "W_Open(%s, %s): invalid mode\n", filename, mode );
- + return NULL;
- + }
- +
- + for( ind = 1; mode[ind] != '\0'; ind++ )
- + {
- + switch( mode[ind] )
- + {
- + case '+':
- + mod = O_RDWR;
- + break;
- + case 'b':
- + opt |= O_BINARY;
- + break;
- + default:
- + MsgDev( D_ERROR, "W_Open: %s: unknown char in mode (%c)\n", filename, mode, mode[ind] );
- + break;
- + }
- + }
- +
- + wad->handle = open( filename, mod|opt, 0666 );
- if( wad->handle < 0 )
- {
- - W_Close( wad );
- MsgDev( D_ERROR, "W_Open: couldn't open %s\n", filename );
- + if( error ) *error = WAD_LOAD_COULDNT_OPEN;
- + W_Close( wad );
- return NULL;
- }
- // copy wad name
- Q_strncpy( wad->filename, filename, sizeof( wad->filename ));
- - wad->mempool = Mem_AllocPool( filename );
- wad->filetime = FS_SysFileTime( filename );
- + wad->mempool = Mem_AllocPool( filename );
- +
- + wadsize = lseek( wad->handle, 0, SEEK_END );
- + lseek( wad->handle, 0, SEEK_SET );
- // if the file is opened in "write", "append", or "read/write" mode
- - if( mode[0] == 'w' )
- + if( mod == O_WRONLY || !wadsize )
- {
- - dwadinfo_t hdr;
- + dwadinfo_t hdr;
- wad->numlumps = 0; // blank wad
- wad->lumps = NULL; //
- @@ -3310,95 +3372,122 @@ wfile_t *W_Open( const char *filename, const char *mode )
- write( wad->handle, comment, Q_strlen( comment ) + 1 );
- wad->infotableofs = tell( wad->handle );
- }
- - else if( mode[0] == 'r' || mode[0] == 'a' )
- + else if( mod == O_RDWR || mod == O_RDONLY )
- {
- - if( mode[0] == 'a' )
- - {
- - lseek( wad->handle, 0, SEEK_SET );
- + if( mod == O_RDWR )
- wad->mode = O_APPEND;
- - }
- + else wad->mode = O_RDONLY;
- if( read( wad->handle, &header, sizeof( dwadinfo_t )) != sizeof( dwadinfo_t ))
- {
- MsgDev( D_ERROR, "W_Open: %s can't read header\n", filename );
- + if( error ) *error = WAD_LOAD_BAD_HEADER;
- W_Close( wad );
- return NULL;
- }
- - switch( header.ident )
- + if( header.ident != IDWAD3HEADER )
- {
- - case IDWAD2HEADER:
- - case IDWAD3HEADER:
- - break; // WAD2, WAD3 allow r\w mode
- - default:
- - MsgDev( D_ERROR, "W_Open: %s unknown wadtype\n", filename );
- + MsgDev( D_ERROR, "W_Open: %s is not a WAD3 file\n", filename );
- + if( error ) *error = WAD_LOAD_BAD_HEADER;
- W_Close( wad );
- return NULL;
- }
- - wad->numlumps = header.numlumps;
- - if( wad->numlumps >= MAX_FILES_IN_WAD && wad->mode == O_APPEND )
- + lumpcount = header.numlumps;
- +
- + if( lumpcount >= MAX_FILES_IN_WAD && wad->mode == O_APPEND )
- {
- - MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", wad->numlumps );
- + MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", filename, lumpcount );
- + if( error ) *error = WAD_LOAD_TOO_MANY_FILES;
- wad->mode = O_RDONLY; // set read-only mode
- }
- + else if( lumpcount <= 0 && wad->mode == O_RDONLY )
- + {
- + MsgDev( D_ERROR, "W_Open: %s has no lumps\n", filename );
- + if( error ) *error = WAD_LOAD_NO_FILES;
- + W_Close( wad );
- + return NULL;
- + }
- + else if( error ) *error = WAD_LOAD_OK;
- +
- wad->infotableofs = header.infotableofs; // save infotableofs position
- +
- if( lseek( wad->handle, wad->infotableofs, SEEK_SET ) == -1 )
- {
- MsgDev( D_ERROR, "W_Open: %s can't find lump allocation table\n", filename );
- + if( error ) *error = WAD_LOAD_BAD_FOLDERS;
- W_Close( wad );
- return NULL;
- }
- + lat_size = lumpcount * sizeof( dlumpinfo_t );
- +
- // NOTE: lumps table can be reallocated for O_APPEND mode
- - wad->lumps = Mem_Alloc( wad->mempool, wad->numlumps * sizeof( dlumpinfo_t ));
- + srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
- - if( wad->mode == O_APPEND )
- - {
- - size_t lat_size = wad->numlumps * sizeof( dlumpinfo_t );
- + if( read( wad->handle, srclumps, lat_size ) != lat_size )
- + {
- + MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
- + if( error ) *error = WAD_LOAD_CORRUPTED;
- + Mem_Free( srclumps );
- + W_Close( wad );
- + return NULL;
- + }
- - if( read( wad->handle, wad->lumps, lat_size ) != lat_size )
- - {
- - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
- - W_Close( wad );
- - return NULL;
- - }
- + // starting to add lumps
- + wad->lumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
- + wad->numlumps = 0;
- - // if we are in append mode - we need started from infotableofs poisition
- - // overwrite lumptable as well, we have her copy in wad->lumps
- - lseek( wad->handle, wad->infotableofs, SEEK_SET );
- - }
- - else
- + // sort lumps for binary search
- + for( i = 0; i < lumpcount; i++ )
- {
- - // setup lump allocation table
- - switch( header.ident )
- - {
- - case IDWAD2HEADER:
- - case IDWAD3HEADER:
- - if(!W_ReadLumpTable( wad ))
- - return NULL;
- - break;
- - }
- + char name[16];
- + int k;
- +
- + // cleanup lumpname
- + Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name ));
- +
- + // check for '*' symbol issues (quake1)
- + k = Q_strlen( Q_strrchr( name, '*' ));
- + if( k ) name[Q_strlen( name ) - k] = '!';
- +
- + W_AddFileToWad( name, wad, &srclumps[i] );
- }
- +
- + // release source lumps
- + Mem_Free( srclumps );
- +
- + // if we are in append mode - we need started from infotableofs poisition
- + // overwrite lumptable as well, we have her copy in wad->lumps
- + if( wad->mode == O_APPEND )
- + lseek( wad->handle, wad->infotableofs, SEEK_SET );
- }
- - // and leaves the file open
- +
- + // and leave the file open
- return wad;
- }
- +/*
- +===========
- +W_Close
- +
- +finalize wad or just close
- +===========
- +*/
- void W_Close( wfile_t *wad )
- {
- - fs_offset_t ofs;
- -
- if( !wad ) return;
- if( wad->handle >= 0 && ( wad->mode == O_APPEND || wad->mode == O_WRONLY ))
- {
- dwadinfo_t hdr;
- + long ofs;
- // write the lumpinfo
- ofs = tell( wad->handle );
- write( wad->handle, wad->lumps, wad->numlumps * sizeof( dlumpinfo_t ));
- -
- +
- // write the header
- hdr.ident = IDWAD3HEADER;
- hdr.numlumps = wad->numlumps;
- @@ -3409,7 +3498,9 @@ void W_Close( wfile_t *wad )
- }
- Mem_FreePool( &wad->mempool );
- - if( wad->handle >= 0 ) close( wad->handle );
- + if( wad->handle >= 0 )
- + close( wad->handle );
- +
- Mem_Free( wad ); // free himself
- }
- @@ -3420,7 +3511,127 @@ FILESYSTEM IMPLEMENTATION
- =============================================================================
- */
- -static byte *W_LoadFile( const char *path, fs_offset_t *lumpsizeptr, qboolean gamedironly )
- +/*
- +===========
- +W_SaveLump
- +
- +write new or replace existed lump
- +===========
- +*/
- +size_t W_SaveFile( wfile_t *wad, const char *lump, const void *data, size_t datasize, char type, qboolean replace )
- +{
- + dlumpinfo_t *find, newlump;
- + size_t lat_size, oldpos;
- + char hint, lumpname[64];
- +
- + if( !wad || !lump ) return -1;
- +
- + if( !data || !datasize )
- + {
- + MsgDev( D_WARN, "W_SaveLump: ignore blank lump %s - nothing to save\n", lump );
- + return -1;
- + }
- +
- + if( wad->mode == O_RDONLY )
- + {
- + MsgDev( D_ERROR, "W_SaveLump: %s opened in readonly mode\n", wad->filename );
- + return -1;
- + }
- +
- + if( wad->numlumps >= MAX_FILES_IN_WAD )
- + {
- + MsgDev( D_ERROR, "W_SaveLump: %s is full\n", wad->filename );
- + return -1;
- + }
- +
- + find = W_FindLump( wad, lump, type );
- +
- + if( find != NULL && replace )
- + {
- + if( FBitSet( find->attribs, ATTR_READONLY ))
- + {
- + // g-cont. i left this limitation as a protect of the replacement of compressed lumps
- + MsgDev( D_ERROR, "W_ReplaceLump: %s is read-only\n", find->name );
- + return -1;
- + }
- +
- + if( datasize != find->size )
- + {
- + MsgDev( D_ERROR, "W_ReplaceLump: %s [%s] should be [%s]\n",
- + lumpname, Q_memprint( datasize ), Q_memprint( find->size ));
- + return -1;
- + }
- +
- + oldpos = tell( wad->handle ); // don't forget restore original position
- +
- + if( lseek( wad->handle, find->filepos, SEEK_SET ) == -1 )
- + {
- + MsgDev( D_ERROR, "W_ReplaceLump: %s is corrupted\n", find->name );
- + lseek( wad->handle, oldpos, SEEK_SET );
- + return -1;
- + }
- +
- + if( write( wad->handle, data, datasize ) != find->disksize )
- + MsgDev( D_WARN, "W_ReplaceLump: %s probably replaced with errors\n", find->name );
- +
- + // restore old position
- + lseek( wad->handle, oldpos, SEEK_SET );
- +
- + return wad->numlumps;
- + }
- + else
- + {
- + MsgDev( D_ERROR, "W_SaveLump: %s already exist\n", lump );
- + return -1;
- + }
- +
- + // prepare lump name
- + Q_strncpy( lumpname, lump, sizeof( lumpname ));
- +
- + // extract image hint
- + hint = W_HintFromSuf( lumpname );
- +
- + if( hint != IMG_DIFFUSE )
- + lumpname[Q_strlen( lumpname ) - HINT_NAMELEN] = '\0'; // kill the suffix
- +
- + if( Q_strlen( lumpname ) >= WAD3_NAMELEN )
- + {
- + // name is too long
- + MsgDev( D_ERROR, "W_SaveLump: %s more than %i symbols\n", lumpname, WAD3_NAMELEN );
- + return -1;
- + }
- +
- + lat_size = sizeof( dlumpinfo_t ) * (wad->numlumps + 1);
- +
- + // reallocate lumptable
- + wad->lumps = (dlumpinfo_t *)Mem_Realloc( wad->mempool, wad->lumps, lat_size );
- +
- + memset( &newlump, 0, sizeof( newlump ));
- +
- + // write header
- + Q_strnupr( lumpname, newlump.name, WAD3_NAMELEN );
- + newlump.filepos = tell( wad->handle );
- + newlump.attribs = ATTR_NONE;
- + newlump.img_type = hint;
- + newlump.type = type;
- +
- + if( !W_WriteLump( wad, &newlump, data, datasize ))
- + return -1;
- +
- + // record entry and re-sort table
- + W_AddFileToWad( lumpname, wad, &newlump );
- +
- + return wad->numlumps;
- +}
- +
- +/*
- +===========
- +W_LoadFile
- +
- +loading lump into the tmp buffer
- +===========
- +*/
- +static byte *W_LoadFile( const char *path, long *lumpsizeptr, qboolean gamedironly )
- {
- searchpath_t *search;
- int index;
- diff --git b/engine/common/filesystem.h a/engine/common/filesystem.h
- index a5bf2cc..9f5cbeb 100644
- --- b/engine/common/filesystem.h
- +++ a/engine/common/filesystem.h
- @@ -58,9 +58,6 @@ 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" quake1 gfx.wad
- -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads
- -
- #define WAD3_NAMELEN 16
- #define HINT_NAMELEN 5 // e.g. _mask, _norm
- #define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount
- @@ -73,9 +70,9 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
- typedef struct
- {
- - int ident; // should be IWAD, WAD2 or WAD3
- + int ident; // should be WAD3
- int numlumps; // num files
- - int infotableofs;
- + int infotableofs; // LUT offset
- } dwadinfo_t;
- typedef struct
- diff --git b/engine/common/host.c a/engine/common/host.c
- index 84b5468..cb32669 100644
- --- b/engine/common/host.c
- +++ a/engine/common/host.c
- @@ -39,8 +39,6 @@ convar_t *host_framerate;
- convar_t *con_gamemaps;
- convar_t *build, *ver;
- -static int num_decals;
- -
- // these cvars will be duplicated on each client across network
- int Host_ServerState( void )
- {
- @@ -74,23 +72,26 @@ Host_PrintEngineFeatures
- */
- void Host_PrintEngineFeatures( void )
- {
- - if( host.features & ENGINE_WRITE_LARGE_COORD )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 big world support enabled\n" );
- + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
- + MsgDev( D_REPORT, "^3EXT:^7 big world support enabled\n" );
- +
- + if( FBitSet( host.features, ENGINE_BUILD_SURFMESHES ))
- + MsgDev( D_REPORT, "^3EXT:^7 surfmeshes enabled\n" );
- - if( host.features & ENGINE_BUILD_SURFMESHES )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 surfmeshes enabled\n" );
- + if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
- + MsgDev( D_REPORT, "^3EXT:^7 deluxemap support enabled\n" );
- - if( host.features & ENGINE_LOAD_DELUXEDATA )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 deluxemap support enabled\n" );
- + if( FBitSet( host.features, ENGINE_TRANSFORM_TRACE_AABB ))
- + MsgDev( D_REPORT, "^3EXT:^7 Transform trace AABB enabled\n" );
- - if( host.features & ENGINE_TRANSFORM_TRACE_AABB )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 Transform trace AABB enabled\n" );
- + if( FBitSet( host.features, ENGINE_LARGE_LIGHTMAPS ))
- + MsgDev( D_REPORT, "^3EXT:^7 Large lightmaps enabled\n" );
- - if( host.features & ENGINE_LARGE_LIGHTMAPS )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 Large lightmaps enabled\n" );
- + if( FBitSet( host.features, ENGINE_COMPENSATE_QUAKE_BUG ))
- + MsgDev( D_REPORT, "^3EXT:^7 Compensate quake bug enabled\n" );
- - if( host.features & ENGINE_COMPENSATE_QUAKE_BUG )
- - MsgDev( D_AICONSOLE, "^3EXT:^7 Compensate quake bug enabled\n" );
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + MsgDev( D_REPORT, "^3EXT:^7 fixed main cycle\n" );
- }
- /*
- @@ -118,7 +119,7 @@ void Host_EndGame( const char *message, ... )
- static char string[MAX_SYSPATH];
- va_start( argptr, message );
- - Q_vsprintf( string, message, argptr );
- + Q_vsnprintf( string, sizeof( string ), message, argptr );
- va_end( argptr );
- MsgDev( D_INFO, "Host_EndGame: %s\n", string );
- @@ -233,10 +234,10 @@ void Host_Exec_f( void )
- return;
- }
- - // HACKHACK: don't execute listenserver.cfg in singleplayer
- - if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 )))
- + // don't execute listenserver.cfg in singleplayer
- + if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 )))
- {
- - if( Cvar_VariableValue( "maxplayers" ) == 1.0f )
- + if( Cvar_VariableInteger( "maxplayers" ) == 1 )
- return;
- }
- @@ -309,12 +310,12 @@ qboolean Host_IsLocalClient( void )
- Host_RegisterDecal
- =================
- */
- -qboolean Host_RegisterDecal( const char *name )
- +qboolean Host_RegisterDecal( const char *name, int *count )
- {
- char shortname[CS_SIZE];
- int i;
- - if( !name || !name[0] )
- + if( !name || !*name )
- return 0;
- FS_FileBase( name, shortname );
- @@ -333,7 +334,7 @@ qboolean Host_RegisterDecal( const char *name )
- // register new decal
- Q_strncpy( host.draw_decals[i], shortname, sizeof( host.draw_decals[i] ));
- - num_decals++;
- + *count += 1;
- return true;
- }
- @@ -346,17 +347,16 @@ Host_InitDecals
- void Host_InitDecals( void )
- {
- search_t *t;
- - int i;
- + int i, num_decals = 0;
- memset( host.draw_decals, 0, sizeof( host.draw_decals ));
- - num_decals = 0;
- // lookup all decals in decals.wad
- t = FS_Search( "decals.wad/*.*", true, false );
- for( i = 0; t && i < t->numfilenames; i++ )
- {
- - if( !Host_RegisterDecal( t->filenames[i] ))
- + if( !Host_RegisterDecal( t->filenames[i], &num_decals ))
- break;
- }
- @@ -373,27 +373,25 @@ Write ambient sounds into demo
- */
- void Host_RestartAmbientSounds( void )
- {
- - soundlist_t soundInfo[64];
- + soundlist_t soundInfo[128];
- string curtrack, looptrack;
- int i, nSounds;
- - fs_offset_t position;
- + long position;
- - if( !SV_Active( ))
- - {
- - return;
- - }
- + if( !SV_Active( )) return;
- - nSounds = S_GetCurrentStaticSounds( soundInfo, 64 );
- + nSounds = S_GetCurrentStaticSounds( soundInfo, 128 );
- for( i = 0; i < nSounds; i++ )
- {
- - if( !soundInfo[i].looping || soundInfo[i].entnum == -1 )
- + soundlist_t *si = &soundInfo[i];
- +
- + if( !si->looping || si->entnum == -1 )
- continue;
- MsgDev( D_NOTE, "Restarting sound %s...\n", soundInfo[i].name );
- - S_StopSound( soundInfo[i].entnum, soundInfo[i].channel, soundInfo[i].name );
- - SV_StartSound( pfnPEntityOfEntIndex( soundInfo[i].entnum ), CHAN_STATIC, soundInfo[i].name,
- - soundInfo[i].volume, soundInfo[i].attenuation, 0, soundInfo[i].pitch );
- + S_StopSound( si->entnum, si->channel, si->name );
- + SV_StartSound( pfnPEntityOfEntIndex( si->entnum ), CHAN_STATIC, si->name, si->volume, si->attenuation, 0, si->pitch );
- }
- // restart soundtrack
- @@ -418,10 +416,7 @@ void Host_RestartDecals( void )
- sizebuf_t *msg;
- int i;
- - if( !SV_Active( ))
- - {
- - return;
- - }
- + if( !SV_Active( )) return;
- // g-cont. add space for studiodecals if present
- host.decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
- @@ -465,20 +460,103 @@ void Host_RestartDecals( void )
- /*
- ===================
- -Host_GetConsoleCommands
- +Host_GetCommands
- Add them exactly as if they had been typed at the console
- ===================
- */
- -void Host_GetConsoleCommands( void )
- +void Host_GetCommands( void )
- {
- char *cmd;
- - if( host.type == HOST_DEDICATED )
- + if( host.type != HOST_DEDICATED )
- + return;
- +
- + cmd = Con_Input();
- + if( cmd ) Cbuf_AddText( cmd );
- +}
- +
- +/*
- +===================
- +Host_FrameTime
- +
- +Returns false if the time is too short to run a frame
- +===================
- +*/
- +qboolean Host_FrameTime( float time )
- +{
- + static double oldtime;
- + double minframetime;
- + double fps;
- +
- + host.realtime += time;
- +
- + // limit fps to withing tolerable range
- + fps = bound( HOST_MINFPS, HOST_FPS, HOST_MAXFPS );
- + minframetime = ( 1.0 / fps );
- +
- + if(( host.realtime - oldtime ) < minframetime )
- + {
- + // framerate is too high
- + return false;
- + }
- +
- + host.frametime = host.realtime - oldtime;
- + host.realframetime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
- + oldtime = host.realtime;
- +
- + if( host_framerate->value > 0 && ( Host_IsLocalGame( )))
- + {
- + float fps = host_framerate->value;
- + if( fps > 1 ) fps = 1.0f / fps;
- + host.frametime = fps;
- + }
- + else
- + { // don't allow really long or short frames
- + host.frametime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
- + }
- +
- + return true;
- +}
- +
- +/*
- +===================
- +Host_RenderTime
- +
- +Returns false if the time is too short to render a frame
- +===================
- +*/
- +qboolean Host_RenderTime( float time )
- +{
- + static double oldtime;
- + static double newtime;
- + double fps;
- +
- + newtime += time;
- +
- + // dedicated's tic_rate regulates server frame rate. Don't apply fps filter here.
- + fps = host_maxfps->value;
- +
- + // clamp the fps in multiplayer games
- + if( fps != 0 )
- {
- - cmd = Con_Input();
- - if( cmd ) Cbuf_AddText( cmd );
- + double minframetime;
- +
- + // limit fps to withing tolerable range
- + fps = bound( MIN_FPS, fps, MAX_FPS );
- +
- + minframetime = 1.0 / fps;
- +
- + if(( newtime - oldtime ) < minframetime )
- + {
- + // framerate is too high
- + return false;
- + }
- }
- +
- + oldtime = newtime;
- +
- + return true;
- }
- /*
- @@ -498,6 +576,7 @@ qboolean Host_FilterTime( float time )
- // dedicated's tic_rate regulates server frame rate. Don't apply fps filter here.
- fps = host_maxfps->value;
- + // clamp the fps in multiplayer games
- if( fps != 0 )
- {
- float minframetime;
- @@ -542,18 +621,39 @@ void Host_Frame( float time )
- if( setjmp( host.abortframe ))
- return;
- - Host_InputFrame (); // input frame
- + // new-style game loop
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + // decide the simulation time
- + if( Host_FrameTime( time ))
- + {
- + Host_InputFrame (); // input frame
- + Host_GetCommands(); // dedicated
- + Host_ServerFrame(); // server frame
- + Host_ClientFrame(); // client frame
- + host.framecount++;
- + }
- - // decide the simulation time
- - if( !Host_FilterTime( time ))
- - return;
- + // clamp the renderer time
- + if( !Host_RenderTime( time ))
- + return;
- +
- + Host_RenderFrame (); // render frame
- + }
- + else // classic game loop
- + {
- + Host_InputFrame (); // input frame
- - Host_GetConsoleCommands ();
- + // decide the simulation time
- + if( !Host_FilterTime( time ))
- + return;
- - Host_ServerFrame (); // server frame
- - Host_ClientFrame (); // client frame
- + Host_GetCommands ();
- + Host_ServerFrame (); // server frame
- + Host_ClientFrame (); // client frame
- - host.framecount++;
- + host.framecount++;
- + }
- }
- /*
- @@ -707,7 +807,7 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
- GlobalMemoryStatus( &lpBuffer );
- if( !GetCurrentDirectory( sizeof( host.rootdir ), host.rootdir ))
- - Sys_Error( "couldn't determine current directory" );
- + Sys_Error( "couldn't determine current directory\n" );
- if( host.rootdir[Q_strlen( host.rootdir ) - 1] == '/' )
- host.rootdir[Q_strlen( host.rootdir ) - 1] = 0;
- @@ -718,7 +818,7 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
- host.state = HOST_INIT; // initialzation started
- host.developer = host.old_developer = 0;
- - CRT_Init(); // init some CRT functions
- + Memory_Init(); // init memory subsystem
- // some commands may turn engine into infinity loop,
- // e.g. xash.exe +game xash -game xash
- @@ -728,7 +828,9 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
- host.mempool = Mem_AllocPool( "Zone Engine" );
- - if( Sys_CheckParm( "-console" )) host.developer = 1;
- + if( Sys_CheckParm( "-console" ))
- + host.developer = 1;
- +
- if( Sys_CheckParm( "-dev" ))
- {
- if( Sys_GetParmFromCmdLine( "-dev", dev_level ))
- @@ -943,9 +1045,9 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
- Cmd_RemoveCommand( "setgl" );
- // we need to execute it again here
- - Cmd_ExecuteString( "exec config.cfg\n", src_command );
- - oldtime = Sys_DoubleTime();
- - SCR_CheckStartupVids(); // must be last
- + Cmd_ExecuteString( "exec config.cfg\n" );
- + oldtime = Sys_DoubleTime() - 0.1;
- + SCR_CheckStartupVids(); // must be last
- // main window message loop
- while( !host.crashed )
- diff --git b/engine/common/imagelib/img_bmp.c a/engine/common/imagelib/img_bmp.c
- index e57f5ae..c7d6f31 100644
- --- b/engine/common/imagelib/img_bmp.c
- +++ a/engine/common/imagelib/img_bmp.c
- @@ -14,6 +14,7 @@ GNU General Public License for more details.
- */
- #include "imagelib.h"
- +#include "mathlib.h"
- /*
- =============
- @@ -26,6 +27,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
- byte palette[256][4];
- int i, columns, column, rows, row, bpp = 1;
- int cbPalBytes = 0, padSize = 0, bps = 0;
- + int reflectivity[3] = { 0, 0, 0 };
- qboolean load_qfont = false;
- bmp_t bhdr;
- @@ -53,7 +55,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
- if( bhdr.reserved0 != 0 ) return false;
- if( bhdr.planes != 1 ) return false;
- - if( Q_memcmp( bhdr.id, "BM", 2 ))
- + if( memcmp( bhdr.id, "BM", 2 ))
- {
- MsgDev( D_ERROR, "Image_LoadBMP: only Windows-style BMP files supported (%s)\n", name );
- return false;
- @@ -108,7 +110,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
- else cbPalBytes = bhdr.colors * sizeof( RGBQUAD );
- }
- - Q_memcpy( palette, buf_p, cbPalBytes );
- + memcpy( palette, buf_p, cbPalBytes );
- if( host.overview_loading && bhdr.bitsPerPixel == 8 )
- {
- @@ -280,13 +282,20 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
- Mem_Free( image.rgba );
- return false;
- }
- +
- if( !Image_CheckFlag( IL_KEEP_8BIT ) && ( red != green || green != blue ))
- image.flags |= IMAGE_HAS_COLOR;
- +
- + reflectivity[0] += red;
- + reflectivity[1] += green;
- + reflectivity[2] += blue;
- }
- buf_p += padSize; // actual only for 4-bit bmps
- }
- + VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
- if( image.palette ) Image_GetPaletteBMP( image.palette );
- + image.depth = 1;
- return true;
- }
- @@ -378,7 +387,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
- if( host.write_to_clipboard )
- {
- - Q_memcpy( clipbuf + cur_size, &bmih, sizeof( bmih ));
- + memcpy( clipbuf + cur_size, &bmih, sizeof( bmih ));
- cur_size += sizeof( bmih );
- }
- else
- @@ -409,7 +418,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
- if( host.write_to_clipboard )
- {
- - Q_memcpy( clipbuf + cur_size, rgrgbPalette, cbPalBytes );
- + memcpy( clipbuf + cur_size, rgrgbPalette, cbPalBytes );
- cur_size += cbPalBytes;
- }
- else
- @@ -450,7 +459,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
- if( host.write_to_clipboard )
- {
- - Q_memcpy( clipbuf + cur_size, pbBmpBits, cbBmpBits );
- + memcpy( clipbuf + cur_size, pbBmpBits, cbBmpBits );
- cur_size += cbBmpBits;
- Sys_SetClipboardData( clipbuf, total_size );
- Z_Free( clipbuf );
- diff --git b/engine/common/imagelib/img_dds.c a/engine/common/imagelib/img_dds.c
- index 837ade9..c6f36f8 100644
- --- b/engine/common/imagelib/img_dds.c
- +++ a/engine/common/imagelib/img_dds.c
- @@ -14,6 +14,7 @@ GNU General Public License for more details.
- */
- #include "imagelib.h"
- +#include "mathlib.h"
- qboolean Image_CheckDXT3Alpha( dds_t *hdr, byte *fin )
- {
- @@ -175,10 +176,10 @@ size_t Image_DXTCalcMipmapSize( dds_t *hdr )
- int i, width, height;
- // now correct buffer size
- - for( i = 0; i < hdr->dwMipMapCount; i++ )
- + for( i = 0; i < Q_max( 1, ( hdr->dwMipMapCount )); i++ )
- {
- - width = max( 1, ( hdr->dwWidth >> i ));
- - height = max( 1, ( hdr->dwHeight >> i ));
- + width = Q_max( 1, ( hdr->dwWidth >> i ));
- + height = Q_max( 1, ( hdr->dwHeight >> i ));
- buffsize += Image_DXTGetLinearSize( image.type, width, height, image.depth );
- }
- @@ -247,7 +248,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, size_t filesize )
- return false;
- }
- - Q_memcpy( &header, buffer, sizeof( dds_t ));
- + memcpy( &header, buffer, sizeof( dds_t ));
- if( header.dwIdent != DDSHEADER )
- return false; // it's not a dds file, just skip it
- @@ -295,27 +296,37 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, size_t filesize )
- switch( image.encode )
- {
- case DXT_ENCODE_COLOR_YCoCg:
- - image.flags |= IMAGE_HAS_COLOR;
- + SetBits( image.flags, IMAGE_HAS_COLOR );
- break;
- case DXT_ENCODE_NORMAL_AG_ORTHO:
- case DXT_ENCODE_NORMAL_AG_STEREO:
- case DXT_ENCODE_NORMAL_AG_PARABOLOID:
- case DXT_ENCODE_NORMAL_AG_QUARTIC:
- case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
- - image.flags |= IMAGE_HAS_COLOR;
- + SetBits( image.flags, IMAGE_HAS_COLOR );
- break;
- default: // check for real alpha-pixels
- if( image.type == PF_DXT3 && Image_CheckDXT3Alpha( &header, fin ))
- - image.flags |= IMAGE_HAS_ALPHA;
- + SetBits( image.flags, IMAGE_HAS_ALPHA );
- else if( image.type == PF_DXT5 && Image_CheckDXT5Alpha( &header, fin ))
- - image.flags |= IMAGE_HAS_ALPHA;
- - image.flags |= IMAGE_HAS_COLOR;
- + SetBits( image.flags, IMAGE_HAS_ALPHA );
- + if( !FBitSet( header.dsPixelFormat.dwFlags, DDS_LUMINANCE ))
- + SetBits( image.flags, IMAGE_HAS_COLOR ); // FIXME: analyze colors
- break;
- }
- + if( header.dwReserved1[1] != 0 )
- + {
- + // store texture reflectivity
- + image.fogParams[0] = ((header.dwReserved1[1] & 0x000000FF) >> 0 );
- + image.fogParams[1] = ((header.dwReserved1[1] & 0x0000FF00) >> 8 );
- + image.fogParams[2] = ((header.dwReserved1[1] & 0x00FF0000) >> 16);
- + image.fogParams[3] = ((header.dwReserved1[1] & 0xFF000000) >> 24);
- + }
- +
- // dds files will be uncompressed on a render. requires minimal of info for set this
- image.rgba = Mem_Alloc( host.imagepool, image.size );
- - Q_memcpy( image.rgba, fin, image.size );
- + memcpy( image.rgba, fin, image.size );
- image.flags |= IMAGE_DDS_FORMAT;
- return true;
- diff --git b/engine/common/imagelib/img_main.c a/engine/common/imagelib/img_main.c
- index 8ed68f0..0b86257 100644
- --- b/engine/common/imagelib/img_main.c
- +++ a/engine/common/imagelib/img_main.c
- @@ -102,12 +102,12 @@ void Image_Reset( void )
- image.source_width = image.source_height = 0;
- image.source_type = image.num_mips = 0;
- image.num_sides = image.flags = 0;
- + image.encode = DXT_ENCODE_DEFAULT;
- image.type = PF_UNKNOWN;
- image.fogParams[0] = 0;
- image.fogParams[1] = 0;
- image.fogParams[2] = 0;
- image.fogParams[3] = 0;
- - image.encode = 0;
- // pointers will be saved with prevoius picture struct
- // don't care about it
- @@ -203,7 +203,7 @@ qboolean FS_AddSideToPack( const char *name, int adjust_flags )
- if( resampled ) image.rgba = Image_Copy( image.size );
- image.cubemap = Mem_Realloc( host.imagepool, image.cubemap, image.ptr + image.size );
- - Q_memcpy( image.cubemap + image.ptr, image.rgba, image.size ); // add new side
- + memcpy( image.cubemap + image.ptr, image.rgba, image.size ); // add new side
- Mem_Free( image.rgba ); // release source buffer
- image.ptr += image.size; // move to next
- @@ -494,13 +494,13 @@ rgbdata_t *FS_CopyImage( rgbdata_t *in )
- if( palSize )
- {
- out->palette = Mem_Alloc( host.imagepool, palSize );
- - Q_memcpy( out->palette, in->palette, palSize );
- + memcpy( out->palette, in->palette, palSize );
- }
- if( in->size )
- {
- out->buffer = Mem_Alloc( host.imagepool, in->size );
- - Q_memcpy( out->buffer, in->buffer, in->size );
- + memcpy( out->buffer, in->buffer, in->size );
- }
- return out;
- diff --git b/engine/common/imagelib/img_quant.c a/engine/common/imagelib/img_quant.c
- index 4ea8250..2ad8f7d 100644
- --- b/engine/common/imagelib/img_quant.c
- +++ a/engine/common/imagelib/img_quant.c
- @@ -375,31 +375,25 @@ void learn( void )
- if( rad <= 1 ) rad = 0;
- for( i = 0; i < rad; i++ )
- - {
- - radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
- - }
- + radpower[i] = alpha * ((( rad * rad - i * i ) * radbias ) / ( rad * rad ));
- +
- + if( delta <= 0 ) return;
- if(( lengthcount % prime1 ) != 0 )
- {
- - step = image.bpp * prime1;
- + step = prime1 * image.bpp;
- + }
- + else if(( lengthcount % prime2 ) != 0 )
- + {
- + step = prime2 * image.bpp;
- + }
- + else if(( lengthcount % prime3 ) != 0 )
- + {
- + step = prime3 * image.bpp;
- }
- else
- {
- - if(( lengthcount % prime2 ) != 0 )
- - {
- - step = image.bpp * prime2;
- - }
- - else
- - {
- - if(( lengthcount % prime3 ) != 0 )
- - {
- - step = image.bpp * prime3;
- - }
- - else
- - {
- - step = image.bpp * prime4;
- - }
- - }
- + step = prime4 * image.bpp;
- }
- i = 0;
- @@ -427,7 +421,7 @@ void learn( void )
- if( rad <= 1 ) rad = 0;
- for( j = 0; j < rad; j++ )
- - radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
- + radpower[j] = alpha * ((( rad * rad - j * j ) * radbias ) / ( rad * rad ));
- }
- }
- }
- @@ -470,7 +464,7 @@ rgbdata_t *Image_Quantize( rgbdata_t *pic )
- }
- pic->buffer = Mem_Realloc( host.imagepool, pic->buffer, image.size );
- - Q_memcpy( pic->buffer, image.tempbuffer, image.size );
- + memcpy( pic->buffer, image.tempbuffer, image.size );
- pic->type = PF_INDEXED_24;
- pic->size = image.size;
- diff --git b/engine/common/imagelib/img_tga.c a/engine/common/imagelib/img_tga.c
- index 8c771b1..9fa019d 100644
- --- b/engine/common/imagelib/img_tga.c
- +++ a/engine/common/imagelib/img_tga.c
- @@ -14,6 +14,7 @@ GNU General Public License for more details.
- */
- #include "imagelib.h"
- +#include "mathlib.h"
- /*
- =============
- @@ -26,6 +27,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
- byte *buf_p, *pixbuf, *targa_rgba;
- byte palette[256][4], red = 0, green = 0, blue = 0, alpha = 0;
- int readpixelcount, pixelcount;
- + int reflectivity[3] = { 0, 0, 0 };
- qboolean compressed;
- tga_t targa_header;
- @@ -193,6 +195,10 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
- if( red != green || green != blue )
- image.flags |= IMAGE_HAS_COLOR;
- + reflectivity[0] += red;
- + reflectivity[1] += green;
- + reflectivity[2] += blue;
- +
- *pixbuf++ = red;
- *pixbuf++ = green;
- *pixbuf++ = blue;
- @@ -206,6 +212,10 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
- }
- }
- }
- +
- + VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
- + image.depth = 1;
- +
- return true;
- }
- @@ -229,7 +239,6 @@ qboolean Image_SaveTGA( const char *name, rgbdata_t *pix )
- else outsize = pix->width * pix->height * 3 + 18 + Q_strlen( comment );
- buffer = (byte *)Mem_Alloc( host.imagepool, outsize );
- - Q_memset( buffer, 0, 18 );
- // prepare header
- buffer[0] = Q_strlen( comment ); // tga comment length
- diff --git b/engine/common/imagelib/img_utils.c a/engine/common/imagelib/img_utils.c
- index 651d270..23c5c0b 100644
- --- b/engine/common/imagelib/img_utils.c
- +++ a/engine/common/imagelib/img_utils.c
- @@ -177,6 +177,11 @@ void Image_Init( void )
- image.loadformats = load_game;
- image.saveformats = save_game;
- break;
- + case HOST_DEDICATED:
- + image.cmd_flags = 0;
- + image.loadformats = load_game;
- + image.saveformats = save_null;
- + break;
- default: // all other instances not using imagelib or will be reinstalling later
- image.loadformats = load_null;
- image.saveformats = save_null;
- @@ -197,7 +202,7 @@ byte *Image_Copy( size_t size )
- byte *out;
- out = Mem_Alloc( host.imagepool, size );
- - Q_memcpy( out, image.tempbuffer, size );
- + memcpy( out, image.tempbuffer, size );
- return out;
- }
- @@ -279,9 +284,9 @@ int Image_ComparePalette( const byte *pal )
- {
- if( pal == NULL )
- return PAL_INVALID;
- - else if( !Q_memcmp( palette_q1, pal, 768 ))
- + else if( !memcmp( palette_q1, pal, 768 ))
- return PAL_QUAKE1;
- - else if( !Q_memcmp( palette_hl, pal, 768 ))
- + else if( !memcmp( palette_hl, pal, 768 ))
- return PAL_HALFLIFE;
- return PAL_CUSTOM;
- }
- @@ -442,7 +447,7 @@ void Image_CopyPalette32bit( void )
- {
- if( image.palette ) return; // already created ?
- image.palette = Mem_Alloc( host.imagepool, 1024 );
- - Q_memcpy( image.palette, image.d_currentpal, 1024 );
- + memcpy( image.palette, image.d_currentpal, 1024 );
- }
- void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
- @@ -462,6 +467,8 @@ void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
- maxcol = max( max( r, g ), b ) / 255.0f;
- mincol = min( min( r, g ), b ) / 255.0f;
- +
- + if( maxcol == 0 ) continue;
- val = maxcol;
- sat = (maxcol - mincol) / maxcol;
- @@ -528,7 +535,7 @@ void Image_CopyParms( rgbdata_t *src )
- image.size = src->size;
- image.palette = src->palette; // may be NULL
- - Q_memcpy( image.fogParams, src->fogParams, sizeof( image.fogParams ));
- + memcpy( image.fogParams, src->fogParams, sizeof( image.fogParams ));
- }
- /*
- @@ -567,7 +574,7 @@ qboolean Image_Copy8bitRGBA( const byte *in, byte *out, int pixels )
- // check for color
- for( i = 0; i < 256; i++ )
- {
- - col = (rgba_t *)image.d_currentpal[i];
- + col = (rgba_t *)&image.d_currentpal[i];
- if( col[0] != col[1] || col[1] != col[2] )
- {
- image.flags |= IMAGE_HAS_COLOR;
- @@ -713,7 +720,7 @@ void Image_Resample32Lerp( const void *indata, int inwidth, int inheight, void *
- if( yi != oldy )
- {
- inrow = (byte *)indata + inwidth4 * yi;
- - if (yi == oldy+1) Q_memcpy( resamplerow1, resamplerow2, outwidth4 );
- + if (yi == oldy+1) memcpy( resamplerow1, resamplerow2, outwidth4 );
- else Image_Resample32LerpLine( inrow, resamplerow1, inwidth, outwidth );
- Image_Resample32LerpLine( inrow + inwidth4, resamplerow2, inwidth, outwidth );
- oldy = yi;
- @@ -779,12 +786,12 @@ void Image_Resample32Lerp( const void *indata, int inwidth, int inheight, void *
- if( yi != oldy )
- {
- inrow = (byte *)indata + inwidth4*yi;
- - if( yi == oldy + 1 ) Q_memcpy( resamplerow1, resamplerow2, outwidth4 );
- + if( yi == oldy + 1 ) memcpy( resamplerow1, resamplerow2, outwidth4 );
- else Image_Resample32LerpLine( inrow, resamplerow1, inwidth, outwidth);
- oldy = yi;
- }
- - Q_memcpy( out, resamplerow1, outwidth4 );
- + memcpy( out, resamplerow1, outwidth4 );
- }
- }
- @@ -860,7 +867,7 @@ void Image_Resample24Lerp( const void *indata, int inwidth, int inheight, void *
- if( yi != oldy )
- {
- inrow = (byte *)indata + inwidth3 * yi;
- - if( yi == oldy + 1) Q_memcpy( resamplerow1, resamplerow2, outwidth3 );
- + if( yi == oldy + 1) memcpy( resamplerow1, resamplerow2, outwidth3 );
- else Image_Resample24LerpLine( inrow, resamplerow1, inwidth, outwidth );
- Image_Resample24LerpLine( inrow + inwidth3, resamplerow2, inwidth, outwidth );
- oldy = yi;
- @@ -919,12 +926,12 @@ void Image_Resample24Lerp( const void *indata, int inwidth, int inheight, void *
- if( yi != oldy )
- {
- inrow = (byte *)indata + inwidth3*yi;
- - if( yi == oldy + 1) Q_memcpy( resamplerow1, resamplerow2, outwidth3 );
- + if( yi == oldy + 1) memcpy( resamplerow1, resamplerow2, outwidth3 );
- else Image_Resample24LerpLine( inrow, resamplerow1, inwidth, outwidth );
- oldy = yi;
- }
- - Q_memcpy( out, resamplerow1, outwidth3 );
- + memcpy( out, resamplerow1, outwidth3 );
- }
- }
- @@ -1103,8 +1110,8 @@ byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int ou
- return (byte *)indata;
- }
- - if( samples == 1 ) Q_memset( out, 0xFF, newsize ); // last palette color
- - else Q_memset( out, 0x00808080, newsize ); // gray (alpha leaved 0x00)
- + if( samples == 1 ) memset( out, 0xFF, newsize ); // last palette color
- + else memset( out, 0x00808080, newsize ); // gray (alpha leaved 0x00)
- for( y = 0; y < outheight; y++ )
- {
- @@ -1114,7 +1121,7 @@ byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int ou
- {
- if( x < inwidth )
- *out++ = *in++;
- - else *out++;
- + else out++;
- }
- }
- }
- @@ -1260,7 +1267,7 @@ qboolean Image_AddIndexedImageToPack( const byte *in, int width, int height )
- // reallocate image buffer
- image.rgba = Mem_Alloc( host.imagepool, image.size );
- - if( !expand_to_rgba ) Q_memcpy( image.rgba, in, image.size );
- + if( !expand_to_rgba ) memcpy( image.rgba, in, image.size );
- else if( !Image_Copy8bitRGBA( in, image.rgba, mipsize ))
- return false; // probably pallette not installed
- @@ -1331,7 +1338,7 @@ qboolean Image_Decompress( const byte *data )
- break;
- case PF_RGBA_32:
- // fast default case
- - Q_memcpy( fout, fin, size );
- + memcpy( fout, fin, size );
- break;
- default: return false;
- }
- @@ -1357,7 +1364,7 @@ rgbdata_t *Image_DecompressInternal( rgbdata_t *pic )
- pic->type = PF_RGBA_32;
- pic->buffer = Mem_Realloc( host.imagepool, pic->buffer, image.size );
- - Q_memcpy( pic->buffer, image.tempbuffer, image.size );
- + memcpy( pic->buffer, image.tempbuffer, image.size );
- if( pic->palette ) Mem_Free( pic->palette );
- pic->flags = image.flags;
- pic->palette = NULL;
- @@ -1538,7 +1545,7 @@ qboolean Image_ApplyFilter( rgbdata_t *pic, int filter, float factor, float bias
- }
- // copy result back
- - Q_memcpy( fin, fout, size );
- + memcpy( fin, fout, size );
- return true;
- }
- @@ -1567,7 +1574,7 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
- if( flags & IMAGE_MAKE_LUMA )
- {
- out = Image_CreateLumaInternal( pic->buffer, pic->width, pic->height, pic->type, pic->flags );
- - if( pic->buffer != out ) Q_memcpy( pic->buffer, image.tempbuffer, pic->size );
- + if( pic->buffer != out ) memcpy( pic->buffer, image.tempbuffer, pic->size );
- pic->flags &= ~IMAGE_HAS_LUMA;
- }
- @@ -1585,7 +1592,7 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
- if( filter ) Image_ApplyFilter( pic, filter->filter, filter->factor, filter->bias, filter->flags, filter->blendFunc );
- out = Image_FlipInternal( pic->buffer, &pic->width, &pic->height, pic->type, flags );
- - if( pic->buffer != out ) Q_memcpy( pic->buffer, image.tempbuffer, pic->size );
- + if( pic->buffer != out ) memcpy( pic->buffer, image.tempbuffer, pic->size );
- if(( flags & IMAGE_RESAMPLE && width > 0 && height > 0 ) || ( flags & IMAGE_ROUND ) || ( flags & IMAGE_ROUNDFILLER ))
- {
- diff --git b/engine/common/imagelib/img_wad.c a/engine/common/imagelib/img_wad.c
- index 3c0f490..4f90112 100644
- --- b/engine/common/imagelib/img_wad.c
- +++ a/engine/common/imagelib/img_wad.c
- @@ -58,6 +58,7 @@ qboolean Image_LoadPAL( const char *name, const byte *buffer, size_t filesize )
- image.rgba = NULL; // only palette, not real image
- image.size = 1024; // expanded palette
- image.width = image.height = 0;
- + image.depth = 1;
- return true;
- }
- @@ -80,7 +81,7 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
- if( filesize < sizeof( font ))
- return false;
- - Q_memcpy( &font, buffer, sizeof( font ));
- + memcpy( &font, buffer, sizeof( font ));
- // last sixty four bytes - what the hell ????
- size = sizeof( qfont_t ) - 4 + ( font.height * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
- @@ -119,6 +120,7 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
- }
- image.type = PF_INDEXED_32; // 32-bit palette
- + image.depth = 1;
- return Image_AddIndexedImageToPack( fin, image.width, image.height );
- }
- @@ -170,6 +172,7 @@ qboolean Image_LoadMDL( const char *name, const byte *buffer, size_t filesize )
- }
- image.type = PF_INDEXED_32; // 32-bit palete
- + image.depth = 1;
- return Image_AddIndexedImageToPack( fin, image.width, image.height );
- }
- @@ -214,6 +217,7 @@ qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize )
- // sorry, can't validate palette rendermode
- if( !Image_LumpValidSize( name )) return false;
- image.type = PF_INDEXED_32; // 32-bit palete
- + image.depth = 1;
- // detect alpha-channel by palette type
- switch( image.d_rendermode )
- @@ -253,24 +257,12 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize )
- if( Q_stristr( name, "palette.lmp" ))
- return Image_LoadPAL( name, buffer, filesize );
- - // greatest hack from id software
- - if( image.hint != IL_HINT_HL && Q_stristr( name, "conchars" ))
- - {
- - image.width = image.height = 128;
- - image.flags |= IMAGE_HAS_ALPHA;
- - rendermode = LUMP_QFONT;
- - filesize += sizeof(lmp);
- - fin = (byte *)buffer;
- - }
- - else
- - {
- - fin = (byte *)buffer;
- - Q_memcpy( &lmp, fin, sizeof( lmp ));
- - image.width = lmp.width;
- - image.height = lmp.height;
- - rendermode = LUMP_NORMAL;
- - fin += sizeof(lmp);
- - }
- + fin = (byte *)buffer;
- + memcpy( &lmp, fin, sizeof( lmp ));
- + image.width = lmp.width;
- + image.height = lmp.height;
- + rendermode = LUMP_NORMAL;
- + fin += sizeof( lmp );
- pixels = image.width * image.height;
- @@ -305,6 +297,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize )
- if( fin[0] == 255 ) image.flags |= IMAGE_HAS_ALPHA;
- Image_GetPaletteLMP( pal, rendermode );
- image.type = PF_INDEXED_32; // 32-bit palete
- + image.depth = 1;
- return Image_AddIndexedImageToPack( fin, image.width, image.height );
- }
- @@ -321,6 +314,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
- byte *fin, *pal;
- int ofs[4], rendermode;
- int i, pixels, numcolors;
- + int reflectivity[3] = { 0, 0, 0 };
- if( filesize < sizeof( mip ))
- {
- @@ -328,14 +322,14 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
- return false;
- }
- - Q_memcpy( &mip, buffer, sizeof( mip ));
- + memcpy( &mip, buffer, sizeof( mip ));
- image.width = mip.width;
- image.height = mip.height;
- if( !Image_ValidSize( name ))
- return false;
- - Q_memcpy( ofs, mip.offsets, sizeof( ofs ));
- + memcpy( ofs, mip.offsets, sizeof( ofs ));
- pixels = image.width * image.height;
- if( image.hint != IL_HINT_Q1 && filesize >= (int)sizeof(mip) + ((pixels * 85)>>6) + sizeof(short) + 768)
- @@ -462,7 +456,20 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
- // calc the decal reflectivity
- image.fogParams[3] = VectorAvg( image.fogParams );
- }
- + else if( pal != NULL )// calc texture reflectivity
- + {
- + for( i = 0; i < 256; i++ )
- + {
- + reflectivity[0] += pal[i*3+0];
- + reflectivity[1] += pal[i*3+1];
- + reflectivity[2] += pal[i*3+2];
- + }
- +
- + VectorDivide( reflectivity, 256, image.fogParams );
- + }
- image.type = PF_INDEXED_32; // 32-bit palete
- + image.depth = 1;
- +
- return Image_AddIndexedImageToPack( fin, image.width, image.height );
- }
- \ No newline at end of file
- diff --git b/engine/common/input.c a/engine/common/input.c
- index 046f082..8a0f684 100644
- --- b/engine/common/input.c
- +++ a/engine/common/input.c
- @@ -105,8 +105,8 @@ static int Host_MapKey( int key )
- case 0x0D: return K_KP_ENTER;
- case 0x2F: return K_KP_SLASH;
- case 0xAF: return K_KP_PLUS;
- + default: return result;
- }
- - return result;
- }
- }
- @@ -290,7 +290,7 @@ void IN_DeactivateMouse( void )
- /*
- ================
- -IN_Mouse
- +IN_MouseMove
- ================
- */
- void IN_MouseMove( void )
- @@ -331,12 +331,12 @@ void IN_MouseEvent( int mstate )
- // perform button actions
- for( i = 0; i < in_mouse_buttons; i++ )
- {
- - if(( mstate & ( 1<<i )) && !( in_mouse_oldbuttonstate & ( 1<<i )))
- + if( FBitSet( mstate, BIT( i )) && !FBitSet( in_mouse_oldbuttonstate, BIT( i )))
- {
- Key_Event( K_MOUSE1 + i, true );
- }
- - if(!( mstate & ( 1<<i )) && ( in_mouse_oldbuttonstate & ( 1<<i )))
- + if( !FBitSet( mstate, BIT( i )) && FBitSet( in_mouse_oldbuttonstate, BIT( i )))
- {
- Key_Event( K_MOUSE1 + i, false );
- }
- @@ -383,13 +383,13 @@ void Host_InputFrame( void )
- Cbuf_Execute ();
- - if( host.state == HOST_RESTART )
- - host.state = HOST_FRAME; // restart is finished
- -
- if( host.type == HOST_DEDICATED )
- {
- - // let the dedicated server some sleep
- - Sys_Sleep( 1 );
- + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + // let the dedicated server some sleep
- + Sys_Sleep( 1 );
- + }
- }
- else
- {
- @@ -435,7 +435,7 @@ IN_WndProc
- main window procedure
- ====================
- */
- -long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
- +LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam )
- {
- int i, temp = 0;
- qboolean fActivate;
- @@ -455,7 +455,8 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
- IN_ActivateCursor();
- break;
- case WM_MOUSEWHEEL:
- - if( !in_mouseactive ) break;
- + if( !in_mouseactive )
- + break;
- if(( short )HIWORD( wParam ) > 0 )
- {
- Key_Event( K_MWHEELUP, true );
- @@ -478,17 +479,12 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
- case WM_ACTIVATE:
- if( host.state == HOST_SHUTDOWN )
- break; // no need to activate
- - if( host.state != HOST_RESTART )
- - {
- - if( HIWORD( wParam ))
- - host.state = HOST_SLEEP;
- - else if( LOWORD( wParam ) == WA_INACTIVE )
- - host.state = HOST_NOFOCUS;
- - else host.state = HOST_FRAME;
- - fActivate = (host.state == HOST_FRAME) ? true : false;
- - }
- - else fActivate = true; // video sucessfully restarted
- -
- + if( HIWORD( wParam ))
- + host.state = HOST_SLEEP;
- + else if( LOWORD( wParam ) == WA_INACTIVE )
- + host.state = HOST_NOFOCUS;
- + else host.state = HOST_FRAME;
- + fActivate = (host.state == HOST_FRAME) ? true : false;
- wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER;
- S_Activate( fActivate, host.hWnd );
- @@ -500,7 +496,7 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
- SetForegroundWindow( hWnd );
- ShowWindow( hWnd, SW_RESTORE );
- }
- - else if( Cvar_VariableInteger( "fullscreen" ) && host.state != HOST_RESTART )
- + else if( Cvar_VariableInteger( "fullscreen" ))
- {
- ShowWindow( hWnd, SW_MINIMIZE );
- }
- diff --git b/engine/common/input.h a/engine/common/input.h
- index 284cfa2..9bff4fc 100644
- --- b/engine/common/input.h
- +++ a/engine/common/input.h
- @@ -45,7 +45,7 @@ void IN_MouseEvent( int mstate );
- void IN_ActivateMouse( qboolean force );
- void IN_DeactivateMouse( void );
- void IN_ToggleClientMouse( int newstate, int oldstate );
- -long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam );
- +LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam );
- void IN_SetCursor( HICON hCursor );
- #endif//INPUT_H
- \ No newline at end of file
- diff --git b/engine/common/keys.c a/engine/common/keys.c
- index 4674409..aa9e2ab 100644
- --- b/engine/common/keys.c
- +++ a/engine/common/keys.c
- @@ -46,18 +46,18 @@ keyname_t keynames[] =
- {"RIGHTARROW", K_RIGHTARROW, "+right" },
- {"ALT", K_ALT, "+strafe" },
- {"CTRL", K_CTRL, "+attack" },
- -{"SHIFT", K_SHIFT, "+speed" }, // replace with +attack2 ?
- +{"SHIFT", K_SHIFT, "+speed" },
- {"CAPSLOCK", K_CAPSLOCK, "" },
- {"F1", K_F1, "cmd help" },
- {"F2", K_F2, "menu_savegame" },
- {"F3", K_F3, "menu_loadgame" },
- -{"F4", K_F4, "menu_keys" },
- -{"F5", K_F5, "menu_startserver" },
- +{"F4", K_F4, "menu_controls" },
- +{"F5", K_F5, "menu_creategame" },
- {"F6", K_F6, "savequick" },
- {"F7", K_F7, "loadquick" },
- {"F8", K_F8, "stop" },
- {"F9", K_F9, "" },
- -{"F10", K_F10, "menu_quit" },
- +{"F10", K_F10, "menu_main" },
- {"F11", K_F11, "" },
- {"F12", K_F12, "screenshot" },
- {"INS", K_INS, "" },
- @@ -106,7 +106,7 @@ Key_IsDown
- */
- qboolean Key_IsDown( int keynum )
- {
- - if ( keynum == -1 )
- + if( keynum == -1 )
- return false;
- return keys[keynum].down;
- }
- @@ -179,6 +179,7 @@ int Key_StringToKeynum( const char *str )
- if( !Q_stricmp( str, kn->name ))
- return kn->keynum;
- }
- +
- return -1;
- }
- @@ -275,6 +276,7 @@ int Key_GetKey( const char *binding )
- if( keys[i].binding && !Q_stricmp( binding, keys[i].binding ))
- return i;
- }
- +
- return -1;
- }
- @@ -294,11 +296,13 @@ void Key_Unbind_f( void )
- }
- b = Key_StringToKeynum( Cmd_Argv( 1 ));
- +
- if( b == -1 )
- {
- Msg( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ));
- return;
- }
- +
- Key_SetBinding( b, "" );
- }
- @@ -325,8 +329,8 @@ Key_Reset_f
- */
- void Key_Reset_f( void )
- {
- - int i;
- keyname_t *kn;
- + int i;
- // clear all keys first
- for( i = 0; i < 256; i++ )
- @@ -347,8 +351,8 @@ Key_Bind_f
- */
- void Key_Bind_f( void )
- {
- - int i, c, b;
- char cmd[1024];
- + int i, c, b;
- c = Cmd_Argc();
- @@ -398,12 +402,13 @@ void Key_WriteBindings( file_t *f )
- int i;
- if( !f ) return;
- +
- FS_Printf( f, "unbindall\n" );
- for( i = 0; i < 256; i++ )
- {
- if( keys[i].binding && keys[i].binding[0] )
- - FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
- + FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
- }
- }
- @@ -551,11 +556,15 @@ void Key_Event( int key, qboolean down )
- // escape is always handled special
- if( key == K_ESCAPE && down )
- {
- - kb = keys[key].binding;
- -
- switch( cls.key_dest )
- {
- case key_game:
- + if( gl_showtextures->integer )
- + {
- + // close texture atlas
- + Cvar_SetFloat( "r_showtextures", 0.0f );
- + return;
- + }
- if( host.mouse_visible && cls.state != ca_cinematic )
- {
- clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding );
- @@ -717,9 +726,7 @@ void Key_ClearStates( void )
- }
- if( clgame.hInstance )
- - {
- clgame.dllFuncs.IN_ClearStates();
- - }
- }
- /*
- diff --git b/engine/common/library.c a/engine/common/library.c
- index f2688e3..efd3cfc 100644
- --- b/engine/common/library.c
- +++ a/engine/common/library.c
- @@ -53,10 +53,10 @@ typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
- static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
- {
- - int i, size;
- - byte *dest;
- - byte *codeBase = module->codeBase;
- - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
- + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
- + byte *codeBase = module->codeBase;
- + int i, size;
- + byte *dest;
- for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
- {
- @@ -85,9 +85,9 @@ static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMO
- static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
- {
- - int i, size;
- - byte *codeBase = module->codeBase;
- - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
- + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
- + byte *codeBase = module->codeBase;
- + int i, size;
- for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
- {
- @@ -96,13 +96,13 @@ static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
- size = old_headers->OptionalHeader.SectionAlignment;
- if( size > 0 )
- {
- - VirtualFree( codeBase + section->VirtualAddress, size, MEM_DECOMMIT );
- + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), size, MEM_DECOMMIT );
- section->Misc.PhysicalAddress = 0;
- }
- continue;
- }
- - VirtualFree( codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_DECOMMIT );
- + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), section->SizeOfRawData, MEM_DECOMMIT );
- section->Misc.PhysicalAddress = 0;
- }
- }
- @@ -147,16 +147,16 @@ static void FinalizeSections( MEMORYMODULE *module )
- {
- // change memory access flags
- if( !VirtualProtect((LPVOID)section->Misc.PhysicalAddress, size, protect, &oldProtect ))
- - Sys_Error( "Com_FinalizeSections: error protecting memory page\n" );
- + Sys_Error( "FinalizeSections: error protecting memory page\n" );
- }
- }
- }
- static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
- {
- - DWORD i;
- - byte *codeBase = module->codeBase;
- - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
- + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
- + byte *codeBase = module->codeBase;
- + DWORD i;
- if( directory->Size > 0 )
- {
- @@ -200,12 +200,12 @@ static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
- static FARPROC MemoryGetProcAddress( void *module, const char *name )
- {
- - int idx = -1;
- - DWORD i, *nameRef;
- - WORD *ordinal;
- - PIMAGE_EXPORT_DIRECTORY exports;
- - byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
- - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
- + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
- + byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
- + PIMAGE_EXPORT_DIRECTORY exports;
- + int idx = -1;
- + DWORD i, *nameRef;
- + WORD *ordinal;
- if( directory->Size == 0 )
- {
- @@ -253,9 +253,9 @@ static FARPROC MemoryGetProcAddress( void *module, const char *name )
- static int BuildImportTable( MEMORYMODULE *module )
- {
- - int result=1;
- - byte *codeBase = module->codeBase;
- - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
- + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
- + byte *codeBase = module->codeBase;
- + int result = 1;
- if( directory->Size > 0 )
- {
- diff --git b/engine/common/mathlib.c a/engine/common/mathlib.c
- index 9d31d24..0811f85 100644
- --- b/engine/common/mathlib.c
- +++ a/engine/common/mathlib.c
- @@ -430,17 +430,22 @@ AngleQuaternion
- ====================
- */
- -void AngleQuaternion( const vec3_t angles, vec4_t q )
- +void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio )
- {
- - float angle;
- float sr, sp, sy, cr, cp, cy;
- - angle = angles[2] * 0.5f;
- - SinCos( angle, &sy, &cy );
- - angle = angles[1] * 0.5f;
- - SinCos( angle, &sp, &cp );
- - angle = angles[0] * 0.5f;
- - SinCos( angle, &sr, &cr );
- + if( studio )
- + {
- + SinCos( angles[ROLL] * 0.5f, &sy, &cy );
- + SinCos( angles[YAW] * 0.5f, &sp, &cp );
- + SinCos( angles[PITCH] * 0.5f, &sr, &cr );
- + }
- + else
- + {
- + SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy );
- + SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp );
- + SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr );
- + }
- q[0] = sr * cp * cy - cr * sp * sy; // X
- q[1] = cr * sp * cy + sr * cp * sy; // Y
- @@ -450,6 +455,19 @@ void AngleQuaternion( const vec3_t angles, vec4_t q )
- /*
- ====================
- +QuaternionAngle
- +
- +====================
- +*/
- +void QuaternionAngle( const vec4_t q, vec3_t angles )
- +{
- + matrix3x4 mat;
- + Matrix3x4_FromOriginQuat( mat, q, vec3_origin );
- + Matrix3x4_AnglesFromMatrix( mat, angles );
- +}
- +
- +/*
- +====================
- QuaternionSlerp
- ====================
- diff --git b/engine/common/mathlib.h a/engine/common/mathlib.h
- index f44e3ff..c88c8e6 100644
- --- b/engine/common/mathlib.h
- +++ a/engine/common/mathlib.h
- @@ -55,10 +55,21 @@ GNU General Public License for more details.
- #define RAD_TO_STUDIO (32768.0 / M_PI)
- #define STUDIO_TO_RAD (M_PI / 32768.0)
- -#define nanmask (255<<23)
- +
- +#define INV127F ( 1.0f / 127.0f )
- +#define INV255F ( 1.0f / 255.0f )
- +#define MAKE_SIGNED( x ) ((( x ) * INV127F ) - 1.0f )
- +
- +#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
- +#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
- +#define Q_recip( a ) ((float)(1.0f / (float)(a)))
- +#define Q_floor( a ) ((float)(long)(a))
- +#define Q_ceil( a ) ((float)(long)((a) + 1))
- #define Q_rint(x) ((x) < 0 ? ((int)((x)-0.5f)) : ((int)((x)+0.5f)))
- -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
- +#define IS_NAN(x) (((*(int *)&x) & (255<<23)) == (255<<23))
- +
- +#define ALIGN( x, a ) ((( x ) + (( size_t )( a ) - 1 )) & ~(( size_t )( a ) - 1 ))
- #define VectorIsNAN(v) (IS_NAN(v[0]) || IS_NAN(v[1]) || IS_NAN(v[2]))
- #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
- @@ -123,7 +134,8 @@ qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t m
- qboolean BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t origin, float radius );
- float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
- -void AngleQuaternion( const vec3_t angles, vec4_t q );
- +void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio );
- +void QuaternionAngle( const vec4_t q, vec3_t angles );
- void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt );
- float RemapVal( float val, float A, float B, float C, float D );
- float ApproachVal( float target, float value, float speed );
- @@ -132,7 +144,7 @@ float ApproachVal( float target, float value, float speed );
- // matrixlib.c
- //
- #define Matrix3x4_LoadIdentity( mat ) Matrix3x4_Copy( mat, matrix3x4_identity )
- -#define Matrix3x4_Copy( out, in ) Q_memcpy( out, in, sizeof( matrix3x4 ))
- +#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
- void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] );
- void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] );
- @@ -145,9 +157,10 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal,
- void Matrix3x4_SetOrigin( matrix3x4 out, float x, float y, float z );
- void Matrix3x4_Invert_Simple( matrix3x4 out, const matrix3x4 in1 );
- void Matrix3x4_OriginFromMatrix( const matrix3x4 in, float *out );
- +void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
- #define Matrix4x4_LoadIdentity( mat ) Matrix4x4_Copy( mat, matrix4x4_identity )
- -#define Matrix4x4_Copy( out, in ) Q_memcpy( out, in, sizeof( matrix4x4 ))
- +#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
- void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] );
- void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] );
- diff --git b/engine/common/matrixlib.c a/engine/common/matrixlib.c
- index af992d2..fdeea66 100644
- --- b/engine/common/matrixlib.c
- +++ a/engine/common/matrixlib.c
- @@ -94,6 +94,26 @@ void Matrix3x4_OriginFromMatrix( const matrix3x4 in, float *out )
- out[2] = in[2][3];
- }
- +void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out )
- +{
- + float xyDist = sqrt( in[0][0] * in[0][0] + in[1][0] * in[1][0] );
- +
- + if( xyDist > 0.001f )
- + {
- + // enough here to get angles?
- + out[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
- + out[1] = RAD2DEG( atan2( in[1][0], in[0][0] ));
- + out[2] = RAD2DEG( atan2( in[2][1], in[2][2] ));
- + }
- + else
- + {
- + // forward is mostly Z, gimbal lock
- + out[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
- + out[1] = RAD2DEG( atan2( -in[0][1], in[1][1] ));
- + out[2] = 0.0f;
- + }
- +}
- +
- void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin )
- {
- out[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2];
- diff --git b/engine/common/mod_local.h a/engine/common/mod_local.h
- index 896c944..0f61ce5 100644
- --- b/engine/common/mod_local.h
- +++ a/engine/common/mod_local.h
- @@ -42,6 +42,14 @@ GNU General Public License for more details.
- #define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces))
- #define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data))
- +#define CHECKVISBIT( vis, b ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] & (1 << ((b) & 7))) : (byte)false )
- +#define SETVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] |= (1 << ((b) & 7))) : (byte)false )
- +#define CLEARVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] &= ~(1 << ((b) & 7))) : (byte)false )
- +
- +#define REFPVS_RADIUS 2.0f // radius for rendering
- +#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
- +#define FATPHS_RADIUS 16.0f
- +
- // model flags (stored in model_t->flags)
- #define MODEL_CONVEYOR BIT( 0 )
- #define MODEL_HAS_ORIGIN BIT( 1 )
- @@ -72,19 +80,30 @@ typedef struct
- vec3_t hull_sizes[MAX_MAP_HULLS]; // actual hull sizes
- msurface_t **draw_surfaces; // used for sorting translucent surfaces
- int max_surfaces; // max surfaces per submodel (for all models)
- - size_t visdatasize; // actual size of the visdata
- - size_t litdatasize; // actual size of the lightdata
- - size_t vecdatasize; // actual size of the deluxdata
- - size_t entdatasize; // actual size of the entity string
- - size_t texdatasize; // actual size of the textures lump
- +
- qboolean loading; // true if worldmodel is loading
- qboolean sky_sphere; // true when quake sky-sphere is used
- qboolean has_mirrors; // one or more brush models contain reflective textures
- + qboolean custom_skybox; // if sky_sphere is active and custom skybox set
- + qboolean water_alpha; // allow translucency water
- int lm_sample_size; // defaulting to 16 (BSP31 uses 8)
- int block_size; // lightmap blocksize
- color24 *deluxedata; // deluxemap data pointer
- char message[2048]; // just for debug
- + // visibility info
- + byte *visdata; // uncompressed visdata
- + size_t visbytes; // cluster size
- + size_t fatbytes; // fatpvs size
- + int visclusters; // num visclusters
- +
- + // world stats
- + size_t visdatasize; // actual size of the visdata
- + size_t litdatasize; // actual size of the lightdata
- + size_t vecdatasize; // actual size of the deluxdata
- + size_t entdatasize; // actual size of the entity string
- + size_t texdatasize; // actual size of the textures lump
- +
- vec3_t mins; // real accuracy world bounds
- vec3_t maxs;
- vec3_t size;
- @@ -117,20 +136,21 @@ model_t *Mod_FindName( const char *name, qboolean create );
- model_t *Mod_LoadModel( model_t *mod, qboolean world );
- model_t *Mod_ForName( const char *name, qboolean world );
- qboolean Mod_RegisterModel( const char *name, int index );
- -int Mod_PointLeafnum( const vec3_t p );
- -byte *Mod_LeafPVS( mleaf_t *leaf, model_t *model );
- -byte *Mod_LeafPHS( mleaf_t *leaf, model_t *model );
- mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
- +qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, short *lastleaf );
- void Mod_TesselatePolygon( msurface_t *surf, model_t *mod, float tessSize );
- int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *lastleaf );
- +int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
- qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
- +int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
- +int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
- +int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
- void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info );
- void Mod_AmbientLevels( const vec3_t p, byte *pvolumes );
- -byte *Mod_CompressVis( const byte *in, size_t *size );
- -byte *Mod_DecompressVis( const byte *in );
- +int Mod_SampleSizeForFace( msurface_t *surf );
- +byte *Mod_GetPVSForPoint( const vec3_t p );
- modtype_t Mod_GetType( int handle );
- model_t *Mod_Handle( int handle );
- -struct wadlist_s *Mod_WadList( void );
- //
- // mod_studio.c
- diff --git b/engine/common/mod_studio.c a/engine/common/mod_studio.c
- index a64d856..264a55b 100644
- --- b/engine/common/mod_studio.c
- +++ a/engine/common/mod_studio.c
- @@ -208,8 +208,6 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
- mstudiobbox_t *phitbox;
- int i, j;
- - ASSERT( numhitboxes );
- -
- *numhitboxes = 0; // assume error
- if( mod_studiocache->integer )
- @@ -230,8 +228,6 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
- mod_studiohdr = Mod_Extradata( model );
- if( !mod_studiohdr ) return NULL; // probably not a studiomodel
- - ASSERT( pBlendAPI != NULL );
- -
- VectorCopy( angles, angles2 );
- if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
- @@ -406,13 +402,13 @@ static void Mod_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbon
- if( !VectorCompare( angle1, angle2 ))
- {
- - AngleQuaternion( angle1, q1 );
- - AngleQuaternion( angle2, q2 );
- + AngleQuaternion( angle1, q1, true );
- + AngleQuaternion( angle2, q2, true );
- QuaternionSlerp( q1, q2, s, q );
- }
- else
- {
- - AngleQuaternion( angle1, q );
- + AngleQuaternion( angle1, q, true );
- }
- }
- @@ -745,8 +741,6 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *origin,
- if( mod_studiohdr->numattachments <= 0 )
- return;
- - ASSERT( pBlendAPI != NULL );
- -
- if( mod_studiohdr->numattachments > MAXSTUDIOATTACHMENTS )
- {
- mod_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it
- @@ -794,8 +788,6 @@ void Mod_GetBonePosition( const edict_t *e, int iBone, float *origin, float *ang
- mod_studiohdr = (studiohdr_t *)Mod_Extradata( mod );
- if( !mod_studiohdr ) return;
- - ASSERT( pBlendAPI != NULL );
- -
- pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, e->v.angles, e->v.origin,
- e->v.controller, e->v.blending, iBone, e );
- @@ -987,7 +979,7 @@ void Mod_InitStudioAPI( void )
- pBlendIface = (STUDIOAPI)Com_GetProcAddress( svgame.hInstance, "Server_GetBlendingInterface" );
- if( pBlendIface && pBlendIface( SV_BLENDING_INTERFACE_VERSION, &pBlendAPI, &gStudioAPI, &studio_transform, &studio_bones ))
- {
- - MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized Server Blending interface ^7ver. %i\n", SV_BLENDING_INTERFACE_VERSION );
- + MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized Server Blending interface ^7ver. %i\n", SV_BLENDING_INTERFACE_VERSION );
- return;
- }
- diff --git b/engine/common/model.c a/engine/common/model.c
- index e0c9c24..678ec15 100644
- --- b/engine/common/model.c
- +++ a/engine/common/model.c
- @@ -22,6 +22,7 @@ GNU General Public License for more details.
- #include "gl_local.h"
- #include "features.h"
- #include "client.h"
- +#include "server.h" // LUMP_ error codes
- #define MAX_SIDE_VERTS 512 // per one polygon
- @@ -160,6 +161,7 @@ void Mod_PrintBSPFileSizes_f( void )
- Msg( "=== Total BSP file data space used: %s ===\n", Q_memprint( totalmemory ));
- Msg( "World size ( %g %g %g ) units\n", world.size[0], world.size[1], world.size[2] );
- + Msg( "Supports transparency world water: %s\n", world.water_alpha ? "Yes" : "No" );
- Msg( "original name: ^1%s\n", worldmodel->name );
- Msg( "internal name: %s\n", (world.message[0]) ? va( "^2%s", world.message ) : "none" );
- }
- @@ -204,94 +206,50 @@ void Mod_SetupHulls( vec3_t mins[MAX_MAP_HULLS], vec3_t maxs[MAX_MAP_HULLS] )
- /*
- ===================
- -Mod_CompressVis
- +Mod_DecompressVis
- ===================
- */
- -byte *Mod_CompressVis( const byte *in, size_t *size )
- +static void Mod_DecompressVis( const byte *in, const byte *inend, byte *out, byte *outend )
- {
- - int j, rep;
- - int visrow;
- - byte *dest_p;
- + byte *outstart = out;
- + int c;
- - if( !worldmodel )
- + while( out < outend )
- {
- - Host_Error( "Mod_CompressVis: no worldmodel\n" );
- - return NULL;
- - }
- -
- - dest_p = visdata;
- - visrow = (worldmodel->numleafs + 7) >> 3;
- -
- - for( j = 0; j < visrow; j++ )
- - {
- - *dest_p++ = in[j];
- - if( in[j] ) continue;
- -
- - rep = 1;
- - for( j++; j < visrow; j++ )
- + if( in == inend )
- {
- - if( in[j] || rep == 255 )
- - break;
- - else rep++;
- + MsgDev( D_WARN, "Mod_DecompressVis: input underrun (decompressed %i of %i output bytes)\n",
- + (int)(out - outstart), (int)(outend - outstart));
- + return;
- }
- - *dest_p++ = rep;
- - j--;
- - }
- -
- - if( size ) *size = dest_p - visdata;
- -
- - return visdata;
- -}
- -/*
- -===================
- -Mod_DecompressVis
- -===================
- -*/
- -byte *Mod_DecompressVis( const byte *in )
- -{
- - int c, row;
- - byte *out;
- + c = *in++;
- - if( !worldmodel )
- - {
- - Host_Error( "Mod_DecompressVis: no worldmodel\n" );
- - return NULL;
- - }
- -
- - row = (worldmodel->numleafs + 7) >> 3;
- - out = visdata;
- -
- - if( !in )
- - {
- - // no vis info, so make all visible
- - while( row )
- + if( c )
- {
- - *out++ = 0xff;
- - row--;
- + *out++ = c;
- }
- - return visdata;
- - }
- -
- - do
- - {
- - if( *in )
- + else
- {
- - *out++ = *in++;
- - continue;
- - }
- -
- - c = in[1];
- - in += 2;
- + if( in == inend )
- + {
- + MsgDev( D_REPORT, "Mod_DecompressVis: input underrun (during zero-run) (decompressed %i of %i output bytes)\n",
- + (int)(out - outstart), (int)(outend - outstart));
- + return;
- + }
- - while( c )
- - {
- - *out++ = 0;
- - c--;
- + for( c = *in++; c > 0; c-- )
- + {
- + if( out == outend )
- + {
- + MsgDev( D_REPORT, "Mod_DecompressVis: output overrun (decompressed %i of %i output bytes)\n",
- + (int)(out - outstart), (int)(outend - outstart));
- + return;
- + }
- + *out++ = 0;
- + }
- }
- - } while( out - visdata < row );
- -
- - return visdata;
- + }
- }
- /*
- @@ -317,41 +275,99 @@ mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
- /*
- ==================
- -Mod_LeafPVS
- +Mod_GetPVSForPoint
- +Returns PVS data for a given point
- +NOTE: can return NULL
- ==================
- */
- -byte *Mod_LeafPVS( mleaf_t *leaf, model_t *model )
- +byte *Mod_GetPVSForPoint( const vec3_t p )
- {
- - if( !model || !leaf || leaf == model->leafs || !model->visdata )
- - return Mod_DecompressVis( NULL );
- - return Mod_DecompressVis( leaf->compressed_vis );
- + mnode_t *node;
- + mleaf_t *leaf = NULL;
- +
- + ASSERT( worldmodel != NULL );
- +
- + node = worldmodel->nodes;
- +
- + while( 1 )
- + {
- + if( node->contents < 0 )
- + {
- + leaf = (mleaf_t *)node;
- + break; // we found a leaf
- + }
- + node = node->children[PlaneDiff( p, node->plane ) < 0];
- + }
- +
- + if( leaf && leaf->cluster >= 0 )
- + return world.visdata + leaf->cluster * world.visbytes;
- + return NULL;
- }
- /*
- ==================
- -Mod_LeafPHS
- +Mod_FatPVS_RecursiveBSPNode
- ==================
- */
- -byte *Mod_LeafPHS( mleaf_t *leaf, model_t *model )
- +static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node )
- {
- - if( !model || !leaf || leaf == model->leafs || !model->visdata )
- - return Mod_DecompressVis( NULL );
- - return Mod_DecompressVis( leaf->compressed_pas );
- + int i;
- +
- + while( node->contents >= 0 )
- + {
- + float d = PlaneDiff( org, node->plane );
- +
- + if( d > radius )
- + node = node->children[0];
- + else if( d < -radius )
- + node = node->children[1];
- + else
- + {
- + // go down both sides
- + Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0] );
- + node = node->children[1];
- + }
- + }
- +
- + // if this leaf is in a cluster, accumulate the vis bits
- + if(((mleaf_t *)node)->cluster >= 0 )
- + {
- + byte *vis = world.visdata + ((mleaf_t *)node)->cluster * world.visbytes;
- +
- + for( i = 0; i < visbytes; i++ )
- + visbuffer[i] |= vis[i];
- + }
- }
- /*
- ==================
- -Mod_PointLeafnum
- +Mod_FatPVS_RecursiveBSPNode
- +Calculates a PVS that is the inclusive or of all leafs
- +within radius pixels of the given point.
- ==================
- */
- -int Mod_PointLeafnum( const vec3_t p )
- +int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
- {
- - // map not loaded
- - if ( !worldmodel ) return 0;
- - return Mod_PointInLeaf( p, worldmodel->nodes ) - worldmodel->leafs;
- + mleaf_t *leaf = Mod_PointInLeaf( org, worldmodel->nodes );
- + int bytes = world.visbytes;
- +
- + bytes = Q_min( bytes, visbytes );
- +
- + // enable full visibility for some reasons
- + if( fullvis || !world.visclusters || !leaf || leaf->cluster < 0 )
- + {
- + memset( visbuffer, 0xFF, bytes );
- + return bytes;
- + }
- +
- + if( !merge ) memset( visbuffer, 0x00, bytes );
- +
- + Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes );
- +
- + return bytes;
- }
- /*
- @@ -363,8 +379,7 @@ LEAF LISTING
- */
- static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
- {
- - mplane_t *plane;
- - int s;
- + int sides;
- while( 1 )
- {
- @@ -382,18 +397,17 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
- return;
- }
- - ll->list[ll->count++] = leaf - worldmodel->leafs - 1;
- + ll->list[ll->count++] = leaf->cluster;
- return;
- }
- - plane = node->plane;
- - s = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, plane );
- + sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
- - if( s == 1 )
- + if( sides == 1 )
- {
- node = node->children[0];
- }
- - else if( s == 2 )
- + else if( sides == 2 )
- {
- node = node->children[1];
- }
- @@ -421,11 +435,12 @@ int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int list
- VectorCopy( mins, ll.mins );
- VectorCopy( maxs, ll.maxs );
- - ll.count = 0;
- +
- ll.maxcount = listsize;
- - ll.list = list;
- - ll.topnode = -1;
- ll.overflowed = false;
- + ll.topnode = -1;
- + ll.list = list;
- + ll.count = 0;
- Mod_BoxLeafnums_r( &ll, worldmodel->nodes );
- @@ -453,15 +468,42 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi
- for( i = 0; i < count; i++ )
- {
- - int leafnum = leafList[i];
- -
- - if( leafnum != -1 && visbits[leafnum>>3] & (1<<( leafnum & 7 )))
- + if( CHECKVISBIT( visbits, leafList[i] ))
- return true;
- }
- return false;
- }
- /*
- +=============
- +Mod_HeadnodeVisible
- +=============
- +*/
- +qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, short *lastleaf )
- +{
- + if( !node || node->contents == CONTENTS_SOLID )
- + return false;
- +
- + if( node->contents < 0 )
- + {
- + if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
- + return false;
- +
- + if( lastleaf )
- + *lastleaf = ((mleaf_t *)node)->cluster;
- + return true;
- + }
- +
- + if( Mod_HeadnodeVisible( node->children[0], visbits, lastleaf ))
- + return true;
- +
- + if( Mod_HeadnodeVisible( node->children[1], visbits, lastleaf ))
- + return true;
- +
- + return false;
- +}
- +
- +/*
- ==================
- Mod_AmbientLevels
- @@ -480,6 +522,56 @@ void Mod_AmbientLevels( const vec3_t p, byte *pvolumes )
- }
- /*
- +==================
- +Mod_SampleSizeForFace
- +
- +return the current lightmap resolution per face
- +==================
- +*/
- +int Mod_SampleSizeForFace( msurface_t *surf )
- +{
- + if( !surf || !surf->texinfo || !surf->texinfo->faceinfo )
- + return LM_SAMPLE_SIZE;
- +
- + return surf->texinfo->faceinfo->texture_step;
- +}
- +
- +/*
- +==================
- +Mod_CheckWaterAlphaSupport
- +
- +converted maps potential may don't
- +support water transparency
- +==================
- +*/
- +static qboolean Mod_CheckWaterAlphaSupport( void )
- +{
- + mleaf_t *leaf;
- + int i, j;
- + const byte *pvs;
- +
- + if( world.visdatasize <= 0 ) return true;
- +
- + // check all liquid leafs to see if they can see into empty leafs, if any
- + // can we can assume this map supports r_wateralpha
- + for( i = 0, leaf = loadmodel->leafs; i < loadmodel->numleafs; i++, leaf++ )
- + {
- + if(( leaf->contents == CONTENTS_WATER || leaf->contents == CONTENTS_SLIME ) && leaf->cluster >= 0 )
- + {
- + pvs = world.visdata + leaf->cluster * world.visbytes;
- +
- + for( j = 0; j < loadmodel->numleafs; j++ )
- + {
- + if( CHECKVISBIT( pvs, loadmodel->leafs[j].cluster ) && loadmodel->leafs[j].contents == CONTENTS_EMPTY )
- + return true;
- + }
- + }
- + }
- +
- + return false;
- +}
- +
- +/*
- ================
- Mod_FreeUserData
- ================
- @@ -490,10 +582,21 @@ static void Mod_FreeUserData( model_t *mod )
- if( !mod || !mod->name[0] )
- return;
- - if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
- + if( host.type == HOST_DEDICATED )
- {
- - // let the client.dll free custom data
- - clgame.drawFuncs.Mod_ProcessUserData( mod, false, NULL );
- + if( svgame.physFuncs.Mod_ProcessUserData != NULL )
- + {
- + // let the server.dll free custom data
- + svgame.physFuncs.Mod_ProcessUserData( mod, false, NULL );
- + }
- + }
- + else
- + {
- + if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
- + {
- + // let the client.dll free custom data
- + clgame.drawFuncs.Mod_ProcessUserData( mod, false, NULL );
- + }
- }
- }
- @@ -618,7 +721,7 @@ static void Mod_LoadSubmodels( const dlump_t *l )
- {
- for( j = 0; j < 3; j++ )
- {
- - // spread the mins / maxs by a pixel
- + // spread the mins / maxs by a unit
- out->mins[j] = in->mins[j] - 1.0f;
- out->maxs[j] = in->maxs[j] + 1.0f;
- out->origin[j] = in->origin[j];
- @@ -640,7 +743,7 @@ static void Mod_LoadSubmodels( const dlump_t *l )
- VectorAverage( out->mins, out->maxs, out->origin );
- }
- - world.max_surfaces = max( world.max_surfaces, out->numfaces );
- + world.max_surfaces = Q_max( world.max_surfaces, out->numfaces );
- }
- if( world.loading )
- @@ -671,6 +774,7 @@ static void Mod_LoadTextures( const dlump_t *l )
- GL_FreeTexture( tr.alphaskyTexture );
- tr.solidskyTexture = tr.alphaskyTexture = 0;
- world.texdatasize = l->filelen;
- + world.custom_skybox = false;
- world.has_mirrors = false;
- world.sky_sphere = false;
- }
- @@ -744,7 +848,6 @@ static void Mod_LoadTextures( const dlump_t *l )
- if( load_external )
- {
- tr.solidskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP, NULL );
- - GL_SetTextureType( tr.solidskyTexture, TEX_BRUSH );
- load_external = false;
- }
- @@ -766,7 +869,6 @@ static void Mod_LoadTextures( const dlump_t *l )
- if( load_external )
- {
- tr.alphaskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP, NULL );
- - GL_SetTextureType( tr.alphaskyTexture, TEX_BRUSH );
- load_external = false;
- }
- }
- @@ -918,13 +1020,6 @@ static void Mod_LoadTextures( const dlump_t *l )
- }
- }
- }
- -
- - if( tx->gl_texturenum != tr.defaultTexture )
- - {
- - // apply texture type (just for debug)
- - GL_SetTextureType( tx->gl_texturenum, TEX_BRUSH );
- - GL_SetTextureType( tx->fb_texturenum, TEX_BRUSH );
- - }
- }
- // sequence the animations
- @@ -932,11 +1027,11 @@ static void Mod_LoadTextures( const dlump_t *l )
- {
- tx = loadmodel->textures[i];
- - if( !tx || tx->name[0] != '+' )
- + if( tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0 )
- continue;
- if( tx->anim_next )
- - continue; // allready sequenced
- + continue; // already sequenced
- // find the number of frames in the animation
- memset( anims, 0, sizeof( anims ));
- @@ -959,23 +1054,22 @@ static void Mod_LoadTextures( const dlump_t *l )
- altanims[altmax] = tx;
- altmax++;
- }
- - else Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
- + else MsgDev( D_ERROR, "Mod_LoadTextures: bad animating texture %s\n", tx->name );
- for( j = i + 1; j < loadmodel->numtextures; j++ )
- {
- tx2 = loadmodel->textures[j];
- - if( !tx2 || tx2->name[0] != '+' )
- - continue;
- - if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
- + if( tx2->name[0] != '+' || Q_strcmp( tx2->name + 2, tx->name + 2 ))
- continue;
- num = tx2->name[1];
- +
- if( num >= '0' && num <= '9' )
- {
- num -= '0';
- anims[num] = tx2;
- - if (num+1 > max)
- + if( num + 1 > max )
- max = num + 1;
- }
- else if( num >= 'a' && num <= 'j' )
- @@ -985,14 +1079,21 @@ static void Mod_LoadTextures( const dlump_t *l )
- if( num + 1 > altmax )
- altmax = num + 1;
- }
- - else Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
- + else MsgDev( D_ERROR, "Mod_LoadTextures: bad animating texture %s\n", tx->name );
- }
- // link them all together
- for( j = 0; j < max; j++ )
- {
- tx2 = anims[j];
- - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- +
- + if( !tx2 )
- + {
- + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- + tx->anim_total = 0;
- + break;
- + }
- +
- tx2->anim_total = max * ANIM_CYCLE;
- tx2->anim_min = j * ANIM_CYCLE;
- tx2->anim_max = (j + 1) * ANIM_CYCLE;
- @@ -1003,7 +1104,14 @@ static void Mod_LoadTextures( const dlump_t *l )
- for( j = 0; j < altmax; j++ )
- {
- tx2 = altanims[j];
- - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- +
- + if( !tx2 )
- + {
- + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- + tx->anim_total = 0;
- + break;
- + }
- +
- tx2->anim_total = altmax * ANIM_CYCLE;
- tx2->anim_min = j * ANIM_CYCLE;
- tx2->anim_max = (j+1) * ANIM_CYCLE;
- @@ -1017,11 +1125,11 @@ static void Mod_LoadTextures( const dlump_t *l )
- {
- tx = loadmodel->textures[i];
- - if( !tx || tx->name[0] != '-' )
- + if( tx->name[0] != '-' || tx->name[1] == 0 || tx->name[2] == 0 )
- continue;
- if( tx->anim_next )
- - continue; // allready sequenced
- + continue; // already sequenced
- // find the number of frames in the sequence
- memset( anims, 0, sizeof( anims ));
- @@ -1034,33 +1142,39 @@ static void Mod_LoadTextures( const dlump_t *l )
- anims[max] = tx;
- max++;
- }
- - else Host_Error( "Mod_LoadTextures: bad detail texture %s\n", tx->name );
- + else MsgDev( D_ERROR, "Mod_LoadTextures: bad detail texture %s\n", tx->name );
- for( j = i + 1; j < loadmodel->numtextures; j++ )
- {
- tx2 = loadmodel->textures[j];
- - if( !tx2 || tx2->name[0] != '-' )
- - continue;
- - if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
- + if( tx2->name[0] != '-' || Q_strcmp( tx2->name + 2, tx->name + 2 ))
- continue;
- num = tx2->name[1];
- +
- if( num >= '0' && num <= '9' )
- {
- num -= '0';
- anims[num] = tx2;
- - if( num+1 > max )
- + if( num + 1 > max )
- max = num + 1;
- }
- - else Host_Error( "Mod_LoadTextures: bad detail texture %s\n", tx->name );
- + else MsgDev( D_ERROR, "Mod_LoadTextures: bad detail texture %s\n", tx->name );
- }
- // link them all together
- for( j = 0; j < max; j++ )
- {
- tx2 = anims[j];
- - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- +
- + if( !tx2 )
- + {
- + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
- + tx->anim_total = 0;
- + break;
- + }
- +
- tx2->anim_total = -( max * ANIM_CYCLE ); // to differentiate from animations
- tx2->anim_min = j * ANIM_CYCLE;
- tx2->anim_max = (j + 1) * ANIM_CYCLE;
- @@ -1074,14 +1188,49 @@ static void Mod_LoadTextures( const dlump_t *l )
- Mod_LoadTexInfo
- =================
- */
- -static void Mod_LoadTexInfo( const dlump_t *l )
- +static mfaceinfo_t *Mod_LoadFaceInfo( const dlump_t *l, int *numfaceinfo )
- +{
- + dfaceinfo_t *in;
- + mfaceinfo_t *out, *faceinfo;
- + int i, count;
- +
- + in = (void *)(mod_base + l->fileofs);
- + if( l->filelen % sizeof( *in ))
- + Host_Error( "Mod_LoadFaceInfo: funny lump size in %s\n", loadmodel->name );
- +
- + count = l->filelen / sizeof( *in );
- + faceinfo = out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
- +
- + for( i = 0; i < count; i++, in++, out++ )
- + {
- + Q_strncpy( out->landname, in->landname, sizeof( out->landname ));
- + out->texture_step = in->texture_step;
- + out->max_extent = in->max_extent;
- + out->groupid = in->groupid;
- + }
- +
- + *numfaceinfo = count;
- +
- + return faceinfo;
- +}
- +
- +/*
- +=================
- +Mod_LoadTexInfo
- +=================
- +*/
- +static void Mod_LoadTexInfo( const dlump_t *l, dextrahdr_t *extrahdr )
- {
- dtexinfo_t *in;
- mtexinfo_t *out;
- int miptex;
- + mfaceinfo_t *fi = NULL;
- + int fi_count;
- int i, j, count;
- - float len1, len2;
- -
- +
- + if( extrahdr != NULL )
- + fi = Mod_LoadFaceInfo( &extrahdr->lumps[LUMP_FACEINFO], &fi_count );
- +
- in = (void *)(mod_base + l->fileofs);
- if( l->filelen % sizeof( *in ))
- Host_Error( "Mod_LoadTexInfo: funny lump size in %s\n", loadmodel->name );
- @@ -1097,22 +1246,16 @@ static void Mod_LoadTexInfo( const dlump_t *l )
- for( j = 0; j < 8; j++ )
- out->vecs[0][j] = in->vecs[0][j];
- - len1 = VectorLength( out->vecs[0] );
- - len2 = VectorLength( out->vecs[1] );
- - len1 = ( len1 + len2 ) / 2;
- -
- - // g-cont: can use this info for GL_TEXTURE_LOAD_BIAS_EXT ?
- - if( len1 < 0.32f ) out->mipadjust = 4;
- - else if( len1 < 0.49f ) out->mipadjust = 3;
- - else if( len1 < 0.99f ) out->mipadjust = 2;
- - else out->mipadjust = 1;
- -
- miptex = in->miptex;
- if( miptex < 0 || miptex > loadmodel->numtextures )
- Host_Error( "Mod_LoadTexInfo: bad miptex number in '%s'\n", loadmodel->name );
- out->texture = loadmodel->textures[miptex];
- out->flags = in->flags;
- +
- + // make sure what faceinfo is really exist
- + if( extrahdr != NULL && in->faceinfo != -1 && in->faceinfo < fi_count )
- + out->faceinfo = &fi[in->faceinfo];
- }
- }
- @@ -1182,10 +1325,35 @@ static void Mod_LoadDeluxemap( void )
- /*
- =================
- +Mod_LoadLightVecs
- +=================
- +*/
- +static void Mod_LoadLightVecs( const dlump_t *l )
- +{
- + byte *in;
- +
- + in = (void *)(mod_base + l->fileofs);
- + world.vecdatasize = l->filelen;
- +
- + if( world.vecdatasize != world.litdatasize )
- + {
- + MsgDev( D_ERROR, "Mod_LoadLightVecs: has mismatched size (%i should be %i)\n", world.vecdatasize, world.litdatasize );
- + world.deluxedata = NULL;
- + world.vecdatasize = 0;
- + return;
- + }
- +
- + world.deluxedata = Mem_Alloc( loadmodel->mempool, world.vecdatasize );
- + memcpy( world.deluxedata, in, world.vecdatasize );
- + MsgDev( D_INFO, "Mod_LoadLightVecs: loaded\n" );
- +}
- +
- +/*
- +=================
- Mod_LoadLighting
- =================
- */
- -static void Mod_LoadLighting( const dlump_t *l )
- +static void Mod_LoadLighting( const dlump_t *l, dextrahdr_t *extrahdr )
- {
- byte d, *in;
- color24 *out;
- @@ -1229,8 +1397,20 @@ static void Mod_LoadLighting( const dlump_t *l )
- break;
- }
- + if( !world.loading ) return; // only world can have deluxedata (FIXME: what about quake models?)
- +
- + // not supposed to be load ?
- + if( !FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
- + {
- + world.deluxedata = NULL;
- + world.vecdatasize = 0;
- + return;
- + }
- +
- // try to loading deluxemap too
- - Mod_LoadDeluxemap ();
- + if( extrahdr != NULL )
- + Mod_LoadLightVecs( &extrahdr->lumps[LUMP_LIGHTVECS] );
- + else Mod_LoadDeluxemap (); // old method
- }
- /*
- @@ -1244,10 +1424,11 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
- {
- float mins[2], maxs[2], val;
- int bmins[2], bmaxs[2];
- - int i, j, e;
- + int i, j, e, sample_size;
- mtexinfo_t *tex;
- mvertex_t *v;
- + sample_size = Mod_SampleSizeForFace( surf );
- tex = surf->texinfo;
- mins[0] = mins[1] = 999999;
- @@ -1273,13 +1454,13 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
- for( i = 0; i < 2; i++ )
- {
- - bmins[i] = floor( mins[i] / LM_SAMPLE_SIZE );
- - bmaxs[i] = ceil( maxs[i] / LM_SAMPLE_SIZE );
- + bmins[i] = floor( mins[i] / sample_size );
- + bmaxs[i] = ceil( maxs[i] / sample_size );
- - surf->texturemins[i] = bmins[i] * LM_SAMPLE_SIZE;
- - surf->extents[i] = (bmaxs[i] - bmins[i]) * LM_SAMPLE_SIZE;
- + surf->texturemins[i] = bmins[i] * sample_size;
- + surf->extents[i] = (bmaxs[i] - bmins[i]) * sample_size;
- - if(!( tex->flags & TEX_SPECIAL ) && surf->extents[i] > 4096 )
- + if( !FBitSet( tex->flags, TEX_SPECIAL ) && surf->extents[i] > 4096 )
- MsgDev( D_ERROR, "Bad surface extents %i\n", surf->extents[i] );
- }
- }
- @@ -1324,7 +1505,7 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
- uint bufSize;
- vec3_t normal, tangent, binormal;
- mtexinfo_t *texinfo = surf->texinfo;
- - int i, numElems;
- + int i, numElems, sample_size;
- byte *buffer;
- msurfmesh_t *mesh;
- @@ -1334,6 +1515,7 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
- bufSize = sizeof( msurfmesh_t ) + numVerts * sizeof( glvert_t ) + numElems * sizeof( word );
- buffer = Mem_Alloc( loadmodel->mempool, bufSize );
- + sample_size = Mod_SampleSizeForFace( surf );
- mesh = (msurfmesh_t *)buffer;
- buffer += sizeof( msurfmesh_t );
- mesh->numVerts = numVerts;
- @@ -1390,14 +1572,14 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
- // lightmap texture coordinates
- s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
- - s += surf->light_s * LM_SAMPLE_SIZE;
- - s += LM_SAMPLE_SIZE >> 1;
- - s /= BLOCK_SIZE * LM_SAMPLE_SIZE;
- + s += surf->light_s * sample_size;
- + s += sample_size >> 1;
- + s /= BLOCK_SIZE * sample_size;
- t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
- - t += surf->light_t * LM_SAMPLE_SIZE;
- - t += LM_SAMPLE_SIZE >> 1;
- - t /= BLOCK_SIZE * LM_SAMPLE_SIZE;
- + t += surf->light_t * sample_size;
- + t += sample_size >> 1;
- + t /= BLOCK_SIZE * sample_size;
- out->lmcoord[0] = s;
- out->lmcoord[1] = t;
- @@ -1421,6 +1603,7 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
- vec3_t normal, tangent, binormal, mins, maxs;
- mtexinfo_t *texinfo = surf->texinfo;
- vec2_t totalST, totalLM;
- + int sample_size;
- float s, t, scale;
- int i, j, f, b;
- uint bufSize;
- @@ -1432,6 +1615,8 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
- for( i = 0, v = verts; i < numVerts; i++, v += 3 )
- AddPointToBounds( v, mins, maxs );
- + sample_size = Mod_SampleSizeForFace( surf );
- +
- for( i = 0; i < 3; i++ )
- {
- m = tessSize * (float)floor((( mins[i] + maxs[i] ) * 0.5f ) / tessSize + 0.5f );
- @@ -1558,14 +1743,14 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
- {
- // lightmap texture coordinates
- s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
- - s += surf->light_s * LM_SAMPLE_SIZE;
- - s += LM_SAMPLE_SIZE >> 1;
- - s /= BLOCK_SIZE * LM_SAMPLE_SIZE;
- + s += surf->light_s * sample_size;
- + s += sample_size >> 1;
- + s /= BLOCK_SIZE * sample_size;
- t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
- - t += surf->light_t * LM_SAMPLE_SIZE;
- - t += LM_SAMPLE_SIZE >> 1;
- - t /= BLOCK_SIZE * LM_SAMPLE_SIZE;
- + t += surf->light_t * sample_size;
- + t += sample_size >> 1;
- + t /= BLOCK_SIZE * sample_size;
- }
- else
- {
- @@ -1726,7 +1911,7 @@ void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info )
- }
- // subdivide water or sky sphere for Quake1 maps
- - if(( surf->flags & SURF_DRAWTURB && !( surf->flags & SURF_REFLECT )) || ( surf->flags & SURF_DRAWSKY && world.loading && world.sky_sphere ))
- + if( surf->flags & SURF_DRAWTURB && !( surf->flags & SURF_REFLECT ))
- {
- Mod_SubdividePolygon( info, surf, surf->numedges, verts[0], 64.0f );
- Mod_ConvertSurface( info, surf );
- @@ -1905,9 +2090,6 @@ static void Mod_LoadSurfaces( const dlump_t *l )
- if( host.features & ENGINE_BUILD_SURFMESHES && (( out->flags & SURF_DRAWTILED ) || !out->samples ))
- Mod_BuildSurfacePolygons( out, info );
- - if( out->flags & SURF_DRAWSKY && world.loading && world.sky_sphere )
- - GL_SubdivideSurface( out ); // cut up polygon for warps
- -
- if( out->flags & SURF_DRAWTURB )
- GL_SubdivideSurface( out ); // cut up polygon for warps
- }
- @@ -2105,6 +2287,17 @@ static void Mod_LoadLeafs( const dlump_t *l )
- loadmodel->leafs = out;
- loadmodel->numleafs = count;
- + if( world.loading )
- + {
- + // get visleafs from the submodel data
- + world.visclusters = loadmodel->submodels[0].visleafs;
- + world.visbytes = (world.visclusters + 7) >> 3;
- + world.visdata = (byte *)Mem_Alloc( loadmodel->mempool, world.visclusters * world.visbytes );
- +
- + // enable full visibility as default
- + memset( world.visdata, 0xFF, world.visclusters * world.visbytes );
- + }
- +
- for( i = 0; i < count; i++, in++, out++ )
- {
- for( j = 0; j < 3; j++ )
- @@ -2117,6 +2310,29 @@ static void Mod_LoadLeafs( const dlump_t *l )
- p = in->visofs;
- + if( world.loading )
- + {
- + out->cluster = ( i - 1 ); // solid leaf 0 has no visdata
- + if( out->cluster >= world.visclusters )
- + out->cluster = -1;
- +
- + // ignore visofs errors on leaf 0 (solid)
- + if( p >= 0 && out->cluster >= 0 && loadmodel->visdata )
- + {
- + if( p < world.visdatasize )
- + {
- + byte *inrow = loadmodel->visdata + p;
- + byte *inrowend = loadmodel->visdata + world.visdatasize;
- + byte *outrow = world.visdata + out->cluster * world.visbytes;
- + byte *outrowend = world.visdata + (out->cluster + 1) * world.visbytes;
- +
- + Mod_DecompressVis( inrow, inrowend, outrow, outrowend );
- + }
- + else MsgDev( D_WARN, "Mod_LoadLeafs: invalid visofs for leaf #%i\n", i );
- + }
- + }
- + else out->cluster = -1; // no visclusters on bmodels
- +
- if( p == -1 ) out->compressed_vis = NULL;
- else out->compressed_vis = loadmodel->visdata + p;
- @@ -2140,6 +2356,14 @@ static void Mod_LoadLeafs( const dlump_t *l )
- if( loadmodel->leafs[0].contents != CONTENTS_SOLID )
- Host_Error( "Mod_LoadLeafs: Map %s has leaf 0 is not CONTENTS_SOLID\n", loadmodel->name );
- +
- + // do some final things for world
- + if( world.loading )
- + {
- + // store size of fat pvs
- + world.fatbytes = (world.visclusters + 31) >> 3;
- + world.water_alpha = Mod_CheckWaterAlphaSupport();
- + }
- }
- /*
- @@ -2172,6 +2396,9 @@ static void Mod_LoadPlanes( const dlump_t *l )
- out->signbits |= 1<<j;
- }
- + if( VectorIsNull( out->normal ))
- + Host_Error( "Mod_LoadPlanes: bad normal for plane #%i\n", i );
- +
- out->dist = in->dist;
- out->type = in->type;
- }
- @@ -2210,6 +2437,7 @@ static void Mod_LoadEntities( const dlump_t *l )
- char *pfile;
- string keyname;
- char token[2048];
- + char wadstring[2048];
- // make sure what we really has terminator
- loadmodel->entities = Mem_Alloc( loadmodel->mempool, l->filelen + 1 );
- @@ -2245,23 +2473,19 @@ static void Mod_LoadEntities( const dlump_t *l )
- if( !Q_stricmp( keyname, "wad" ))
- {
- - char *path = token;
- - string wadpath;
- + char *pszWadFile;
- +
- + Q_strncpy( wadstring, token, 2046 );
- + wadstring[2046] = 0;
- +
- + if( !Q_strchr( wadstring, ';' ))
- + Q_strcat( wadstring, ";" );
- // parse wad pathes
- - while( path )
- + for (pszWadFile = strtok( wadstring, ";" ); pszWadFile!= NULL; pszWadFile = strtok( NULL, ";" ))
- {
- - char *end = Q_strchr( path, ';' );
- - if( !end )
- - {
- - // if specified only once wad
- - if( !wadlist.count )
- - FS_FileBase( path, wadlist.wadnames[wadlist.count++] );
- - break;
- - }
- - Q_strncpy( wadpath, path, (end - path) + 1 );
- - FS_FileBase( wadpath, wadlist.wadnames[wadlist.count++] );
- - path += (end - path) + 1; // move pointer
- + COM_FixSlashes( pszWadFile );
- + FS_FileBase( pszWadFile, wadlist.wadnames[wadlist.count++] );
- if( wadlist.count >= 256 ) break; // too many wads...
- }
- }
- @@ -2510,135 +2734,6 @@ static void Mod_MakeHull0( void )
- /*
- =================
- -Mod_CalcPHS
- -=================
- -*/
- -void Mod_CalcPHS( void )
- -{
- - int hcount, vcount;
- - int i, j, k, l, index, num;
- - int rowbytes, rowwords;
- - int bitbyte, rowsize;
- - int *visofs, total_size = 0;
- - byte *vismap, *vismap_p;
- - byte *uncompressed_vis;
- - byte *uncompressed_pas;
- - byte *compressed_pas;
- - byte *scan, *comp;
- - uint *dest, *src;
- - double timestart;
- - size_t phsdatasize;
- -
- - // no worldmodel or no visdata
- - if( !world.loading || !worldmodel || !worldmodel->visdata )
- - return;
- -
- - MsgDev( D_NOTE, "Building PAS...\n" );
- - timestart = Sys_DoubleTime();
- -
- - // NOTE: first leaf is skipped becuase is a outside leaf. Now all leafs have shift up by 1.
- - // and last leaf (which equal worldmodel->numleafs) has no visdata! Add one extra leaf
- - // to avoid this situation.
- - num = worldmodel->numleafs;
- - rowwords = (num + 31) >> 5;
- - rowbytes = rowwords * 4;
- -
- - // typically PHS reqiured more room because RLE fails on multiple 1 not 0
- - phsdatasize = world.visdatasize * 32; // empirically determined
- -
- - // allocate pvs and phs data single array
- - visofs = Mem_Alloc( worldmodel->mempool, num * sizeof( int ));
- - uncompressed_vis = Mem_Alloc( worldmodel->mempool, rowbytes * num * 2 );
- - uncompressed_pas = uncompressed_vis + rowbytes * num;
- - compressed_pas = Mem_Alloc( worldmodel->mempool, phsdatasize );
- - vismap = vismap_p = compressed_pas; // compressed PHS buffer
- - scan = uncompressed_vis;
- - vcount = 0;
- -
- - // uncompress pvs first
- - for( i = 0; i < num; i++, scan += rowbytes )
- - {
- - memcpy( scan, Mod_LeafPVS( worldmodel->leafs + i, worldmodel ), rowbytes );
- - if( i == 0 ) continue;
- -
- - for( j = 0; j < num; j++ )
- - {
- - if( scan[j>>3] & (1<<( j & 7 )))
- - vcount++;
- - }
- - }
- -
- - scan = uncompressed_vis;
- - hcount = 0;
- -
- - dest = (uint *)uncompressed_pas;
- -
- - for( i = 0; i < num; i++, dest += rowwords, scan += rowbytes )
- - {
- - memcpy( dest, scan, rowbytes );
- -
- - for( j = 0; j < rowbytes; j++ )
- - {
- - bitbyte = scan[j];
- - if( !bitbyte ) continue;
- -
- - for( k = 0; k < 8; k++ )
- - {
- - if(!( bitbyte & ( 1<<k )))
- - continue;
- - // or this pvs row into the phs
- - // +1 because pvs is 1 based
- - index = ((j<<3) + k + 1);
- - if( index >= num ) continue;
- -
- - src = (uint *)uncompressed_vis + index * rowwords;
- - for( l = 0; l < rowwords; l++ )
- - dest[l] |= src[l];
- - }
- - }
- -
- - // compress PHS data back
- - comp = Mod_CompressVis( (byte *)dest, &rowsize );
- - visofs[i] = vismap_p - vismap; // leaf 0 is a common solid
- - total_size += rowsize;
- -
- - if( total_size > phsdatasize )
- - {
- - Host_Error( "CalcPHS: vismap expansion overflow %s > %s\n", Q_memprint( total_size ), Q_memprint( phsdatasize ));
- - }
- -
- - memcpy( vismap_p, comp, rowsize );
- - vismap_p += rowsize; // move pointer
- -
- - if( i == 0 ) continue;
- -
- - for( j = 0; j < num; j++ )
- - {
- - if(((byte *)dest)[j>>3] & (1<<( j & 7 )))
- - hcount++;
- - }
- - }
- -
- - // adjust compressed pas data to fit the size
- - compressed_pas = Mem_Realloc( worldmodel->mempool, compressed_pas, total_size );
- -
- - // apply leaf pointers
- - for( i = 0; i < worldmodel->numleafs; i++ )
- - worldmodel->leafs[i].compressed_pas = compressed_pas + visofs[i];
- -
- - // release uncompressed data
- - Mem_Free( uncompressed_vis );
- - Mem_Free( visofs ); // release vis offsets
- -
- - // NOTE: we don't need to store off pointer to compressed pas-data
- - // because this is will be automatiaclly frees by mempool internal pointer
- - // and we never use this pointer after this point
- - MsgDev( D_NOTE, "Average leaves visible / audible / total: %i / %i / %i\n", vcount / num, hcount / num, num );
- - MsgDev( D_NOTE, "PAS building time: %g secs\n", Sys_DoubleTime() - timestart );
- -}
- -
- -/*
- -=================
- Mod_UnloadBrushModel
- Release all uploaded textures
- @@ -2679,17 +2774,23 @@ Mod_LoadBrushModel
- */
- static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded )
- {
- - int i, j;
- - int sample_size;
- - char *ents;
- - dheader_t *header;
- - dmodel_t *bm;
- + int i, j;
- + int sample_size;
- + char *ents;
- + dheader_t *header;
- + dextrahdr_t *extrahdr;
- + dmodel_t *bm;
- if( loaded ) *loaded = false;
- header = (dheader_t *)buffer;
- loadmodel->type = mod_brush;
- i = header->version;
- + // BSP31 and BSP30 have different offsets
- + if( i == XTBSP_VERSION )
- + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
- + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
- +
- switch( i )
- {
- case 28: // get support for quake1 beta
- @@ -2720,12 +2821,18 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
- MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)", loadmodel->name, i, world.version );
- return;
- }
- +
- + loadmodel->numframes = sample_size; // NOTE: world store sample size into model_t->numframes
- bmodel_version = i; // share it
- // swap all the lumps
- mod_base = (byte *)header;
- loadmodel->mempool = Mem_AllocPool( va( "^2%s^7", loadmodel->name ));
- + // make sure what extrahdr is valid
- + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
- + extrahdr = NULL; // no extra header
- +
- // load into heap
- if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 && (header->lumps[LUMP_ENTITIES].filelen % sizeof( dplane_t )) == 0 )
- {
- @@ -2744,13 +2851,14 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
- if( world.version <= 29 && world.mapversion == 220 && (header->lumps[LUMP_LIGHTING].filelen % 3) == 0 )
- world.version = bmodel_version = HLBSP_VERSION;
- + Mod_LoadSubmodels( &header->lumps[LUMP_MODELS] );
- Mod_LoadVertexes( &header->lumps[LUMP_VERTEXES] );
- Mod_LoadEdges( &header->lumps[LUMP_EDGES] );
- Mod_LoadSurfEdges( &header->lumps[LUMP_SURFEDGES] );
- Mod_LoadTextures( &header->lumps[LUMP_TEXTURES] );
- - Mod_LoadLighting( &header->lumps[LUMP_LIGHTING] );
- + Mod_LoadLighting( &header->lumps[LUMP_LIGHTING], extrahdr );
- Mod_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
- - Mod_LoadTexInfo( &header->lumps[LUMP_TEXINFO] );
- + Mod_LoadTexInfo( &header->lumps[LUMP_TEXINFO], extrahdr );
- Mod_LoadSurfaces( &header->lumps[LUMP_FACES] );
- Mod_LoadMarkSurfaces( &header->lumps[LUMP_MARKSURFACES] );
- Mod_LoadLeafs( &header->lumps[LUMP_LEAFS] );
- @@ -2759,11 +2867,9 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
- if( bmodel_version == XTBSP_VERSION )
- Mod_LoadClipnodes31( &header->lumps[LUMP_CLIPNODES], &header->lumps[LUMP_CLIPNODES2], &header->lumps[LUMP_CLIPNODES3] );
- else Mod_LoadClipnodes( &header->lumps[LUMP_CLIPNODES] );
- - Mod_LoadSubmodels( &header->lumps[LUMP_MODELS] );
- Mod_MakeHull0 ();
- -
- - loadmodel->numframes = 2; // regular and alternate animation
- +
- ents = loadmodel->entities;
- // set up the submodels
- @@ -2791,12 +2897,14 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
- if( i != 0 )
- {
- // HACKHACK: c2a1 issues
- - if( !bm->origin[0] && !bm->origin[1] ) mod->flags |= MODEL_HAS_ORIGIN;
- + if( !bm->origin[0] && !bm->origin[1] )
- + SetBits( mod->flags, MODEL_HAS_ORIGIN );
- Mod_FindModelOrigin( ents, va( "*%i", i ), bm->origin );
- // flag 2 is indicated model with origin brush!
- - if( !VectorIsNull( bm->origin )) mod->flags |= MODEL_HAS_ORIGIN;
- + if( !VectorIsNull( bm->origin ))
- + SetBits( mod->flags, MODEL_HAS_ORIGIN );
- }
- for( j = 0; i != 0 && j < mod->nummodelsurfaces; j++ )
- @@ -2815,7 +2923,7 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
- if( surf->plane->type == PLANE_Z )
- {
- // kill bottom plane too
- - if( info->mins[2] == bm->mins[2] + 1 )
- + if( info->mins[2] == bm->mins[2] + 1.0f )
- surf->flags |= SURF_WATERCSG;
- }
- else
- @@ -2971,10 +3079,24 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
- return NULL;
- }
- - else if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
- + else
- {
- - // let the client.dll load custom data
- - clgame.drawFuncs.Mod_ProcessUserData( mod, true, buf );
- + if( host.type == HOST_DEDICATED )
- + {
- + if( svgame.physFuncs.Mod_ProcessUserData != NULL )
- + {
- + // let the server.dll load custom data
- + svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
- + }
- + }
- + else
- + {
- + if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
- + {
- + // let the client.dll load custom data
- + clgame.drawFuncs.Mod_ProcessUserData( mod, true, buf );
- + }
- + }
- }
- Mem_Free( buf );
- @@ -3010,7 +3132,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
- // now replacement table is invalidate
- memset( com_models, 0, sizeof( com_models ));
- -
- com_models[1] = cm_models; // make link to world
- // update the lightmap blocksize
- @@ -3031,7 +3152,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
- }
- // clear all studio submodels on restart
- - // HACKHACK: throw all external BSP-models to refresh their lightmaps properly
- for( i = 1; i < cm_nummodels; i++ )
- {
- if( cm_models[i].type == mod_studio )
- @@ -3052,9 +3172,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
- world.loading = false;
- if( checksum ) *checksum = world.checksum;
- -
- - // calc Potentially Hearable Set and compress it
- - Mod_CalcPHS();
- }
- /*
- @@ -3106,7 +3223,9 @@ void Mod_GetFrames( int handle, int *numFrames )
- return;
- }
- - *numFrames = mod->numframes;
- + if( mod->type == mod_brush )
- + *numFrames = 2; // regular and alternate animation
- + else *numFrames = mod->numframes;
- if( *numFrames < 1 ) *numFrames = 1;
- }
- @@ -3246,7 +3365,233 @@ model_t *Mod_Handle( int handle )
- return com_models[handle];
- }
- -wadlist_t *Mod_WadList( void )
- +/*
- +==================
- +Mod_CheckLump
- +
- +check lump for existing
- +==================
- +*/
- +int Mod_CheckLump( const char *filename, const int lump, int *lumpsize )
- +{
- + file_t *f = FS_Open( filename, "rb", true );
- + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
- + size_t prefetch_size = sizeof( buffer );
- + dextrahdr_t *extrahdr;
- + dheader_t *header;
- +
- + if( !f ) return LUMP_LOAD_COULDNT_OPEN;
- +
- + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_BAD_HEADER;
- + }
- +
- + header = (dheader_t *)buffer;
- +
- + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_BAD_VERSION;
- + }
- +
- + // BSP31 and BSP30 have different offsets
- + if( header->version == XTBSP_VERSION )
- + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
- + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
- +
- + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_NO_EXTRADATA;
- + }
- +
- + if( lump < 0 || lump >= EXTRA_LUMPS )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_INVALID_NUM;
- + }
- +
- + if( extrahdr->lumps[lump].filelen <= 0 )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_NOT_EXIST;
- + }
- +
- + if( lumpsize )
- + *lumpsize = extrahdr->lumps[lump].filelen;
- +
- + FS_Close( f );
- +
- + return LUMP_LOAD_OK;
- +}
- +
- +/*
- +==================
- +Mod_ReadLump
- +
- +reading random lump by user request
- +==================
- +*/
- +int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize )
- +{
- + file_t *f = FS_Open( filename, "rb", true );
- + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
- + size_t prefetch_size = sizeof( buffer );
- + dextrahdr_t *extrahdr;
- + dheader_t *header;
- + byte *data;
- + int length;
- +
- + if( !f ) return LUMP_LOAD_COULDNT_OPEN;
- +
- + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_BAD_HEADER;
- + }
- +
- + header = (dheader_t *)buffer;
- +
- + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_BAD_VERSION;
- + }
- +
- + // BSP31 and BSP30 have different offsets
- + if( header->version == XTBSP_VERSION )
- + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
- + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
- +
- + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_NO_EXTRADATA;
- + }
- +
- + if( lump < 0 || lump >= EXTRA_LUMPS )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_INVALID_NUM;
- + }
- +
- + if( extrahdr->lumps[lump].filelen <= 0 )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_NOT_EXIST;
- + }
- +
- + data = malloc( extrahdr->lumps[lump].filelen + 1 );
- + length = extrahdr->lumps[lump].filelen;
- +
- + if( !data )
- + {
- + FS_Close( f );
- + return LUMP_LOAD_MEM_FAILED;
- + }
- +
- + FS_Seek( f, extrahdr->lumps[lump].fileofs, SEEK_SET );
- +
- + if( FS_Read( f, data, length ) != length )
- + {
- + Mem_Free( data );
- + FS_Close( f );
- + return LUMP_LOAD_CORRUPTED;
- + }
- +
- + data[length] = 0; // write term
- + FS_Close( f );
- +
- + if( lumpsize )
- + *lumpsize = length;
- + *lumpdata = data;
- +
- + return LUMP_LOAD_OK;
- +}
- +
- +/*
- +==================
- +Mod_SaveLump
- +
- +writing lump by user request
- +only empty lumps is allows
- +==================
- +*/
- +int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize )
- {
- - return &wadlist;
- + file_t *f = FS_Open( filename, "e+b", true );
- + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
- + size_t prefetch_size = sizeof( buffer );
- + dextrahdr_t *extrahdr;
- + dheader_t *header;
- +
- + if( !f ) return LUMP_SAVE_COULDNT_OPEN;
- +
- + if( !lumpdata || lumpsize <= 0 )
- + return LUMP_SAVE_NO_DATA;
- +
- + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_BAD_HEADER;
- + }
- +
- + header = (dheader_t *)buffer;
- +
- + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_BAD_VERSION;
- + }
- +
- + // BSP31 and BSP30 have different offsets
- + if( header->version == XTBSP_VERSION )
- + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
- + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
- +
- + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_NO_EXTRADATA;
- + }
- +
- + if( lump < 0 || lump >= EXTRA_LUMPS )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_INVALID_NUM;
- + }
- +
- + if( extrahdr->lumps[lump].filelen != 0 )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_ALREADY_EXIST;
- + }
- +
- + FS_Seek( f, 0, SEEK_END );
- +
- + // will be saved later
- + extrahdr->lumps[lump].fileofs = FS_Tell( f );
- + extrahdr->lumps[lump].filelen = lumpsize;
- +
- + if( FS_Write( f, lumpdata, lumpsize ) != lumpsize )
- + {
- + FS_Close( f );
- + return LUMP_SAVE_CORRUPTED;
- + }
- +
- + // update the header
- + if( header->version == XTBSP_VERSION )
- + FS_Seek( f, sizeof( dheader31_t ), SEEK_SET );
- + else FS_Seek( f, sizeof( dheader_t ), SEEK_SET );
- +
- + if( FS_Write( f, extrahdr, sizeof( dextrahdr_t )) != sizeof( dextrahdr_t ))
- + {
- + FS_Close( f );
- + return LUMP_SAVE_CORRUPTED;
- + }
- +
- + FS_Close( f );
- + return LUMP_SAVE_OK;
- }
- \ No newline at end of file
- diff --git b/engine/common/net_buffer.c a/engine/common/net_buffer.c
- index 2c645e3..96c693a 100644
- --- b/engine/common/net_buffer.c
- +++ a/engine/common/net_buffer.c
- @@ -26,15 +26,7 @@ static dword ExtraMasks[32];
- short MSG_BigShort( short swap )
- {
- - short *s = &swap;
- -
- - __asm {
- - mov ebx, s
- - mov al, [ebx+1]
- - mov ah, [ebx ]
- - mov [ebx], ax
- - }
- - return *s;
- + return (swap >> 8)|(swap << 8);
- }
- void MSG_InitMasks( void )
- @@ -57,32 +49,32 @@ void MSG_InitMasks( void )
- ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
- }
- -void MSG_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
- +void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
- {
- - bf->pDebugName = pDebugName;
- + sb->pDebugName = pDebugName;
- - MSG_StartWriting( bf, pData, nBytes, 0, nMaxBits );
- + MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
- }
- -void MSG_StartWriting( sizebuf_t *bf, void *pData, int nBytes, int iStartBit, int nBits )
- +void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
- {
- // make sure it's dword aligned and padded.
- Assert(((dword)pData & 3 ) == 0 );
- - bf->pData = (byte *)pData;
- + sb->pData = (byte *)pData;
- if( nBits == -1 )
- {
- - bf->nDataBits = nBytes << 3;
- + sb->nDataBits = nBytes << 3;
- }
- else
- {
- Assert( nBits <= nBytes * 8 );
- - bf->nDataBits = nBits;
- + sb->nDataBits = nBits;
- }
- - bf->iCurBit = iStartBit;
- - bf->bOverflow = false;
- + sb->iCurBit = iStartBit;
- + sb->bOverflow = false;
- }
- /*
- @@ -92,70 +84,68 @@ MSG_Clear
- for clearing overflowed buffer
- =======================
- */
- -void MSG_Clear( sizebuf_t *bf )
- +void MSG_Clear( sizebuf_t *sb )
- {
- - bf->iCurBit = 0;
- - bf->bOverflow = false;
- + sb->iCurBit = 0;
- + sb->bOverflow = false;
- }
- -static qboolean MSG_Overflow( sizebuf_t *bf, int nBits )
- +static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
- {
- - if( bf->iCurBit + nBits > bf->nDataBits )
- - bf->bOverflow = true;
- - return bf->bOverflow;
- + if( sb->iCurBit + nBits > sb->nDataBits )
- + sb->bOverflow = true;
- + return sb->bOverflow;
- }
- -qboolean MSG_CheckOverflow( sizebuf_t *bf )
- +qboolean MSG_CheckOverflow( sizebuf_t *sb )
- {
- - ASSERT( bf );
- -
- - return MSG_Overflow( bf, 0 );
- + return MSG_Overflow( sb, 0 );
- }
- -void MSG_SeekToBit( sizebuf_t *bf, int bitPos )
- +void MSG_SeekToBit( sizebuf_t *sb, int bitPos )
- {
- - bf->iCurBit = bitPos;
- + sb->iCurBit = bitPos;
- }
- -void MSG_SeekToByte( sizebuf_t *bf, int bytePos )
- +void MSG_SeekToByte( sizebuf_t *sb, int bytePos )
- {
- - bf->iCurBit = bytePos << 3;
- + sb->iCurBit = bytePos << 3;
- }
- -void MSG_WriteOneBit( sizebuf_t *bf, int nValue )
- +void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
- {
- - if( !MSG_Overflow( bf, 1 ))
- + if( !MSG_Overflow( sb, 1 ))
- {
- - if( nValue ) bf->pData[bf->iCurBit>>3] |= BIT( bf->iCurBit & 7 );
- - else bf->pData[bf->iCurBit>>3] &= ~BIT( bf->iCurBit & 7 );
- + if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 );
- + else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 );
- - bf->iCurBit++;
- + sb->iCurBit++;
- }
- }
- -void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bCheckRange )
- +void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
- {
- Assert( numbits >= 0 && numbits <= 32 );
- // bounds checking..
- - if(( bf->iCurBit + numbits ) > bf->nDataBits )
- + if(( sb->iCurBit + numbits ) > sb->nDataBits )
- {
- - bf->bOverflow = true;
- - bf->iCurBit = bf->nDataBits;
- + sb->bOverflow = true;
- + sb->iCurBit = sb->nDataBits;
- }
- else
- {
- int nBitsLeft = numbits;
- - int iCurBit = bf->iCurBit;
- + int iCurBit = sb->iCurBit;
- uint iDWord = iCurBit >> 5; // Mask in a dword.
- dword iCurBitMasked;
- int nBitsWritten;
- - Assert(( iDWord * 4 + sizeof( long )) <= (uint)MSG_GetMaxBytes( bf ));
- + Assert(( iDWord * 4 + sizeof( long )) <= (uint)MSG_GetMaxBytes( sb ));
- iCurBitMasked = iCurBit & 31;
- - ((dword *)bf->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
- - ((dword *)bf->pData)[iDWord] |= curData << iCurBitMasked;
- + ((dword *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
- + ((dword *)sb->pData)[iDWord] |= curData << iCurBitMasked;
- // did it span a dword?
- nBitsWritten = 32 - iCurBitMasked;
- @@ -167,10 +157,10 @@ void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bC
- curData >>= nBitsWritten;
- iCurBitMasked = iCurBit & 31;
- - ((dword *)bf->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
- - ((dword *)bf->pData)[iDWord+1] |= curData << iCurBitMasked;
- + ((dword *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
- + ((dword *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
- }
- - bf->iCurBit += numbits;
- + sb->iCurBit += numbits;
- }
- }
- @@ -181,33 +171,33 @@ MSG_WriteSBitLong
- sign bit comes first
- =======================
- */
- -void MSG_WriteSBitLong( sizebuf_t *bf, int data, int numbits )
- +void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits )
- {
- // do we have a valid # of bits to encode with?
- - Assert( numbits >= 1 );
- + Assert( numbits >= 1 && numbits <= 32 );
- // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
- // (Some old code writes direct integers right into the buffer).
- if( data < 0 )
- {
- - MSG_WriteUBitLongExt( bf, (uint)( 0x80000000 + data ), numbits - 1, false );
- - MSG_WriteOneBit( bf, 1 );
- + MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 );
- + MSG_WriteOneBit( sb, 1 );
- }
- else
- {
- - MSG_WriteUBitLong( bf, (uint)data, numbits - 1 );
- - MSG_WriteOneBit( bf, 0 );
- + MSG_WriteUBitLong( sb, (uint)data, numbits - 1 );
- + MSG_WriteOneBit( sb, 0 );
- }
- }
- -void MSG_WriteBitLong( sizebuf_t *bf, uint data, int numbits, qboolean bSigned )
- +void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned )
- {
- if( bSigned )
- - MSG_WriteSBitLong( bf, (int)data, numbits );
- - else MSG_WriteUBitLong( bf, data, numbits );
- + MSG_WriteSBitLong( sb, (int)data, numbits );
- + else MSG_WriteUBitLong( sb, data, numbits );
- }
- -qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
- +qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
- {
- byte *pOut = (byte *)pData;
- int nBitsLeft = nBits;
- @@ -215,7 +205,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
- // get output dword-aligned.
- while((( dword )pOut & 3 ) != 0 && nBitsLeft >= 8 )
- {
- - MSG_WriteUBitLongExt( bf, *pOut, 8, false );
- + MSG_WriteUBitLong( sb, *pOut, 8 );
- nBitsLeft -= 8;
- ++pOut;
- @@ -224,7 +214,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
- // read dwords.
- while( nBitsLeft >= 32 )
- {
- - MSG_WriteUBitLongExt( bf, *(( dword *)pOut ), 32, false );
- + MSG_WriteUBitLong( sb, *(( dword *)pOut ), 32 );
- pOut += sizeof( dword );
- nBitsLeft -= 32;
- @@ -233,7 +223,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
- // read the remaining bytes.
- while( nBitsLeft >= 8 )
- {
- - MSG_WriteUBitLongExt( bf, *pOut, 8, false );
- + MSG_WriteUBitLong( sb, *pOut, 8 );
- nBitsLeft -= 8;
- ++pOut;
- @@ -242,13 +232,13 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
- // Read the remaining bits.
- if( nBitsLeft )
- {
- - MSG_WriteUBitLongExt( bf, *pOut, nBitsLeft, false );
- + MSG_WriteUBitLong( sb, *pOut, nBitsLeft );
- }
- - return !bf->bOverflow;
- + return !sb->bOverflow;
- }
- -void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits )
- +void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits )
- {
- uint mask, shift;
- int d;
- @@ -263,136 +253,141 @@ void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits )
- d = (int)(( fAngle * shift ) / 360.0f );
- d &= mask;
- - MSG_WriteUBitLong( bf, (uint)d, numbits );
- + MSG_WriteUBitLong( sb, (uint)d, numbits );
- }
- -void MSG_WriteCoord( sizebuf_t *bf, float val )
- +void MSG_WriteCoord( sizebuf_t *sb, float val )
- {
- // g-cont. we loose precision here but keep old size of coord variable!
- - if( host.features & ENGINE_WRITE_LARGE_COORD )
- - MSG_WriteShort( bf, (int)( val * 2.0f ));
- - else MSG_WriteShort( bf, (int)( val * 8.0f ));
- + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
- + MSG_WriteShort( sb, (int)( val * 2.0f ));
- + else MSG_WriteShort( sb, (int)( val * 8.0f ));
- }
- -void MSG_WriteVec3Coord( sizebuf_t *bf, const float *fa )
- +void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa )
- {
- - MSG_WriteCoord( bf, fa[0] );
- - MSG_WriteCoord( bf, fa[1] );
- - MSG_WriteCoord( bf, fa[2] );
- + MSG_WriteCoord( sb, fa[0] );
- + MSG_WriteCoord( sb, fa[1] );
- + MSG_WriteCoord( sb, fa[2] );
- }
- -void MSG_WriteBitFloat( sizebuf_t *bf, float val )
- +void MSG_WriteBitFloat( sizebuf_t *sb, float val )
- {
- long intVal;
- - ASSERT( sizeof( long ) == sizeof( float ));
- - ASSERT( sizeof( float ) == 4 );
- + Assert( sizeof( long ) == sizeof( float ));
- + Assert( sizeof( float ) == 4 );
- intVal = *((long *)&val );
- - MSG_WriteUBitLong( bf, intVal, 32 );
- + MSG_WriteUBitLong( sb, intVal, 32 );
- +}
- +
- +void MSG_WriteChar( sizebuf_t *sb, int val )
- +{
- + MSG_WriteSBitLong( sb, val, sizeof( char ) << 3 );
- }
- -void MSG_WriteChar( sizebuf_t *bf, int val )
- +void MSG_WriteByte( sizebuf_t *sb, int val )
- {
- - MSG_WriteSBitLong( bf, val, sizeof( char ) << 3 );
- + MSG_WriteUBitLong( sb, val, sizeof( byte ) << 3 );
- }
- -void MSG_WriteByte( sizebuf_t *bf, int val )
- +void MSG_WriteShort( sizebuf_t *sb, int val )
- {
- - MSG_WriteUBitLong( bf, val, sizeof( byte ) << 3 );
- + MSG_WriteSBitLong( sb, val, sizeof(short ) << 3 );
- }
- -void MSG_WriteShort( sizebuf_t *bf, int val )
- +void MSG_WriteWord( sizebuf_t *sb, int val )
- {
- - MSG_WriteSBitLong( bf, val, sizeof(short ) << 3 );
- + MSG_WriteUBitLong( sb, val, sizeof( word ) << 3 );
- }
- -void MSG_WriteWord( sizebuf_t *bf, int val )
- +void MSG_WriteLong( sizebuf_t *sb, long val )
- {
- - MSG_WriteUBitLong( bf, val, sizeof( word ) << 3 );
- + MSG_WriteSBitLong( sb, val, sizeof( long ) << 3 );
- }
- -void MSG_WriteLong( sizebuf_t *bf, long val )
- +void MSG_WriteDword( sizebuf_t *sb, dword val )
- {
- - MSG_WriteSBitLong( bf, val, sizeof( long ) << 3 );
- + MSG_WriteUBitLong( sb, val, sizeof( dword ) << 3 );
- }
- -void MSG_WriteFloat( sizebuf_t *bf, float val )
- +void MSG_WriteFloat( sizebuf_t *sb, float val )
- {
- - MSG_WriteBits( bf, &val, sizeof( val ) << 3 );
- + MSG_WriteBits( sb, &val, sizeof( val ) << 3 );
- }
- -qboolean MSG_WriteBytes( sizebuf_t *bf, const void *pBuf, int nBytes )
- +qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes )
- {
- - return MSG_WriteBits( bf, pBuf, nBytes << 3 );
- + return MSG_WriteBits( sb, pBuf, nBytes << 3 );
- }
- -qboolean MSG_WriteString( sizebuf_t *bf, const char *pStr )
- +qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr )
- {
- if( pStr )
- {
- do
- {
- - MSG_WriteChar( bf, *pStr );
- + MSG_WriteChar( sb, *pStr );
- pStr++;
- } while( *( pStr - 1 ));
- }
- - else MSG_WriteChar( bf, 0 );
- + else MSG_WriteChar( sb, 0 );
- - return !bf->bOverflow;
- + return !sb->bOverflow;
- }
- -int MSG_ReadOneBit( sizebuf_t *bf )
- +int MSG_ReadOneBit( sizebuf_t *sb )
- {
- - if( !MSG_Overflow( bf, 1 ))
- + if( !MSG_Overflow( sb, 1 ))
- {
- - int value = bf->pData[bf->iCurBit >> 3] & (1 << ( bf->iCurBit & 7 ));
- - bf->iCurBit++;
- + int value = sb->pData[sb->iCurBit >> 3] & (1 << ( sb->iCurBit & 7 ));
- + sb->iCurBit++;
- return !!value;
- }
- return 0;
- }
- -uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits )
- +uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
- {
- int idword1;
- uint dword1, ret;
- if( numbits == 8 )
- {
- - int leftBits = MSG_GetNumBitsLeft( bf );
- + int leftBits = MSG_GetNumBitsLeft( sb );
- if( leftBits >= 0 && leftBits < 8 )
- return 0; // end of message
- }
- - if(( bf->iCurBit + numbits ) > bf->nDataBits )
- + if(( sb->iCurBit + numbits ) > sb->nDataBits )
- {
- - bf->bOverflow = true;
- - bf->iCurBit = bf->nDataBits;
- + sb->bOverflow = true;
- + sb->iCurBit = sb->nDataBits;
- return 0;
- }
- - ASSERT( numbits > 0 && numbits <= 32 );
- + Assert( numbits > 0 && numbits <= 32 );
- // Read the current dword.
- - idword1 = bf->iCurBit >> 5;
- - dword1 = ((uint *)bf->pData)[idword1];
- - dword1 >>= ( bf->iCurBit & 31 ); // get the bits we're interested in.
- + idword1 = sb->iCurBit >> 5;
- + dword1 = ((uint *)sb->pData)[idword1];
- + dword1 >>= ( sb->iCurBit & 31 ); // get the bits we're interested in.
- - bf->iCurBit += numbits;
- + sb->iCurBit += numbits;
- ret = dword1;
- // Does it span this dword?
- - if(( bf->iCurBit - 1 ) >> 5 == idword1 )
- + if(( sb->iCurBit - 1 ) >> 5 == idword1 )
- {
- if( numbits != 32 )
- ret &= ExtraMasks[numbits];
- }
- else
- {
- - int nExtraBits = bf->iCurBit & 31;
- - uint dword2 = ((uint *)bf->pData)[idword1+1] & ExtraMasks[nExtraBits];
- + int nExtraBits = sb->iCurBit & 31;
- + uint dword2 = ((uint *)sb->pData)[idword1+1] & ExtraMasks[nExtraBits];
- // no need to mask since we hit the end of the dword.
- // shift the second dword's part into the high bits.
- @@ -401,33 +396,33 @@ uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits )
- return ret;
- }
- -float MSG_ReadBitFloat( sizebuf_t *bf )
- +float MSG_ReadBitFloat( sizebuf_t *sb )
- {
- long val;
- int bit, byte;
- - ASSERT( sizeof( float ) == sizeof( long ));
- - ASSERT( sizeof( float ) == 4 );
- + Assert( sizeof( float ) == sizeof( long ));
- + Assert( sizeof( float ) == 4 );
- - if( MSG_Overflow( bf, 32 ))
- + if( MSG_Overflow( sb, 32 ))
- return 0.0f;
- - bit = bf->iCurBit & 0x7;
- - byte = bf->iCurBit >> 3;
- + bit = sb->iCurBit & 0x7;
- + byte = sb->iCurBit >> 3;
- - val = bf->pData[byte] >> bit;
- - val |= ((int)bf->pData[byte + 1]) << ( 8 - bit );
- - val |= ((int)bf->pData[byte + 2]) << ( 16 - bit );
- - val |= ((int)bf->pData[byte + 3]) << ( 24 - bit );
- + val = sb->pData[byte] >> bit;
- + val |= ((int)sb->pData[byte + 1]) << ( 8 - bit );
- + val |= ((int)sb->pData[byte + 2]) << ( 16 - bit );
- + val |= ((int)sb->pData[byte + 3]) << ( 24 - bit );
- if( bit != 0 )
- - val |= ((int)bf->pData[byte + 4]) << ( 32 - bit );
- - bf->iCurBit += 32;
- + val |= ((int)sb->pData[byte + 4]) << ( 32 - bit );
- + sb->iCurBit += 32;
- return *((float *)&val);
- }
- -qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
- +qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
- {
- byte *pOut = (byte *)pOutData;
- int nBitsLeft = nBits;
- @@ -435,7 +430,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
- // get output dword-aligned.
- while((( dword )pOut & 3) != 0 && nBitsLeft >= 8 )
- {
- - *pOut = (byte)MSG_ReadUBitLong( bf, 8 );
- + *pOut = (byte)MSG_ReadUBitLong( sb, 8 );
- ++pOut;
- nBitsLeft -= 8;
- }
- @@ -443,7 +438,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
- // read dwords.
- while( nBitsLeft >= 32 )
- {
- - *((dword *)pOut) = MSG_ReadUBitLong( bf, 32 );
- + *((dword *)pOut) = MSG_ReadUBitLong( sb, 32 );
- pOut += sizeof( dword );
- nBitsLeft -= 32;
- }
- @@ -451,7 +446,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
- // read the remaining bytes.
- while( nBitsLeft >= 8 )
- {
- - *pOut = MSG_ReadUBitLong( bf, 8 );
- + *pOut = MSG_ReadUBitLong( sb, 8 );
- ++pOut;
- nBitsLeft -= 8;
- }
- @@ -459,20 +454,20 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
- // read the remaining bits.
- if( nBitsLeft )
- {
- - *pOut = MSG_ReadUBitLong( bf, nBitsLeft );
- + *pOut = MSG_ReadUBitLong( sb, nBitsLeft );
- }
- - return !bf->bOverflow;
- + return !sb->bOverflow;
- }
- -float MSG_ReadBitAngle( sizebuf_t *bf, int numbits )
- +float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
- {
- float fReturn, shift;
- int i;
- shift = (float)( 1 << numbits );
- - i = MSG_ReadUBitLong( bf, numbits );
- + i = MSG_ReadUBitLong( sb, numbits );
- fReturn = (float)i * ( 360.0f / shift );
- // clamp the finale angle
- @@ -483,83 +478,89 @@ float MSG_ReadBitAngle( sizebuf_t *bf, int numbits )
- }
- // Append numbits least significant bits from data to the current bit stream
- -int MSG_ReadSBitLong( sizebuf_t *bf, int numbits )
- +int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
- {
- int r, sign;
- - r = MSG_ReadUBitLong( bf, numbits - 1 );
- + r = MSG_ReadUBitLong( sb, numbits - 1 );
- // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
- // (Some old code writes direct integers right into the buffer).
- - sign = MSG_ReadOneBit( bf );
- + sign = MSG_ReadOneBit( sb );
- if( sign ) r = -( BIT( numbits - 1 ) - r );
- return r;
- }
- -uint MSG_ReadBitLong( sizebuf_t *bf, int numbits, qboolean bSigned )
- +uint MSG_ReadBitLong( sizebuf_t *sb, int numbits, qboolean bSigned )
- {
- if( bSigned )
- - return (uint)MSG_ReadSBitLong( bf, numbits );
- - return MSG_ReadUBitLong( bf, numbits );
- + return (uint)MSG_ReadSBitLong( sb, numbits );
- + return MSG_ReadUBitLong( sb, numbits );
- }
- -int MSG_ReadChar( sizebuf_t *bf )
- +int MSG_ReadChar( sizebuf_t *sb )
- {
- - return MSG_ReadSBitLong( bf, sizeof( char ) << 3 );
- + return MSG_ReadSBitLong( sb, sizeof( char ) << 3 );
- }
- -int MSG_ReadByte( sizebuf_t *bf )
- +int MSG_ReadByte( sizebuf_t *sb )
- {
- - return MSG_ReadUBitLong( bf, sizeof( byte ) << 3 );
- + return MSG_ReadUBitLong( sb, sizeof( byte ) << 3 );
- }
- -int MSG_ReadShort( sizebuf_t *bf )
- +int MSG_ReadShort( sizebuf_t *sb )
- {
- - return MSG_ReadSBitLong( bf, sizeof( short ) << 3 );
- + return MSG_ReadSBitLong( sb, sizeof( short ) << 3 );
- }
- -int MSG_ReadWord( sizebuf_t *bf )
- +int MSG_ReadWord( sizebuf_t *sb )
- {
- - return MSG_ReadUBitLong( bf, sizeof( word ) << 3 );
- + return MSG_ReadUBitLong( sb, sizeof( word ) << 3 );
- }
- -float MSG_ReadCoord( sizebuf_t *bf )
- +float MSG_ReadCoord( sizebuf_t *sb )
- {
- // g-cont. we loose precision here but keep old size of coord variable!
- - if( host.features & ENGINE_WRITE_LARGE_COORD )
- - return (float)(MSG_ReadShort( bf ) * ( 1.0f / 2.0f ));
- - return (float)(MSG_ReadShort( bf ) * ( 1.0f / 8.0f ));
- + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
- + return (float)(MSG_ReadShort( sb ) * ( 1.0f / 2.0f ));
- + return (float)(MSG_ReadShort( sb ) * ( 1.0f / 8.0f ));
- }
- -void MSG_ReadVec3Coord( sizebuf_t *bf, vec3_t fa )
- +void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa )
- {
- - fa[0] = MSG_ReadCoord( bf );
- - fa[1] = MSG_ReadCoord( bf );
- - fa[2] = MSG_ReadCoord( bf );
- + fa[0] = MSG_ReadCoord( sb );
- + fa[1] = MSG_ReadCoord( sb );
- + fa[2] = MSG_ReadCoord( sb );
- }
- -long MSG_ReadLong( sizebuf_t *bf )
- +long MSG_ReadLong( sizebuf_t *sb )
- {
- - return MSG_ReadSBitLong( bf, sizeof( long ) << 3 );
- + return MSG_ReadSBitLong( sb, sizeof( long ) << 3 );
- }
- -float MSG_ReadFloat( sizebuf_t *bf )
- +dword MSG_ReadDword( sizebuf_t *sb )
- +{
- + return MSG_ReadUBitLong( sb, sizeof( dword ) << 3 );
- +}
- +
- +float MSG_ReadFloat( sizebuf_t *sb )
- {
- float ret;
- - ASSERT( sizeof( ret ) == 4 );
- - MSG_ReadBits( bf, &ret, 32 );
- + Assert( sizeof( ret ) == 4 );
- +
- + MSG_ReadBits( sb, &ret, 32 );
- return ret;
- }
- -qboolean MSG_ReadBytes( sizebuf_t *bf, void *pOut, int nBytes )
- +qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
- {
- - return MSG_ReadBits( bf, pOut, nBytes << 3 );
- + return MSG_ReadBits( sb, pOut, nBytes << 3 );
- }
- -char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
- +char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
- {
- static char string[MAX_SYSPATH];
- int l = 0, c;
- @@ -567,7 +568,7 @@ char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
- do
- {
- // use MSG_ReadByte so -1 is out of bounds
- - c = MSG_ReadByte( bf );
- + c = MSG_ReadByte( sb );
- if( c == 0 ) break;
- else if( bLine && c == '\n' )
- @@ -585,20 +586,20 @@ char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
- return string;
- }
- -void MSG_ExciseBits( sizebuf_t *bf, int startbit, int bitstoremove )
- +void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
- {
- int i, endbit = startbit + bitstoremove;
- - int remaining_to_end = bf->nDataBits - endbit;
- + int remaining_to_end = sb->nDataBits - endbit;
- sizebuf_t temp;
- - MSG_StartWriting( &temp, bf->pData, bf->nDataBits << 3, startbit, -1 );
- - MSG_SeekToBit( bf, endbit );
- + MSG_StartWriting( &temp, sb->pData, sb->nDataBits << 3, startbit, -1 );
- + MSG_SeekToBit( sb, endbit );
- for( i = 0; i < remaining_to_end; i++ )
- {
- - MSG_WriteOneBit( &temp, MSG_ReadOneBit( bf ));
- + MSG_WriteOneBit( &temp, MSG_ReadOneBit( sb ));
- }
- - MSG_SeekToBit( bf, startbit );
- - bf->nDataBits -= bitstoremove;
- + MSG_SeekToBit( sb, startbit );
- + sb->nDataBits -= bitstoremove;
- }
- \ No newline at end of file
- diff --git b/engine/common/net_buffer.h a/engine/common/net_buffer.h
- index 674ad65..c8c6fd1 100644
- --- b/engine/common/net_buffer.h
- +++ a/engine/common/net_buffer.h
- @@ -45,80 +45,81 @@ typedef struct sizebuf_s
- int nDataBits;
- } sizebuf_t;
- -#define MSG_WriteUBitLong( bf, data, bits ) MSG_WriteUBitLongExt( bf, data, bits, true );
- #define MSG_StartReading MSG_StartWriting
- #define MSG_GetNumBytesRead MSG_GetNumBytesWritten
- #define MSG_GetRealBytesRead MSG_GetRealBytesWritten
- #define MSG_GetNumBitsRead MSG_GetNumBitsWritten
- #define MSG_ReadBitAngles MSG_ReadBitVec3Coord
- -#define MSG_ReadString( bf ) MSG_ReadStringExt( bf, false )
- -#define MSG_ReadStringLine( bf ) MSG_ReadStringExt( bf, true )
- -#define MSG_ReadAngle( bf ) (float)(MSG_ReadChar( bf ) * ( 360.0f / 256.0f ))
- -#define MSG_Init( bf, name, data, bytes ) MSG_InitExt( bf, name, data, bytes, -1 )
- +#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
- +#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
- +#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
- +#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
- // common functions
- -void MSG_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
- +void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
- void MSG_InitMasks( void ); // called once at startup engine
- -void MSG_SeekToBit( sizebuf_t *bf, int bitPos );
- -void MSG_SeekToByte( sizebuf_t *bf, int bytePos );
- -void MSG_ExciseBits( sizebuf_t *bf, int startbit, int bitstoremove );
- -qboolean MSG_CheckOverflow( sizebuf_t *bf );
- +void MSG_SeekToBit( sizebuf_t *sb, int bitPos );
- +void MSG_SeekToByte( sizebuf_t *sb, int bytePos );
- +void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
- +qboolean MSG_CheckOverflow( sizebuf_t *sb );
- short MSG_BigShort( short swap );
- // init writing
- -void MSG_StartWriting( sizebuf_t *bf, void *pData, int nBytes, int iStartBit, int nBits );
- -void MSG_Clear( sizebuf_t *bf );
- +void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
- +void MSG_Clear( sizebuf_t *sb );
- // Bit-write functions
- -void MSG_WriteOneBit( sizebuf_t *bf, int nValue );
- -void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bCheckRange );
- -void MSG_WriteSBitLong( sizebuf_t *bf, int data, int numbits );
- -void MSG_WriteBitLong( sizebuf_t *bf, uint data, int numbits, qboolean bSigned );
- -qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits );
- -void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits );
- -void MSG_WriteBitFloat( sizebuf_t *bf, float val );
- +void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
- +void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
- +void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
- +void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
- +qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
- +void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits );
- +void MSG_WriteBitFloat( sizebuf_t *sb, float val );
- // Byte-write functions
- -void MSG_WriteChar( sizebuf_t *bf, int val );
- -void MSG_WriteByte( sizebuf_t *bf, int val );
- -void MSG_WriteShort( sizebuf_t *bf, int val );
- -void MSG_WriteWord( sizebuf_t *bf, int val );
- -void MSG_WriteLong( sizebuf_t *bf, long val );
- -void MSG_WriteCoord( sizebuf_t *bf, float val );
- -void MSG_WriteFloat( sizebuf_t *bf, float val );
- -void MSG_WriteVec3Coord( sizebuf_t *bf, const float *fa );
- -qboolean MSG_WriteBytes( sizebuf_t *bf, const void *pBuf, int nBytes ); // same as MSG_WriteData
- -qboolean MSG_WriteString( sizebuf_t *bf, const char *pStr ); // returns false if it overflows the buffer.
- +void MSG_WriteChar( sizebuf_t *sb, int val );
- +void MSG_WriteByte( sizebuf_t *sb, int val );
- +void MSG_WriteShort( sizebuf_t *sb, int val );
- +void MSG_WriteWord( sizebuf_t *sb, int val );
- +void MSG_WriteLong( sizebuf_t *sb, long val );
- +void MSG_WriteDword( sizebuf_t *sb, dword val );
- +void MSG_WriteCoord( sizebuf_t *sb, float val );
- +void MSG_WriteFloat( sizebuf_t *sb, float val );
- +void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
- +qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
- +qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
- // helper functions
- -_inline int MSG_GetNumBytesWritten( sizebuf_t *bf ) { return BitByte( bf->iCurBit ); }
- -_inline int MSG_GetRealBytesWritten( sizebuf_t *bf ) { return bf->iCurBit >> 3; } // unpadded
- -_inline int MSG_GetNumBitsWritten( sizebuf_t *bf ) { return bf->iCurBit; }
- -_inline int MSG_GetMaxBits( sizebuf_t *bf ) { return bf->nDataBits; }
- -_inline int MSG_GetMaxBytes( sizebuf_t *bf ) { return bf->nDataBits >> 3; }
- -_inline int MSG_GetNumBitsLeft( sizebuf_t *bf ) { return bf->nDataBits - bf->iCurBit; }
- -_inline int MSG_GetNumBytesLeft( sizebuf_t *bf ) { return MSG_GetNumBitsLeft( bf ) >> 3; }
- -_inline byte *MSG_GetData( sizebuf_t *bf ) { return bf->pData; }
- +_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
- +_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
- +_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
- +_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
- +_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
- +_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
- +_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
- +_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
- // Bit-read functions
- -int MSG_ReadOneBit( sizebuf_t *bf );
- -float MSG_ReadBitFloat( sizebuf_t *bf );
- -qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits );
- -float MSG_ReadBitAngle( sizebuf_t *bf, int numbits );
- -int MSG_ReadSBitLong( sizebuf_t *bf, int numbits );
- -uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits );
- -uint MSG_ReadBitLong( sizebuf_t *bf, int numbits, qboolean bSigned );
- +int MSG_ReadOneBit( sizebuf_t *sb );
- +float MSG_ReadBitFloat( sizebuf_t *sb );
- +qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits );
- +float MSG_ReadBitAngle( sizebuf_t *sb, int numbits );
- +int MSG_ReadSBitLong( sizebuf_t *sb, int numbits );
- +uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits );
- +uint MSG_ReadBitLong( sizebuf_t *sb, int numbits, qboolean bSigned );
- // Byte-read functions
- -int MSG_ReadChar( sizebuf_t *bf );
- -int MSG_ReadByte( sizebuf_t *bf );
- -int MSG_ReadShort( sizebuf_t *bf );
- -int MSG_ReadWord( sizebuf_t *bf );
- -long MSG_ReadLong( sizebuf_t *bf );
- -float MSG_ReadCoord( sizebuf_t *bf );
- -float MSG_ReadFloat( sizebuf_t *bf );
- -void MSG_ReadVec3Coord( sizebuf_t *bf, vec3_t fa );
- -qboolean MSG_ReadBytes( sizebuf_t *bf, void *pOut, int nBytes );
- -char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine );
- +int MSG_ReadChar( sizebuf_t *sb );
- +int MSG_ReadByte( sizebuf_t *sb );
- +int MSG_ReadShort( sizebuf_t *sb );
- +int MSG_ReadWord( sizebuf_t *sb );
- +long MSG_ReadLong( sizebuf_t *sb );
- +dword MSG_ReadDword( sizebuf_t *sb );
- +float MSG_ReadCoord( sizebuf_t *sb );
- +float MSG_ReadFloat( sizebuf_t *sb );
- +void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
- +qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
- +char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
- #endif//NET_BUFFER_H
- \ No newline at end of file
- diff --git b/engine/common/net_chan.c a/engine/common/net_chan.c
- index cafa55e..08ea6e7 100644
- --- b/engine/common/net_chan.c
- +++ a/engine/common/net_chan.c
- @@ -17,6 +17,7 @@ GNU General Public License for more details.
- #include "netchan.h"
- #include "mathlib.h"
- #include "net_encode.h"
- +#include "protocol.h"
- #define MAKE_FRAGID( id, count ) ((( id & 0xffff ) << 16 ) | ( count & 0xffff ))
- #define FRAG_GETID( fragid ) (( fragid >> 16 ) & 0xffff )
- @@ -121,7 +122,6 @@ void Netchan_Init( void )
- net_mempool = Mem_AllocPool( "Network Pool" );
- - Huff_Init (); // initialize huffman compression
- MSG_InitMasks (); // initialize bit-masks
- }
- @@ -163,7 +163,6 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport )
- chan->incoming_sequence = 0;
- chan->outgoing_sequence = 1;
- chan->rate = DEFAULT_RATE;
- - chan->compress = false; // work but low efficiency
- chan->qport = qport;
- MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
- @@ -1166,8 +1165,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- qboolean send_reliable_fragment;
- qboolean send_resending = false;
- qboolean send_reliable;
- - size_t size1, size2;
- - uint w1, w2, hdr_size;
- + uint w1, w2;
- int i, j;
- float fRate;
- @@ -1351,9 +1349,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- }
- if( send_reliable && send_reliable_fragment )
- - {
- - w1 |= ( 1 << 30 );
- - }
- + SetBits( w1, BIT( 30 ));
- chan->outgoing_sequence++;
- chan->last_sent = host.realtime;
- @@ -1385,8 +1381,6 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- }
- }
- - hdr_size = MSG_GetNumBytesWritten( &send );
- -
- // copy the reliable message to the packet first
- if( send_reliable )
- {
- @@ -1396,16 +1390,11 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- // is there room for the unreliable payload?
- if( MSG_GetNumBitsLeft( &send ) >= length )
- - {
- MSG_WriteBits( &send, data, length );
- - }
- - else
- - {
- - MsgDev( D_WARN, "Netchan_Transmit: unreliable message overflow\n" );
- - }
- + else MsgDev( D_WARN, "Netchan_Transmit: unreliable message overflow\n" );
- // deal with packets that are too small for some networks
- - if( MSG_GetNumBytesWritten( &send ) < 16 ) // packet too small for some networks
- + if( MSG_GetNumBytesWritten( &send ) < 16 && !NET_IsLocalAddress( chan->remote_address )) // packet too small for some networks
- {
- int i;
- @@ -1413,7 +1402,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- for( i = MSG_GetNumBytesWritten( &send ); i < 16; i++ )
- {
- // NOTE: that the server can parse svc_nop, too.
- - MSG_WriteByte( &send, 1 );
- + MSG_WriteByte( &send, svc_nop );
- }
- }
- @@ -1424,12 +1413,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
- Netchan_UpdateFlow( chan );
- - size1 = MSG_GetNumBytesWritten( &send );
- - if( chan->compress ) Huff_CompressPacket( &send, hdr_size );
- - size2 = MSG_GetNumBytesWritten( &send );
- -
- - chan->total_sended += size2;
- - chan->total_sended_uncompressed += size1;
- + chan->total_sended += MSG_GetNumBytesWritten( &send );
- // send the datagram
- if( !CL_IsPlaybackDemo( ))
- @@ -1488,21 +1472,18 @@ modifies net_message so that it points to the packet payload
- */
- qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
- {
- - uint sequence, sequence_ack, hdr_size;
- + uint sequence, sequence_ack;
- uint reliable_ack, reliable_message;
- uint fragid[MAX_STREAMS] = { 0, 0 };
- qboolean frag_message[MAX_STREAMS] = { false, false };
- int frag_offset[MAX_STREAMS] = { 0, 0 };
- int frag_length[MAX_STREAMS] = { 0, 0 };
- qboolean message_contains_fragments;
- - size_t size1, size2;
- int i, qport;
- if( !CL_IsPlaybackDemo() && !NET_CompareAdr( net_from, chan->remote_address ))
- - {
- return false;
- - }
- -
- +
- // get sequence numbers
- MSG_Clear( msg );
- sequence = MSG_ReadLong( msg );
- @@ -1517,7 +1498,7 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
- reliable_message = sequence >> 31;
- reliable_ack = sequence_ack >> 31;
- - message_contains_fragments = sequence & ( 1 << 30 ) ? true : false;
- + message_contains_fragments = FBitSet( sequence, BIT( 30 )) ? true : false;
- if( message_contains_fragments )
- {
- @@ -1533,9 +1514,9 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
- }
- }
- - sequence &= ~(1<<31);
- - sequence &= ~(1<<30);
- - sequence_ack &= ~(1<<31);
- + sequence &= ~BIT( 31 );
- + sequence &= ~BIT( 30 );
- + sequence_ack &= ~BIT( 31 );
- if( net_showpackets->integer == 2 )
- {
- @@ -1619,14 +1600,8 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
- chan->flow[FLOW_INCOMING].current++;
- Netchan_UpdateFlow( chan );
- - hdr_size = MSG_GetNumBytesRead( msg );
- -
- - size1 = MSG_GetMaxBytes( msg );
- - if( chan->compress ) Huff_DecompressPacket( msg, hdr_size );
- - size2 = MSG_GetMaxBytes( msg );
- - chan->total_received += size1;
- - chan->total_received_uncompressed += size2;
- + chan->total_received += MSG_GetMaxBytes( msg );
- chan->good_count += 1;
- if( message_contains_fragments )
- diff --git b/engine/common/net_encode.c a/engine/common/net_encode.c
- index 7e9c52c..b7a2df9 100644
- --- b/engine/common/net_encode.c
- +++ a/engine/common/net_encode.c
- @@ -375,7 +375,7 @@ void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
- {
- int i;
- - ASSERT( dt != NULL );
- + Assert( dt != NULL );
- // set all fields is active by default
- for( i = 0; i < dt->numFields; i++ )
- @@ -424,7 +424,7 @@ qboolean Delta_AddField( const char *pStructName, const char *pName, int flags,
- // get the delta struct
- dt = Delta_FindStruct( pStructName );
- - ASSERT( dt != NULL );
- + Assert( dt != NULL );
- // check for coexisting field
- for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
- @@ -472,16 +472,16 @@ void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pFiel
- int nameIndex;
- delta_info_t *dt;
- - ASSERT( pField );
- + Assert( pField );
- if( !pField->name || !*pField->name )
- return; // not initialized ?
- dt = Delta_FindStructByIndex( tableIndex );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
- - ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
- + Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
- MSG_WriteByte( msg, svc_deltatable );
- MSG_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables
- @@ -516,10 +516,10 @@ void Delta_ParseTableField( sizebuf_t *msg )
- tableIndex = MSG_ReadUBitLong( msg, 4 );
- dt = Delta_FindStructByIndex( tableIndex );
- - ASSERT( dt != NULL );
- + Assert( dt != NULL );
- nameIndex = MSG_ReadUBitLong( msg, 8 ); // read field name index
- - ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
- + Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
- pName = dt->pInfo[nameIndex].name;
- flags = MSG_ReadUBitLong( msg, 10 );
- bits = MSG_ReadUBitLong( msg, 5 ) + 1;
- @@ -695,7 +695,7 @@ void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encode
- // assume we have handled '{'
- while(( *delta_script = COM_ParseFile( *delta_script, token )) != NULL )
- {
- - ASSERT( dt->numFields <= dt->maxFields );
- + Assert( dt->numFields <= dt->maxFields );
- if( !Q_strcmp( token, "DEFINE_DELTA" ))
- {
- @@ -747,9 +747,10 @@ void Delta_InitFields( void )
- while(( pfile = COM_ParseFile( pfile, token )) != NULL )
- {
- dt = Delta_FindStruct( token );
- +
- if( dt == NULL )
- {
- - Sys_Error( "delta.lst: unknown struct %s\n", token );
- + Sys_Error( "%s: unknown struct %s\n", DELTA_PATH, token );
- }
- pfile = COM_ParseFile( pfile, encodeDll );
- @@ -760,10 +761,11 @@ void Delta_InitFields( void )
- // jump to '{'
- pfile = COM_ParseFile( pfile, token );
- +
- if( token[0] != '{' )
- {
- - Sys_Error( "delta.lst: missing '{' in section %s\n", dt->pName );
- - }
- + Sys_Error( "%s: missing '{' in section %s\n", DELTA_PATH, dt->pName );
- + }
- Delta_ParseTable( &pfile, dt, encodeDll, encodeFunc );
- }
- @@ -787,7 +789,7 @@ void Delta_Init( void )
- dt = Delta_FindStruct( "movevars_t" );
- - ASSERT( dt != NULL );
- + Assert( dt != NULL );
- if( dt->bInitialized ) return; // "movevars_t" already specified by user
- // create movevars_t delta internal
- @@ -804,15 +806,19 @@ void Delta_Init( void )
- Delta_AddField( "movevars_t", "bounce", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
- Delta_AddField( "movevars_t", "stepsize", DT_FLOAT|DT_SIGNED, 16, 16.0f, 1.0f );
- Delta_AddField( "movevars_t", "maxvelocity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
- - Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 18, 1.0f, 1.0f ); // no fractional part
- +
- + if( host.features & ENGINE_WRITE_LARGE_COORD )
- + Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 18, 1.0f, 1.0f );
- + else Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
- +
- Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 16.0f, 8.0f );
- Delta_AddField( "movevars_t", "skyName", DT_STRING, 1, 1.0f, 1.0f );
- Delta_AddField( "movevars_t", "footsteps", DT_INTEGER, 1, 1.0f, 1.0f );
- Delta_AddField( "movevars_t", "rollangle", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
- Delta_AddField( "movevars_t", "rollspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
- - Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f ); // 0 - 264
- - Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f );
- - Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f );
- + Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f ); // 0 - 264
- + Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
- + Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
- Delta_AddField( "movevars_t", "skyvec_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1
- Delta_AddField( "movevars_t", "skyvec_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
- Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
- @@ -822,6 +828,7 @@ void Delta_Init( void )
- Delta_AddField( "movevars_t", "skyangle", DT_ANGLE, 16, 1.0f, 1.0f ); // 0 - 360
- Delta_AddField( "movevars_t", "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
- Delta_AddField( "movevars_t", "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f );
- +
- // now done
- dt->bInitialized = true;
- }
- @@ -964,9 +971,9 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba
- float val_a, val_b;
- int fromF, toF;
- - ASSERT( pField );
- - ASSERT( from );
- - ASSERT( to );
- + Assert( pField );
- + Assert( from );
- + Assert( to );
- if( pField->bInactive )
- return true;
- @@ -1027,7 +1034,7 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba
- if( pField->multiplier != 1.0f ) fromF *= pField->multiplier;
- if( pField->multiplier != 1.0f ) toF *= pField->multiplier;
- }
- - else if( pField->flags & ( DT_FLOAT|DT_ANGLE ))
- + else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
- {
- // don't convert floats to integers
- fromF = *((int *)((byte *)from + pField->offset ));
- @@ -1145,7 +1152,7 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to
- else if( pField->flags & DT_TIMEWINDOW_BIG )
- {
- flValue = *(float *)((byte *)to + pField->offset );
- - flTime = (timebase * pField->multiplier) - (flValue * pField->multiplier);
- + flTime = Q_rint( timebase * pField->multiplier ) - Q_rint( flValue * pField->multiplier );
- iValue = (uint)abs( flTime );
- MSG_WriteBitLong( msg, iValue, pField->bits, bSigned );
- @@ -1177,7 +1184,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to,
- bChanged = MSG_ReadOneBit( msg );
- - ASSERT( pField->multiplier != 0.0f );
- + Assert( pField->multiplier != 0.0f );
- if( pField->flags & DT_BYTE )
- {
- @@ -1308,10 +1315,10 @@ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
- int i;
- dt = Delta_FindStruct( "usercmd_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // activate fields and call custom encode func
- Delta_CustomEncode( dt, from, to );
- @@ -1335,10 +1342,10 @@ void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
- int i;
- dt = Delta_FindStruct( "usercmd_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- *to = *from;
- @@ -1368,10 +1375,10 @@ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
- int i;
- dt = Delta_FindStruct( "event_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // activate fields and call custom encode func
- Delta_CustomEncode( dt, from, to );
- @@ -1395,10 +1402,10 @@ void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
- int i;
- dt = Delta_FindStruct( "event_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- *to = *from;
- @@ -1424,10 +1431,10 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t
- int numChanges = 0;
- dt = Delta_FindStruct( "movevars_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- startBit = msg->iCurBit;
- @@ -1459,10 +1466,10 @@ void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
- int i;
- dt = Delta_FindStruct( "movevars_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- *to = *from;
- @@ -1495,10 +1502,10 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to,
- int i;
- dt = Delta_FindStruct( "clientdata_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // activate fields and call custom encode func
- Delta_CustomEncode( dt, from, to );
- @@ -1524,10 +1531,10 @@ void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, f
- int i;
- dt = Delta_FindStruct( "clientdata_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- *to = *from;
- @@ -1561,10 +1568,10 @@ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to
- int numChanges = 0;
- dt = Delta_FindStruct( "weapon_data_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // activate fields and call custom encode func
- Delta_CustomEncode( dt, from, to );
- @@ -1599,10 +1606,10 @@ void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to,
- int i;
- dt = Delta_FindStruct( "weapon_data_t" );
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- *to = *from;
- @@ -1666,10 +1673,11 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
- MSG_WriteWord( msg, to->number );
- MSG_WriteUBitLong( msg, 0, 2 ); // alive
- - if( to->entityType != from->entityType )
- + if( force || ( to->entityType != from->entityType ))
- {
- MSG_WriteOneBit( msg, 1 );
- MSG_WriteUBitLong( msg, to->entityType, 2 );
- + numChanges++;
- }
- else MSG_WriteOneBit( msg, 0 );
- @@ -1689,10 +1697,10 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
- dt = Delta_FindStruct( "custom_entity_state_t" );
- }
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // activate fields and call custom encode func
- Delta_CustomEncode( dt, from, to );
- @@ -1772,10 +1780,10 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
- dt = Delta_FindStruct( "custom_entity_state_t" );
- }
- - ASSERT( dt && dt->bInitialized );
- + Assert( dt && dt->bInitialized );
- pField = dt->pFields;
- - ASSERT( pField );
- + Assert( pField );
- // process fields
- for( i = 0; i < dt->numFields; i++, pField++ )
- diff --git b/engine/common/net_huff.c a/engine/common/net_huff.c
- deleted file mode 100644
- index a851d51..0000000
- diff --git b/engine/common/netchan.h a/engine/common/netchan.h
- index 8d59a9c..228f9f3 100644
- --- b/engine/common/netchan.h
- +++ a/engine/common/netchan.h
- @@ -38,7 +38,7 @@ GNU General Public License for more details.
- // NETWORKING INFO
- // This is the packet payload without any header bytes (which are attached for actual sending)
- -#define NET_MAX_PAYLOAD 80000
- +#define NET_MAX_PAYLOAD 96000
- // This is the payload plus any header info (excluding UDP header)
- @@ -59,12 +59,13 @@ GNU General Public License for more details.
- // bytes will be stripped by the networking channel layer
- #define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
- -#define MASTERSERVER_ADR "celest.in:27010"
- +#define MASTERSERVER_ADR "ms.xash.su:27010"
- #define PORT_MASTER 27010
- #define PORT_CLIENT 27005
- #define PORT_SERVER 27015
- #define MULTIPLAYER_BACKUP 64 // how many data slots to use when in multiplayer (must be power of 2)
- #define SINGLEPLAYER_BACKUP 16 // same for single player
- +#define NUM_PACKET_ENTITIES 128
- /*
- ==============================================================
- @@ -130,9 +131,7 @@ typedef struct netchan_s
- netsrc_t sock; // NS_SERVER or NS_CLIENT, depending on channel.
- netadr_t remote_address; // address this channel is talking to.
- int qport; // qport value to write when transmitting
- -
- - qboolean compress; // enable huffman compression
- -
- +
- double last_received; // for timeouts
- double last_sent; // for retransmits
- @@ -185,10 +184,7 @@ typedef struct netchan_s
- // added for net_speeds
- size_t total_sended;
- - size_t total_sended_uncompressed;
- -
- size_t total_received;
- - size_t total_received_uncompressed;
- } netchan_t;
- extern netadr_t net_from;
- @@ -216,9 +212,4 @@ qboolean Netchan_CanPacket( netchan_t *chan );
- void Netchan_FragSend( netchan_t *chan );
- void Netchan_Clear( netchan_t *chan );
- -// huffman compression
- -void Huff_Init( void );
- -void Huff_CompressPacket( sizebuf_t *msg, int offset );
- -void Huff_DecompressPacket( sizebuf_t *msg, int offset );
- -
- #endif//NET_MSG_H
- \ No newline at end of file
- diff --git b/engine/common/pm_trace.c a/engine/common/pm_trace.c
- index 49e7b51..af087cf 100644
- --- b/engine/common/pm_trace.c
- +++ a/engine/common/pm_trace.c
- @@ -117,7 +117,8 @@ hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
- {
- hull_t *hull;
- - ASSERT( pe && pe->model != NULL );
- + Assert( pe != NULL );
- + Assert( pe->model != NULL );
- switch( pmove->usehull )
- {
- @@ -135,7 +136,7 @@ hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
- break;
- }
- - ASSERT( hull != NULL );
- + Assert( hull != NULL );
- // force to use hull0 because other hulls doesn't exist for water
- if( pe->model->flags & MODEL_LIQUID && pe->solid != SOLID_TRIGGER )
- @@ -202,7 +203,7 @@ qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec
- }
- if( num < hull->firstclipnode || num > hull->lastclipnode )
- - Sys_Error( "PM_RecursiveHullCheck: bad node number\n" );
- + Host_Error( "PM_RecursiveHullCheck: bad node number %i\n", num );
- // find the point distances
- node = hull->clipnodes + num;
- diff --git b/engine/common/protocol.h a/engine/common/protocol.h
- index eac68b2..bb6b1df 100644
- --- b/engine/common/protocol.h
- +++ a/engine/common/protocol.h
- @@ -65,6 +65,7 @@ GNU General Public License for more details.
- #define svc_resourcelist 43 // [short][...]
- #define svc_deltamovevars 44 // [movevars_t]
- #define svc_customization 45 // <see code>
- +
- #define svc_crosshairangle 47 // [byte][byte]
- #define svc_soundfade 48 // [float*4] sound fade parms
- @@ -88,7 +89,7 @@ GNU General Public License for more details.
- #define clc_requestcvarvalue 9
- #define clc_requestcvarvalue2 10
- -#define MAX_VISIBLE_PACKET 512 // 512 visible entities per frame (hl1 has 256)
- +#define MAX_VISIBLE_PACKET 1024 // 1024 visible entities per frame (hl1 has 256)
- // additional protocol data
- #define MAX_CLIENT_BITS 5
- diff --git b/engine/common/random.c a/engine/common/random.c
- index ae84496..bbadde5 100644
- --- b/engine/common/random.c
- +++ a/engine/common/random.c
- @@ -23,9 +23,9 @@ static long idum = 0;
- #define IQ 127773
- #define IR 2836
- #define NTAB 32
- -#define NDIV (1+(IM-1)/NTAB)
- -#define AM (1.0/IM)
- #define EPS 1.2e-7
- +#define NDIV (1 + (IM - 1) / NTAB)
- +#define AM (1.0 / IM)
- #define RNMX (1.0 - EPS)
- void COM_SetRandomSeed( long lSeed )
- @@ -41,15 +41,14 @@ void COM_SetRandomSeed( long lSeed )
- long lran1( void )
- {
- - int j;
- - long k;
- + static long iy = 0;
- + static long iv[NTAB];
- + int j;
- + long k;
- - static long iy = 0;
- - static long iv[NTAB];
- -
- if( idum <= 0 || !iy )
- {
- - if(-(idum) < 1) idum=1;
- + if( -(idum) < 1 ) idum = 1;
- else idum = -(idum);
- for( j = NTAB + 7; j >= 0; j-- )
- @@ -59,10 +58,11 @@ long lran1( void )
- if( idum < 0 ) idum += IM;
- if( j < NTAB ) iv[j] = idum;
- }
- +
- iy = iv[0];
- }
- - k = (idum)/IQ;
- + k = (idum) / IQ;
- idum = IA * (idum - k * IQ) - IR * k;
- if( idum < 0 ) idum += IM;
- j = iy / NDIV;
- @@ -72,7 +72,7 @@ long lran1( void )
- return iy;
- }
- -// fran1 -- return a random floating-point number on the interval [0,1)
- +// fran1 -- return a random floating-point number on the interval [0,1]
- float fran1( void )
- {
- float temp = (float)AM * lran1();
- @@ -85,20 +85,20 @@ float Com_RandomFloat( float flLow, float flHigh )
- {
- float fl;
- - if( idum == 0 ) COM_SetRandomSeed(0);
- + if( idum == 0 ) COM_SetRandomSeed( 0 );
- - fl = fran1(); // float in [0, 1)
- + fl = fran1(); // float in [0,1]
- return (fl * (flHigh - flLow)) + flLow; // float in [low, high)
- }
- long Com_RandomLong( long lLow, long lHigh )
- {
- dword maxAcceptable;
- - dword n, x = lHigh-lLow + 1;
- + dword n, x = lHigh - lLow + 1;
- - if( idum == 0 ) COM_SetRandomSeed(0);
- + if( idum == 0 ) COM_SetRandomSeed( 0 );
- - if( x <= 0 || MAX_RANDOM_RANGE < x-1 )
- + if( x <= 0 || MAX_RANDOM_RANGE < x - 1 )
- return lLow;
- // The following maps a uniform distribution on the interval [0, MAX_RANDOM_RANGE]
- @@ -108,7 +108,7 @@ long Com_RandomLong( long lLow, long lHigh )
- // the average number of times through the loop is 2. For cases where x is
- // much smaller than MAX_RANDOM_RANGE, the average number of times through the
- // loop is very close to 1.
- - maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE+1) % x );
- + maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x );
- do
- {
- n = lran1();
- diff --git b/engine/common/soundlib/snd_mp3.c a/engine/common/soundlib/snd_mp3.c
- index 1b901d3..e697cec 100644
- --- b/engine/common/soundlib/snd_mp3.c
- +++ a/engine/common/soundlib/snd_mp3.c
- @@ -119,7 +119,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
- outsize = ( sound.size - bytesWrite );
- else outsize = mpeg.outsize;
- - Q_memcpy( &sound.wav[bytesWrite], mpeg.out, outsize );
- + memcpy( &sound.wav[bytesWrite], mpeg.out, outsize );
- bytesWrite += outsize;
- }
- @@ -218,7 +218,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
- mpeg_t *mpg;
- mpg = (mpeg_t *)stream->ptr;
- - ASSERT( mpg != NULL );
- + Assert( mpg != NULL );
- while( 1 )
- {
- @@ -262,7 +262,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
- // copy raw sample to output buffer
- data = (byte *)buffer + bytesWritten;
- - Q_memcpy( data, &mpg->out[stream->buffsize], outsize );
- + memcpy( data, &mpg->out[stream->buffsize], outsize );
- bytesWritten += outsize;
- mpg->outsize -= outsize;
- stream->buffsize += outsize;
- diff --git b/engine/common/soundlib/snd_utils.c a/engine/common/soundlib/snd_utils.c
- index 43670b8..45f50cc 100644
- --- b/engine/common/soundlib/snd_utils.c
- +++ a/engine/common/soundlib/snd_utils.c
- @@ -88,7 +88,7 @@ byte *Sound_Copy( size_t size )
- byte *out;
- out = Mem_Alloc( host.soundpool, size );
- - Q_memcpy( out, sound.tempbuffer, size );
- + memcpy( out, sound.tempbuffer, size );
- return out;
- }
- diff --git b/engine/common/soundlib/snd_wav.c a/engine/common/soundlib/snd_wav.c
- index 8b2e212..da934d0 100644
- --- b/engine/common/soundlib/snd_wav.c
- +++ a/engine/common/soundlib/snd_wav.c
- @@ -270,7 +270,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize )
- if(( filesize - hdr_size ) < 16384 )
- {
- sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, 16384 );
- - Q_memcpy( sound.tempbuffer, buffer + (iff_dataPtr - buffer), filesize - hdr_size );
- + memcpy( sound.tempbuffer, buffer + (iff_dataPtr - buffer), filesize - hdr_size );
- return Sound_LoadMPG( name, sound.tempbuffer, 16384 );
- }
- @@ -281,7 +281,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize )
- sound.size = sound.samples * sound.width * sound.channels;
- sound.wav = Mem_Alloc( host.soundpool, sound.size );
- - Q_memcpy( sound.wav, buffer + (iff_dataPtr - buffer), sound.size );
- + memcpy( sound.wav, buffer + (iff_dataPtr - buffer), sound.size );
- // now convert 8-bit sounds to signed
- if( sound.width == 1 )
- diff --git b/engine/common/sys_win.c a/engine/common/sys_win.c
- index 038e8db..68a2e7e 100644
- --- b/engine/common/sys_win.c
- +++ a/engine/common/sys_win.c
- @@ -48,8 +48,15 @@ create buffer, that contain clipboard
- */
- char *Sys_GetClipboardData( void )
- {
- - char *data = NULL;
- - char *cliptext;
- + static char *data = NULL;
- + char *cliptext;
- +
- + if( data )
- + {
- + // release previous cbd
- + Z_Free( data );
- + data = NULL;
- + }
- if( OpenClipboard( NULL ) != 0 )
- {
- @@ -66,6 +73,7 @@ char *Sys_GetClipboardData( void )
- }
- CloseClipboard();
- }
- +
- return data;
- }
- @@ -259,9 +267,9 @@ qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size )
- {
- int argc = Sys_CheckParm( parm );
- - if( !argc ) return false;
- - if( !out ) return false;
- - if( !host.argv[argc + 1] ) return false;
- + if( !argc || !out || !host.argv[argc + 1] )
- + return false;
- +
- Q_strncpy( out, host.argv[argc+1], size );
- return true;
- @@ -534,8 +542,8 @@ print into window console
- void Sys_Print( const char *pMsg )
- {
- const char *msg;
- - char buffer[32768];
- - char logbuf[32768];
- + char buffer[MAX_PRINT_MSG];
- + char logbuf[MAX_PRINT_MSG];
- char *b = buffer;
- char *c = logbuf;
- int i = 0;
- @@ -554,22 +562,20 @@ void Sys_Print( const char *pMsg )
- if( msg[i] == '\n' && msg[i+1] == '\r' )
- {
- b[0] = '\r';
- - b[1] = '\n';
- - c[0] = '\n';
- + b[1] = c[0] = '\n';
- b += 2, c++;
- i++;
- }
- else if( msg[i] == '\r' )
- {
- - b[0] = '\r';
- + b[0] = c[0] = '\r';
- b[1] = '\n';
- - b += 2;
- + b += 2, c++;
- }
- else if( msg[i] == '\n' )
- {
- b[0] = '\r';
- - b[1] = '\n';
- - c[0] = '\n';
- + b[1] = c[0] = '\n';
- b += 2, c++;
- }
- else if( msg[i] == '\35' || msg[i] == '\36' || msg[i] == '\37' )
- @@ -588,7 +594,7 @@ void Sys_Print( const char *pMsg )
- i++;
- }
- - *b = *c = 0; // cutoff garbage
- + *b = *c = 0; // terminator
- Sys_PrintLog( logbuf );
- Con_WinPrint( buffer );
- @@ -604,7 +610,7 @@ formatted message
- void Msg( const char *pMsg, ... )
- {
- va_list argptr;
- - char text[8192];
- + char text[MAX_PRINT_MSG];
- va_start( argptr, pMsg );
- Q_vsnprintf( text, sizeof( text ), pMsg, argptr );
- @@ -623,7 +629,7 @@ formatted developer message
- void MsgDev( int level, const char *pMsg, ... )
- {
- va_list argptr;
- - char text[8192];
- + char text[MAX_PRINT_MSG];
- if( host.developer < level ) return;
- @@ -641,7 +647,7 @@ void MsgDev( int level, const char *pMsg, ... )
- break;
- case D_INFO:
- case D_NOTE:
- - case D_AICONSOLE:
- + case D_REPORT:
- Sys_Print( text );
- break;
- }
- diff --git b/engine/common/system.h a/engine/common/system.h
- index 96f4776..2be0c58 100644
- --- b/engine/common/system.h
- +++ a/engine/common/system.h
- @@ -86,8 +86,6 @@ void Sys_SetClipboardData( const byte *buffer, size_t size );
- qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size );
- void Sys_ShellExecute( const char *path, const char *parms, qboolean exit );
- void Sys_SendKeyEvents( void );
- -qboolean Sys_CheckMMX( void );
- -qboolean Sys_CheckSSE( void );
- void Sys_Print( const char *pMsg );
- void Sys_PrintLog( const char *pMsg );
- void Sys_InitLog( void );
- diff --git b/engine/common/titles.c a/engine/common/titles.c
- index e5a6a8a..0a318d6 100644
- --- b/engine/common/titles.c
- +++ a/engine/common/titles.c
- @@ -121,32 +121,6 @@ static int ParseFloats( const char *pText, float *pFloat, int count )
- return 0;
- }
- -// trims all whitespace from the front and end of a string
- -void TrimSpace( const char *source, char *dest )
- -{
- - int start, end, length;
- -
- - start = 0;
- - end = Q_strlen( source );
- -
- - while( source[start] && IsWhiteSpace( source[start] ))
- - start++;
- -
- - end--;
- - while( end > 0 && IsWhiteSpace( source[end] ))
- - end--;
- -
- - end++;
- -
- - length = end - start;
- - if( length > 0 )
- - memcpy( dest, source + start, length );
- - else length = 0;
- -
- - // terminate the dest string
- - dest[length] = 0;
- -}
- -
- static int IsToken( const char *pText, const char *pTokenName )
- {
- if( !pText || !pTokenName )
- @@ -253,7 +227,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
- while( COM_MemFgets( pMemFile, fileSize, &filePos, buf, 512 ) != NULL )
- {
- - TrimSpace( buf, trim );
- + COM_TrimSpace( buf, trim );
- switch( mode )
- {
- diff --git b/engine/common/zone.c a/engine/common/zone.c
- index 10f9d2a..9df8dc4 100644
- --- b/engine/common/zone.c
- +++ a/engine/common/zone.c
- @@ -15,8 +15,8 @@ GNU General Public License for more details.
- #include "common.h"
- -#define MEMCLUMPSIZE (65536 - 1536) // give malloc padding so we can't waste most of a page at the end
- #define MEMUNIT 8 // smallest unit we care about is this many bytes
- +#define MEMCLUMPSIZE (65536 - 1536) // give malloc padding so we can't waste most of a page at the end
- #define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
- #define MEMBITINTS (MEMBITS / 32)
- @@ -71,7 +71,7 @@ void *_Mem_Alloc( byte *poolptr, size_t size, const char *filename, int fileline
- int i, j, k, needed, endbit, largest;
- memclump_t *clump, **clumpchainpointer;
- memheader_t *mem;
- - mempool_t *pool = (mempool_t *)((byte *)poolptr);
- + mempool_t *pool = (mempool_t *)poolptr;
- if( size <= 0 ) return NULL;
- if( poolptr == NULL ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
- @@ -115,7 +115,7 @@ loopcontinue:;
- pool->realsize += sizeof( memclump_t );
- clump = malloc( sizeof( memclump_t ));
- if( clump == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
- - _memset( clump, 0, sizeof( memclump_t ), filename, fileline );
- + memset( clump, 0, sizeof( memclump_t ));
- *clumpchainpointer = clump;
- clump->sentinel1 = MEMCLUMP_SENTINEL;
- clump->sentinel2 = MEMCLUMP_SENTINEL;
- @@ -153,7 +153,7 @@ choseclump:
- mem->prev = NULL;
- pool->chain = mem;
- if( mem->next ) mem->next->prev = mem;
- - _memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size, filename, fileline );
- + memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
- return (void *)((byte *)mem + sizeof( memheader_t ));
- }
- @@ -232,7 +232,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
- }
- pool->realsize -= sizeof( memclump_t );
- - _memset( clump, 0xBF, sizeof( memclump_t ), filename, fileline );
- + memset( clump, 0xBF, sizeof( memclump_t ));
- free( clump );
- }
- else
- @@ -257,8 +257,8 @@ void _Mem_Free( void *data, const char *filename, int fileline )
- void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, const char *filename, int fileline )
- {
- - char *nb;
- memheader_t *memhdr = NULL;
- + char *nb;
- if( size <= 0 ) return memptr; // no need to reallocate
- @@ -272,11 +272,8 @@ void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, const char *filena
- if( memptr ) // first allocate?
- {
- - size_t newsize;
- -
- - // get size of old block
- - newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
- - _memcpy( nb, memptr, newsize, filename, fileline );
- + size_t newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
- + memcpy( nb, memptr, newsize );
- _Mem_Free( memptr, filename, fileline ); // free unused old block
- }
- @@ -289,7 +286,7 @@ byte *_Mem_AllocPool( const char *name, const char *filename, int fileline )
- pool = (mempool_t *)malloc( sizeof( mempool_t ));
- if( pool == NULL ) Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
- - _memset( pool, 0, sizeof( mempool_t ), filename, fileline );
- + memset( pool, 0, sizeof( mempool_t ));
- // fill header
- pool->sentinel1 = MEMHEADER_SENTINEL1;
- @@ -303,27 +300,27 @@ byte *_Mem_AllocPool( const char *name, const char *filename, int fileline )
- pool->next = poolchain;
- poolchain = pool;
- - return (byte *)((mempool_t *)pool);
- + return (byte *)pool;
- }
- void _Mem_FreePool( byte **poolptr, const char *filename, int fileline )
- {
- - mempool_t *pool = (mempool_t *)((byte *)*poolptr );
- + mempool_t *pool = (mempool_t *)*poolptr;
- mempool_t **chainaddress;
- if( pool )
- {
- // unlink pool from chain
- for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
- - if( *chainaddress != pool) Sys_Error("Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
- - if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
- - if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
- + if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
- + if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
- + if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
- *chainaddress = pool->next;
- // free memory owned by the pool
- while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
- // free the pool itself
- - _memset( pool, 0xBF, sizeof( mempool_t ), filename, fileline );
- + memset( pool, 0xBF, sizeof( mempool_t ));
- free( pool );
- *poolptr = NULL;
- }
- @@ -331,7 +328,7 @@ void _Mem_FreePool( byte **poolptr, const char *filename, int fileline )
- void _Mem_EmptyPool( byte *poolptr, const char *filename, int fileline )
- {
- - mempool_t *pool = (mempool_t *)((byte *)poolptr);
- + mempool_t *pool = (mempool_t *)poolptr;
- if( poolptr == NULL ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
- if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
- @@ -370,7 +367,7 @@ Check pointer for memory
- qboolean Mem_IsAllocatedExt( byte *poolptr, void *data )
- {
- mempool_t *pool = NULL;
- - if( poolptr ) pool = (mempool_t *)((byte *)poolptr);
- + if( poolptr ) pool = (mempool_t *)poolptr;
- return Mem_CheckAlloc( pool, data );
- }
- @@ -379,13 +376,17 @@ void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
- {
- memheader_t *mem;
- - if (data == NULL) Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
- + if( data == NULL )
- + Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
- +
- mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
- +
- if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
- {
- mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
- Sys_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
- }
- +
- if( *((byte *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 )
- {
- mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
- diff --git b/engine/engine.dsp a/engine/engine.dsp
- index 4f91fe0..6e6a201 100644
- --- b/engine/engine.dsp
- +++ a/engine/engine.dsp
- @@ -61,9 +61,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!release
- InputPath=\Xash3D\src_main\temp\engine\!release\xash.dll
- SOURCE="$(InputPath)"
- +BuildCmds= \
- + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \
- + copy $(TargetDir)\xash.dll "D:\Paranoia2\xash.dll" \
- +
- +
- "D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll"
- + $(BuildCmds)
- +"D:\Paranoia2\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- + $(BuildCmds)
- # End Custom Build
- !ELSEIF "$(CFG)" == "engine - Win32 Debug"
- @@ -98,9 +105,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!debug
- InputPath=\Xash3D\src_main\temp\engine\!debug\xash.dll
- SOURCE="$(InputPath)"
- +BuildCmds= \
- + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \
- + copy $(TargetDir)\xash.dll "D:\Paranoia2\xash.dll" \
- +
- +
- "D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll"
- + $(BuildCmds)
- +"D:\Paranoia2\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- + $(BuildCmds)
- # End Custom Build
- !ENDIF
- @@ -142,11 +156,15 @@ SOURCE=.\client\cl_game.c
- # End Source File
- # Begin Source File
- +SOURCE=.\client\cl_gameui.c
- +# End Source File
- +# Begin Source File
- +
- SOURCE=.\client\cl_main.c
- # End Source File
- # Begin Source File
- -SOURCE=.\client\cl_menu.c
- +SOURCE=.\client\cl_netgraph.c
- # End Source File
- # Begin Source File
- @@ -366,10 +384,6 @@ SOURCE=.\common\net_encode.c
- # End Source File
- # Begin Source File
- -SOURCE=.\common\net_huff.c
- -# End Source File
- -# Begin Source File
- -
- SOURCE=.\common\network.c
- # End Source File
- # Begin Source File
- diff --git b/engine/physint.h a/engine/physint.h
- index af923a0..d6f2223 100644
- --- b/engine/physint.h
- +++ a/engine/physint.h
- @@ -26,6 +26,28 @@ GNU General Public License for more details.
- #define SERVER_LOADING 1
- #define SERVER_ACTIVE 2
- +// LUMP reading errors
- +#define LUMP_LOAD_OK 0
- +#define LUMP_LOAD_COULDNT_OPEN 1
- +#define LUMP_LOAD_BAD_HEADER 2
- +#define LUMP_LOAD_BAD_VERSION 3
- +#define LUMP_LOAD_NO_EXTRADATA 4
- +#define LUMP_LOAD_INVALID_NUM 5
- +#define LUMP_LOAD_NOT_EXIST 6
- +#define LUMP_LOAD_MEM_FAILED 7
- +#define LUMP_LOAD_CORRUPTED 8
- +
- +// LUMP saving errors
- +#define LUMP_SAVE_OK 0
- +#define LUMP_SAVE_COULDNT_OPEN 1
- +#define LUMP_SAVE_BAD_HEADER 2
- +#define LUMP_SAVE_BAD_VERSION 3
- +#define LUMP_SAVE_NO_EXTRADATA 4
- +#define LUMP_SAVE_INVALID_NUM 5
- +#define LUMP_SAVE_ALREADY_EXIST 6
- +#define LUMP_SAVE_NO_DATA 7
- +#define LUMP_SAVE_CORRUPTED 8
- +
- typedef struct areanode_s
- {
- int axis; // -1 = leaf node
- @@ -64,6 +86,24 @@ typedef struct server_physics_api_s
- // static allocations
- void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline );
- void (*pfnMemFree)( void *mem, const char *filename, const int fileline );
- +
- + // trace & contents
- + int (*pfnMaskPointContents)( const float *pos, int groupmask );
- + trace_t (*pfnTrace)( const float *p0, float *mins, float *maxs, const float *p1, int type, edict_t *e );
- + trace_t (*pfnTraceNoEnts)( const float *p0, float *mins, float *maxs, const float *p1, int type, edict_t *e );
- + int (*pfnBoxInPVS)( const float *org, const float *boxmins, const float *boxmaxs );
- +
- + // message handler (missed function to write raw bytes)
- + void (*pfnWriteBytes)( byte *bytes, int count );
- +
- + // BSP lump management
- + int (*pfnCheckLump)( const char *filename, const int lump, int *lumpsize );
- + int (*pfnReadLump)( const char *filename, const int lump, void **lumpdata, int *lumpsize );
- + int (*pfnSaveLump)( const char *filename, const int lump, void *lumpdata, int lumpsize );
- +
- + // FS tools
- + int (*pfnSaveFile)( const char *filename, const void *data, long len );
- + const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height );
- } server_physics_api_t;
- // physic callbacks
- @@ -109,6 +149,10 @@ typedef struct physics_interface_s
- const char* (*pfnGetString)( string_t iString );
- // helper for restore custom decals that have custom message (e.g. Paranoia)
- int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
- + // handle custom trigger touching for player
- + void (*PM_PlayerTouch)( struct playermove_s *ppmove, edict_t *client );
- + // alloc or destroy model custom data (called only for dedicated servers, otherwise using an client version)
- + void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer );
- } physics_interface_t;
- #endif//PHYSINT_H
- \ No newline at end of file
- diff --git b/engine/server/server.h a/engine/server/server.h
- index a877ccf..38ef3cd 100644
- --- b/engine/server/server.h
- +++ a/engine/server/server.h
- @@ -37,7 +37,7 @@ extern int SV_UPDATE_BACKUP;
- // hostflags
- #define SVF_SKIPLOCALHOST BIT( 0 )
- #define SVF_PLAYERSONLY BIT( 1 )
- -#define SVF_PORTALPASS BIT( 2 ) // we are do portal pass
- +#define SVF_MERGE_VISIBILITY BIT( 2 ) // we are do portal pass
- // mapvalid flags
- #define MAP_IS_EXIST BIT( 0 )
- @@ -53,10 +53,18 @@ extern int SV_UPDATE_BACKUP;
- #define MAKE_STRING(str) SV_MakeString( str )
- #define MAX_PUSHED_ENTS 256
- -#define MAX_CAMERAS 32
- +#define MAX_VIEWENTS 128
- +
- +#define FCL_RESEND_USERINFO BIT( 0 )
- +#define FCL_RESEND_MOVEVARS BIT( 1 )
- +#define FCL_SKIP_NET_MESSAGE BIT( 2 )
- +#define FCL_SEND_NET_MESSAGE BIT( 3 )
- +#define FCL_PREDICT_MOVEMENT BIT( 4 ) // movement prediction is enabled
- +#define FCL_LOCAL_WEAPONS BIT( 5 ) // weapon prediction is enabled
- +#define FCL_LAG_COMPENSATION BIT( 6 ) // lag compensation is enabled
- +#define FCL_FAKECLIENT BIT( 7 ) // this client is a fake player controlled by the game DLL
- +#define FCL_HLTV_PROXY BIT( 8 ) // this is a proxy for a HLTV client (spectator)
- -#define DVIS_PVS 0
- -#define DVIS_PHS 1
- typedef enum
- {
- @@ -114,7 +122,9 @@ typedef struct server_s
- int viewentity; // applied on client restore. this is temporare place
- // until client connected
- - double time; // sv.time += host.frametime
- + double time; // sv.time += sv.frametime
- + double time_residual; // unclamped
- + float frametime; // 1.0 / sv_fps->value
- int net_framenum; // to avoid send edicts twice through portals
- int hostflags; // misc server flags: predicting etc
- @@ -143,10 +153,6 @@ typedef struct server_s
- sv_baselines_t instanced; // instanced baselines
- - // unreliable data to send to clients.
- - sizebuf_t datagram;
- - byte datagram_buf[NET_MAX_PAYLOAD];
- -
- // reliable data to send to clients.
- sizebuf_t reliable_datagram; // copied to all clients at end of frame
- byte reliable_datagram_buf[NET_MAX_PAYLOAD];
- @@ -165,6 +171,7 @@ typedef struct server_s
- uint checksum; // for catching cheater maps
- qboolean write_bad_message; // just for debug
- + qboolean simulating; // physics is running
- qboolean paused;
- } server_t;
- @@ -175,7 +182,7 @@ typedef struct
- float latency;
- clientdata_t clientdata;
- - weapon_data_t weapondata[64];
- + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
- int num_entities;
- int first_entity; // into the circular sv_packet_entities[]
- @@ -185,35 +192,24 @@ typedef struct sv_client_s
- {
- cl_state_t state;
- char name[32]; // extracted from userinfo, color string allowed
- + int flags; // client flags, some info
- char userinfo[MAX_INFO_STRING]; // name, etc (received from client)
- char physinfo[MAX_INFO_STRING]; // set on server (transmit to client)
- - qboolean send_message;
- - qboolean skip_message;
- -
- - qboolean local_weapons; // enable weapon predicting
- - qboolean lag_compensation; // enable lag compensation
- - qboolean hltv_proxy; // this is spectator proxy (hltv)
- -
- netchan_t netchan;
- int chokecount; // number of messages rate supressed
- int delta_sequence; // -1 = no compression.
- double next_messagetime; // time when we should send next world state update
- - double cl_updaterate; // default time to wait for next message
- double next_checkpingtime; // time to send all players pings to client
- + double cl_updaterate; // client requested updaterate
- double timebase; // client timebase
- customization_t customization; // player customization linked list
- resource_t resource1;
- resource_t resource2; // <mapname.res> from client (server downloading)
- - qboolean sendmovevars;
- - qboolean sendinfo;
- -
- - qboolean fakeclient; // This client is a fake player controlled by the game DLL
- -
- usercmd_t lastcmd; // for filling in big drops
- double last_cmdtime;
- @@ -231,8 +227,8 @@ typedef struct sv_client_s
- edict_t *pViewEntity; // svc_setview member
- int messagelevel; // for filtering printed messages
- - edict_t *cameras[MAX_CAMERAS]; // list of portal cameras in player PVS
- - int num_cameras; // num of portal cameras that can merge PVS
- + edict_t *viewentity[MAX_VIEWENTS]; // list of portal cameras in player PVS
- + int num_viewents; // num of portal cameras that can merge PVS
- // the datagram is written to by sound calls, prints, temp ents, etc.
- // it can be harmlessly overflowed.
- @@ -269,8 +265,8 @@ typedef struct sv_client_s
- typedef struct
- {
- netadr_t adr;
- - int challenge;
- double time;
- + int challenge;
- qboolean connected;
- } challenge_t;
- @@ -443,9 +439,12 @@ void SV_ExecuteUserCommand (char *s);
- void SV_InitOperatorCommands( void );
- void SV_KillOperatorCommands( void );
- void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo );
- +void SV_RemoteCommand( netadr_t from, sizebuf_t *msg );
- void SV_PrepWorldFrame( void );
- void SV_ProcessFile( sv_client_t *cl, char *filename );
- void SV_SendResourceList( sv_client_t *cl );
- +void SV_AddToMaster( netadr_t from, sizebuf_t *msg );
- +qboolean SV_IsSimulating( void );
- void Master_Add( void );
- void Master_Heartbeat( void );
- void Master_Packet( void );
- @@ -489,7 +488,7 @@ void SV_WaterMove( edict_t *ent );
- //
- void SV_SendClientMessages( void );
- void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... );
- -void SV_BroadcastPrintf( int level, char *fmt, ... );
- +void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... );
- void SV_BroadcastCommand( char *fmt, ... );
- //
- @@ -500,7 +499,6 @@ void SV_RefreshUserinfo( void );
- void SV_GetChallenge( netadr_t from );
- void SV_DirectConnect( netadr_t from );
- void SV_TogglePause( const char *msg );
- -void SV_PutClientInServer( edict_t *ent );
- qboolean SV_ShouldUpdatePing( sv_client_t *cl );
- const char *SV_GetClientIDString( sv_client_t *cl );
- void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg );
- @@ -550,12 +548,14 @@ void SV_FreeEdict( edict_t *pEdict );
- void SV_InitEdict( edict_t *pEdict );
- const char *SV_ClassName( const edict_t *e );
- void SV_SetModel( edict_t *ent, const char *name );
- +void SV_FreePrivateData( edict_t *pEdict );
- void SV_CopyTraceToGlobal( trace_t *trace );
- void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max );
- edict_t* SV_FindEntityByString( edict_t *pStartEdict, const char *pszField, const char *pszValue );
- void SV_PlaybackEventFull( 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 );
- void SV_PlaybackReliableEvent( sizebuf_t *msg, word eventindex, float delay, event_args_t *args );
- +qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax );
- void SV_BaselineForEntity( edict_t *pEdict );
- void SV_WriteEntityPatch( const char *filename );
- char *SV_ReadEntityScript( const char *filename, int *flags );
- @@ -572,6 +572,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- void SV_CreateStaticEntity( struct sizebuf_s *msg, sv_static_entity_t *ent );
- edict_t* pfnPEntityOfEntIndex( int iEntIndex );
- int pfnIndexOfEdict( const edict_t *pEdict );
- +void pfnWriteBytes( const byte *bytes, int count );
- void SV_UpdateBaseVelocity( edict_t *ent );
- byte *pfnSetFatPVS( const float *org );
- byte *pfnSetFatPAS( const float *org );
- @@ -610,7 +611,6 @@ void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs )
- //
- void SV_ClearWorld( void );
- void SV_UnlinkEdict( edict_t *ent );
- -qboolean SV_HeadnodeVisible( mnode_t *node, byte *visbits, int *lastleaf );
- void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace );
- void SV_CustomClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace );
- trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end );
- diff --git b/engine/server/sv_client.c a/engine/server/sv_client.c
- index 75784e5..d1a96ed 100644
- --- b/engine/server/sv_client.c
- +++ a/engine/server/sv_client.c
- @@ -97,10 +97,10 @@ A connection request that did not come from the master
- void SV_DirectConnect( netadr_t from )
- {
- char userinfo[MAX_INFO_STRING];
- + char physinfo[MAX_PHYSINFO_STRING];
- sv_client_t temp, *cl, *newcl;
- - char physinfo[512];
- - int i, edictnum;
- int qport, version;
- + int i, edictnum;
- int count = 0;
- int challenge;
- edict_t *ent;
- @@ -245,13 +245,14 @@ gotnewcl:
- Netchan_OutOfBandPrint( NS_SERVER, from, "client_connect" );
- newcl->state = cs_connected;
- - newcl->cl_updaterate = 0.05; // 20 fps as default
- newcl->lastmessage = host.realtime;
- newcl->lastconnect = host.realtime;
- + newcl->cl_updaterate = 0.05; // 20 fps as default
- newcl->delta_sequence = -1;
- // parse some info from the info strings (this can override cl_updaterate)
- - SV_UserinfoChanged( newcl, userinfo );
- + Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
- + SV_UserinfoChanged( newcl, newcl->userinfo );
- newcl->next_messagetime = host.realtime + newcl->cl_updaterate;
- @@ -280,16 +281,7 @@ void SV_DisconnectClient( edict_t *pClient )
- // don't send to other clients
- pClient->v.modelindex = 0;
- - if( pClient->pvPrivateData != NULL )
- - {
- - // NOTE: new interface can be missing
- - if( svgame.dllFuncs2.pfnOnFreeEntPrivateData != NULL )
- - svgame.dllFuncs2.pfnOnFreeEntPrivateData( pClient );
- -
- - // clear any dlls data but keep engine data
- - Mem_Free( pClient->pvPrivateData );
- - pClient->pvPrivateData = NULL;
- - }
- + SV_FreePrivateData( pClient );
- // invalidate serial number
- pClient->serialnumber++;
- @@ -355,9 +347,9 @@ edict_t *SV_FakeConnect( const char *netname )
- ent = EDICT_NUM( edictnum );
- newcl->edict = ent;
- newcl->challenge = -1; // fake challenge
- - newcl->fakeclient = true;
- newcl->delta_sequence = -1;
- newcl->userid = g_userid++; // create unique userid
- + SetBits( newcl->flags, FCL_FAKECLIENT );
- // get the game a chance to reject this connection or modify the userinfo
- if( !SV_ClientConnect( ent, userinfo ))
- @@ -367,15 +359,16 @@ edict_t *SV_FakeConnect( const char *netname )
- }
- // parse some info from the info strings
- - SV_UserinfoChanged( newcl, userinfo );
- + Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
- + SV_UserinfoChanged( newcl, newcl->userinfo );
- + SetBits( cl->flags, FCL_RESEND_USERINFO );
- MsgDev( D_NOTE, "Bot %i connecting with challenge %p\n", i, -1 );
- - ent->v.flags |= FL_FAKECLIENT; // mark it as fakeclient
- + SetBits( ent->v.flags, FL_FAKECLIENT ); // mark it as fakeclient
- newcl->state = cs_spawned;
- newcl->lastmessage = host.realtime; // don't timeout
- newcl->lastconnect = host.realtime;
- - newcl->sendinfo = true;
- return ent;
- }
- @@ -425,21 +418,19 @@ void SV_DropClient( sv_client_t *drop )
- return; // already dropped
- // add the disconnect
- - if( !drop->fakeclient )
- - {
- + if( !FBitSet( drop->flags, FCL_FAKECLIENT ))
- MSG_WriteByte( &drop->netchan.message, svc_disconnect );
- - }
- // let the game known about client state
- SV_DisconnectClient( drop->edict );
- - drop->fakeclient = false;
- - drop->hltv_proxy = false;
- + ClearBits( drop->flags, FCL_FAKECLIENT );
- + ClearBits( drop->flags, FCL_HLTV_PROXY );
- drop->state = cs_zombie; // become free in a few seconds
- drop->name[0] = 0;
- if( drop->frames )
- - Mem_Free( drop->frames ); // fakeclients doesn't have frames
- + Mem_Free( drop->frames ); // release delta
- drop->frames = NULL;
- if( NET_CompareBaseAdr( drop->netchan.remote_address, host.rd.address ) )
- @@ -492,7 +483,7 @@ void SV_BeginRedirect( netadr_t adr, int target, char *buffer, int buffersize, v
- void SV_FlushRedirect( netadr_t adr, int dest, char *buf )
- {
- - if( svs.currentPlayer && svs.currentPlayer->fakeclient )
- + if( svs.currentPlayer && FBitSet( svs.currentPlayer->flags, FCL_FAKECLIENT ))
- return;
- switch( dest )
- @@ -548,7 +539,7 @@ char *SV_StatusString( void )
- cl = &svs.clients[i];
- if( cl->state == cs_connected || cl->state == cs_spawned )
- {
- - Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, cl->ping, cl->name );
- + Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, (int)cl->ping, cl->name );
- playerLength = Q_strlen( player );
- if( statusLength + playerLength >= sizeof( status ))
- break; // can't hold any more
- @@ -642,7 +633,7 @@ void SV_Info( netadr_t from )
- int version;
- // ignore in single player
- - if( sv_maxclients->integer == 1 )
- + if( sv_maxclients->integer == 1 || !svs.initialized )
- return;
- version = Q_atoi( Cmd_Argv( 1 ));
- @@ -660,9 +651,9 @@ void SV_Info( netadr_t from )
- Info_SetValueForKey( string, "host", hostname->string );
- Info_SetValueForKey( string, "map", sv.name );
- - Info_SetValueForKey( string, "dm", va( "%i", svgame.globals->deathmatch ));
- - Info_SetValueForKey( string, "team", va( "%i", svgame.globals->teamplay ));
- - Info_SetValueForKey( string, "coop", va( "%i", svgame.globals->coop ));
- + Info_SetValueForKey( string, "dm", va( "%i", (int)svgame.globals->deathmatch ));
- + Info_SetValueForKey( string, "team", va( "%i", (int)svgame.globals->teamplay ));
- + Info_SetValueForKey( string, "coop", va( "%i", (int)svgame.globals->coop ));
- Info_SetValueForKey( string, "numcl", va( "%i", count ));
- Info_SetValueForKey( string, "maxcl", va( "%i", sv_maxclients->integer ));
- Info_SetValueForKey( string, "gamedir", GI->gamefolder );
- @@ -685,7 +676,7 @@ void SV_BuildNetAnswer( netadr_t from )
- int i, count = 0;
- // ignore in single player
- - if( sv_maxclients->integer == 1 )
- + if( sv_maxclients->integer == 1 || !svs.initialized )
- return;
- version = Q_atoi( Cmd_Argv( 1 ));
- @@ -693,18 +684,27 @@ void SV_BuildNetAnswer( netadr_t from )
- type = Q_atoi( Cmd_Argv( 3 ));
- if( version != PROTOCOL_VERSION )
- + {
- + // handle the unsupported protocol
- + string[0] = '\0';
- + Info_SetValueForKey( string, "neterror", "protocol" );
- +
- + // send error unsupported protocol
- + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- return;
- + }
- if( type == NETAPI_REQUEST_PING )
- {
- - Q_snprintf( answer, sizeof( answer ), "netinfo %i %i\n", context, type );
- - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
- + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, "" );
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- }
- else if( type == NETAPI_REQUEST_RULES )
- {
- // send serverinfo
- Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, Cvar_Serverinfo( ));
- - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- }
- else if( type == NETAPI_REQUEST_PLAYERS )
- {
- @@ -716,14 +716,14 @@ void SV_BuildNetAnswer( netadr_t from )
- {
- edict_t *ed = svs.clients[i].edict;
- float time = host.realtime - svs.clients[i].lastconnect;
- - Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, ed->v.frags, time ), sizeof( string ));
- + Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, (int)ed->v.frags, time ), sizeof( string ));
- count++;
- }
- }
- // send playernames
- Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
- - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- }
- else if( type == NETAPI_REQUEST_DETAILS )
- {
- @@ -740,7 +740,16 @@ void SV_BuildNetAnswer( netadr_t from )
- // send serverinfo
- Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
- - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- + }
- + else
- + {
- + string[0] = '\0';
- + Info_SetValueForKey( string, "neterror", "undefined" );
- +
- + // send error undefined request type
- + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
- + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
- }
- }
- @@ -781,8 +790,8 @@ Redirect all printfs
- */
- void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
- {
- - char remaining[1024];
- static char outputbuf[2048];
- + char remaining[1024];
- int i;
- MsgDev( D_INFO, "Rcon from %s:\n%s\n", NET_AdrToString( from ), MSG_GetData( msg ) + 4 );
- @@ -796,7 +805,7 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
- Q_strcat( remaining, Cmd_Argv( i ));
- Q_strcat( remaining, " " );
- }
- - Cmd_ExecuteString( remaining, src_command );
- + Cmd_ExecuteString( remaining );
- }
- else MsgDev( D_ERROR, "Bad rcon_password.\n" );
- @@ -817,7 +826,7 @@ int SV_CalcPing( sv_client_t *cl )
- client_frame_t *frame;
- // bots don't have a real ping
- - if( cl->fakeclient || !cl->frames )
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ) || !cl->frames )
- return 5;
- count = 0;
- @@ -872,7 +881,7 @@ void SV_EstablishTimeBase( sv_client_t *cl, usercmd_t *cmds, int dropped, int nu
- for( ; numcmds > 0; numcmds-- )
- runcmd_time += cmds[numcmds - 1].msec / 1000.0;
- - cl->timebase = sv.time + cl->cl_updaterate - runcmd_time;
- + cl->timebase = sv.frametime + svgame.globals->time - runcmd_time;
- }
- /*
- @@ -945,6 +954,9 @@ void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg )
- char info[MAX_INFO_STRING];
- int i;
- + // process userinfo before updating
- + SV_UserinfoChanged( cl, cl->userinfo );
- +
- i = cl - svs.clients;
- MSG_WriteByte( msg, svc_updateuserinfo );
- @@ -971,11 +983,14 @@ SV_RefreshUserinfo
- */
- void SV_RefreshUserinfo( void )
- {
- - int i;
- sv_client_t *cl;
- + int i;
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- - if( cl->state >= cs_connected ) cl->sendinfo = true;
- + {
- + if( cl->state >= cs_connected )
- + SetBits( cl->flags, FCL_RESEND_USERINFO );
- + }
- }
- /*
- @@ -1004,10 +1019,10 @@ if this person needs ping data.
- */
- qboolean SV_ShouldUpdatePing( sv_client_t *cl )
- {
- - if( !cl->hltv_proxy )
- + if( !FBitSet( cl->flags, FCL_HLTV_PROXY ))
- {
- SV_CalcPing( cl );
- - return cl->lastcmd.buttons & IN_SCORE; // they are viewing the scoreboard. Send them pings.
- + return FBitSet( cl->lastcmd.buttons, IN_SCORE ); // they are viewing the scoreboard. Send them pings.
- }
- if( host.realtime > cl->next_checkpingtime )
- @@ -1068,85 +1083,101 @@ Called when a player connects to a server or respawns in
- a deathmatch.
- ============
- */
- -void SV_PutClientInServer( edict_t *ent )
- +void SV_PutClientInServer( sv_client_t *cl )
- {
- - sv_client_t *client;
- + edict_t *ent = cl->edict;
- - client = SV_ClientFromEdict( ent, true );
- - ASSERT( client != NULL );
- + // now client is spawned
- + cl->state = cs_spawned;
- if( !sv.loadgame )
- {
- - client->hltv_proxy = Q_atoi( Info_ValueForKey( client->userinfo, "hltv" )) ? true : false;
- + if( Q_atoi( Info_ValueForKey( cl->userinfo, "hltv" )))
- + SetBits( cl->flags, FCL_HLTV_PROXY );
- - if( client->hltv_proxy )
- - ent->v.flags |= FL_PROXY;
- + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
- + SetBits( ent->v.flags, FL_PROXY );
- else ent->v.flags = 0;
- - ent->v.netname = MAKE_STRING( client->name );
- + ent->v.netname = MAKE_STRING( cl->name );
- // fisrt entering
- svgame.globals->time = sv.time;
- svgame.dllFuncs.pfnClientPutInServer( ent );
- if( sv.background ) // don't attack player in background mode
- - ent->v.flags |= (FL_GODMODE|FL_NOTARGET);
- + SetBits( ent->v.flags, FL_GODMODE|FL_NOTARGET );
- - client->pViewEntity = NULL; // reset pViewEntity
- + cl->pViewEntity = NULL; // reset pViewEntity
- if( svgame.globals->cdAudioTrack )
- {
- - MSG_WriteByte( &client->netchan.message, svc_stufftext );
- - MSG_WriteString( &client->netchan.message, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
- + MSG_WriteByte( &cl->netchan.message, svc_stufftext );
- + MSG_WriteString( &cl->netchan.message, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
- svgame.globals->cdAudioTrack = 0;
- }
- }
- else
- {
- // enable dev-mode to prevent crash cheat-protecting from Invasion mod
- - if( ent->v.flags & (FL_GODMODE|FL_NOTARGET) && !Q_stricmp( GI->gamefolder, "invasion" ))
- - SV_ExecuteClientCommand( client, "test\n" );
- + if( FBitSet( ent->v.flags, FL_GODMODE|FL_NOTARGET ) && !Q_stricmp( GI->gamefolder, "invasion" ))
- + SV_ExecuteClientCommand( cl, "test\n" );
- // NOTE: we needs to setup angles on restore here
- if( ent->v.fixangle == 1 )
- {
- - MSG_WriteByte( &client->netchan.message, svc_setangle );
- - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[0], 16 );
- - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[1], 16 );
- - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[2], 16 );
- + MSG_WriteByte( &cl->netchan.message, svc_setangle );
- + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[0], 16 );
- + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[1], 16 );
- + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[2], 16 );
- ent->v.fixangle = 0;
- }
- - ent->v.effects |= EF_NOINTERP;
- + SetBits( ent->v.effects, EF_NOINTERP );
- // reset weaponanim
- - MSG_WriteByte( &client->netchan.message, svc_weaponanim );
- - MSG_WriteByte( &client->netchan.message, 0 );
- - MSG_WriteByte( &client->netchan.message, 0 );
- + MSG_WriteByte( &cl->netchan.message, svc_weaponanim );
- + MSG_WriteByte( &cl->netchan.message, 0 );
- + MSG_WriteByte( &cl->netchan.message, 0 );
- // trigger_camera restored here
- if( sv.viewentity > 0 && sv.viewentity < GI->max_edicts )
- - client->pViewEntity = EDICT_NUM( sv.viewentity );
- - else client->pViewEntity = NULL;
- + cl->pViewEntity = EDICT_NUM( sv.viewentity );
- + else cl->pViewEntity = NULL;
- }
- + // refresh the userinfo and movevars
- + // NOTE: because movevars can be changed during the connection process
- + SetBits( cl->flags, FCL_RESEND_USERINFO|FCL_RESEND_MOVEVARS );
- +
- // reset client times
- - client->last_cmdtime = 0.0;
- - client->last_movetime = 0.0;
- - client->next_movetime = 0.0;
- + cl->last_cmdtime = 0.0;
- + cl->last_movetime = 0.0;
- + cl->next_movetime = 0.0;
- - if( !client->fakeclient )
- + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
- {
- - int viewEnt;
- + sv_client_t *cur;
- + int i, viewEnt;
- - // resend the signon
- - MSG_WriteBits( &client->netchan.message, MSG_GetData( &sv.signon ), MSG_GetNumBitsWritten( &sv.signon ));
- + MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.signon ), MSG_GetNumBitsWritten( &sv.signon ));
- - if( client->pViewEntity )
- - viewEnt = NUM_FOR_EDICT( client->pViewEntity );
- - else viewEnt = NUM_FOR_EDICT( client->edict );
- + if( cl->pViewEntity )
- + viewEnt = NUM_FOR_EDICT( cl->pViewEntity );
- + else viewEnt = NUM_FOR_EDICT( cl->edict );
- - MSG_WriteByte( &client->netchan.message, svc_setview );
- - MSG_WriteWord( &client->netchan.message, viewEnt );
- + MSG_WriteByte( &cl->netchan.message, svc_setview );
- + MSG_WriteWord( &cl->netchan.message, viewEnt );
- +
- + // collect the info about all the players and send to me
- + for( i = 0, cur = svs.clients; i < sv_maxclients->integer; i++, cur++ )
- + {
- + if( !cur->edict ) continue; // not in game yet
- +
- + if( cur == cl || cur->state != cs_spawned )
- + continue;
- +
- + SV_FullClientUpdate( cur, &cl->netchan.message );
- + }
- }
- // clear any temp states
- @@ -1169,7 +1200,7 @@ void SV_TogglePause( const char *msg )
- sv.paused ^= 1;
- - if( msg ) SV_BroadcastPrintf( PRINT_HIGH, "%s", msg );
- + if( msg ) SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", msg );
- // send notification to all clients
- MSG_WriteByte( &sv.reliable_datagram, svc_setpause );
- @@ -1194,11 +1225,10 @@ This will be sent on the initial connection and upon each server load.
- void SV_New_f( sv_client_t *cl )
- {
- int playernum;
- - edict_t *ent;
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "new is not valid from the console\n" );
- + MsgDev( D_INFO, "'new' is not valid from the console\n" );
- return;
- }
- @@ -1218,15 +1248,11 @@ void SV_New_f( sv_client_t *cl )
- MSG_WriteString( &cl->netchan.message, GI->gamefolder );
- MSG_WriteLong( &cl->netchan.message, host.features );
- - // refresh userinfo on spawn
- - SV_RefreshUserinfo();
- -
- // game server
- if( sv.state == ss_active )
- {
- // set up the entity for the client
- - ent = EDICT_NUM( playernum + 1 );
- - cl->edict = ent;
- + cl->edict = EDICT_NUM( playernum + 1 );
- // NOTE: custom resources download is disabled until is done
- if( /*sv_maxclients->integer ==*/ 1 )
- @@ -1255,7 +1281,7 @@ void SV_ContinueLoading_f( sv_client_t *cl )
- {
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "continueloading is not valid from the console\n" );
- + MsgDev( D_INFO, "'continueloading' is not valid from the console\n" );
- return;
- }
- @@ -1345,14 +1371,14 @@ void SV_WriteModels_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "modellist is not valid from the console\n" );
- + MsgDev( D_INFO, "'modellist' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "modellist from different level\n" );
- + MsgDev( D_INFO, "'modellist' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1391,14 +1417,14 @@ void SV_WriteSounds_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "soundlist is not valid from the console\n" );
- + MsgDev( D_INFO, "'soundlist' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "soundlist from different level\n" );
- + MsgDev( D_INFO, "'soundlist' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1437,14 +1463,14 @@ void SV_WriteEvents_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "eventlist is not valid from the console\n" );
- + MsgDev( D_INFO, "'eventlist' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "eventlist from different level\n" );
- + MsgDev( D_INFO, "'eventlist' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1483,14 +1509,14 @@ void SV_WriteLightstyles_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "lightstyles is not valid from the console\n" );
- + MsgDev( D_INFO, "'lightstyles' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "lightstyles from different level\n" );
- + MsgDev( D_INFO, "'lightstyles' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1531,14 +1557,14 @@ void SV_UserMessages_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "usermessages is not valid from the console\n" );
- + MsgDev( D_INFO, "'usermsgs' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "usermessages from different level\n" );
- + MsgDev( D_INFO, "'usermsgs' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1581,14 +1607,14 @@ void SV_DeltaInfo_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "deltainfo is not valid from the console\n" );
- + MsgDev( D_INFO, "'deltainfo' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "deltainfo from different level\n" );
- + MsgDev( D_INFO, "'deltainfo' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1644,14 +1670,14 @@ void SV_Baselines_f( sv_client_t *cl )
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "baselines is not valid from the console\n" );
- + MsgDev( D_INFO, "'baselines' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - MsgDev( D_INFO, "baselines from different level\n" );
- + MsgDev( D_INFO, "'baselines' from different level\n" );
- SV_New_f( cl );
- return;
- }
- @@ -1664,7 +1690,7 @@ void SV_Baselines_f( sv_client_t *cl )
- while( MSG_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < svgame.numEntities )
- {
- base = &svs.baselines[start];
- - if( base->number && ( base->modelindex || base->effects != EF_NODRAW ))
- + if(( !start || base->number ) && ( base->modelindex || base->effects != EF_NODRAW ))
- {
- MSG_WriteByte( &cl->netchan.message, svc_spawnbaseline );
- MSG_WriteDeltaEntity( &nullstate, base, &cl->netchan.message, true, SV_IsPlayerIndex( base->number ), sv.time );
- @@ -1689,20 +1715,19 @@ void SV_Begin_f( sv_client_t *cl )
- {
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "begin is not valid from the console\n" );
- + MsgDev( D_INFO, "'begin' is not valid from the console\n" );
- return;
- }
- // handle the case of a level changing while a client was connecting
- if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
- {
- - Msg( "begin from different level\n" );
- + Msg( "'begin' from different level\n" );
- SV_New_f( cl );
- return;
- }
- - cl->state = cs_spawned;
- - SV_PutClientInServer( cl->edict );
- + SV_PutClientInServer( cl );
- // if we are paused, tell the client
- if( sv.paused )
- @@ -1754,7 +1779,7 @@ void SV_Pause_f( sv_client_t *cl )
- return;
- }
- - if( cl->hltv_proxy )
- + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
- {
- SV_ClientPrintf( cl, PRINT_HIGH, "Spectators can not pause.\n" );
- return;
- @@ -1779,27 +1804,33 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
- {
- int i, dupc = 1;
- edict_t *ent = cl->edict;
- - string temp1, temp2;
- + string name1, name2;
- sv_client_t *current;
- char *val;
- if( !userinfo || !userinfo[0] ) return; // ignored
- - Q_strncpy( cl->userinfo, userinfo, sizeof( cl->userinfo ));
- -
- val = Info_ValueForKey( cl->userinfo, "name" );
- - Q_strncpy( temp2, val, sizeof( temp2 ));
- - TrimSpace( temp2, temp1 );
- + Q_strncpy( name2, val, sizeof( name2 ));
- + COM_TrimSpace( name2, name1 );
- - if( !Q_stricmp( temp1, "console" )) // keyword came from OSHLDS
- + if( !Q_stricmp( name1, "console" ))
- {
- Info_SetValueForKey( cl->userinfo, "name", "unnamed" );
- val = Info_ValueForKey( cl->userinfo, "name" );
- }
- - else if( Q_strcmp( temp1, val ))
- + else if( Q_strcmp( name1, val ))
- {
- - Info_SetValueForKey( cl->userinfo, "name", temp1 );
- + Info_SetValueForKey( cl->userinfo, "name", name1 );
- + val = Info_ValueForKey( cl->userinfo, "name" );
- + }
- +
- + if( !Q_strlen( name1 ))
- + {
- + Info_SetValueForKey( cl->userinfo, "name", "unnamed" );
- val = Info_ValueForKey( cl->userinfo, "name" );
- + Q_strncpy( name2, "unnamed", sizeof( name2 ));
- + Q_strncpy( name1, "unnamed", sizeof( name1 ));
- }
- // check to see if another user by the same name exists
- @@ -1817,15 +1848,15 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
- if( i != sv_maxclients->integer )
- {
- // dup name
- - Q_snprintf( temp2, sizeof( temp2 ), "%s (%u)", temp1, dupc++ );
- - Info_SetValueForKey( cl->userinfo, "name", temp2 );
- + Q_snprintf( name2, sizeof( name2 ), "%s (%u)", name1, dupc++ );
- + Info_SetValueForKey( cl->userinfo, "name", name2 );
- val = Info_ValueForKey( cl->userinfo, "name" );
- - Q_strncpy( cl->name, temp2, sizeof( cl->name ));
- + Q_strncpy( cl->name, name2, sizeof( cl->name ));
- }
- else
- {
- if( dupc == 1 ) // unchanged
- - Q_strncpy( cl->name, temp1, sizeof( cl->name ));
- + Q_strncpy( cl->name, name1, sizeof( cl->name ));
- break;
- }
- }
- @@ -1837,18 +1868,31 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
- else cl->netchan.rate = DEFAULT_RATE;
- // msg command
- - val = Info_ValueForKey( cl->userinfo, "msg" );
- + val = Info_ValueForKey( cl->userinfo, "cl_msglevel" );
- if( Q_strlen( val )) cl->messagelevel = Q_atoi( val );
- - cl->local_weapons = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) ? true : false;
- - cl->lag_compensation = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )) ? true : false;
- + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_predict" )))
- + SetBits( cl->flags, FCL_PREDICT_MOVEMENT );
- + else ClearBits( cl->flags, FCL_PREDICT_MOVEMENT );
- +
- + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )))
- + SetBits( cl->flags, FCL_LAG_COMPENSATION );
- + else ClearBits( cl->flags, FCL_LAG_COMPENSATION );
- +
- + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )))
- + SetBits( cl->flags, FCL_LOCAL_WEAPONS );
- + else ClearBits( cl->flags, FCL_LOCAL_WEAPONS );
- val = Info_ValueForKey( cl->userinfo, "cl_updaterate" );
- if( Q_strlen( val ))
- {
- - int i = bound( 10, Q_atoi( val ), 300 );
- - cl->cl_updaterate = 1.0f / i;
- + if( Q_atoi( val ) != 0 )
- + {
- + int i = bound( 10, Q_atoi( val ), 300 );
- + cl->cl_updaterate = 1.0 / i;
- + }
- + else cl->cl_updaterate = 0.0;
- }
- if( sv_maxclients->integer > 1 )
- @@ -1873,9 +1917,10 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
- // call prog code to allow overrides
- svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
- - ent->v.netname = MAKE_STRING( cl->name );
- - if( cl->state >= cs_connected ) cl->sendinfo = true; // needs for update client info
- + val = Info_ValueForKey( userinfo, "name" );
- + Q_strncpy( cl->name, val, sizeof( cl->name ));
- + ent->v.netname = MAKE_STRING( cl->name );
- }
- /*
- @@ -1885,7 +1930,10 @@ SV_UpdateUserinfo_f
- */
- static void SV_UpdateUserinfo_f( sv_client_t *cl )
- {
- - SV_UserinfoChanged( cl, Cmd_Argv( 1 ));
- + Q_strncpy( cl->userinfo, Cmd_Argv( 1 ), sizeof( cl->userinfo ));
- +
- + if( cl->state >= cs_connected )
- + SetBits( cl->flags, FCL_RESEND_USERINFO ); // needs for update client info
- }
- /*
- @@ -1926,7 +1974,7 @@ static void SV_Godmode_f( sv_client_t *cl )
- pEntity->v.flags = pEntity->v.flags ^ FL_GODMODE;
- - if ( !( pEntity->v.flags & FL_GODMODE ))
- + if( !FBitSet( pEntity->v.flags, FL_GODMODE ))
- SV_ClientPrintf( cl, PRINT_HIGH, "godmode OFF\n" );
- else SV_ClientPrintf( cl, PRINT_HIGH, "godmode ON\n" );
- }
- @@ -1945,7 +1993,7 @@ static void SV_Notarget_f( sv_client_t *cl )
- pEntity->v.flags = pEntity->v.flags ^ FL_NOTARGET;
- - if ( !( pEntity->v.flags & FL_NOTARGET ))
- + if( !FBitSet( pEntity->v.flags, FL_NOTARGET ))
- SV_ClientPrintf( cl, PRINT_HIGH, "notarget OFF\n" );
- else SV_ClientPrintf( cl, PRINT_HIGH, "notarget ON\n" );
- }
- @@ -1957,12 +2005,12 @@ SV_SendRes_f
- */
- void SV_SendRes_f( sv_client_t *cl )
- {
- - sizebuf_t msg;
- static byte buffer[65535];
- + sizebuf_t msg;
- if( cl->state != cs_connected )
- {
- - MsgDev( D_INFO, "sendres is not valid from the console\n" );
- + MsgDev( D_INFO, "'sendres' is not valid from the console\n" );
- return;
- }
- @@ -2039,6 +2087,71 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s )
- }
- /*
- +==================
- +SV_TSourceEngineQuery
- +==================
- +*/
- +void SV_TSourceEngineQuery( netadr_t from )
- +{
- + // A2S_INFO
- + char answer[1024] = "";
- + int count = 0, bots = 0;
- + int index;
- + sizebuf_t buf;
- +
- + if( svs.clients )
- + {
- + for( index = 0; index < sv_maxclients->integer; index++ )
- + {
- + if( svs.clients[index].state >= cs_connected )
- + {
- + if( FBitSet( svs.clients[index].flags, FCL_FAKECLIENT ))
- + bots++;
- + else count++;
- + }
- + }
- + }
- +
- + MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
- +
- + MSG_WriteByte( &buf, 'm' );
- + MSG_WriteString( &buf, NET_AdrToString( net_local ) );
- + MSG_WriteString( &buf, hostname->string );
- + MSG_WriteString( &buf, sv.name );
- + MSG_WriteString( &buf, GI->gamefolder );
- + MSG_WriteString( &buf, GI->title );
- + MSG_WriteByte( &buf, count );
- + MSG_WriteByte( &buf, sv_maxclients->integer );
- + MSG_WriteByte( &buf, PROTOCOL_VERSION );
- + MSG_WriteByte( &buf, host.type == HOST_DEDICATED ? 'D' : 'L');
- + MSG_WriteByte( &buf, 'W' );
- +
- + if( Q_stricmp( GI->gamedir, "valve" ))
- + {
- + MSG_WriteByte( &buf, 1 ); // mod
- + MSG_WriteString( &buf, GI->game_url );
- + MSG_WriteString( &buf, GI->update_url );
- + MSG_WriteByte( &buf, 0 );
- + MSG_WriteLong( &buf, (long)GI->version );
- + MSG_WriteLong( &buf, GI->size );
- +
- + if( GI->gamemode == 2 )
- + MSG_WriteByte( &buf, 1 ); // multiplayer_only
- + else MSG_WriteByte( &buf, 0 );
- +
- + if( Q_strstr( GI->game_dll, "hl." ))
- + MSG_WriteByte( &buf, 0 ); // Half-Life DLL
- + else MSG_WriteByte( &buf, 1 ); // Own DLL
- + }
- + else MSG_WriteByte( &buf, 0 ); // Half-Life
- +
- + MSG_WriteByte( &buf, GI->secure ); // unsecure
- + MSG_WriteByte( &buf, bots );
- +
- + NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
- +}
- +
- +/*
- =================
- SV_ConnectionlessPacket
- @@ -2053,9 +2166,6 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
- char *args;
- char *c, buf[MAX_SYSPATH];
- int len = sizeof( buf );
- - uint challenge;
- - int index, count = 0;
- - char query[512], ostype = 'w';
- MSG_Clear( msg );
- MSG_ReadLong( msg );// skip the -1 marker
- @@ -2074,46 +2184,9 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
- else if( !Q_strcmp( c, "connect" )) SV_DirectConnect( from );
- else if( !Q_strcmp( c, "rcon" )) SV_RemoteCommand( from, msg );
- else if( !Q_strcmp( c, "netinfo" )) SV_BuildNetAnswer( from );
- - else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x73 && msg->pData[5] == 0x0A )
- - {
- - memcpy(&challenge, &msg->pData[6], sizeof(int));
- -
- - for( index = 0; index < sv_maxclients->integer; index++ )
- - {
- - if( svs.clients[index].state >= cs_connected )
- - count++;
- - }
- -
- - Q_snprintf( query, sizeof( query ),
- - "0\n"
- - "\\protocol\\%d" // protocol version
- - "\\challenge\\%u" // challenge number that got after FF FF FF FF 73 0A
- - "\\players\\%d" // current player number
- - "\\max\\%d" // max_players
- - "\\bots\\0" // bot number?
- - "\\gamedir\\%s" // gamedir. _xash appended, because Xash3D is not compatible with GS in multiplayer
- - "\\map\\%s" // current map
- - "\\type\\d" // server type
- - "\\password\\0" // is password set
- - "\\os\\%c" // server OS?
- - "\\secure\\0" // server anti-cheat? VAC?
- - "\\lan\\0" // is LAN server?
- - "\\version\\%f" // server version
- - "\\region\\255" // server region
- - "\\product\\%s\n", // product? Where is the difference with gamedir?
- - PROTOCOL_VERSION,
- - challenge,
- - count,
- - sv_maxclients->integer,
- - GI->gamefolder,
- - sv.name,
- - ostype,
- - XASH_VERSION,
- - GI->gamefolder
- - );
- -
- - NET_SendPacket( NS_SERVER, Q_strlen( query ), query, from );
- - }
- + else if( !Q_strcmp( c, "s")) SV_AddToMaster( from, msg );
- + else if( !Q_strcmp( c, "T" "Source" )) SV_TSourceEngineQuery( from );
- + else if( !Q_strcmp( c, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
- else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
- {
- // user out of band message (must be handled in CL_ConnectionlessPacket)
- @@ -2139,11 +2212,10 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
- client_frame_t *frame;
- int key, size, checksum1, checksum2;
- int i, numbackup, newcmds, numcmds;
- - usercmd_t nullcmd, *from;
- - usercmd_t cmds[32], *to;
- + usercmd_t nullcmd, *to, *from;
- + usercmd_t cmds[32];
- edict_t *player;
- - numbackup = 2;
- player = cl->edict;
- frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
- @@ -2167,7 +2239,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
- return;
- }
- - from = &nullcmd; // first cmd are starting from null-comressed usercmd_t
- + from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
- for( i = numcmds - 1; i >= 0; i-- )
- {
- @@ -2248,10 +2320,10 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
- // adjust latency time by 1/2 last client frame since
- // the message probably arrived 1/2 through client's frame loop
- frame->latency -= cl->lastcmd.msec * 0.5f / 1000.0f;
- - frame->latency = max( 0.0f, frame->latency );
- + frame->latency = Q_max( 0.0f, frame->latency );
- - if( player->v.animtime > sv.time + host.frametime )
- - player->v.animtime = sv.time + host.frametime;
- + if( player->v.animtime > svgame.globals->time + host.frametime )
- + player->v.animtime = svgame.globals->time + host.frametime;
- }
- /*
- @@ -2280,7 +2352,7 @@ void SV_ParseCvarValue( sv_client_t *cl, sizebuf_t *msg )
- if( svgame.dllFuncs2.pfnCvarValue != NULL )
- svgame.dllFuncs2.pfnCvarValue( cl->edict, value );
- - MsgDev( D_AICONSOLE, "Cvar query response: name:%s, value:%s\n", cl->name, value );
- + MsgDev( D_REPORT, "Cvar query response: name:%s, value:%s\n", cl->name, value );
- }
- /*
- @@ -2299,7 +2371,7 @@ void SV_ParseCvarValue2( sv_client_t *cl, sizebuf_t *msg )
- if( svgame.dllFuncs2.pfnCvarValue2 != NULL )
- svgame.dllFuncs2.pfnCvarValue2( cl->edict, requestID, name, value );
- - MsgDev( D_AICONSOLE, "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
- + MsgDev( D_REPORT, "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
- }
- /*
- @@ -2319,7 +2391,7 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
- // calc ping time
- frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
- - // raw ping doesn't factor in message interval, either
- + // ping time doesn't factor in message interval, either
- frame->ping_time = host.realtime - frame->senttime - cl->cl_updaterate;
- // on first frame ( no senttime ) don't skew ping
- @@ -2364,7 +2436,9 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
- case clc_nop:
- break;
- case clc_userinfo:
- - SV_UserinfoChanged( cl, MSG_ReadString( msg ));
- + Q_strncpy( cl->userinfo, MSG_ReadString( msg ), sizeof( cl->userinfo ));
- + if( cl->state >= cs_connected )
- + SetBits( cl->flags, FCL_RESEND_USERINFO ); // needs for update client info
- break;
- case clc_delta:
- cl->delta_sequence = MSG_ReadByte( msg );
- diff --git b/engine/server/sv_cmds.c a/engine/server/sv_cmds.c
- index 88f039e..7ba96db 100644
- --- b/engine/server/sv_cmds.c
- +++ a/engine/server/sv_cmds.c
- @@ -25,10 +25,10 @@ Sends text across to be displayed if the level passes
- */
- void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... )
- {
- - va_list argptr;
- char string[MAX_SYSPATH];
- + va_list argptr;
- - if( level < cl->messagelevel || cl->fakeclient )
- + if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
- return;
- va_start( argptr, fmt );
- @@ -47,14 +47,15 @@ SV_BroadcastPrintf
- Sends text to all active clients
- =================
- */
- -void SV_BroadcastPrintf( int level, char *fmt, ... )
- +void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... )
- {
- char string[MAX_SYSPATH];
- va_list argptr;
- sv_client_t *cl;
- int i;
- - if( !sv.state ) return;
- + if( sv.state == ss_dead )
- + return;
- va_start( argptr, fmt );
- Q_vsprintf( string, fmt, argptr );
- @@ -65,9 +66,11 @@ void SV_BroadcastPrintf( int level, char *fmt, ... )
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- - if( level < cl->messagelevel ) continue;
- - if( cl->state != cs_spawned ) continue;
- - if( cl->fakeclient ) continue;
- + if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
- + continue;
- +
- + if( cl == ignore || cl->state != cs_spawned )
- + continue;
- MSG_WriteByte( &cl->netchan.message, svc_print );
- MSG_WriteByte( &cl->netchan.message, level );
- @@ -84,10 +87,12 @@ Sends text to all active clients
- */
- void SV_BroadcastCommand( char *fmt, ... )
- {
- - va_list argptr;
- char string[MAX_SYSPATH];
- -
- - if( !sv.state ) return;
- + va_list argptr;
- +
- + if( sv.state == ss_dead )
- + return;
- +
- va_start( argptr, fmt );
- Q_vsprintf( string, fmt, argptr );
- va_end( argptr );
- @@ -187,6 +192,7 @@ void SV_Map_f( void )
- // hold mapname to other place
- Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
- + FS_StripExtension( mapname );
- // determine spawn entity classname
- if( sv_maxclients->integer == 1 )
- @@ -195,19 +201,19 @@ void SV_Map_f( void )
- flags = SV_MapIsValid( mapname, spawn_entity, NULL );
- - if( flags & MAP_INVALID_VERSION )
- + if( FBitSet( flags, MAP_INVALID_VERSION ))
- {
- Msg( "SV_NewMap: map %s is invalid or not supported\n", mapname );
- return;
- }
- - if(!( flags & MAP_IS_EXIST ))
- + if( !FBitSet( flags, MAP_IS_EXIST ))
- {
- Msg( "SV_NewMap: map %s doesn't exist\n", mapname );
- return;
- }
- - if(!( flags & MAP_HAS_SPAWNPOINT ))
- + if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
- {
- Msg( "SV_NewMap: map %s doesn't have a valid spawnpoint\n", mapname );
- return;
- @@ -259,16 +265,24 @@ void SV_MapBackground_f( void )
- // hold mapname to other place
- Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
- + FS_StripExtension( mapname );
- +
- flags = SV_MapIsValid( mapname, GI->sp_entity, NULL );
- - if(!( flags & MAP_IS_EXIST ))
- + if( FBitSet( flags, MAP_INVALID_VERSION ))
- + {
- + Msg( "SV_NewMap: map %s is invalid or not supported\n", mapname );
- + return;
- + }
- +
- + if( !FBitSet( flags, MAP_IS_EXIST ))
- {
- Msg( "SV_NewMap: map %s doesn't exist\n", mapname );
- return;
- }
- // background maps allow without spawnpoints (just throw warning)
- - if(!( flags & MAP_HAS_SPAWNPOINT ))
- + if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
- MsgDev( D_WARN, "SV_NewMap: map %s doesn't have a valid spawnpoint\n", mapname );
- Q_strncpy( host.finalmsg, "", MAX_STRING );
- @@ -453,7 +467,8 @@ Saves the state of the map just being exited and goes to a new map.
- */
- void SV_ChangeLevel_f( void )
- {
- - char *spawn_entity, *mapname;
- + string mapname;
- + char *spawn_entity;
- int flags, c = Cmd_Argc();
- if( c < 2 )
- @@ -462,7 +477,9 @@ void SV_ChangeLevel_f( void )
- return;
- }
- - mapname = Cmd_Argv( 1 );
- + // hold mapname to other place
- + Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
- + FS_StripExtension( mapname );
- // determine spawn entity classname
- if( sv_maxclients->integer == 1 )
- @@ -471,19 +488,19 @@ void SV_ChangeLevel_f( void )
- flags = SV_MapIsValid( mapname, spawn_entity, Cmd_Argv( 2 ));
- - if( flags & MAP_INVALID_VERSION )
- + if( FBitSet( flags, MAP_INVALID_VERSION ))
- {
- Msg( "SV_ChangeLevel: map %s is invalid or not supported\n", mapname );
- return;
- }
- - if(!( flags & MAP_IS_EXIST ))
- + if( !FBitSet( flags, MAP_IS_EXIST ))
- {
- Msg( "SV_ChangeLevel: map %s doesn't exist\n", mapname );
- return;
- }
- - if( c >= 3 && !( flags & MAP_HAS_LANDMARK ))
- + if( c >= 3 && !FBitSet( flags, MAP_HAS_LANDMARK ))
- {
- if( sv_validate_changelevel->integer )
- {
- @@ -501,7 +518,7 @@ void SV_ChangeLevel_f( void )
- return;
- }
- - if( c == 2 && !( flags & MAP_HAS_SPAWNPOINT ))
- + if( c == 2 && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
- {
- if( sv_validate_changelevel->integer )
- {
- @@ -510,7 +527,7 @@ void SV_ChangeLevel_f( void )
- }
- }
- - // bad changelevel position invoke enables in one-way transtion
- + // bad changelevel position invoke enables in one-way transition
- if( sv.net_framenum < 15 )
- {
- if( sv_validate_changelevel->integer )
- @@ -611,7 +628,7 @@ void SV_Kick_f( void )
- return;
- }
- - SV_BroadcastPrintf( PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name );
- + SV_BroadcastPrintf( svs.currentPlayer, PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name );
- SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "You were kicked from the game\n" );
- SV_DropClient( svs.currentPlayer );
- @@ -633,7 +650,7 @@ void SV_Kill_f( void )
- if( svs.currentPlayer->edict->v.health <= 0.0f )
- {
- - SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "Can't suicide -- allready dead!\n");
- + SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "Can't suicide - already dead!\n");
- return;
- }
- @@ -673,8 +690,8 @@ SV_Status_f
- */
- void SV_Status_f( void )
- {
- - int i;
- sv_client_t *cl;
- + int i;
- if( !svs.clients || sv.background )
- {
- @@ -698,7 +715,7 @@ void SV_Status_f( void )
- if( cl->state == cs_connected ) Msg( "Connect" );
- else if( cl->state == cs_zombie ) Msg( "Zombie " );
- - else if( cl->fakeclient ) Msg( "Bot " );
- + else if( FBitSet( cl->flags, FCL_FAKECLIENT )) Msg( "Bot " );
- else
- {
- ping = cl->ping < 9999 ? cl->ping : 9999;
- @@ -812,7 +829,9 @@ Kick everyone off, possibly in preparation for a new game
- */
- void SV_KillServer_f( void )
- {
- - if( !svs.initialized ) return;
- + if( !svs.initialized )
- + return;
- +
- Q_strncpy( host.finalmsg, "Server was killed", MAX_STRING );
- SV_Shutdown( false );
- NET_Config ( false ); // close network sockets
- @@ -830,18 +849,18 @@ void SV_PlayersOnly_f( void )
- if( !Cvar_VariableInteger( "sv_cheats" )) return;
- sv.hostflags = sv.hostflags ^ SVF_PLAYERSONLY;
- - if(!( sv.hostflags & SVF_PLAYERSONLY ))
- - SV_BroadcastPrintf( D_INFO, "Resume server physic\n" );
- - else SV_BroadcastPrintf( D_INFO, "Freeze server physic\n" );
- + if( !FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
- + SV_BroadcastPrintf( NULL, PRINT_HIGH, "Resume server physic\n" );
- + else SV_BroadcastPrintf( NULL, PRINT_HIGH, "Freeze server physic\n" );
- }
- /*
- ===============
- -SV_EdictsInfo_f
- +SV_EdictUsage_f
- ===============
- */
- -void SV_EdictsInfo_f( void )
- +void SV_EdictUsage_f( void )
- {
- int active;
- @@ -924,7 +943,7 @@ void SV_InitOperatorCommands( void )
- Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );
- Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
- Cmd_AddCommand( "entpatch", SV_EntPatch_f, "write entity patch to allow external editing" );
- - Cmd_AddCommand( "edicts_info", SV_EdictsInfo_f, "show info about edicts" );
- + Cmd_AddCommand( "edict_usage", SV_EdictUsage_f, "show info about edicts usage" );
- Cmd_AddCommand( "entity_info", SV_EntityInfo_f, "show more info about edicts" );
- if( host.type == HOST_DEDICATED )
- @@ -968,7 +987,7 @@ void SV_KillOperatorCommands( void )
- Cmd_RemoveCommand( "restart" );
- Cmd_RemoveCommand( "reload" );
- Cmd_RemoveCommand( "entpatch" );
- - Cmd_RemoveCommand( "edicts_info" );
- + Cmd_RemoveCommand( "edict_usage" );
- Cmd_RemoveCommand( "entity_info" );
- if( host.type == HOST_DEDICATED )
- diff --git b/engine/server/sv_custom.c a/engine/server/sv_custom.c
- index 67f082e..2a63484 100644
- --- b/engine/server/sv_custom.c
- +++ a/engine/server/sv_custom.c
- @@ -302,7 +302,7 @@ void SV_SendConsistencyList( sizebuf_t *msg )
- int lastIndex;
- int i;
- - if( mp_consistency->integer && ( sv.num_consistency_resources > 0 ) && !svs.currentPlayer->hltv_proxy )
- + if( mp_consistency->integer && ( sv.num_consistency_resources > 0 ) && !FBitSet( svs.currentPlayer->flags, FCL_HLTV_PROXY ))
- {
- lastIndex = 0;
- MSG_WriteOneBit( msg, 1 );
- diff --git b/engine/server/sv_frame.c a/engine/server/sv_frame.c
- index edefd98..43b7dbe 100644
- --- b/engine/server/sv_frame.c
- +++ a/engine/server/sv_frame.c
- @@ -24,9 +24,6 @@ typedef struct
- entity_state_t entities[MAX_VISIBLE_PACKET];
- } sv_ents_t;
- -static byte *clientpvs; // FatPVS
- -static byte *clientphs; // FatPHS
- -
- int c_fullsend; // just a debug counter
- /*
- @@ -55,77 +52,84 @@ SV_AddEntitiesToPacket
- =============
- */
- -static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents )
- +static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents, qboolean from_client )
- {
- edict_t *ent;
- - byte *pset;
- + byte *clientpvs;
- + byte *clientphs;
- qboolean fullvis = false;
- sv_client_t *netclient;
- sv_client_t *cl = NULL;
- entity_state_t *state;
- - int e, player;
- + int e;
- // during an error shutdown message we may need to transmit
- // the shutdown message after the server has shutdown, so
- // specifically check for it
- - if( !sv.state ) return;
- + if( sv.state == ss_dead )
- + return;
- cl = SV_ClientFromEdict( pClient, true );
- ASSERT( cl != NULL );
- - if( pClient && !( sv.hostflags & SVF_PORTALPASS ))
- + // portals can't change hostflags
- + if( pClient && from_client )
- {
- - // portals can't change hostflags
- - sv.hostflags &= ~SVF_SKIPLOCALHOST;
- -
- // setup hostflags
- - if( cl->local_weapons )
- - {
- - sv.hostflags |= SVF_SKIPLOCALHOST;
- - }
- + if( FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
- + SetBits( sv.hostflags, SVF_SKIPLOCALHOST );
- + else ClearBits( sv.hostflags, SVF_SKIPLOCALHOST );
- - // reset cameras each frame
- - cl->num_cameras = 0;
- + // reset viewents each frame
- + cl->num_viewents = 0;
- }
- svgame.dllFuncs.pfnSetupVisibility( pViewEnt, pClient, &clientpvs, &clientphs );
- if( !clientpvs ) fullvis = true;
- + // don't send the world
- for( e = 1; e < svgame.numEntities; e++ )
- {
- + byte *pset;
- +
- ent = EDICT_NUM( e );
- - if( ent->free ) continue;
- +
- + if( !SV_IsValidEdict( ent ))
- + continue;
- // don't double add an entity through portals (already added)
- // HACHACK: use pushmsec to keep net_framenum
- if( ent->v.pushmsec == sv.net_framenum )
- continue;
- - if( ent->v.effects & EF_REQUEST_PHS )
- + if( FBitSet( ent->v.effects, EF_REQUEST_PHS ))
- pset = clientphs;
- else pset = clientpvs;
- state = &ents->entities[ents->num_entities];
- netclient = SV_ClientFromEdict( ent, true );
- - player = ( netclient != NULL );
- // add entity to the net packet
- - if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, player, pset ))
- + if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, ( netclient != NULL ), pset ))
- {
- // to prevent adds it twice through portals
- ent->v.pushmsec = sv.net_framenum;
- - if( netclient && netclient->modelindex ) // apply custom model if present
- + if( netclient && netclient->modelindex )
- + {
- + // update playermodel if this was changed
- state->modelindex = netclient->modelindex;
- + }
- - if( SV_IsValidEdict( ent->v.aiment ) && ( ent->v.aiment->v.effects & EF_MERGE_VISIBILITY ))
- + if( SV_IsValidEdict( ent->v.aiment ) && FBitSet( ent->v.aiment->v.effects, EF_MERGE_VISIBILITY ))
- {
- - if( cl != NULL && cl->num_cameras < MAX_CAMERAS )
- + if( cl != NULL && cl->num_viewents < MAX_VIEWENTS )
- {
- - cl->cameras[cl->num_cameras] = ent->v.aiment;
- - cl->num_cameras++;
- + cl->viewentity[cl->num_viewents] = ent->v.aiment;
- + cl->num_viewents++;
- }
- + else MsgDev( D_ERROR, "SV_AddEntitiesToPacket: too many viewentities!\n" );
- }
- // if we are full, silently discard entities
- @@ -146,11 +150,11 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
- if( fullvis ) continue; // portal ents will be added anyway, ignore recursion
- // if its a portal entity, add everything visible from its camera position
- - if( !( sv.hostflags & SVF_PORTALPASS ) && ent->v.effects & EF_MERGE_VISIBILITY )
- + if( from_client && FBitSet( ent->v.effects, EF_MERGE_VISIBILITY ))
- {
- - sv.hostflags |= SVF_PORTALPASS;
- - SV_AddEntitiesToPacket( ent, pClient, frame, ents );
- - sv.hostflags &= ~SVF_PORTALPASS;
- + SetBits( sv.hostflags, SVF_MERGE_VISIBILITY );
- + SV_AddEntitiesToPacket( ent, pClient, frame, ents, false );
- + ClearBits( sv.hostflags, SVF_MERGE_VISIBILITY );
- }
- }
- }
- @@ -173,8 +177,8 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
- {
- entity_state_t *oldent, *newent;
- int oldindex, newindex;
- - int oldnum, newnum;
- int from_num_entities;
- + int oldnum, newnum;
- client_frame_t *from;
- // this is the frame that we are going to delta update from
- @@ -184,7 +188,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
- from_num_entities = from->num_entities;
- // the snapshot's entities may still have rolled off the buffer, though
- - if( from->first_entity <= svs.next_client_entities - svs.num_client_entities )
- + if( from->first_entity <= ( svs.next_client_entities - svs.num_client_entities ))
- {
- MsgDev( D_WARN, "%s: delta request from out of date entities.\n", cl->name );
- @@ -223,7 +227,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
- }
- else
- {
- - newent = &svs.packet_entities[(to->first_entity+newindex)%svs.num_client_entities];
- + newent = &svs.packet_entities[(to->first_entity+newindex) % svs.num_client_entities];
- newnum = newent->number;
- }
- @@ -233,7 +237,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
- }
- else
- {
- - oldent = &svs.packet_entities[(from->first_entity+oldindex)%svs.num_client_entities];
- + oldent = &svs.packet_entities[(from->first_entity+oldindex) % svs.num_client_entities];
- oldnum = oldent->number;
- }
- @@ -315,7 +319,7 @@ static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
- for( j = 0; j < to->num_entities; j++ )
- {
- - state = &svs.packet_entities[(to->first_entity+j)%svs.num_client_entities];
- + state = &svs.packet_entities[(to->first_entity+j) % svs.num_client_entities];
- if( state->number == ent_index )
- break;
- }
- @@ -331,10 +335,10 @@ static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
- info->packet_index = j;
- info->args.ducking = 0;
- - if(!( info->args.flags & FEVENT_ORIGIN ))
- + if( !FBitSet( info->args.flags, FEVENT_ORIGIN ))
- VectorClear( info->args.origin );
- - if(!( info->args.flags & FEVENT_ANGLES ))
- + if( !FBitSet( info->args.flags, FEVENT_ANGLES ))
- VectorClear( info->args.angles );
- VectorClear( info->args.velocity );
- @@ -477,14 +481,15 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
- }
- clent->v.fixangle = 0; // reset fixangle
- - clent->v.pushmsec = 0; // reset net framenum
- +
- memset( &frame->clientdata, 0, sizeof( frame->clientdata ));
- + clent->v.pushmsec = 0; // reset net framenum
- // update clientdata_t
- - svgame.dllFuncs.pfnUpdateClientData( clent, cl->local_weapons, &frame->clientdata );
- + svgame.dllFuncs.pfnUpdateClientData( clent, FBitSet( cl->flags, FCL_LOCAL_WEAPONS ), &frame->clientdata );
- MSG_WriteByte( msg, svc_clientdata );
- - if( cl->hltv_proxy ) return; // don't send more nothing
- + if( FBitSet( cl->flags, FCL_HLTV_PROXY )) return; // don't send more nothing
- if( cl->delta_sequence == -1 ) from_cd = &nullcd;
- else from_cd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].clientdata;
- @@ -503,11 +508,11 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
- // write clientdata_t
- MSG_WriteClientData( msg, from_cd, to_cd, sv.time );
- - if( cl->local_weapons && svgame.dllFuncs.pfnGetWeaponData( clent, frame->weapondata ))
- + if( FBitSet( cl->flags, FCL_LOCAL_WEAPONS ) && svgame.dllFuncs.pfnGetWeaponData( clent, frame->weapondata ))
- {
- memset( &nullwd, 0, sizeof( nullwd ));
- - for( i = 0; i < 64; i++ )
- + for( i = 0; i < MAX_LOCAL_WEAPONS; i++ )
- {
- if( cl->delta_sequence == -1 ) from_wd = &nullwd;
- else from_wd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].weapondata[i];
- @@ -536,22 +541,22 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
- static sv_ents_t frame_ents;
- int i, send_pings;
- + frame = &cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK];
- clent = cl->edict;
- - viewent = cl->pViewEntity; // himself or trigger_camera
- - frame = &cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK];
- + viewent = cl->pViewEntity; // himself or trigger_camera
- send_pings = SV_ShouldUpdatePing( cl );
- + ClearBits( sv.hostflags, SVF_MERGE_VISIBILITY );
- sv.net_framenum++; // now all portal-through entities are invalidate
- - sv.hostflags &= ~SVF_PORTALPASS;
- // clear everything in this snapshot
- frame_ents.num_entities = c_fullsend = 0;
- // add all the entities directly visible to the eye, which
- // may include portal entities that merge other viewpoints
- - SV_AddEntitiesToPacket( viewent, clent, frame, &frame_ents );
- + SV_AddEntitiesToPacket( viewent, clent, frame, &frame_ents, true );
- // if there were portals visible, there may be out of order entities
- // in the list which will need to be resorted for the delta compression
- @@ -559,6 +564,15 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
- // of an entity being included twice.
- qsort( frame_ents.entities, frame_ents.num_entities, sizeof( frame_ents.entities[0] ), SV_EntityNumbers );
- + // it will break all connected clients, but it takes more than one week to overflow it
- + if(( (uint)svs.next_client_entities ) + frame_ents.num_entities >= 0x7FFFFFFE )
- + {
- + // just reset counter
- + svs.next_client_entities = 0;
- + // delta is broken now, cannot keep connected clients
- + SV_FinalMessage( "Server is running to long, reconnecting!", true );
- + }
- +
- // copy the entity states out
- frame->num_entities = 0;
- frame->first_entity = svs.next_client_entities;
- @@ -569,10 +583,6 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
- state = &svs.packet_entities[svs.next_client_entities % svs.num_client_entities];
- *state = frame_ents.entities[i];
- svs.next_client_entities++;
- -
- - // this should never hit, map should always be restarted first in SV_Frame
- - if( svs.next_client_entities >= 0x7FFFFFFE )
- - Host_Error( "svs.next_client_entities wrapped\n" );
- frame->num_entities++;
- }
- @@ -595,11 +605,11 @@ SV_SendClientDatagram
- */
- void SV_SendClientDatagram( sv_client_t *cl )
- {
- - byte msg_buf[NET_MAX_PAYLOAD];
- - sizebuf_t msg;
- + static byte msg_buf[NET_MAX_PAYLOAD];
- + sizebuf_t msg;
- - svs.currentPlayer = cl;
- svs.currentPlayerNum = (cl - svs.clients);
- + svs.currentPlayer = cl;
- MSG_Init( &msg, "Datagram", msg_buf, sizeof( msg_buf ));
- @@ -634,8 +644,8 @@ SV_UpdateToReliableMessages
- */
- void SV_UpdateToReliableMessages( void )
- {
- - int i;
- sv_client_t *cl;
- + int i;
- // check for changes to be sent over the reliable streams to all clients
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- @@ -645,37 +655,30 @@ void SV_UpdateToReliableMessages( void )
- if( cl->state != cs_spawned )
- continue;
- - if( cl->sendinfo )
- + if( FBitSet( cl->flags, FCL_RESEND_USERINFO ))
- {
- - cl->sendinfo = false;
- SV_FullClientUpdate( cl, &sv.reliable_datagram );
- + ClearBits( cl->flags, FCL_RESEND_USERINFO );
- }
- - if( cl->sendmovevars )
- + if( FBitSet( cl->flags, FCL_RESEND_MOVEVARS ))
- {
- - cl->sendmovevars = false;
- SV_FullUpdateMovevars( cl, &cl->netchan.message );
- - }
- + ClearBits( cl->flags, FCL_RESEND_MOVEVARS );
- + }
- }
- // 1% chanse for simulate random network bugs
- if( sv.write_bad_message && Com_RandomLong( 0, 512 ) == 404 )
- {
- // just for network debugging (send only for local client)
- - MSG_WriteByte( &sv.datagram, svc_bad );
- - MSG_WriteLong( &sv.datagram, rand( )); // send some random data
- - MSG_WriteString( &sv.datagram, host.finalmsg ); // send final message
- + MSG_WriteByte( &sv.reliable_datagram, svc_bad );
- + MSG_WriteLong( &sv.reliable_datagram, rand( )); // send some random data
- + MSG_WriteString( &sv.reliable_datagram, host.finalmsg ); // send final message
- sv.write_bad_message = false;
- }
- // clear the server datagram if it overflowed.
- - if( MSG_CheckOverflow( &sv.datagram ))
- - {
- - MsgDev( D_ERROR, "sv.datagram overflowed!\n" );
- - MSG_Clear( &sv.datagram );
- - }
- -
- - // clear the server datagram if it overflowed.
- if( MSG_CheckOverflow( &sv.spectator_datagram ))
- {
- MsgDev( D_ERROR, "sv.spectator_datagram overflowed!\n" );
- @@ -685,22 +688,18 @@ void SV_UpdateToReliableMessages( void )
- // now send the reliable and server datagrams to all clients.
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- - if( cl->state < cs_connected || cl->fakeclient )
- + if( cl->state < cs_connected || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue; // reliables go to all connected or spawned
- MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
- - MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
- - if( cl->hltv_proxy )
- - {
- + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
- MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spectator_datagram ), MSG_GetNumBitsWritten( &sv.spectator_datagram ));
- - }
- }
- // now clear the reliable and datagram buffers.
- MSG_Clear( &sv.spectator_datagram );
- MSG_Clear( &sv.reliable_datagram );
- - MSG_Clear( &sv.datagram );
- }
- /*
- @@ -714,7 +713,7 @@ void SV_SendClientMessages( void )
- int i;
- svs.currentPlayer = NULL;
- - svs.currentPlayerNum = 0;
- + svs.currentPlayerNum = -1;
- if( sv.state == ss_dead )
- return;
- @@ -724,32 +723,22 @@ void SV_SendClientMessages( void )
- // send a message to each connected client
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- - if( !cl->state || cl->fakeclient )
- + if( !cl->state || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue;
- - if( cl->skip_message )
- + if( FBitSet( cl->flags, FCL_SKIP_NET_MESSAGE ))
- {
- - cl->skip_message = false;
- + ClearBits( cl->flags, FCL_SKIP_NET_MESSAGE );
- continue;
- }
- if( !host_limitlocal->integer && NET_IsLocalAddress( cl->netchan.remote_address ))
- - cl->send_message = true;
- + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
- if( cl->state == cs_spawned )
- {
- - // Try to send a message as soon as we can.
- - // If the target time for sending is within the next frame interval ( based on last frame ),
- - // trigger the send now. Note that in single player,
- - // send_message is also set to true any time a packet arrives from the client.
- - float time_unti_next_message = cl->next_messagetime - (host.realtime + host.frametime);
- -
- - if( time_unti_next_message <= 0.0f )
- - cl->send_message = true;
- -
- - // something got hosed
- - if( time_unti_next_message > 2.0f )
- - cl->send_message = true;
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ) || ( host.realtime + host.frametime ) >= cl->next_messagetime )
- + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
- }
- // if the reliable message overflowed, drop the client
- @@ -757,51 +746,48 @@ void SV_SendClientMessages( void )
- {
- MSG_Clear( &cl->netchan.message );
- MSG_Clear( &cl->datagram );
- - SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name );
- + SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s overflowed\n", cl->name );
- MsgDev( D_WARN, "reliable overflow for %s\n", cl->name );
- SV_DropClient( cl );
- - cl->send_message = true;
- - cl->netchan.cleartime = 0; // don't choke this message
- + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
- + cl->netchan.cleartime = 0.0; // don't choke this message
- }
- - else if( cl->send_message )
- + else if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE ))
- {
- // If we haven't gotten a message in sv_failuretime seconds, then stop sending messages to this client
- // until we get another packet in from the client. This prevents crash/drop and reconnect where they are
- // being hosed with "sequenced packet without connection" packets.
- if(( host.realtime - cl->netchan.last_received ) > sv_failuretime->value )
- - cl->send_message = false;
- + ClearBits( cl->flags, FCL_SEND_NET_MESSAGE );
- }
- // only send messages if the client has sent one
- // and the bandwidth is not choked
- - if( !cl->send_message ) continue;
- -
- - // Bandwidth choke active?
- - if( !Netchan_CanPacket( &cl->netchan ))
- + if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE ))
- {
- - cl->chokecount++;
- - continue;
- - }
- -
- - cl->send_message = false;
- + // bandwidth choke active?
- + if( !Netchan_CanPacket( &cl->netchan ))
- + {
- + cl->chokecount++;
- + continue;
- + }
- - // Now that we were able to send, reset timer to point to next possible send time.
- - cl->next_messagetime = host.realtime + host.frametime + cl->cl_updaterate;
- + // now that we were able to send, reset timer to point to next possible send time.
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + cl->next_messagetime = host.realtime + cl->cl_updaterate;
- + else cl->next_messagetime = host.realtime + host.frametime + cl->cl_updaterate;
- + ClearBits( cl->flags, FCL_SEND_NET_MESSAGE );
- - if( cl->state == cs_spawned )
- - {
- - SV_SendClientDatagram( cl );
- - }
- - else
- - {
- - // just update reliable
- - Netchan_Transmit( &cl->netchan, 0, NULL );
- + // NOTE: we should send frame even if server is not simulated to prevent overflow
- + if( cl->state == cs_spawned )
- + SV_SendClientDatagram( cl );
- + else Netchan_Transmit( &cl->netchan, 0, NULL ); // just update reliable
- }
- }
- // reset current client
- svs.currentPlayer = NULL;
- - svs.currentPlayerNum = 0;
- + svs.currentPlayerNum = -1;
- }
- /*
- @@ -813,8 +799,8 @@ e.g. before changing level
- */
- void SV_SendMessagesToAll( void )
- {
- - int i;
- sv_client_t *cl;
- + int i;
- if( sv.state == ss_dead )
- return;
- @@ -822,8 +808,9 @@ void SV_SendMessagesToAll( void )
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- if( cl->state >= cs_connected )
- - cl->send_message = true;
- + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
- }
- +
- SV_SendClientMessages();
- }
- @@ -836,17 +823,18 @@ used before changing level
- */
- void SV_SkipUpdates( void )
- {
- - int i;
- sv_client_t *cl;
- + int i;
- if( sv.state == ss_dead )
- return;
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- - if( cl->state != cs_spawned || cl->fakeclient )
- + if( cl->state != cs_spawned || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue;
- - cl->skip_message = true;
- +
- + SetBits( cl->flags, FCL_SKIP_NET_MESSAGE );
- }
- }
- @@ -871,7 +859,7 @@ void SV_InactivateClients( void )
- if( !cl->state || !cl->edict )
- continue;
- - if( !cl->edict || (cl->edict->v.flags & FL_FAKECLIENT))
- + if( !cl->edict || FBitSet( cl->edict->v.flags, FL_FAKECLIENT ))
- continue;
- if( svs.clients[i].state > cs_connected )
- diff --git b/engine/server/sv_game.c a/engine/server/sv_game.c
- index 483a888..5a99b55 100644
- --- b/engine/server/sv_game.c
- +++ a/engine/server/sv_game.c
- @@ -28,8 +28,6 @@ static byte fatpvs[MAX_MAP_LEAFS/8];
- static byte fatphs[MAX_MAP_LEAFS/8];
- static byte clientpvs[MAX_MAP_LEAFS/8]; // for find client in PVS
- static vec3_t viewPoint[MAX_CLIENTS];
- -static byte *bitvector;
- -static int fatbytes;
- // exports
- typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
- @@ -218,35 +216,37 @@ Check visibility through client camera, portal camera, etc
- */
- qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
- {
- - int i, leafnum, clientnum;
- - float *viewOrg = NULL;
- + int i, clientnum;
- + vec3_t vieworg;
- + mleaf_t *leaf;
- if( !mask ) return true; // full visibility
- clientnum = cl - svs.clients;
- - viewOrg = viewPoint[clientnum];
- + VectorCopy( viewPoint[clientnum], vieworg );
- // Invasion issues: wrong camera position received in ENGINE_SET_PVS
- - if( cl->pViewEntity && !VectorCompare( viewOrg, cl->pViewEntity->v.origin ))
- - viewOrg = cl->pViewEntity->v.origin;
- + if( cl->pViewEntity && !VectorCompare( vieworg, cl->pViewEntity->v.origin ))
- + VectorCopy( cl->pViewEntity->v.origin, vieworg );
- - // -1 is because pvs rows are 1 based, not 0 based like leafs
- - leafnum = Mod_PointLeafnum( viewOrg ) - 1;
- - if( leafnum == -1 || (mask[leafnum>>3] & (1<<( leafnum & 7 ))))
- + leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
- +
- + if( CHECKVISBIT( mask, leaf->cluster ))
- return true; // visible from player view or camera view
- // now check all the portal cameras
- - for( i = 0; i < cl->num_cameras; i++ )
- + for( i = 0; i < cl->num_viewents; i++ )
- {
- - edict_t *cam = cl->cameras[i];
- + edict_t *view = cl->viewentity[i];
- - if( !SV_IsValidEdict( cam ))
- + if( !SV_IsValidEdict( view ))
- continue;
- - leafnum = Mod_PointLeafnum( cam->v.origin ) - 1;
- - // g-cont. probably camera in bad leaf... allow to send message here?
- - if( leafnum == -1 || (mask[leafnum>>3] & (1<<( leafnum & 7 ))))
- - return true;
- + VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
- + leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
- +
- + if( CHECKVISBIT( mask, leaf->cluster ))
- + return true; // visible from portal camera view
- }
- // not visible from any viewpoint
- @@ -263,10 +263,10 @@ then clears sv.multicast.
- MSG_ONE send to one client (ent can't be NULL)
- MSG_ALL same as broadcast (origin can be NULL)
- MSG_PVS send to clients potentially visible from org
- -MSG_PHS send to clients potentially hearable from org
- +MSG_PHS send to clients potentially audible from org
- =================
- */
- -qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
- +qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent, qboolean usermessage, qboolean filter )
- {
- byte *mask = NULL;
- int j, numclients = sv_maxclients->integer;
- @@ -274,7 +274,6 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
- qboolean reliable = false;
- qboolean specproxy = false;
- int numsends = 0;
- - mleaf_t *leaf;
- switch( dest )
- {
- @@ -298,16 +297,15 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
- // intentional fallthrough
- case MSG_PAS:
- if( origin == NULL ) return false;
- - leaf = Mod_PointInLeaf( origin, sv.worldmodel->nodes );
- - mask = Mod_LeafPHS( leaf, sv.worldmodel );
- + Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, false );
- + mask = fatphs; // using the FatPVS like a PHS
- break;
- case MSG_PVS_R:
- reliable = true;
- // intentional fallthrough
- case MSG_PVS:
- if( origin == NULL ) return false;
- - leaf = Mod_PointInLeaf( origin, sv.worldmodel->nodes );
- - mask = Mod_LeafPVS( leaf, sv.worldmodel );
- + mask = Mod_GetPVSForPoint( origin );
- break;
- case MSG_ONE:
- reliable = true;
- @@ -333,13 +331,18 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
- if( cl->state == cs_free || cl->state == cs_zombie )
- continue;
- - if( cl->state != cs_spawned && !reliable )
- + if( cl->state != cs_spawned && ( !reliable || usermessage ))
- continue;
- - if( specproxy && !cl->hltv_proxy )
- + if( specproxy && !FBitSet( cl->flags, FCL_HLTV_PROXY ))
- continue;
- - if( !cl->edict || cl->fakeclient )
- + if( !cl->edict || FBitSet( cl->flags, FCL_FAKECLIENT ))
- + continue;
- +
- + // reject step sounds while predicting is enabled
- + // FIXME: make sure what this code doesn't cutoff something important!!!
- + if( filter && cl == svs.currentPlayer && FBitSet( svs.currentPlayer->flags, FCL_PREDICT_MOVEMENT ))
- continue;
- if( ent != NULL && ent->v.groupinfo && cl->edict->v.groupinfo )
- @@ -359,7 +362,7 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
- MSG_Clear( &sv.multicast );
- - return numsends; // debug
- + return numsends; // just for debug
- }
- /*
- @@ -525,67 +528,15 @@ void SV_RestartStaticEnts( void )
- }
- /*
- -=============================================================================
- -
- -The PVS must include a small area around the client to allow head bobbing
- -or other small motion on the client side. Otherwise, a bob might cause an
- -entity that should be visible to not show up, especially when the bob
- -crosses a waterline.
- -
- -=============================================================================
- -*/
- -static void SV_AddToFatPVS( const vec3_t org, int type, mnode_t *node )
- -{
- - byte *vis;
- - float d;
- -
- - while( 1 )
- - {
- - // if this is a leaf, accumulate the pvs bits
- - if( node->contents < 0 )
- - {
- - if( node->contents != CONTENTS_SOLID )
- - {
- - mleaf_t *leaf;
- - int i;
- -
- - leaf = (mleaf_t *)node;
- -
- - if( type == DVIS_PVS )
- - vis = Mod_LeafPVS( leaf, sv.worldmodel );
- - else if( type == DVIS_PHS )
- - vis = Mod_LeafPHS( leaf, sv.worldmodel );
- - else vis = Mod_DecompressVis( NULL ); // get full visibility
- -
- - for( i = 0; i < fatbytes; i++ )
- - bitvector[i] |= vis[i];
- - }
- - return;
- - }
- -
- - d = PlaneDiff( org, node->plane );
- - if( d > 8.0f ) node = node->children[0];
- - else if( d < -8.0f ) node = node->children[1];
- - else
- - {
- - // go down both
- - SV_AddToFatPVS( org, type, node->children[0] );
- - node = node->children[1];
- - }
- - }
- -}
- -
- -/*
- ==============
- SV_BoxInPVS
- check brush boxes in fat pvs
- ==============
- */
- -static qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
- +qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
- {
- - mleaf_t *leaf = Mod_PointInLeaf( org, sv.worldmodel->nodes );
- - byte *vis = Mod_LeafPVS( leaf, sv.worldmodel );
- + byte *vis = Mod_GetPVSForPoint( org );
- if( !Mod_BoxVisible( absmin, absmax, vis ))
- return false;
- @@ -834,7 +785,7 @@ void SV_InitEdict( edict_t *pEdict )
- void SV_FreeEdict( edict_t *pEdict )
- {
- - ASSERT( pEdict );
- + ASSERT( pEdict != NULL );
- ASSERT( pEdict->free == false );
- // unlink from world
- @@ -1033,7 +984,10 @@ void SV_BaselineForEntity( edict_t *pEdict )
- float *mins, *maxs;
- sv_client_t *cl;
- - if( pEdict->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( pEdict, false )))
- + if( !SV_IsValidEdict( pEdict ))
- + return;
- +
- + if( FBitSet( pEdict->v.flags, FL_CLIENT ) && ( cl = SV_ClientFromEdict( pEdict, false )))
- {
- usehull = ( pEdict->v.flags & FL_DUCKING ) ? true : false;
- modelindex = cl->modelindex ? cl->modelindex : pEdict->v.modelindex;
- @@ -1422,7 +1376,7 @@ edict_t *pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float fl
- return ent;
- }
- - return NULL;
- + return svgame.edicts;
- }
- /*
- @@ -1435,31 +1389,27 @@ build the new client PVS
- int SV_CheckClientPVS( int check, qboolean bMergePVS )
- {
- byte *pvs;
- - edict_t *ent;
- - mleaf_t *leaf;
- - vec3_t view;
- + vec3_t vieworg;
- sv_client_t *cl;
- int i, j, k;
- - int pvsbytes;
- + edict_t *ent = NULL;
- // cycle to the next one
- check = bound( 1, check, svgame.globals->maxClients );
- if( check == svgame.globals->maxClients )
- - i = 1;
- + i = 1; // reset cycle
- else i = check + 1;
- for( ;; i++ )
- {
- - if( i == svgame.globals->maxClients + 1 )
- + if( i == ( svgame.globals->maxClients + 1 ))
- i = 1;
- ent = EDICT_NUM( i );
- + if( i == check ) break; // didn't find anything else
- - if( i == check )
- - break; // didn't find anything else
- -
- - if( ent->free || !ent->pvPrivateData || ( ent->v.flags & FL_NOTARGET ))
- + if( ent->free || !ent->pvPrivateData || FBitSet( ent->v.flags, FL_NOTARGET ))
- continue;
- // anything that is a client, or has a client as an enemy
- @@ -1467,31 +1417,28 @@ int SV_CheckClientPVS( int check, qboolean bMergePVS )
- }
- cl = SV_ClientFromEdict( ent, true );
- - pvsbytes = (sv.worldmodel->numleafs + 7) >> 3;
- + memset( clientpvs, 0xFF, world.visbytes );
- // get the PVS for the entity
- - VectorAdd( ent->v.origin, ent->v.view_ofs, view );
- - leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
- - pvs = Mod_LeafPVS( leaf, sv.worldmodel );
- - memcpy( clientpvs, pvs, pvsbytes );
- + VectorAdd( ent->v.origin, ent->v.view_ofs, vieworg );
- + pvs = Mod_GetPVSForPoint( vieworg );
- + if( pvs ) memcpy( clientpvs, pvs, world.visbytes );
- // transition in progress
- if( !cl ) return i;
- - // now merge PVS with all portal cameras
- - for( k = 0; k < cl->num_cameras && bMergePVS; k++ )
- + // now merge PVS with all the portal cameras
- + for( k = 0; k < cl->num_viewents && bMergePVS; k++ )
- {
- - edict_t *cam = cl->cameras[k];
- + edict_t *view = cl->viewentity[k];
- - if( !SV_IsValidEdict( cam ))
- + if( !SV_IsValidEdict( view ))
- continue;
- - VectorAdd( cam->v.origin, cam->v.view_ofs, view );
- - leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
- - if( leaf == NULL ) continue; // skip outside cameras
- - pvs = Mod_LeafPVS( leaf, sv.worldmodel );
- + VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
- + pvs = Mod_GetPVSForPoint( vieworg );
- - for( j = 0; j < pvsbytes; j++ )
- + for( j = 0; j < world.visbytes && pvs; j++ )
- clientpvs[j] |= pvs[j];
- }
- @@ -1511,7 +1458,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
- float delta;
- model_t *mod;
- qboolean bMergePVS;
- - int i;
- + mleaf_t *leaf;
- if( !SV_IsValidEdict( pEdict ))
- return svgame.edicts;
- @@ -1519,7 +1466,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
- delta = ( sv.time - sv.lastchecktime );
- // don't merge visibility for portal entity, only for monsters
- - bMergePVS = (pEdict->v.flags & FL_MONSTER) ? true : false;
- + bMergePVS = FBitSet( pEdict->v.flags, FL_MONSTER ) ? true : false;
- // find a new check if on a new frame
- if( delta < 0.0f || delta >= 0.1f )
- @@ -1530,6 +1477,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
- // return check if it might be visible
- pClient = EDICT_NUM( sv.lastcheck );
- +
- if( !SV_ClientFromEdict( pClient, true ))
- return svgame.edicts;
- @@ -1537,7 +1485,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
- // portals & monitors
- // NOTE: this specific break "radiaton tick" in normal half-life. use only as feature
- - if(( host.features & ENGINE_TRANSFORM_TRACE_AABB ) && mod && mod->type == mod_brush && !( mod->flags & MODEL_HAS_ORIGIN ))
- + if( FBitSet( host.features, ENGINE_TRANSFORM_TRACE_AABB ) && mod && mod->type == mod_brush && !FBitSet( mod->flags, MODEL_HAS_ORIGIN ))
- {
- // handle PVS origin for bmodels
- VectorAverage( pEdict->v.mins, pEdict->v.maxs, view );
- @@ -1551,13 +1499,12 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
- if( pEdict->v.effects & EF_INVLIGHT )
- view[2] -= 1.0f; // HACKHACK for barnacle
- - i = Mod_PointLeafnum( view ) - 1;
- + leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
- - if( i < 0 || !((clientpvs[i>>3]) & (1 << (i & 7))))
- - return svgame.edicts;
- + if( CHECKVISBIT( clientpvs, leaf->cluster ))
- + return pClient; // client which currently in PVS
- - // client which currently in PVS
- - return pClient;
- + return svgame.edicts;
- }
- /*
- @@ -1920,6 +1867,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- {
- int sound_idx;
- int entityIndex;
- + qboolean filter = false;
- int msg_dest;
- vec3_t origin;
- @@ -1950,7 +1898,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- VectorAverage( ent->v.mins, ent->v.maxs, origin );
- VectorAdd( origin, ent->v.origin, origin );
- - if( flags & SND_SPAWNING )
- + if( FBitSet( flags, SND_SPAWNING ))
- msg_dest = MSG_INIT;
- else if( chan == CHAN_STATIC )
- msg_dest = MSG_ALL;
- @@ -1958,6 +1906,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- // always sending stop sound command
- if( flags & SND_STOP ) msg_dest = MSG_ALL;
- + if( flags & SND_FILTER_CLIENT ) filter = true;
- if( sample[0] == '!' && Q_isdigit( sample + 1 ))
- {
- @@ -1983,6 +1932,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- if( sound_idx > 255 ) flags |= SND_LARGE_INDEX;
- // not sending (because this is out of range)
- + flags &= ~SND_FILTER_CLIENT;
- flags &= ~SND_SPAWNING;
- MSG_WriteByte( &sv.multicast, svc_sound );
- @@ -1999,7 +1949,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
- MSG_WriteWord( &sv.multicast, entityIndex );
- MSG_WriteVec3Coord( &sv.multicast, origin );
- - SV_Send( msg_dest, origin, NULL );
- + SV_Send( msg_dest, origin, NULL, false, filter );
- }
- /*
- @@ -2079,7 +2029,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
- MSG_WriteWord( &sv.multicast, number );
- MSG_WriteVec3Coord( &sv.multicast, pos );
- - SV_Send( msg_dest, pos, NULL );
- + SV_Send( msg_dest, pos, NULL, false, false );
- }
- /*
- @@ -2088,11 +2038,11 @@ SV_StartMusic
- =================
- */
- -void SV_StartMusic( const char *curtrack, const char *looptrack, fs_offset_t position )
- +void SV_StartMusic( const char *curtrack, const char *looptrack, long position )
- {
- MSG_WriteByte( &sv.multicast, svc_stufftext );
- MSG_WriteString( &sv.multicast, va( "music \"%s\" \"%s\" %i\n", curtrack, looptrack, position ));
- - SV_Send( MSG_ALL, NULL, NULL );
- + SV_Send( MSG_ALL, NULL, NULL, false, false );
- }
- /*
- @@ -2173,6 +2123,9 @@ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v
- return 1;
- }
- + if( pEdict != pentToSkip )
- + MsgDev( D_ERROR, "TRACE_MONSTER_HULL: pEdict != pentToSkip\n" );
- +
- trace = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip );
- if( ptr ) SV_ConvertTrace( ptr, &trace );
- @@ -2341,7 +2294,7 @@ pfnClientCommand
- */
- void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
- {
- - sv_client_t *client;
- + sv_client_t *cl;
- string buffer;
- va_list args;
- @@ -2351,13 +2304,13 @@ void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
- return;
- }
- - if(( client = SV_ClientFromEdict( pEdict, true )) == NULL )
- + if(( cl = SV_ClientFromEdict( pEdict, true )) == NULL )
- {
- MsgDev( D_ERROR, "SV_ClientCommand: client is not spawned!\n" );
- return;
- }
- - if( client->fakeclient )
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
- return;
- va_start( args, szFmt );
- @@ -2366,8 +2319,8 @@ void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
- if( SV_IsValidCmd( buffer ))
- {
- - MSG_WriteByte( &client->netchan.message, svc_stufftext );
- - MSG_WriteString( &client->netchan.message, buffer );
- + MSG_WriteByte( &cl->netchan.message, svc_stufftext );
- + MSG_WriteString( &cl->netchan.message, buffer );
- }
- else MsgDev( D_ERROR, "Tried to stuff bad command %s\n", buffer );
- }
- @@ -2390,18 +2343,20 @@ void pfnParticleEffect( const float *org, const float *dir, float color, float c
- return;
- }
- - MSG_WriteByte( &sv.datagram, svc_particle );
- - MSG_WriteVec3Coord( &sv.datagram, org );
- + MSG_WriteByte( &sv.multicast, svc_particle );
- + MSG_WriteVec3Coord( &sv.multicast, org );
- for( i = 0; i < 3; i++ )
- {
- v = bound( -128, dir[i] * 16.0f, 127 );
- - MSG_WriteChar( &sv.datagram, v );
- + MSG_WriteChar( &sv.multicast, v );
- }
- - MSG_WriteByte( &sv.datagram, count );
- - MSG_WriteByte( &sv.datagram, color );
- - MSG_WriteByte( &sv.datagram, 0 );
- + MSG_WriteByte( &sv.multicast, count );
- + MSG_WriteByte( &sv.multicast, color );
- + MSG_WriteByte( &sv.multicast, 0 );
- +
- + SV_Send( MSG_PVS, org, NULL, false, false );
- }
- /*
- @@ -2617,7 +2572,7 @@ void pfnMessageEnd( void )
- if( !VectorIsNull( svgame.msg_org )) org = svgame.msg_org;
- svgame.msg_dest = bound( MSG_BROADCAST, svgame.msg_dest, MSG_SPEC );
- - SV_Send( svgame.msg_dest, org, svgame.msg_ent );
- + SV_Send( svgame.msg_dest, org, svgame.msg_ent, true, false );
- }
- /*
- @@ -2698,6 +2653,18 @@ void pfnWriteCoord( float flValue )
- /*
- =============
- +pfnWriteBytes
- +
- +=============
- +*/
- +void pfnWriteBytes( const byte *bytes, int count )
- +{
- + MSG_WriteBytes( &sv.multicast, bytes, count );
- + svgame.msg_realsize += count;
- +}
- +
- +/*
- +=============
- pfnWriteString
- =============
- @@ -2786,7 +2753,7 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
- return;
- break;
- case at_aiconsole:
- - if( host.developer < D_AICONSOLE )
- + if( host.developer < D_REPORT )
- return;
- break;
- case at_warning:
- @@ -2821,7 +2788,7 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
- =============
- pfnEngineFprintf
- -legacy. probably was a part of early save\restore system
- +legacy. probably was a part of early version of save\restore system
- =============
- */
- static void pfnEngineFprintf( FILE *pfile, char *szFmt, ... )
- @@ -3115,7 +3082,7 @@ int pfnRegUserMsg( const char *pszName, int iSize )
- MSG_WriteByte( &sv.multicast, svgame.msg[i].number );
- MSG_WriteByte( &sv.multicast, (byte)iSize );
- MSG_WriteString( &sv.multicast, svgame.msg[i].name );
- - SV_Send( MSG_ALL, NULL, NULL );
- + SV_Send( MSG_ALL, NULL, NULL, false, false );
- }
- return svgame.msg[i].number;
- @@ -3185,7 +3152,7 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
- if( sv.state != ss_active )
- {
- // send message into console during loading
- - MsgDev( D_INFO, szMsg );
- + MsgDev( D_INFO, "%s\n", szMsg );
- return;
- }
- @@ -3198,15 +3165,18 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
- switch( ptype )
- {
- case print_console:
- - if( client->fakeclient ) MsgDev( D_INFO, szMsg );
- + if( FBitSet( client->flags, FCL_FAKECLIENT ))
- + MsgDev( D_INFO, "%s", szMsg );
- else SV_ClientPrintf( client, PRINT_HIGH, "%s", szMsg );
- break;
- case print_chat:
- - if( client->fakeclient ) return;
- + if( FBitSet( client->flags, FCL_FAKECLIENT ))
- + return;
- SV_ClientPrintf( client, PRINT_CHAT, "%s", szMsg );
- break;
- case print_center:
- - if( client->fakeclient ) return;
- + if( FBitSet( client->flags, FCL_FAKECLIENT ))
- + return;
- MSG_WriteByte( &client->netchan.message, svc_centerprint );
- MSG_WriteString( &client->netchan.message, szMsg );
- break;
- @@ -3222,8 +3192,8 @@ pfnServerPrint
- void pfnServerPrint( const char *szMsg )
- {
- // while loading in-progress we can sending message only for local client
- - if( sv.state != ss_active ) MsgDev( D_INFO, szMsg );
- - else SV_BroadcastPrintf( PRINT_HIGH, "%s", szMsg );
- + if( sv.state != ss_active ) MsgDev( D_INFO, "%s", szMsg );
- + else SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", szMsg );
- }
- /*
- @@ -3273,7 +3243,8 @@ void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw )
- }
- // fakeclients ignores it silently
- - if( client->fakeclient ) return;
- + if( FBitSet( client->flags, FCL_FAKECLIENT ))
- + return;
- if( pitch > 180.0f ) pitch -= 360;
- if( pitch < -180.0f ) pitch += 360;
- @@ -3317,7 +3288,8 @@ void pfnSetView( const edict_t *pClient, const edict_t *pViewent )
- else client->pViewEntity = (edict_t *)pViewent;
- // fakeclients ignore to send client message (but can see into the trigger_camera through the PVS)
- - if( client->fakeclient ) return;
- + if( FBitSet( client->flags, FCL_FAKECLIENT ))
- + return;
- MSG_WriteByte( &client->netchan.message, svc_setview );
- MSG_WriteWord( &client->netchan.message, NUM_FOR_EDICT( pViewent ));
- @@ -3370,22 +3342,7 @@ pfnGetPlayerWONId
- */
- uint pfnGetPlayerWONId( edict_t *e )
- {
- - sv_client_t *cl;
- - int i;
- -
- - if( sv.state != ss_active )
- - return -1;
- -
- - if( !SV_ClientFromEdict( e, false ))
- - return -1;
- -
- - for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- - {
- - if( cl->edict == e && cl->authentication_method == 0 )
- - return cl->WonID;
- - }
- -
- - return -1;
- + return 0xFFFFFFFF;
- }
- /*
- @@ -3428,7 +3385,8 @@ void pfnFadeClientVolume( const edict_t *pEdict, int fadePercent, int fadeOutSec
- return;
- }
- - if( cl->fakeclient ) return;
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
- + return;
- MSG_WriteByte( &cl->netchan.message, svc_soundfade );
- MSG_WriteByte( &cl->netchan.message, fadePercent );
- @@ -3478,14 +3436,14 @@ void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, floa
- return;
- }
- - if( !cl->fakeclient )
- - return; // only fakeclients allows
- + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
- + return; // only fakeclients allows
- oldcl = svs.currentPlayer;
- svs.currentPlayer = SV_ClientFromEdict( pClient, true );
- svs.currentPlayerNum = (svs.currentPlayer - svs.clients);
- - svs.currentPlayer->timebase = (sv.time + host.frametime) - (msec / 1000.0f);
- + svs.currentPlayer->timebase = (sv.time + sv.frametime) - (msec / 1000.0f);
- memset( &cmd, 0, sizeof( cmd ));
- if( v_angle ) VectorCopy( v_angle, cmd.viewangles );
- @@ -3559,16 +3517,20 @@ pfnSetClientKeyValue
- */
- void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value )
- {
- + sv_client_t *cl;
- +
- clientIndex -= 1;
- - if( clientIndex < 0 || clientIndex >= sv_maxclients->integer )
- + if( !svs.clients || clientIndex < 0 || clientIndex >= sv_maxclients->integer )
- return;
- - if( svs.clients[clientIndex].state < cs_spawned || infobuffer == NULL )
- + cl = &svs.clients[clientIndex];
- +
- + if( cl->state < cs_spawned || infobuffer == NULL )
- return;
- Info_SetValueForKey( infobuffer, key, value );
- - svs.clients[clientIndex].sendinfo = true;
- + SetBits( cl->flags, FCL_RESEND_USERINFO );
- }
- /*
- @@ -3662,7 +3624,7 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
- byte *mask = NULL;
- vec3_t pvspoint;
- - if( flags & FEV_CLIENT )
- + if( FBitSet( flags, FEV_CLIENT ))
- return; // someone stupid joke
- // first check event for out of bounds
- @@ -3710,14 +3672,14 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
- args.entindex = invokerIndex = NUM_FOR_EDICT( pInvoker );
- // g-cont. allow 'ducking' param for all entities
- - args.ducking = (pInvoker->v.flags & FL_DUCKING) ? true : false;
- + args.ducking = FBitSet( pInvoker->v.flags, FL_DUCKING ) ? true : false;
- // this will be send only for reliable event
- - if(!( args.flags & FEVENT_ORIGIN ))
- + if( !FBitSet( args.flags, FEVENT_ORIGIN ))
- VectorCopy( pInvoker->v.origin, args.origin );
- // this will be send only for reliable event
- - if(!( args.flags & FEVENT_ANGLES ))
- + if( !FBitSet( args.flags, FEVENT_ANGLES ))
- VectorCopy( pInvoker->v.angles, args.angles );
- if( sv_sendvelocity->integer )
- @@ -3730,54 +3692,50 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
- invokerIndex = -1;
- }
- - if(!( flags & FEV_GLOBAL ) && VectorIsNull( pvspoint ))
- + if( !FBitSet( flags, FEV_GLOBAL ) && VectorIsNull( pvspoint ))
- {
- MsgDev( D_ERROR, "%s: not a FEV_GLOBAL event missing origin. Ignored.\n", sv.event_precache[eventindex] );
- return;
- }
- // check event for some user errors
- - if( flags & (FEV_NOTHOST|FEV_HOSTONLY))
- + if( FBitSet( flags, FEV_NOTHOST|FEV_HOSTONLY ))
- {
- if( !SV_ClientFromEdict( pInvoker, true ))
- {
- const char *ev_name = sv.event_precache[eventindex];
- - if( flags & FEV_NOTHOST )
- +
- + if( FBitSet( flags, FEV_NOTHOST ))
- {
- MsgDev( D_WARN, "%s: specified FEV_NOTHOST when invoker not a client\n", ev_name );
- - flags &= ~FEV_NOTHOST;
- + ClearBits( flags, FEV_NOTHOST );
- }
- - if( flags & FEV_HOSTONLY )
- + if( FBitSet( flags, FEV_HOSTONLY ))
- {
- MsgDev( D_WARN, "%s: specified FEV_HOSTONLY when invoker not a client\n", ev_name );
- - flags &= ~FEV_HOSTONLY;
- + ClearBits( flags, FEV_HOSTONLY );
- }
- }
- }
- - flags |= FEV_SERVER; // it's a server event!
- + SetBits( flags, FEV_SERVER ); // it's a server event!
- if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
- - if(!( flags & FEV_GLOBAL ))
- - {
- - mleaf_t *leaf;
- -
- - // setup pvs cluster for invoker
- - leaf = Mod_PointInLeaf( pvspoint, sv.worldmodel->nodes );
- - mask = Mod_LeafPVS( leaf, sv.worldmodel );
- - }
- + // setup pvs cluster for invoker
- + if( !FBitSet( flags, FEV_GLOBAL ))
- + mask = Mod_GetPVSForPoint( pvspoint );
- // process all the clients
- for( slot = 0, cl = svs.clients; slot < sv_maxclients->integer; slot++, cl++ )
- {
- - if( cl->state != cs_spawned || !cl->edict || cl->fakeclient )
- + if( cl->state != cs_spawned || !cl->edict || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue;
- if( SV_IsValidEdict( pInvoker ) && pInvoker->v.groupinfo && cl->edict->v.groupinfo )
- {
- - if(( svs.groupop == 0 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 0 )
- - || ( svs.groupop == 1 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 1 ))
- + if(( svs.groupop == 0 && FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ) == 0 )
- + || ( svs.groupop == 1 && FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ) == 1 ))
- continue;
- }
- @@ -3787,16 +3745,16 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
- continue;
- }
- - if( flags & FEV_NOTHOST && cl == svs.currentPlayer && cl->local_weapons )
- + if( FBitSet( flags, FEV_NOTHOST ) && cl == svs.currentPlayer && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
- continue; // will be played on client side
- - if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
- + if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker )
- continue; // sending only to invoker
- // all checks passed, send the event
- // reliable event
- - if( flags & FEV_RELIABLE )
- + if( FBitSet( flags, FEV_RELIABLE ))
- {
- // skipping queue, write direct into reliable datagram
- SV_PlaybackReliableEvent( &cl->netchan.message, eventindex, delay, &args );
- @@ -3807,11 +3765,12 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
- es = &cl->events;
- bestslot = -1;
- - if( flags & FEV_UPDATE )
- + if( FBitSet( flags, FEV_UPDATE ))
- {
- for( j = 0; j < MAX_EVENT_QUEUE; j++ )
- {
- ei = &es->ei[j];
- +
- if( ei->index == eventindex && invokerIndex != -1 && invokerIndex == ei->entity_index )
- {
- bestslot = j;
- @@ -3864,16 +3823,15 @@ so we can't use a single PVS point
- */
- byte *pfnSetFatPVS( const float *org )
- {
- + qboolean fullvis = false;
- +
- if( !sv.worldmodel->visdata || sv_novis->integer || !org || CL_DisableVisibility( ))
- - return Mod_DecompressVis( NULL );
- + fullvis = true;
- ASSERT( svs.currentPlayerNum >= 0 && svs.currentPlayerNum < MAX_CLIENTS );
- - fatbytes = (sv.worldmodel->numleafs+31)>>3;
- - bitvector = fatpvs;
- -
- // portals can't change viewpoint!
- - if(!( sv.hostflags & SVF_PORTALPASS ))
- + if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
- {
- vec3_t viewPos, offset;
- @@ -3885,7 +3843,7 @@ byte *pfnSetFatPVS( const float *org )
- // }
- // so we have unneeded duck calculations who have affect when player
- // is ducked into water. Remove offset to restore right PVS position
- - if( svs.currentPlayer->edict->v.flags & FL_DUCKING )
- + if( FBitSet( svs.currentPlayer->edict->v.flags, FL_DUCKING ))
- {
- VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
- VectorSubtract( org, offset, viewPos );
- @@ -3893,17 +3851,16 @@ byte *pfnSetFatPVS( const float *org )
- else VectorCopy( org, viewPos );
- // build a new PVS frame
- - memset( bitvector, 0, fatbytes );
- -
- - SV_AddToFatPVS( viewPos, DVIS_PVS, sv.worldmodel->nodes );
- + Mod_FatPVS( viewPos, FATPVS_RADIUS, fatpvs, world.fatbytes, false, fullvis );
- VectorCopy( viewPos, viewPoint[svs.currentPlayerNum] );
- }
- else
- {
- - SV_AddToFatPVS( org, DVIS_PVS, sv.worldmodel->nodes );
- + // merge PVS
- + Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, true, fullvis );
- }
- - return bitvector;
- + return fatpvs;
- }
- /*
- @@ -3916,16 +3873,15 @@ so we can't use a single PHS point
- */
- byte *pfnSetFatPAS( const float *org )
- {
- + qboolean fullvis = false;
- +
- if( !sv.worldmodel->visdata || sv_novis->integer || !org || CL_DisableVisibility( ))
- - return Mod_DecompressVis( NULL );
- + fullvis = true;
- ASSERT( svs.currentPlayerNum >= 0 && svs.currentPlayerNum < MAX_CLIENTS );
- - fatbytes = (sv.worldmodel->numleafs+31)>>3;
- - bitvector = fatphs;
- -
- // portals can't change viewpoint!
- - if(!( sv.hostflags & SVF_PORTALPASS ))
- + if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
- {
- vec3_t viewPos, offset;
- @@ -3937,7 +3893,7 @@ byte *pfnSetFatPAS( const float *org )
- // }
- // so we have unneeded duck calculations who have affect when player
- // is ducked into water. Remove offset to restore right PVS position
- - if( svs.currentPlayer->edict->v.flags & FL_DUCKING )
- + if( FBitSet( svs.currentPlayer->edict->v.flags, FL_DUCKING ))
- {
- VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
- VectorSubtract( org, offset, viewPos );
- @@ -3945,17 +3901,15 @@ byte *pfnSetFatPAS( const float *org )
- else VectorCopy( org, viewPos );
- // build a new PHS frame
- - memset( bitvector, 0, fatbytes );
- -
- - SV_AddToFatPVS( viewPos, DVIS_PHS, sv.worldmodel->nodes );
- + Mod_FatPVS( viewPos, FATPHS_RADIUS, fatphs, world.fatbytes, false, fullvis );
- }
- else
- {
- - // merge PVS
- - SV_AddToFatPVS( org, DVIS_PHS, sv.worldmodel->nodes );
- + // merge PHS
- + Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, true, fullvis );
- }
- - return bitvector;
- + return fatphs;
- }
- /*
- @@ -3977,7 +3931,7 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
- // vis not set - fullvis enabled
- if( !pset ) return 1;
- - if( ent->v.flags & FL_CUSTOMENTITY && ent->v.owner && ent->v.owner->v.flags & FL_CLIENT )
- + if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ) && ent->v.owner && FBitSet( ent->v.owner->v.flags, FL_CLIENT ))
- ent = ent->v.owner; // upcast beams to my owner
- if( ent->headnode < 0 )
- @@ -3985,7 +3939,7 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
- // check individual leafs
- for( i = 0; i < ent->num_leafs; i++ )
- {
- - if( pset[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7 )))
- + if( CHECKVISBIT( pset, ent->leafnums[i] ))
- return 1; // visible passed by leaf
- }
- @@ -3993,18 +3947,19 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
- }
- else
- {
- - int leafnum;
- + short leafnum;
- for( i = 0; i < MAX_ENT_LEAFS; i++ )
- {
- leafnum = ent->leafnums[i];
- if( leafnum == -1 ) break;
- - if( pset[leafnum >> 3] & (1 << ( leafnum & 7 )))
- +
- + if( CHECKVISBIT( pset, leafnum ))
- return 1; // visible passed by leaf
- }
- // too many leafs for individual check, go by headnode
- - if( !SV_HeadnodeVisible( &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
- + if( !Mod_HeadnodeVisible( &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
- return 0;
- ((edict_t *)ent)->leafnums[ent->num_leafs] = leafnum;
- @@ -4027,7 +3982,7 @@ int pfnCanSkipPlayer( const edict_t *player )
- if(( cl = SV_ClientFromEdict( player, false )) == NULL )
- return false;
- - return cl->local_weapons;
- + return FBitSet( cl->flags, FCL_LOCAL_WEAPONS );
- }
- /*
- @@ -4038,9 +3993,7 @@ pfnGetCurrentPlayer
- */
- int pfnGetCurrentPlayer( void )
- {
- - if( svs.currentPlayer )
- - return (svs.currentPlayer - svs.clients);
- - return -1;
- + return svs.currentPlayerNum;
- }
- /*
- @@ -4256,7 +4209,7 @@ const char *pfnGetPlayerAuthId( edict_t *e )
- {
- if( cl->edict == e )
- {
- - if( cl->fakeclient )
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
- Q_strncat( result, "BOT", sizeof( result ));
- else if( cl->authentication_method == 0 )
- Q_snprintf( result, sizeof( result ), "%u", (uint)cl->WonID );
- @@ -4362,15 +4315,16 @@ pfnCheckParm
- */
- static int pfnCheckParm( char *parm, char **ppnext )
- {
- - static char str[64];
- + int i = Sys_CheckParm( parm );
- - if( Sys_GetParmFromCmdLine( parm, str ))
- + if( ppnext != NULL )
- {
- - // get the pointer on cmdline param
- - if( ppnext ) *ppnext = str;
- - return 1;
- + if( i > 0 && i < host.argc - 1 )
- + *ppnext = (char*)host.argv[i + 1];
- + else *ppnext = NULL;
- }
- - return 0;
- +
- + return i;
- }
- // engine callbacks
- @@ -4516,7 +4470,7 @@ static enginefuncs_t gEngfuncs =
- Cvar_DirectSet,
- pfnForceUnmodified,
- pfnGetPlayerStats,
- - Cmd_AddGameCommand,
- + Cmd_AddServerCommand,
- pfnVoice_GetClientListening,
- pfnVoice_SetClientListening,
- pfnGetPlayerAuthId,
- @@ -4782,8 +4736,8 @@ void SV_UnloadProgs( void )
- // must unlink all game cvars,
- // before pointers on them will be lost...
- - Cmd_ExecuteString( "@unlink\n", src_command );
- - Cmd_Unlink( CMD_EXTDLL );
- + Cvar_Unlink( CVAR_SERVERDLL );
- + Cmd_Unlink( CMD_SERVERDLL );
- Mod_ResetStudioAPI ();
- @@ -4876,7 +4830,7 @@ qboolean SV_LoadProgs( const char *name )
- return false;
- }
- }
- - else MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
- + else MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
- }
- else if( !GetEntityAPI( &svgame.dllFuncs, version ))
- {
- diff --git b/engine/server/sv_init.c a/engine/server/sv_init.c
- index d4ebc43..77fd89d 100644
- --- b/engine/server/sv_init.c
- +++ a/engine/server/sv_init.c
- @@ -18,10 +18,17 @@ GNU General Public License for more details.
- int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
- +server_t sv; // local server
- server_static_t svs; // persistant server info
- svgame_static_t svgame; // persistant game info
- -server_t sv; // local server
- +/*
- +================
- +SV_ModelIndex
- +
- +register unique model for a server and client
- +================
- +*/
- int SV_ModelIndex( const char *filename )
- {
- char name[64];
- @@ -60,6 +67,13 @@ int SV_ModelIndex( const char *filename )
- return i;
- }
- +/*
- +================
- +SV_SoundIndex
- +
- +register unique sound for client
- +================
- +*/
- int SV_SoundIndex( const char *filename )
- {
- char name[64];
- @@ -98,6 +112,13 @@ int SV_SoundIndex( const char *filename )
- return i;
- }
- +/*
- +================
- +SV_EventIndex
- +
- +register network event for a server and client
- +================
- +*/
- int SV_EventIndex( const char *filename )
- {
- char name[64];
- @@ -135,6 +156,13 @@ int SV_EventIndex( const char *filename )
- return i;
- }
- +/*
- +================
- +SV_GenericIndex
- +
- +register generic resourse for a server and client
- +================
- +*/
- int SV_GenericIndex( const char *filename )
- {
- char name[64];
- @@ -181,8 +209,8 @@ get entity script for current map
- char *SV_EntityScript( void )
- {
- string entfilename;
- - char *ents;
- size_t ft1, ft2;
- + char *ents;
- if( !sv.worldmodel )
- return NULL;
- @@ -224,14 +252,11 @@ baseline will be transmitted
- */
- void SV_CreateBaseline( void )
- {
- - edict_t *pEdict;
- int e;
- for( e = 0; e < svgame.numEntities; e++ )
- {
- - pEdict = EDICT_NUM( e );
- - if( !SV_IsValidEdict( pEdict )) continue;
- - SV_BaselineForEntity( pEdict );
- + SV_BaselineForEntity( EDICT_NUM( e ));
- }
- // create the instanced baselines
- @@ -279,7 +304,6 @@ void SV_ActivateServer( void )
- return;
- // custom muzzleflashes
- - pfnPrecacheModel( "sprites/muzzleflash.spr" );
- pfnPrecacheModel( "sprites/muzzleflash1.spr" );
- pfnPrecacheModel( "sprites/muzzleflash2.spr" );
- pfnPrecacheModel( "sprites/muzzleflash3.spr" );
- @@ -293,6 +317,26 @@ void SV_ActivateServer( void )
- // Activate the DLL server code
- svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svgame.globals->maxClients );
- + if( sv.loadgame || svgame.globals->changelevel )
- + {
- + sv.frametime = 0.001;
- + numFrames = 1;
- + }
- + else if( sv_maxclients->integer <= 1 )
- + {
- + sv.frametime = 0.1f;
- + numFrames = 2;
- + }
- + else
- + {
- + sv.frametime = 0.1f;
- + numFrames = 8;
- + }
- +
- + // run some frames to allow everything to settle
- + for( i = 0; i < numFrames; i++ )
- + SV_Physics();
- +
- // create a baseline for more efficient communications
- SV_CreateBaseline();
- @@ -309,21 +353,6 @@ void SV_ActivateServer( void )
- }
- }
- - numFrames = (sv.loadgame) ? 1 : 2;
- - if( !sv.loadgame || svgame.globals->changelevel )
- - host.frametime = 0.1f;
- -
- - // GoldSrc rules
- - // NOTE: this stuff is breaking sound from func_rotating in multiplayer
- - // e.g. ambience\boomer.wav on snark_pit.bsp
- - numFrames *= sv_maxclients->integer;
- -
- - // run some frames to allow everything to settle
- - for( i = 0; i < numFrames; i++ )
- - {
- - SV_Physics();
- - }
- -
- // invoke to refresh all movevars
- memset( &svgame.oldmovevars, 0, sizeof( movevars_t ));
- svgame.globals->changelevel = false; // changelevel ends here
- @@ -344,10 +373,9 @@ void SV_ActivateServer( void )
- MsgDev( D_INFO, "Game started\n" );
- }
- + // dedicated server purge unused resources here
- if( host.type == HOST_DEDICATED )
- - {
- Mod_FreeUnused ();
- - }
- sv.state = ss_active;
- physinfo->modified = true;
- @@ -356,10 +384,29 @@ void SV_ActivateServer( void )
- Host_SetServerState( sv.state );
- - if( sv_maxclients->integer > 1 && public_server->integer )
- + if( sv_maxclients->integer > 1 )
- {
- - MsgDev( D_INFO, "Add your server, to master server list\n" );
- - Master_Add( );
- + // listenserver is executed on every map change in multiplayer
- + if( host.type != HOST_DEDICATED )
- + {
- +#if 0
- + // temporare disable because it's broken TFC multiplayer
- + char *plservercfgfile = Cvar_VariableString( "lservercfgfile" );
- + if( *plservercfgfile ) Cbuf_AddText( va( "exec %s\n", plservercfgfile ));
- +#endif
- + }
- +
- + if( public_server->integer )
- + {
- + MsgDev( D_INFO, "Adding your server to master server list\n" );
- + Master_Add( );
- + }
- + }
- +
- + // mapchangecfgfile
- + {
- + char *mapchangecfgfile = Cvar_VariableString( "mapchangecfgfile" );
- + if( *mapchangecfgfile ) Cbuf_AddText( va( "exec %s\n", mapchangecfgfile ));
- }
- }
- @@ -379,13 +426,16 @@ void SV_DeactivateServer( void )
- sv.state = ss_dead;
- + svgame.dllFuncs.pfnServerDeactivate();
- +
- SV_FreeEdicts ();
- SV_ClearPhysEnts ();
- Mem_EmptyPool( svgame.stringspool );
- - svgame.dllFuncs.pfnServerDeactivate();
- + if( sv_maxclients->integer > 32 )
- + Cvar_SetFloat( "maxplayers", 32.0f );
- for( i = 0; i < sv_maxclients->integer; i++ )
- {
- @@ -473,7 +523,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
- if( sv.state == ss_dead )
- SV_InitGame(); // the game is just starting
- else if( !sv_maxclients->modified )
- - Cmd_ExecuteString( "latch\n", src_command );
- + Cmd_ExecuteString( "latch\n" );
- else MsgDev( D_ERROR, "SV_SpawnServer: while 'maxplayers' was modified.\n" );
- sv_maxclients->modified = false;
- @@ -510,8 +560,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
- svgame.globals->time = sv.time;
- // initialize buffers
- - MSG_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf ));
- - MSG_Init( &sv.reliable_datagram, "Datagram R", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
- + MSG_Init( &sv.reliable_datagram, "Reliable Datagram", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
- MSG_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
- MSG_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
- MSG_Init( &sv.spectator_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
- @@ -568,9 +617,6 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
- // clear physics interaction links
- SV_ClearWorld();
- - // tell dlls about new level started
- - svgame.dllFuncs.pfnParmsNewLevel();
- -
- return true;
- }
- @@ -584,7 +630,7 @@ A brand new game has been started
- void SV_InitGame( void )
- {
- edict_t *ent;
- - int i;
- + int i, load = sv.loadgame;
- if( svs.initialized )
- {
- @@ -609,7 +655,7 @@ void SV_InitGame( void )
- }
- // now apply latched commands
- - Cmd_ExecuteString( "latch\n", src_command );
- + Cmd_ExecuteString( "latch\n" );
- if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" ))
- {
- @@ -649,9 +695,10 @@ void SV_InitGame( void )
- SV_UPDATE_BACKUP = ( svgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
- svs.clients = Z_Malloc( sizeof( sv_client_t ) * sv_maxclients->integer );
- - svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * 64;
- + svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
- svs.packet_entities = Z_Malloc( sizeof( entity_state_t ) * svs.num_client_entities );
- svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
- + if( !load ) MsgDev( D_INFO, "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
- // client frames will be allocated in SV_DirectConnect
- @@ -661,7 +708,7 @@ void SV_InitGame( void )
- // copy gamemode into svgame.globals
- svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
- svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
- - svgame.globals->coop = Cvar_VariableInteger( "coop" );
- + svgame.globals->coop = ( sv_maxclients->integer > 1 ) ? Cvar_VariableInteger( "coop" ) : 0;
- // heartbeats will always be sent to the id master
- svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
- @@ -671,8 +718,8 @@ void SV_InitGame( void )
- {
- // setup all the clients
- ent = EDICT_NUM( i + 1 );
- - SV_InitEdict( ent );
- svs.clients[i].edict = ent;
- + SV_InitEdict( ent );
- }
- // get actual movevars
- diff --git b/engine/server/sv_main.c a/engine/server/sv_main.c
- index 45c0546..2033d2f 100644
- --- b/engine/server/sv_main.c
- +++ a/engine/server/sv_main.c
- @@ -113,7 +113,7 @@ void SV_CalcPings( void )
- {
- cl = &svs.clients[i];
- - if( cl->state != cs_spawned || cl->fakeclient )
- + if( cl->state != cs_spawned || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue;
- total = count = 0;
- @@ -152,7 +152,7 @@ int SV_CalcPacketLoss( sv_client_t *cl )
- lost = 0;
- count = 0;
- - if( cl->fakeclient )
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
- return 0;
- numsamples = SV_UPDATE_BACKUP / 2;
- @@ -160,9 +160,9 @@ int SV_CalcPacketLoss( sv_client_t *cl )
- for( i = 0; i < numsamples; i++ )
- {
- frame = &cl->frames[(cl->netchan.incoming_acknowledged - 1 - i) & SV_UPDATE_MASK];
- - count++;
- if( frame->latency == -1 )
- lost++;
- + count++;
- }
- if( !count ) return 100;
- @@ -208,7 +208,18 @@ void SV_UpdateMovevars( qboolean initialize )
- // check range
- if( sv_zmax->value < 256.0f ) Cvar_SetFloat( "sv_zmax", 256.0f );
- - if( sv_zmax->value > 131070.0f ) Cvar_SetFloat( "sv_zmax", 131070.0f );
- +
- + // clamp it right
- + if( host.features & ENGINE_WRITE_LARGE_COORD )
- + {
- + if( sv_zmax->value > 131070.0f )
- + Cvar_SetFloat( "sv_zmax", 131070.0f );
- + }
- + else
- + {
- + if( sv_zmax->value > 32767.0f )
- + Cvar_SetFloat( "sv_zmax", 32767.0f );
- + }
- svgame.movevars.gravity = sv_gravity->value;
- svgame.movevars.stopspeed = sv_stopspeed->value;
- @@ -320,7 +331,8 @@ SV_ReadPackets
- void SV_ReadPackets( void )
- {
- sv_client_t *cl;
- - int i, qport, curSize;
- + int i, qport;
- + size_t curSize;
- while( NET_GetPacket( NS_SERVER, &net_from, net_message_buffer, &curSize ))
- {
- @@ -329,7 +341,22 @@ void SV_ReadPackets( void )
- // check for connectionless packet (0xffffffff) first
- if( MSG_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 )
- {
- - SV_ConnectionlessPacket( net_from, &net_message );
- + if( !svs.initialized )
- + {
- + char *args, *c;
- +
- + MSG_Clear( &net_message );
- + MSG_ReadLong( &net_message );// skip the -1 marker
- +
- + args = MSG_ReadStringLine( &net_message );
- + Cmd_TokenizeString( args );
- + c = Cmd_Argv( 0 );
- +
- + if( !Q_strcmp( c, "rcon" ))
- + SV_RemoteCommand( net_from, &net_message );
- + }
- + else SV_ConnectionlessPacket( net_from, &net_message );
- +
- continue;
- }
- @@ -343,7 +370,7 @@ void SV_ReadPackets( void )
- // check for packets from connected clients
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- {
- - if( cl->state == cs_free || cl->fakeclient )
- + if( cl->state == cs_free || FBitSet( cl->flags, FCL_FAKECLIENT ))
- continue;
- if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address ))
- @@ -354,21 +381,21 @@ void SV_ReadPackets( void )
- if( cl->netchan.remote_address.port != net_from.port )
- {
- - MsgDev( D_INFO, "SV_ReadPackets: fixing up a translated port\n");
- + MsgDev( D_NOTE, "SV_ReadPackets: fixing up a translated port\n");
- cl->netchan.remote_address.port = net_from.port;
- }
- if( Netchan_Process( &cl->netchan, &net_message ))
- {
- - if( sv_maxclients->integer == 1 || cl->state != cs_spawned )
- - cl->send_message = true; // reply at end of frame
- + if(( sv_maxclients->integer == 1 && !FBitSet( host.features, ENGINE_FIXED_FRAMERATE )) || cl->state != cs_spawned )
- + SetBits( cl->flags, FCL_SEND_NET_MESSAGE ); // reply at end of frame
- // this is a valid, sequenced packet, so process it
- if( cl->state != cs_zombie )
- {
- cl->lastmessage = host.realtime; // don't timeout
- SV_ExecuteClientMessage( cl, &net_message );
- - svgame.globals->frametime = host.frametime;
- + svgame.globals->frametime = sv.frametime;
- svgame.globals->time = sv.time;
- }
- }
- @@ -393,6 +420,9 @@ void SV_ReadPackets( void )
- if( i != sv_maxclients->integer )
- continue;
- }
- +
- + svs.currentPlayer = NULL;
- + svs.currentPlayerNum = -1;
- }
- /*
- @@ -422,12 +452,13 @@ void SV_CheckTimeouts( void )
- {
- if( cl->state >= cs_connected )
- {
- - if( cl->edict && !( cl->edict->v.flags & (FL_SPECTATOR|FL_FAKECLIENT)))
- + if( cl->edict && !FBitSet( cl->edict->v.flags, FL_SPECTATOR|FL_FAKECLIENT ))
- numclients++;
- }
- // fake clients do not timeout
- - if( cl->fakeclient ) cl->lastmessage = host.realtime;
- + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
- + cl->lastmessage = host.realtime;
- // message times may be wrong across a changelevel
- if( cl->lastmessage > host.realtime )
- @@ -439,11 +470,14 @@ void SV_CheckTimeouts( void )
- continue;
- }
- - if(( cl->state == cs_connected || cl->state == cs_spawned ) && cl->lastmessage < droppoint && !NET_IsLocalAddress( cl->netchan.remote_address ))
- + if(( cl->state == cs_connected || cl->state == cs_spawned ) && cl->lastmessage < droppoint )
- {
- - SV_BroadcastPrintf( PRINT_HIGH, "%s timed out\n", cl->name );
- - SV_DropClient( cl );
- - cl->state = cs_free; // don't bother with zombie state
- + if( !NET_IsLocalAddress( cl->netchan.remote_address ))
- + {
- + SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s timed out\n", cl->name );
- + SV_DropClient( cl );
- + cl->state = cs_free; // don't bother with zombie state
- + }
- }
- }
- @@ -472,7 +506,7 @@ void SV_PrepWorldFrame( void )
- ent = EDICT_NUM( i );
- if( ent->free ) continue;
- - ent->v.effects &= ~(EF_MUZZLEFLASH|EF_NOINTERP);
- + ClearBits( ent->v.effects, EF_MUZZLEFLASH|EF_NOINTERP );
- }
- }
- @@ -501,12 +535,15 @@ qboolean SV_IsSimulating( void )
- return true; // force simulating for background map
- }
- - if( sv.hostflags & SVF_PLAYERSONLY )
- + if( FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
- return false;
- +
- if( !SV_HasActivePlayers())
- return false;
- +
- if( !sv.paused && CL_IsInGame( ))
- return true;
- +
- return false;
- }
- @@ -515,13 +552,38 @@ qboolean SV_IsSimulating( void )
- SV_RunGameFrame
- =================
- */
- -void SV_RunGameFrame( void )
- +/*
- +=================
- +SV_RunGameFrame
- +=================
- +*/
- +qboolean SV_RunGameFrame( void )
- {
- - if( !SV_IsSimulating( )) return;
- + int numFrames = 0;
- - SV_Physics();
- + if( !( sv.simulating = SV_IsSimulating( )))
- + return true;
- - sv.time += host.frametime;
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + {
- + while( sv.time_residual >= sv.frametime )
- + {
- + SV_Physics();
- +
- + sv.time_residual -= sv.frametime;
- + sv.time += sv.frametime;
- + numFrames++;
- + }
- + return (numFrames != 0);
- + }
- + else
- + {
- + SV_Physics();
- +
- + sv.time += sv.frametime;
- +
- + return true;
- + }
- }
- /*
- @@ -535,7 +597,14 @@ void Host_ServerFrame( void )
- // if server is not active, do nothing
- if( !svs.initialized ) return;
- - svgame.globals->frametime = host.frametime;
- + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
- + sv.frametime = ( 1.0 / (double)( GAME_FPS - 0.01 )); // FP issues
- + else sv.frametime = host.frametime;
- +
- + if( sv.simulating || sv.state != ss_active )
- + sv.time_residual += host.frametime;
- +
- + svgame.globals->frametime = sv.frametime;
- // check timeouts
- SV_CheckTimeouts ();
- @@ -556,7 +625,7 @@ void Host_ServerFrame( void )
- SV_UpdateMovevars ( false );
- // let everything in the world think and move
- - SV_RunGameFrame ();
- + if( !SV_RunGameFrame ()) return;
- // send messages back to the clients that had packets read this frame
- SV_SendClientMessages ();
- @@ -584,7 +653,7 @@ void Master_Add( void )
- if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
- MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
- - NET_SendPacket( NS_SERVER, 1, "q", adr );
- + NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
- }
- /*
- @@ -631,6 +700,54 @@ void Master_Shutdown( void )
- NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
- }
- +/*
- +=================
- +SV_AddToMaster
- +
- +A server info answer to master server.
- +Master will validate challenge and this server to public list
- +=================
- +*/
- +void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
- +{
- + uint challenge;
- + char s[MAX_INFO_STRING] = "0\n"; // skip 2 bytes of header
- + int clients = 0, bots = 0, index;
- +
- + if( svs.clients )
- + {
- + for( index = 0; index < sv_maxclients->integer; index++ )
- + {
- + if( svs.clients[index].state >= cs_connected )
- + {
- + if( FBitSet( svs.clients[index].flags, FCL_FAKECLIENT ))
- + bots++;
- + else clients++;
- + }
- + }
- + }
- +
- + challenge = MSG_ReadUBitLong( msg, sizeof( uint ) << 3 );
- +
- + Info_SetValueForKey( s, "protocol", va( "%d", PROTOCOL_VERSION ) ); // protocol version
- + Info_SetValueForKey( s, "challenge", va( "%u", challenge ) ); // challenge number
- + Info_SetValueForKey( s, "players", va( "%d", clients ) ); // current player number, without bots
- + Info_SetValueForKey( s, "max", sv_maxclients->string ); // max_players
- + Info_SetValueForKey( s, "bots", va( "%d", bots ) ); // bot count
- + Info_SetValueForKey( s, "gamedir", GI->gamedir ); // gamedir
- + Info_SetValueForKey( s, "map", sv.name ); // current map
- + Info_SetValueForKey( s, "type", (host.type == HOST_DEDICATED) ? "d" : "l" ); // dedicated or local
- + Info_SetValueForKey( s, "password", "0" ); // is password set
- + Info_SetValueForKey( s, "os", "w" ); // Windows
- + Info_SetValueForKey( s, "secure", "0" ); // server anti-cheat
- + Info_SetValueForKey( s, "lan", "0" ); // LAN servers doesn't send info to master
- + Info_SetValueForKey( s, "version", va( "%g", XASH_VERSION )); // server region. 255 -- all regions
- + Info_SetValueForKey( s, "region", "255" ); // server region. 255 -- all regions
- + Info_SetValueForKey( s, "product", GI->gamefolder ); // product? Where is the difference with gamedir?
- +
- + NET_SendPacket( NS_SERVER, Q_strlen( s ), s, from );
- +}
- +
- //============================================================================
- /*
- @@ -773,11 +890,11 @@ void SV_FinalMessage( char *message, qboolean reconnect )
- // send it twice
- // stagger the packets to crutch operating system limited buffers
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- - if( cl->state >= cs_connected && !cl->fakeclient )
- + if( cl->state >= cs_connected && !FBitSet( cl->flags, FCL_FAKECLIENT ))
- Netchan_Transmit( &cl->netchan, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ));
- for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
- - if( cl->state >= cs_connected && !cl->fakeclient )
- + if( cl->state >= cs_connected && !FBitSet( cl->flags, FCL_FAKECLIENT ))
- Netchan_Transmit( &cl->netchan, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ));
- }
- diff --git b/engine/server/sv_phys.c a/engine/server/sv_phys.c
- index 7e6a23d..2c3ee29 100644
- --- b/engine/server/sv_phys.c
- +++ a/engine/server/sv_phys.c
- @@ -66,12 +66,19 @@ SV_CheckAllEnts
- */
- void SV_CheckAllEnts( void )
- {
- - edict_t *e;
- - int i;
- + static double nextcheck;
- + edict_t *e;
- + int i;
- if( !sv_check_errors->integer || sv.state != ss_active )
- return;
- + if(( nextcheck - Sys_DoubleTime()) > 0.0 )
- + return;
- +
- + // don't check entities every frame (but every 5 secs)
- + nextcheck = Sys_DoubleTime() + 5.0;
- +
- // check edicts errors
- for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
- {
- @@ -193,7 +200,7 @@ qboolean SV_RunThink( edict_t *ent )
- if(!( ent->v.flags & FL_KILLME ))
- {
- thinktime = ent->v.nextthink;
- - if( thinktime <= 0.0f || thinktime > sv.time + host.frametime )
- + if( thinktime <= 0.0f || thinktime > sv.time + sv.frametime )
- return true;
- if( thinktime < sv.time )
- @@ -225,21 +232,23 @@ qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time )
- {
- float thinktime;
- - if(!( ent->v.flags & (FL_KILLME|FL_DORMANT )))
- + if( !FBitSet( ent->v.flags, FL_KILLME|FL_DORMANT ))
- {
- thinktime = ent->v.nextthink;
- - if( thinktime <= 0.0f || thinktime > time + frametime )
- + if( thinktime <= 0.0f || (time + frametime) < thinktime )
- return true;
- - if( thinktime > time )
- - thinktime = time;
- + if( thinktime < time )
- + thinktime = time; // don't let things stay in the past.
- + // it is possible to start that way
- + // by a trigger with a local time.
- ent->v.nextthink = 0.0f;
- svgame.globals->time = thinktime;
- svgame.dllFuncs.pfnThink( ent );
- }
- - if( ent->v.flags & FL_KILLME )
- + if( FBitSet( ent->v.flags, FL_KILLME ))
- SV_FreeEdict( ent );
- return !ent->free;
- @@ -696,8 +705,8 @@ void SV_AddGravity( edict_t *ent )
- else ent_gravity = 1.0f;
- // add gravity incorrectly
- - ent->v.velocity[2] -= ( ent_gravity * sv_gravity->value * host.frametime );
- - ent->v.velocity[2] += ( ent->v.basevelocity[2] * host.frametime );
- + ent->v.velocity[2] -= ( ent_gravity * sv_gravity->value * sv.frametime );
- + ent->v.velocity[2] += ( ent->v.basevelocity[2] * sv.frametime );
- ent->v.basevelocity[2] = 0.0f;
- // bound velocity
- @@ -720,7 +729,7 @@ void SV_AddHalfGravity( edict_t *ent, float timestep )
- // Add 1/2 of the total gravitational effects over this timestep
- ent->v.velocity[2] -= ( 0.5f * ent_gravity * sv_gravity->value * timestep );
- - ent->v.velocity[2] += ( ent->v.basevelocity[2] * host.frametime );
- + ent->v.velocity[2] += ( ent->v.basevelocity[2] * sv.frametime );
- ent->v.basevelocity[2] = 0.0f;
- // bound velocity
- @@ -1121,12 +1130,12 @@ void SV_Physics_Pusher( edict_t *ent )
- oldtime = ent->v.ltime;
- thinktime = ent->v.nextthink;
- - if( thinktime < oldtime + host.frametime )
- + if( thinktime < oldtime + sv.frametime )
- {
- movetime = thinktime - oldtime;
- if( movetime < 0.0f ) movetime = 0.0f;
- }
- - else movetime = host.frametime;
- + else movetime = sv.frametime;
- if( movetime )
- {
- @@ -1240,7 +1249,7 @@ void SV_Physics_Compound( edict_t *ent )
- {
- VectorCopy( parent->v.origin, ent->v.oldorigin );
- VectorCopy( parent->v.angles, ent->v.avelocity );
- - ent->v.ltime = host.frametime;
- + ent->v.ltime = sv.frametime;
- return;
- }
- @@ -1296,8 +1305,8 @@ void SV_Physics_Noclip( edict_t *ent )
- SV_CheckWater( ent );
- - VectorMA( ent->v.origin, host.frametime, ent->v.velocity, ent->v.origin );
- - VectorMA( ent->v.angles, host.frametime, ent->v.avelocity, ent->v.angles );
- + VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin );
- + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles );
- // noclip ents never touch triggers
- SV_LinkEdict( ent, false );
- @@ -1437,10 +1446,10 @@ void SV_Physics_Toss( edict_t *ent )
- {
- case MOVETYPE_TOSS:
- case MOVETYPE_BOUNCE:
- - SV_AngularMove( ent, host.frametime, ent->v.friction );
- + SV_AngularMove( ent, sv.frametime, ent->v.friction );
- break;
- default:
- - SV_AngularMove( ent, host.frametime, 0.0f );
- + SV_AngularMove( ent, sv.frametime, 0.0f );
- break;
- }
- @@ -1450,7 +1459,7 @@ void SV_Physics_Toss( edict_t *ent )
- VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
- SV_CheckVelocity( ent );
- - VectorScale( ent->v.velocity, host.frametime, move );
- + VectorScale( ent->v.velocity, sv.frametime, move );
- VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
- @@ -1489,7 +1498,7 @@ void SV_Physics_Toss( edict_t *ent )
- VectorAdd( ent->v.velocity, ent->v.basevelocity, move );
- vel = DotProduct( move, move );
- - if( ent->v.velocity[2] < sv_gravity->value * host.frametime )
- + if( ent->v.velocity[2] < sv_gravity->value * sv.frametime )
- {
- // we're rolling on the ground, add static friction.
- ent->v.groundentity = trace.ent;
- @@ -1506,8 +1515,8 @@ void SV_Physics_Toss( edict_t *ent )
- }
- else
- {
- - VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move );
- - VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move );
- + VectorScale( ent->v.velocity, (1.0f - trace.fraction) * sv.frametime * 0.9f, move );
- + VectorMA( move, (1.0f - trace.fraction) * sv.frametime * 0.9f, ent->v.basevelocity, move );
- trace = SV_PushEntity( ent, move, vec3_origin, NULL );
- if( ent->free ) return;
- }
- @@ -1554,7 +1563,7 @@ void SV_Physics_Step( edict_t *ent )
- if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 )
- {
- - float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime;
- + float buoyancy = SV_Submerged( ent ) * ent->v.skin * sv.frametime;
- SV_AddGravity( ent );
- ent->v.velocity[2] += buoyancy;
- @@ -1585,7 +1594,7 @@ void SV_Physics_Step( edict_t *ent )
- if( wasonmover ) friction *= 0.5f; // add a little friction
- control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed;
- - newspeed = speed - (host.frametime * control * friction);
- + newspeed = speed - (sv.frametime * control * friction);
- if( newspeed < 0 ) newspeed = 0;
- newspeed /= speed;
- @@ -1597,7 +1606,7 @@ void SV_Physics_Step( edict_t *ent )
- VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
- SV_CheckVelocity( ent );
- - SV_FlyMove( ent, host.frametime, NULL );
- + SV_FlyMove( ent, sv.frametime, NULL );
- if( ent->free ) return;
- SV_CheckVelocity( ent );
- @@ -1678,7 +1687,7 @@ static void SV_Physics_Entity( edict_t *ent )
- if(!( ent->v.flags & FL_BASEVELOCITY ) && !VectorIsNull( ent->v.basevelocity ))
- {
- // Apply momentum (add in half of the previous frame of velocity first)
- - VectorMA( ent->v.velocity, 1.0f + (host.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
- + VectorMA( ent->v.velocity, 1.0f + (sv.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
- VectorClear( ent->v.basevelocity );
- }
- @@ -1770,7 +1779,7 @@ void SV_Physics( void )
- if( sv_skyspeed->value )
- {
- // evaluate sky rotation.
- - float skyAngle = sv_skyangle->value + sv_skyspeed->value * host.frametime;
- + float skyAngle = sv_skyangle->value + sv_skyspeed->value * sv.frametime;
- Cvar_SetFloat( "sv_skyangle", anglemod( skyAngle ));
- }
- @@ -1802,7 +1811,7 @@ Inplementation for new physics interface
- */
- double SV_GetFrameTime( void )
- {
- - return host.frametime;
- + return sv.frametime;
- }
- /*
- @@ -1919,9 +1928,46 @@ static void *pfnMem_Alloc( size_t cb, const char *filename, const int fileline )
- static void pfnMem_Free( void *mem, const char *filename, const int fileline )
- {
- + if( !mem ) return;
- _Mem_Free( mem, filename, fileline );
- }
- +/*
- +=============
- +pfnPointContents
- +
- +=============
- +*/
- +static int pfnPointContents( const float *pos, int groupmask )
- +{
- + int oldmask, cont;
- +
- + if( !pos ) return CONTENTS_NONE;
- + oldmask = svs.groupmask;
- +
- + svs.groupmask = groupmask;
- + cont = SV_PointContents( pos );
- + svs.groupmask = oldmask; // restore old mask
- +
- + return cont;
- +}
- +
- +const byte *pfnLoadImagePixels( const char *filename, int *width, int *height )
- +{
- + rgbdata_t *pic = FS_LoadImage( filename, NULL, 0 );
- + byte *buffer;
- +
- + if( !pic ) return NULL;
- +
- + buffer = Mem_Alloc( svgame.mempool, pic->size );
- + if( buffer ) memcpy( buffer, pic->buffer, pic->size );
- + if( width ) *width = pic->width;
- + if( height ) *height = pic->height;
- + FS_FreeImage( pic );
- +
- + return buffer;
- +}
- +
- static server_physics_api_t gPhysicsAPI =
- {
- SV_LinkEdict,
- @@ -1944,6 +1990,16 @@ static server_physics_api_t gPhysicsAPI =
- GL_TextureData,
- pfnMem_Alloc,
- pfnMem_Free,
- + pfnPointContents,
- + SV_Move,
- + SV_MoveNoEnts,
- + SV_BoxInPVS,
- + pfnWriteBytes,
- + Mod_CheckLump,
- + Mod_ReadLump,
- + Mod_SaveLump,
- + COM_SaveFile,
- + pfnLoadImagePixels,
- };
- /*
- @@ -1962,7 +2018,7 @@ qboolean SV_InitPhysicsAPI( void )
- {
- if( pPhysIface( SV_PHYSICS_INTERFACE_VERSION, &gPhysicsAPI, &svgame.physFuncs ))
- {
- - MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
- + MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
- if( svgame.physFuncs.SV_CheckFeatures != NULL )
- {
- diff --git b/engine/server/sv_pmove.c a/engine/server/sv_pmove.c
- index c478875..6137912 100644
- --- b/engine/server/sv_pmove.c
- +++ a/engine/server/sv_pmove.c
- @@ -148,7 +148,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
- void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
- {
- - if( !cl->lag_compensation || !sv_unlag->integer )
- + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag->integer )
- return;
- // don't allow unlag in singleplayer
- @@ -165,7 +165,7 @@ void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
- void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs )
- {
- - if( !cl->lag_compensation || !sv_unlag->integer )
- + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag->integer )
- return;
- // don't allow unlag in singleplayer
- @@ -225,12 +225,12 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
- continue;
- // ignore monsterclip brushes
- - if(( check->v.flags & FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
- + if( FBitSet( check->v.flags, FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
- continue;
- if( check == pl ) continue; // himself
- - if((( check->v.flags & FL_CLIENT ) && check->v.health <= 0 ) || check->v.deadflag == DEAD_DEAD )
- + if(( FBitSet( check->v.flags, FL_CLIENT|FL_FAKECLIENT ) && check->v.health <= 0.0f ) || check->v.deadflag == DEAD_DEAD )
- continue; // dead body
- if( VectorIsNull( check->v.size ))
- @@ -239,7 +239,7 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
- VectorCopy( check->v.absmin, mins );
- VectorCopy( check->v.absmax, maxs );
- - if( check->v.flags & FL_CLIENT )
- + if( FBitSet( check->v.flags, FL_CLIENT ))
- {
- // trying to get interpolated values
- if( svs.currentPlayer )
- @@ -478,7 +478,7 @@ static void pfnPlaySound( int channel, const char *sample, float volume, float a
- ent = EDICT_NUM( svgame.pmove->player_index + 1 );
- if( !SV_IsValidEdict( ent )) return;
- - SV_StartSound( ent, channel, sample, volume, attenuation, fFlags, pitch );
- + SV_StartSound( ent, channel, sample, volume, attenuation, fFlags|SND_FILTER_CLIENT, pitch );
- }
- static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, float delay, float *origin,
- @@ -620,14 +620,14 @@ static void PM_CheckMovingGround( edict_t *ent, float frametime )
- SV_UpdateBaseVelocity( ent );
- }
- - if( !( ent->v.flags & FL_BASEVELOCITY ))
- + if( !FBitSet( ent->v.flags, FL_BASEVELOCITY ))
- {
- // apply momentum (add in half of the previous frame of velocity first)
- VectorMA( ent->v.velocity, 1.0f + (frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
- VectorClear( ent->v.basevelocity );
- }
- - ent->v.flags &= ~FL_BASEVELOCITY;
- + ClearBits( ent->v.flags, FL_BASEVELOCITY );
- }
- static void SV_SetupPMove( playermove_t *pmove, sv_client_t *cl, usercmd_t *ucmd, const char *physinfo )
- @@ -827,7 +827,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
- return;
- // unlag disabled for current client
- - if( !cl->lag_compensation )
- + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ))
- return;
- has_update = true;
- @@ -986,7 +986,7 @@ void SV_RestoreMoveInterpolant( sv_client_t *cl )
- return;
- // unlag disabled for current client
- - if( !cl->lag_compensation )
- + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ))
- return;
- for( i = 0, check = svs.clients; i < sv_maxclients->integer; i++, check++ )
- @@ -1050,7 +1050,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
- return;
- }
- - if( !cl->fakeclient )
- + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
- {
- SV_SetupMoveInterpolant( cl );
- }
- @@ -1095,29 +1095,37 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
- // copy results back to client
- SV_FinishPMove( svgame.pmove, cl );
- -
- - // link into place and touch triggers
- - SV_LinkEdict( clent, true );
- - VectorCopy( clent->v.velocity, oldvel ); // save velocity
- - // touch other objects
- - for( i = 0; i < svgame.pmove->numtouch; i++ )
- + if( svgame.physFuncs.PM_PlayerTouch != NULL )
- {
- - // never touch the objects when "playersonly" is active
- - if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
- - break;
- + // run custom impact function
- + svgame.physFuncs.PM_PlayerTouch( svgame.pmove, clent );
- + }
- + else
- + {
- + // link into place and touch triggers
- + SV_LinkEdict( clent, true );
- + VectorCopy( clent->v.velocity, oldvel ); // save velocity
- - pmtrace = &svgame.pmove->touchindex[i];
- - touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
- - if( touch == clent ) continue;
- + // touch other objects
- + for( i = 0; i < svgame.pmove->numtouch; i++ )
- + {
- + // never touch the objects when "playersonly" is active
- + if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
- + break;
- - VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
- - SV_ConvertPMTrace( &trace, pmtrace, touch );
- - SV_Impact( touch, clent, &trace );
- - }
- + pmtrace = &svgame.pmove->touchindex[i];
- + touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
- + if( touch == clent ) continue;
- - // restore velocity
- - VectorCopy( oldvel, clent->v.velocity );
- + VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
- + SV_ConvertPMTrace( &trace, pmtrace, touch );
- + SV_Impact( touch, clent, &trace );
- + }
- +
- + // restore velocity
- + VectorCopy( oldvel, clent->v.velocity );
- + }
- svgame.pmove->numtouch = 0;
- svgame.globals->time = cl->timebase;
- @@ -1127,7 +1135,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
- svgame.dllFuncs.pfnPlayerPostThink( clent );
- svgame.dllFuncs.pfnCmdEnd( clent );
- - if( !cl->fakeclient )
- + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
- {
- SV_RestoreMoveInterpolant( cl );
- }
- diff --git b/engine/server/sv_save.c a/engine/server/sv_save.c
- index 3706313..febea2b 100644
- --- b/engine/server/sv_save.c
- +++ a/engine/server/sv_save.c
- @@ -32,7 +32,7 @@ half-life implementation of saverestore system
- #define SAVEGAME_VERSION 0x0065 // Version 0.65
- #define CLIENT_SAVEGAME_VERSION 0x0068 // Version 0.68
- -#define SAVE_AGED_COUNT 1
- +#define SAVE_AGED_COUNT 2
- #define SAVENAME_LENGTH 128 // matches with MAX_OSPATH
- #define LUMP_DECALS_OFFSET 0
- @@ -723,7 +723,8 @@ void SV_DirectoryCopy( const char *pPath, file_t *pFile )
- void SV_DirectoryExtract( file_t *pFile, int fileCount )
- {
- - char szName[SAVENAME_LENGTH], fileName[SAVENAME_LENGTH];
- + char szName[SAVENAME_LENGTH];
- + char fileName[SAVENAME_LENGTH];
- int i, fileSize;
- file_t *pCopy;
- @@ -1066,7 +1067,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
- ClientSections_t sections;
- int i, decalCount;
- int id, version;
- - fs_offset_t header_offset, position;
- + long header_offset, position;
- soundlist_t soundInfo[MAX_CHANNELS];
- string curtrack, looptrack;
- int soundCount = 0;
- diff --git b/engine/server/sv_world.c a/engine/server/sv_world.c
- index 23acc51..116f4ad 100644
- --- b/engine/server/sv_world.c
- +++ a/engine/server/sv_world.c
- @@ -536,15 +536,14 @@ SV_FindTouchedLeafs
- */
- void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
- {
- - mplane_t *splitplane;
- - int sides, leafnum;
- + int sides;
- mleaf_t *leaf;
- if( node->contents == CONTENTS_SOLID )
- return;
- // add an efrag if the node is a leaf
- - if( node->contents < 0 )
- + if( node->contents < 0 )
- {
- if( ent->num_leafs > ( MAX_ENT_LEAFS - 1 ))
- {
- @@ -555,18 +554,16 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
- else
- {
- leaf = (mleaf_t *)node;
- - leafnum = leaf - sv.worldmodel->leafs - 1;
- - ent->leafnums[ent->num_leafs] = leafnum;
- + ent->leafnums[ent->num_leafs] = leaf->cluster;
- ent->num_leafs++;
- }
- return;
- }
- // NODE_MIXED
- - splitplane = node->plane;
- - sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, splitplane );
- + sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, node->plane );
- - if( sides == 3 && *headnode == -1 )
- + if(( sides == 3 ) && ( *headnode == -1 ))
- *headnode = node - sv.worldmodel->nodes;
- // recurse down the contacted sides
- @@ -575,36 +572,6 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
- }
- /*
- -=============
- -SV_HeadnodeVisible
- -=============
- -*/
- -qboolean SV_HeadnodeVisible( mnode_t *node, byte *visbits, int *lastleaf )
- -{
- - int leafnum;
- -
- - if( !node || node->contents == CONTENTS_SOLID )
- - return false;
- -
- - if( node->contents < 0 )
- - {
- - leafnum = ((mleaf_t *)node - sv.worldmodel->leafs) - 1;
- -
- - if(!( visbits[leafnum >> 3] & (1<<( leafnum & 7 ))))
- - return false;
- -
- - if( lastleaf )
- - *lastleaf = leafnum;
- - return true;
- - }
- -
- - if( SV_HeadnodeVisible( node->children[0], visbits, lastleaf ))
- - return true;
- -
- - return SV_HeadnodeVisible( node->children[1], visbits, lastleaf );
- -}
- -
- -/*
- ===============
- SV_LinkEdict
- ===============
- @@ -623,9 +590,9 @@ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
- if( ent->v.movetype == MOVETYPE_FOLLOW && SV_IsValidEdict( ent->v.aiment ))
- {
- - ent->headnode = ent->v.aiment->headnode;
- - ent->num_leafs = ent->v.aiment->num_leafs;
- memcpy( ent->leafnums, ent->v.aiment->leafnums, sizeof( ent->leafnums ));
- + ent->num_leafs = ent->v.aiment->num_leafs;
- + ent->headnode = ent->v.aiment->headnode;
- }
- else
- {
- @@ -1470,6 +1437,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
- mtexinfo_t *tex;
- float front, back, scale, frac;
- int i, map, size, s, t;
- + int sample_size;
- color24 *lm;
- vec3_t mid;
- @@ -1507,6 +1475,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
- // check for impact on this node
- surf = model->surfaces + node->firstsurface;
- + sample_size = Mod_SampleSizeForFace( surf );
- for( i = 0; i < node->numsurfaces; i++, surf++ )
- {
- @@ -1521,16 +1490,16 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
- if(( s < 0.0f || s > surf->extents[0] ) || ( t < 0.0f || t > surf->extents[1] ))
- continue;
- - s /= LM_SAMPLE_SIZE;
- - t /= LM_SAMPLE_SIZE;
- + s /= sample_size;
- + t /= sample_size;
- if( !surf->samples )
- return true;
- VectorClear( sv_pointColor );
- - lm = surf->samples + (t * ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) + s);
- - size = ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) * ((surf->extents[1] / LM_SAMPLE_SIZE) + 1);
- + lm = surf->samples + (t * ((surf->extents[0] / sample_size) + 1) + s);
- + size = ((surf->extents[0] / sample_size) + 1) * ((surf->extents[1] / sample_size) + 1);
- for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
- {
- @@ -1560,7 +1529,7 @@ void SV_RunLightStyles( void )
- // run lightstyles animation
- for( i = 0, ls = sv.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
- {
- - ls->time += host.frametime;
- + ls->time += sv.frametime;
- ofs = (ls->time * 10);
- if( ls->length == 0 ) ls->value = scale; // disable this light
- diff --git b/engine/studio.h a/engine/studio.h
- index 76b15f2..0f60f27 100644
- --- b/engine/studio.h
- +++ a/engine/studio.h
- @@ -31,8 +31,8 @@ Studio models are position independent, so the cache manager can move them.
- #define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ"
- // studio limits
- -#define MAXSTUDIOTRIANGLES 32768 // max triangles per model
- -#define MAXSTUDIOVERTS 4096 // max vertices per submodel
- +#define MAXSTUDIOTRIANGLES 65536 // max triangles per model
- +#define MAXSTUDIOVERTS 32768 // max vertices per submodel
- #define MAXSTUDIOSEQUENCES 256 // total animation sequences
- #define MAXSTUDIOSKINS 256 // total textures
- #define MAXSTUDIOSRCBONES 512 // bones allowed at source movement
- diff --git b/game_launch/game.cpp a/game_launch/game.cpp
- index 337bb18..407c4b0 100644
- --- b/game_launch/game.cpp
- +++ a/game_launch/game.cpp
- @@ -17,6 +17,11 @@ GNU General Public License for more details.
- #define GAME_PATH "valve" // default dir to start from
- +#ifdef WIN32
- +// enable NVIDIA High Performance Graphics while using Integrated Graphics.
- +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
- +#endif
- +
- typedef void (*pfnChangeGame)( const char *progname );
- typedef int (*pfnInit)( const char *progname, int bChangeGame, pfnChangeGame func );
- typedef void (*pfnShutdown)( void );
- diff --git b/mainui/basemenu.cpp a/mainui/basemenu.cpp
- index a3f4709..bc03f81 100644
- --- b/mainui/basemenu.cpp
- +++ a/mainui/basemenu.cpp
- @@ -253,9 +253,14 @@ void UI_DrawString( int x, int y, int w, int h, const char *string, const int co
- {
- if( IsColorString( l ))
- {
- - if( !forceColor )
- + int colorNum = ColorIndex( *(l+1) );
- +
- + if( colorNum == 7 && color != 0 )
- + {
- + modulate = color;
- + }
- + else if( !forceColor )
- {
- - int colorNum = ColorIndex( *(l+1) );
- modulate = PackAlpha( g_iColorTable[colorNum], UnpackAlpha( color ));
- }
- @@ -1535,7 +1540,7 @@ void UI_Init( void )
- Cmd_AddCommand( "menu_multiplayer", UI_MultiPlayer_Menu );
- Cmd_AddCommand( "menu_options", UI_Options_Menu );
- Cmd_AddCommand( "menu_langame", UI_LanGame_Menu );
- - Cmd_AddCommand( "menu_intenetgames", UI_InternetGames_Menu );
- + Cmd_AddCommand( "menu_internetgames", UI_InternetGames_Menu );
- Cmd_AddCommand( "menu_playersetup", UI_PlayerSetup_Menu );
- Cmd_AddCommand( "menu_controls", UI_Controls_Menu );
- Cmd_AddCommand( "menu_advcontrols", UI_AdvControls_Menu );
- @@ -1579,7 +1584,7 @@ void UI_Shutdown( void )
- Cmd_RemoveCommand( "menu_saveload" );
- Cmd_RemoveCommand( "menu_multiplayer" );
- Cmd_RemoveCommand( "menu_options" );
- - Cmd_RemoveCommand( "menu_intenetgames" );
- + Cmd_RemoveCommand( "menu_internetgames" );
- Cmd_RemoveCommand( "menu_langame" );
- Cmd_RemoveCommand( "menu_playersetup" );
- Cmd_RemoveCommand( "menu_controls" );
- @@ -1596,7 +1601,6 @@ void UI_Shutdown( void )
- Cmd_RemoveCommand( "menu_defaults" );
- Cmd_RemoveCommand( "menu_cinematics" );
- Cmd_RemoveCommand( "menu_customgame" );
- - Cmd_RemoveCommand( "menu_quit" );
- memset( &uiStatic, 0, sizeof( uiStatic_t ));
- }
- diff --git b/mainui/basemenu.h a/mainui/basemenu.h
- index 11ee4fd..474e6fc 100644
- --- b/mainui/basemenu.h
- +++ a/mainui/basemenu.h
- @@ -74,7 +74,7 @@ GNU General Public License for more details.
- #define UI_OUTLINE_WIDTH uiStatic.outlineWidth // outline thickness
- #define UI_MAXGAMES 900 // slots for savegame/demos
- -#define UI_MAX_SERVERS 32
- +#define UI_MAX_SERVERS 64
- #define UI_MAX_BGMAPS 32
- #define MAX_HINT_TEXT 512
- diff --git b/mainui/menu_creategame.cpp a/mainui/menu_creategame.cpp
- index 753b065..3998c15 100644
- --- b/mainui/menu_creategame.cpp
- +++ a/mainui/menu_creategame.cpp
- @@ -375,7 +375,7 @@ static void UI_CreateGame_Init( void )
- uiCreateGame.hostName.generic.width = 205;
- uiCreateGame.hostName.generic.height = 32;
- uiCreateGame.hostName.generic.callback = UI_CreateGame_Callback;
- - uiCreateGame.hostName.maxLength = 16;
- + uiCreateGame.hostName.maxLength = 28;
- strcpy( uiCreateGame.hostName.buffer, CVAR_GET_STRING( "hostname" ));
- uiCreateGame.maxClients.generic.id = ID_MAXCLIENTS;
- diff --git b/mainui/menu_internetgames.cpp a/mainui/menu_internetgames.cpp
- index 301048e..75044d5 100644
- --- b/mainui/menu_internetgames.cpp
- +++ a/mainui/menu_internetgames.cpp
- @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- #define ID_YES 130
- #define ID_NO 131
- -#define GAME_LENGTH 18
- +#define GAME_LENGTH 28
- #define MAPNAME_LENGTH 20+GAME_LENGTH
- -#define TYPE_LENGTH 16+MAPNAME_LENGTH
- +#define TYPE_LENGTH 10+MAPNAME_LENGTH
- #define MAXCL_LENGTH 15+TYPE_LENGTH
- typedef struct
- @@ -118,24 +118,30 @@ UI_InternetGames_GetGamesList
- static void UI_InternetGames_GetGamesList( void )
- {
- int i;
- - const char *info;
- + const char *info, *host, *map;
- + int colorOffset[2];
- for( i = 0; i < uiStatic.numServers; i++ )
- {
- if( i >= UI_MAX_SERVERS ) break;
- info = uiStatic.serverNames[i];
- - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH );
- - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH );
- - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );
- - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH );
- + host = Info_ValueForKey( info, "host" );
- + colorOffset[0] = ColorPrexfixCount( host );
- + StringConcat( uiInternetGames.gameDescription[i], host, GAME_LENGTH );
- + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] );
- + map = Info_ValueForKey( info, "map" );
- + colorOffset[1] = ColorPrexfixCount( map );
- + StringConcat( uiInternetGames.gameDescription[i], map, MAPNAME_LENGTH );
- + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] );
- if( !strcmp( Info_ValueForKey( info, "dm" ), "1" ))
- - StringConcat( uiInternetGames.gameDescription[i], "deathmatch", TYPE_LENGTH );
- + StringConcat( uiInternetGames.gameDescription[i], "dm", TYPE_LENGTH );
- else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" ))
- StringConcat( uiInternetGames.gameDescription[i], "coop", TYPE_LENGTH );
- else if( !strcmp( Info_ValueForKey( info, "team" ), "1" ))
- - StringConcat( uiInternetGames.gameDescription[i], "teamplay", TYPE_LENGTH );
- - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH );
- + StringConcat( uiInternetGames.gameDescription[i], "team", TYPE_LENGTH );
- + else StringConcat( uiInternetGames.gameDescription[i], "???", TYPE_LENGTH );
- + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] );
- StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH );
- StringConcat( uiInternetGames.gameDescription[i], "\\", MAXCL_LENGTH );
- StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH );
- @@ -274,7 +280,7 @@ static void UI_InternetGames_Init( void )
- StringConcat( uiInternetGames.hintText, uiEmptyString, MAPNAME_LENGTH );
- StringConcat( uiInternetGames.hintText, "Type", TYPE_LENGTH );
- StringConcat( uiInternetGames.hintText, uiEmptyString, TYPE_LENGTH );
- - StringConcat( uiInternetGames.hintText, "Num/Max Clients", MAXCL_LENGTH );
- + StringConcat( uiInternetGames.hintText, "Clients", MAXCL_LENGTH );
- StringConcat( uiInternetGames.hintText, uiEmptyString, MAXCL_LENGTH );
- uiInternetGames.background.generic.id = ID_BACKGROUND;
- diff --git b/mainui/menu_langame.cpp a/mainui/menu_langame.cpp
- index 7a40bf5..2098d78 100644
- --- b/mainui/menu_langame.cpp
- +++ a/mainui/menu_langame.cpp
- @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- #define ID_YES 130
- #define ID_NO 131
- -#define GAME_LENGTH 18
- +#define GAME_LENGTH 28
- #define MAPNAME_LENGTH 20+GAME_LENGTH
- -#define TYPE_LENGTH 16+MAPNAME_LENGTH
- +#define TYPE_LENGTH 10+MAPNAME_LENGTH
- #define MAXCL_LENGTH 15+TYPE_LENGTH
- typedef struct
- @@ -118,24 +118,30 @@ UI_LanGame_GetGamesList
- static void UI_LanGame_GetGamesList( void )
- {
- int i;
- - const char *info;
- + const char *info, *host, *map;
- + int colorOffset[2];
- for( i = 0; i < uiStatic.numServers; i++ )
- {
- if( i >= UI_MAX_SERVERS ) break;
- info = uiStatic.serverNames[i];
- - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH );
- - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH );
- - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );
- - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH );
- + host = Info_ValueForKey( info, "host" );
- + colorOffset[0] = ColorPrexfixCount( host );
- + StringConcat( uiLanGame.gameDescription[i], host, GAME_LENGTH );
- + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] );
- + map = Info_ValueForKey( info, "map" );
- + colorOffset[1] = ColorPrexfixCount( map );
- + StringConcat( uiLanGame.gameDescription[i], map, MAPNAME_LENGTH );
- + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] );
- if( !strcmp( Info_ValueForKey( info, "dm" ), "1" ))
- - StringConcat( uiLanGame.gameDescription[i], "deathmatch", TYPE_LENGTH );
- + StringConcat( uiLanGame.gameDescription[i], "dm", TYPE_LENGTH );
- else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" ))
- StringConcat( uiLanGame.gameDescription[i], "coop", TYPE_LENGTH );
- else if( !strcmp( Info_ValueForKey( info, "team" ), "1" ))
- - StringConcat( uiLanGame.gameDescription[i], "teamplay", TYPE_LENGTH );
- - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH );
- + StringConcat( uiLanGame.gameDescription[i], "team", TYPE_LENGTH );
- + else StringConcat( uiLanGame.gameDescription[i], "???", TYPE_LENGTH );
- + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] );
- StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH );
- StringConcat( uiLanGame.gameDescription[i], "\\", MAXCL_LENGTH );
- StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH );
- @@ -274,7 +280,7 @@ static void UI_LanGame_Init( void )
- StringConcat( uiLanGame.hintText, uiEmptyString, MAPNAME_LENGTH );
- StringConcat( uiLanGame.hintText, "Type", TYPE_LENGTH );
- StringConcat( uiLanGame.hintText, uiEmptyString, TYPE_LENGTH );
- - StringConcat( uiLanGame.hintText, "Num/Max Clients", MAXCL_LENGTH );
- + StringConcat( uiLanGame.hintText, "Clients", MAXCL_LENGTH );
- StringConcat( uiLanGame.hintText, uiEmptyString, MAXCL_LENGTH );
- uiLanGame.background.generic.id = ID_BACKGROUND;
- diff --git b/mainui/ui_title_anim.cpp a/mainui/ui_title_anim.cpp
- index 85651c1..e36f2ae 100644
- --- b/mainui/ui_title_anim.cpp
- +++ a/mainui/ui_title_anim.cpp
- @@ -92,6 +92,7 @@ void UI_DrawTitleAnim()
- LerpQuad( TitleLerpQuads[f_idx], TitleLerpQuads[s_idx], frac, &c );
- PIC_Set( TransPic, 255, 255, 255, 255 );
- +
- PIC_DrawAdditive( c.x, c.y, c.lx, c.ly, &r );
- }
- diff --git b/mainui/utils.cpp a/mainui/utils.cpp
- index 62b5afd..89b49c3 100644
- --- b/mainui/utils.cpp
- +++ a/mainui/utils.cpp
- @@ -67,6 +67,30 @@ int ColorStrlen( const char *str )
- return len;
- }
- +int ColorPrexfixCount( const char *str )
- +{
- + const char *p;
- +
- + if( !str )
- + return 0;
- +
- + int len = 0;
- + p = str;
- +
- + while( *p )
- + {
- + if( IsColorString( p ))
- + {
- + len += 2;
- + p += 2;
- + continue;
- + }
- + p++;
- + }
- +
- + return len;
- +}
- +
- void StringConcat( char *dst, const char *src, size_t size )
- {
- register char *d = dst;
- @@ -2184,6 +2208,7 @@ void UI_PicButton_Draw( menuPicButton_s *item )
- };
- PIC_Set( item->pic, r, g, b, 255 );
- + PIC_EnableScissor( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height - 2 );
- PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[state] );
- a = (512 - (uiStatic.realTime - item->generic.lastFocusTime)) >> 1;
- @@ -2193,6 +2218,7 @@ void UI_PicButton_Draw( menuPicButton_s *item )
- PIC_Set( item->pic, r, g, b, a );
- PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[BUTTON_FOCUS] );
- }
- + PIC_DisableScissor();
- }
- else
- {
- diff --git b/mainui/utils.h a/mainui/utils.h
- index 54e852d..58b0477 100644
- --- b/mainui/utils.h
- +++ a/mainui/utils.h
- @@ -109,6 +109,7 @@ inline float RemapVal( float val, float A, float B, float C, float D)
- }
- extern int ColorStrlen( const char *str ); // returns string length without color symbols
- +extern int ColorPrexfixCount( const char *str );
- extern const int g_iColorTable[8];
- extern void COM_FileBase( const char *in, char *out ); // ripped out from hlsdk 2.3
- extern int UI_FadeAlpha( int starttime, int endtime );
Add Comment
Please, Sign In to add comment