Guest User

Untitled

a guest
Dec 14th, 2016
727
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.12 MB | None | 0 0
  1. diff --git b/change.log a/change.log
  2. new file mode 100644
  3. index 0000000..1993d14
  4. --- /dev/null
  5. +++ a/change.log
  6. @@ -0,0 +1,797 @@
  7. +build 3597
  8. +
  9. +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
  10. +Engine: rewrite PVS system for variable PVS radius that can be used as FAT pvs or FAT phs without recalculating vis-array
  11. +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)
  12. +Render: some unsed funcs from RenderAPI was replaced with usefully funcs. Backward compatibility stay keep on
  13. +Render: added few function in RenderAPI for SDLash3D by Albatross request
  14. +Render: get support for loading multi-layered textures (for potential landscape implemenantion)
  15. +Client: added two funcs into engine interface for custom interpolation on the client
  16. +Server: allow to write map lums on a server to store userdata (physic collision, ai nodegraph as example). Works with extended BSP format only
  17. +Server: physic interface was updated and expanded to get more control over player and entities simulation
  18. +Client: demo protocol was changed to 2 ( allow comment in demo header)
  19. +Client: demo playing is now using interpolation of client view angles
  20. +Client: fixup some issues on demo playback
  21. +Client: fix broken parametric entities (rockets in TFC as example) in multiplayer
  22. +Client: net graph implementation like in GoldSrc
  23. +Client: fixup ugly "un-duck" effect while after changing level (see for example transition from c0a0b to c0a0c)
  24. +Client: clean-up and rewrite predicting code to get more compatibility for original prediction
  25. +Client: handle colon separately for client version of COM_ParseFile (like in goldsrc)
  26. +Client: finalize NETAPI. Now it can handle servers list from a master server (and display on a built-in client browser of course)
  27. +GameUI: fixup color-strings that sended across network as server names or player names
  28. +Client: texturebrower and overview mode now is not affected to player moving in world
  29. +Client: accumulate pmove entities right after handling delta's not after world rendering
  30. +Client: change master server address and request to actual
  31. +Client: exclude dead bodies from solid objects in pmove processing
  32. +Engine: fixup wad parsing from "wad" string in worldspawn settings (broken in previous version)
  33. +Client: new style of displaying FPS counter
  34. +Network: remove compression routine (very low efficiency)
  35. +Client: fix muzzleflashes decoding from an studio animation event
  36. +Engine: fix crash\hanging while trying to play AVI-file when codec is not-installed
  37. +Client: change color handle for viewbeams (remove color normalization)
  38. +Render: rewrite waves on water surfaces, uses table sin, increase speed and look close GoldSrc
  39. +Render: completely rewrite texture loader, remove obsolete code, added support for multi-layered textures and float textures, fix errors
  40. +Render: now "gl_texturemode" is obsolete and removed. Use "gl_texture_nearest" cvar instead
  41. +Render: improved doble-cloud layering sky for Quake. reduce parallax distorsion
  42. +Render: completely rewrite OpenGL loader. Remove obsolete extensions, fixup some errors
  43. +Render: moved lightstyle animation from render frame loop to client frame loop (to prevent execute lightstyle animation on multipass viewing)
  44. +Client: fixup studio culling on models with non-default scaling (large models in SoHL)
  45. +Sound: change DSP code to get DSP effects like in original GoldSrc
  46. +Sound: rewite sound PHS code. Now it can be useful
  47. +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)
  48. +Sound: sentence sounds now can be freed after playing (and saves some memory)
  49. +Client: get VGUI backend to implement of lastest version of vgui.dll
  50. +Engine: sort commands and cvars in alpha-bethical order. Include scripting functions from SDLash3D
  51. +Console: now map list show an extension or type of various map and mapstats check level for transparent water support
  52. +Console: replace the console buffer with effectively circular buffer (up to 1mb messages)
  53. +FS: do complete revision of filesystem code, remove WAD2 support
  54. +ImageLib: fix crash in quantizer while image is completely black
  55. +Server: ignore sounds from pmove code when prediction is enabled
  56. +Server: change userinfo handling, fixup info send to all the clients
  57. +Server: fixup player animtion timings
  58. +Server: enable cl_msglevel to filter up unneeded messages
  59. +Server: restart server right if circular buffer pointer was exceeded 32-bit limit value
  60. +Server: fixup player think timings
  61. +
  62. +
  63. +build 3366
  64. +
  65. +Render: get support for custom DXT encoding (custom renderers only)
  66. +Render: remove image program stuff (just not used)
  67. +Engine: adding support for new wad filetypes (like DDS images) and wad imagetypes (normalmap, glossmap etc)
  68. +Render: implement tiling on the studiomodels
  69. +Client: do revision of predicting implementation, fix errors, more clean code
  70. +Client: implement prediction error to avoid ugly blinking view on moving platforms when predicting is enabled
  71. +Render: fixup the DDS loading code (invalid calc for mip-sizes)
  72. +Client: fixup parser of detailtextures when texturename contain symbol '{'
  73. +Render: added experimental hint for Nvidia drivers for force select Nvidia videocard when engine is running
  74. +Engine: rewrote condition to calculate level CRC (singleplayer or multiplayer)
  75. +Engine: added cvar r_wadtextures like in HL. First load textures from the wad, then from BSP
  76. +Server: fix bug with cl_updaterate variable (always get default values if not changed by user)
  77. +Server: recalc the ping time correctly
  78. +Server: fix bug with too long player name
  79. +GameUI: fix bug with 4-bit bmps buttons (image cutter)
  80. +
  81. +build 3224
  82. +
  83. +Client: make players solid for prediction code
  84. +Client: change out of band request to make compatibility with custom master-servers
  85. +Client: reject triggers and other like things for prediction code
  86. +Client: fix the potential crash in prediction code
  87. +Render: fix the potential crash in image loader
  88. +Client: fix thirdperson camera culling
  89. +Console: experimental fix for console problems with word-wrapping
  90. +Network: fix bug in BF_WriteBitAngle function (thx mittorn)
  91. +Network: rewrite clamping bounds for delta-variables (it was incorrectly)
  92. +Network: change address of master server (now master is working)
  93. +Server: some changes for client connection\disconnection to prevent possible errors or crash the server
  94. +
  95. +build 3153
  96. +
  97. +Render: RenderAPI update. New parm PARM_REBUILD_GAMMA to differentiate from map restart or change level when called from GL_BuildLightmaps
  98. +GameUI: increased slots for savedgames\multiplayer maps up to 900
  99. +
  100. +build 3145
  101. +
  102. +Engine: add support for studiomodels with fixed texcoords multiplier (a studiomodel format extension)
  103. +Engine: first experimental implementation of client movement predicting code (thx SovietCoder)
  104. +Engine: first experimental implementation of client movement interpolation code (thx SovietCoder)
  105. +Engine: some small bugfixes
  106. +
  107. +build 3030
  108. +
  109. +Client: remove demoheader.tmp while engine is shutting down
  110. +Render: allow .dds format for detail textures
  111. +Render: get support up to 16384 verts per submodel for studio models
  112. +Render: disable vertical sync while level is loading
  113. +ImageLib: allow support big textures up to 8192x8192
  114. +ImageLib: rewrited code for detecting alpha in DXT3, DXT5 formats
  115. +
  116. +build 3000
  117. +
  118. +Render: new render info parm PARM_TEX_GLFORMAT for getting a real format for a given texture
  119. +Server: added a engine memory allocations through internal mempool and function GetTextureData (a part of tracing alpha-textures)
  120. +Client: clamping client pmove time if fps is too high
  121. +Client: new fps counter-style that showing min and max values (cl_showfps 2 to enable)
  122. +Render: get support for DDS textures (DXT1, DXT3, DXT5 and ARGB is allowed)
  123. +Render: get support for floating depth-buffer texture (high prescision depth-buffer)
  124. +Render: added VSDCT internal texture
  125. +Render: add support for seamless cubemaps
  126. +Render: fullscreen resolution auto-detect on first launch
  127. +Render: added resolution 1600x900
  128. +Render: new command line option -gldebug (enable internal GL-driver debug info)
  129. +Engine: fix bug with CRC calculation on BSP31 format (thx [WPMG]PRoSToTeM@)
  130. +FS: additional check to prevent error "Mem_Free: not allocated or double freed (free at filesystem.c:1489)"
  131. +FS: fix FS_Eof function (thx [WPMG]PRoSToTeM@)
  132. +VGUI: handle ESC key while VGUI is shown
  133. +Engine: allows to load "deluxedata" from base folder even if a map placed in game folder (probably it was a stupid limitation)
  134. +Server: replace Host_Error "ED_Alloc: no free edicts" with Sys_Error to prevent possible troubles
  135. +
  136. +build 2900
  137. +
  138. +Console: add detection for Paranoia 2 maps (show message in console)
  139. +Engine: fix playing video when fps_max is 0 and framerate too high
  140. +Engine: add function TraceSurface into pmove, EventAPI and PhysicAPI interfaces
  141. +
  142. +build 2867
  143. +
  144. +Client: another extension for EventAPI: function EV_SoundForIndex to get soundpath from soundindex
  145. +Render: RenderAPI update. New flag TF_NOCOMPARE to disable comparing for depth-textures and PARM_CLIENT_ACTIVE (self-explanatory)
  146. +Server: PhysicAPI update. Add support for file searching.
  147. +Client: fix a little bug in CL_AddVisibleEntity
  148. +Client: check rectangles right for hud.txt
  149. +Client: fix demoplaying in background mode (changelevel etc)
  150. +Client: fix SOLID_CUSTOM support in client trace
  151. +Render: create debug context for powerful OpenGL debugging
  152. +Render: fix bug with kRenderWorldGlow
  153. +Sound: add two new cmds: spk and speak like in GoldSrc
  154. +GameUI: fix buttons bmp loader
  155. +
  156. +build 2664
  157. +
  158. +Engine: restore right ordering of arguments of SV_StudioSetupBones export
  159. +Render: a some cosmetic changes in RenderAPI
  160. +Client: make levelshots for background demos
  161. +Client: now cmd 'startdemos' invoke to play demos sequence like as background map
  162. +Client: increase demo auto-naming from 100 up to 10000
  163. +Client: fix bug with inverted PITCH of non-local playermodel
  164. +Client: added FireCustomDecal into EfxAPI (was missed)
  165. +GameUI: fix some crashes after end the background map (like call of trigger_endsection)
  166. +Client: eliminate muzzleflash copy from mirror reflection in normal view
  167. +Render: fix bug with max_texture_units clamping
  168. +Render: completely remove glScissor calls (just unused)
  169. +Render: update thirdperson code for mirrors
  170. +Render: rewrite viewport setup code
  171. +Render: fix software gamma adjustment bug while flashlight is enabled
  172. +Render: reset vid_displayfrequency if current value isn't support by user display. Throw warning message
  173. +Engine: allow new param in gameinfo.txt who called soundclip_dist <radius>. Default is 1000.
  174. +Sound: new cmd 'playvol' like in GoldSrc
  175. +Server: fix crash in 'Gunman Chronicles' at map end1.bsp
  176. +Engine: show more infos with cmd 'mapstats'
  177. +Network: fix bug with DT_TIMEWINDOW_8
  178. +Server: fix bug with triggers with 'liquid' textures
  179. +Server: fix some bugs in PVS calculation on server
  180. +GameUI: enable auto-refresh of actual multiplayer maps list
  181. +GameUI: update 3D playermodel preview for 16:9 screen aspect
  182. +
  183. +build 2636
  184. +
  185. +Engine: added internal loader for deluxemap data (.dlit file that produces VHLT)
  186. +Engine: msurfmesh_t was reorganized to complex vertex data instead of single arrays (VBO-ready)
  187. +Engine: decal_t now contain msurfmesh_t with all vertices and texcoords
  188. +Render: RenderAPI interface updated to version 35
  189. +Render: get support for float textures format (GL_ARB_texture_float is required)
  190. +Render: implementation of image program preprocessor, like in Doom3, syntax: AddNormals( texture1.tga, texture2.tga );
  191. +Render: get acess to internal tesselator through RenderAPI
  192. +Server: a little update for PhysicInterface: get support for custom decal save\restore
  193. +Client: separate levelshots for wide-screen and normal screen
  194. +Client: revert parametric rocket implementation (previous was lost between two backups)
  195. +Client: fix a potentially crash when calling function IsSpectateOnly
  196. +Client: now 'ESC' button while playing video invoke jump to next video in list (instead of completely stopping video)
  197. +Client: fix bug when demo ends up (Connection Problem)
  198. +Client: now compensate screenshot gamma is toggleable (cvar "gl_compensate_gamma_screenshots")
  199. +Render: optimize decal code, remove unused functions
  200. +Render: now all the lightmaps stored into 1024x1024 texture
  201. +Render: add cvar "gl_detailscale" for customize _detail.txt generation
  202. +Render: fix some errors with studiomodels lighting
  203. +Sound: increase maximum count of words in sentence up to 64 (from 29)
  204. +Engine: fix broken recursion in Cmd_CheckMapLis_R (potentially crash)
  205. +Client: passed keyup event through HUD_KeyEvent callback
  206. +Network: change delta params for skycolor_* variables (in some cases color value was incorrect received)
  207. +Network: fixed TIMEWINDOW_BIG mode
  208. +Engine: add engine build number into console log
  209. +
  210. +build 2463
  211. +
  212. +Engine: reorganize data in texture_t. Release one variable for mod-makers
  213. +Engine: change decal_t structure get compatibility with GoldSrc
  214. +Engine: expanded mextrasurf_t reserved fields up 32
  215. +Engine: update player_info_t (added customization_t like in SDK 2.3)
  216. +Engine: increase local_state_t->weapondata up 64 slots
  217. +Engine: update IVoiceTweak interface
  218. +Engine: new lightstyle system with local time and custom interpolation
  219. +Engine: fix bug with lightstyle save\restore (only first 64 symbols of pattern was saved)
  220. +Engine: update r_efx_api_t interface
  221. +Engine: update engine_studio_api_t, remove uncompatible function StudioGetTexture, added three new (thats came from CS:CZ)
  222. +Engine: added ref_overview to support custom overview implementation
  223. +Engine: render interface is outdated now. New render interface has version 30 (too much changed)
  224. +Engine: update triangleapi_t interface
  225. +Engine: update cl_dll interface (also added support for signle export that called 'F')
  226. +Engine: a lttle update for enginefuncs_t (server interface)
  227. +Client: fixed crash on shutdown when custom renderer uses AVI-files
  228. +Engine: applaying scale for decals on brushmodels or world geometry
  229. +Engine: update model_state_t thats keep info about studiomodels for studio decals. Include body and skin
  230. +Engine: get support for custom studiocache on static and tempents
  231. +Engine: write R_Srpite_WallPuff from pEfxAPI
  232. +Client: fix bug with beam sorting (solid beams was drawing in translucent pass)
  233. +Render: add special flag for decals thats indicated local space (any decal after first shoot)
  234. +Render: apply emboss filter on studiomodel textures
  235. +Render: rewrite client event system for studiomodels. Get more predictable results
  236. +Network: write existing decals and static entities into new demo
  237. +Network: protocol was changed to 48
  238. +ImageLib: fix old bug with save non-aligned 8-bit bmp files
  239. +Server: fix bug with reloading hl.dll when map was changed every time
  240. +Server: a client part of save-file is outdated. New version is 0.68
  241. +
  242. +build 2402
  243. +
  244. +Engine: added new feature flag for compensate stupid quake bug
  245. +Client: update the render interface, added usefully function GL_TextureTarget
  246. +Render: get support for GL_RECTANGLE textures
  247. +Client: fix playerangles in event receive (Paranoia bug with decals)
  248. +Render: fixed mipmap generation for normalmaps (TF_NORMALMAP)
  249. +Render: added two built-in textures: *blankbump and *whiteCube (self-explanatory names)
  250. +Engine: made better check for Half-Life alpha maps (version 29 with colored lighting)
  251. +
  252. +build 2271
  253. +
  254. +Client: fix message TE_GLOWSPRITE. The gaussgun in Xash Mod is properly worked now.
  255. +Client: restore studio check for missed models and ignore them instead of call the Sys_Error
  256. +Server: fix crash in Gunman Chronicles (scorcher issues)
  257. +
  258. +build 2223
  259. +
  260. +Engine: added option "nomodels" for liblist.gam (disallow user to choose playermodel)
  261. +Client: a new callback for render interface who called R_DrawCubemapView. This fixes cmd "envshot" for XashXT
  262. +Client: store screenshots into root of folder "scrshots" instead of "scrshots\mapname"
  263. +Client: engine using callback CL_CameraOffset now
  264. +Client: fix angles for cmd "envshot"
  265. +Render: rename a miss cvar "r_anisotropy" to real name "gl_anisotropy"
  266. +Render: now "r_speeds 4" displays an actual count of "real" static entities that was created by call of MAKE_STATIC function
  267. +Render: fix bug with blinking Quake Sky while autosave in progress
  268. +Render: keep actual hardware gamma for multiple instances of application
  269. +Engine: get support for Half-Life alpha maps (that has version 29)
  270. +Server: fix the client rejection mechanism
  271. +Server: using the pfnClientDisconnect callback
  272. +Server: some changes in physics code (for MOVETYPE_PUSH)
  273. +
  274. +build 2153
  275. +
  276. +Render: added cvar "gl_nosort" that disables sorting of translucent surfaces
  277. +
  278. +build 2148
  279. +
  280. +Engine: implement support of new BSP format that called BSP31
  281. +Engine: added new feature - big lightmaps 256x256 instead of 128x128. This is used for new BSP format 31
  282. +Render: new texture viewer implemented (navigate pages with arrow keys)
  283. +Engine: added cvar gl_keeptjunctions from Quake (removes a collinear points, economy some vertexes)
  284. +Sound: test thing: release sentence sounds after playing
  285. +Engine: rewrited code for anti (_-=ZhekA=-_) system
  286. +Console: don't moving cursor if autocomplete was failed on second or all next arguments
  287. +Engine: release all elements of client game cvar (was potential memory leak)
  288. +Engine: allow change game for dedicated servers
  289. +Server: added default case for Studio Blending Interface while server is not loaded (e.g. remote connection). Was here a potential crashpoint.
  290. +Engine: parse "wad" field from entity string and use wad ordering for loading textures that may have matched names but placed in different wads
  291. +Network: change protocol to 47. Old demos will stop working.
  292. +Network: rewrite delta-comparing code. In theory this may reduce a network traffic
  293. +Server: fix crash for fast switching between singleplayer and multiplayer
  294. +Server: optimize MOVETYPE_COMPOUND code
  295. +Server: added missed flag FL_FAKECLIENT for bots
  296. +
  297. +build 2112
  298. +
  299. +Engine: fix bug with ambient sounds that won't writes into demo
  300. +Client: allow plaque 'loading' between demos change
  301. +Client: make work fade flag FFADE_MODULATE
  302. +Render: fixed underwater fog recursive leaf search code (thx XaeroX)
  303. +Render: replace all 'random' calls in CL_RocketTrail code from RANDOM_LONG to rand() to get more compatibility with original quake particles
  304. +Render: adding default studiomodel bbox for right culling client static entities
  305. +Sound: add info about background track state into console command "s_info"
  306. +Sound: increase static channels count up to 128
  307. +Client: write background track state into demo
  308. +Engine: fix crash when typing 'cvarlist' into console
  309. +FS: allows lookup system files into root directory (e.g. vgui.dll etc)
  310. +Engine: added new command 'modellist" (prints list about all loaded models)
  311. +Engine: add terminator for entity string to be guranteed have valid end of the entity string
  312. +Engine: purge all fake bmodels from previous map when server is changed
  313. +Memory: increase check for filename debug length from 32 to 128 characters
  314. +Server: background track which will be specfied from worldpsawn settings now are looped
  315. +Engine: fix bug with recorded demos in Quake Remake after changelevel
  316. +GameUI: 'gamestartup.mp3' now are looped
  317. +Server: fix the SV_StudioSetupBones interface declaration error (thx maricool)
  318. +Render: change MAXSTUDIOTEXTURES limit from 128 to 256
  319. +Client: change passed argument for HUD_Frame callback from cl.time to host.frametime (thx XWider)
  320. +Client: remove screen align to prevent deform on resolution 1366x768
  321. +FS: do check what mod folder is really existed (this helps avoid to creating empty folder)
  322. +GameUI: replace checkbox "Allow Software" with "Vertical Sync" in menu "Video Modes"
  323. +
  324. +
  325. +build 2015
  326. +
  327. +Server: fix the sound problem with weapons
  328. +Render: added rendermode kRenderWorldGlow (6) like in HL2
  329. +Server: added new callback into PhysicsInterface that named SV_TriggerTouch
  330. +Client: kill a little jitter for monsters that standing on elevators
  331. +Client: fix very old bug (initially comes from Quake1) with efrags relinking on a static client entities
  332. +Sound: got rid of message "S_PickChannel: no free channels" when breakble objects were broken.
  333. +Engine: ignore to load HD-textures when dedicated server is running
  334. +Client: count of static entities increased up to 512
  335. +Render: fixed bug with wrong clamping on 3D textures
  336. +Render: added a new one internal texture - gray cubemap that named as "*grayCube" without quotes
  337. +Render: disable depth mask on studiomodels when render mode is "additive" (original HL rules)
  338. +Sound: added a new untested feature for cull sounds by PAS on the client. Cvar "s_phs".
  339. +Sound: add save\restore for all dynamic sounds in-game
  340. +Sound: add save\restore for background track
  341. +Engine: added two new cvars called "build" and "ver" for more info
  342. +Engine: get support for loading game dlls from packfile
  343. +Engine: get support for transparent conveyor belts. Texture name must starting from "{scroll"
  344. +Sound: fix bug in wav-streaming code
  345. +Server: add save\restore for client static entities (engine function MAKE_STATIC is now useful!)
  346. +Server: remove command "map_backgound" in dedicated server mode
  347. +Server: disable "Touch" function when playersonly-mode is active
  348. +GameUI: don't draw logo.avi from root folder with user mods
  349. +Client: added partially HD-textures support for sprites
  350. +Server: now custom message code check all the visible portals (Xash-mod feature)
  351. +Server: add quake-style for BSP hulls selection (cvar sv_quakehulls set to 1)
  352. +Engine: remove jpeg image support (just unneeded)
  353. +Server: remove ugly movement delay after map loaging in singleplayer
  354. +Render: check studio skins for negative values to prevent possible crashes
  355. +Console: fixup negative values for "scr_conspeed" variable
  356. +Render: fix interpolation bug for studiomodels on internal studio renderer
  357. +Physic: transform trace BBox into local space of bmodel
  358. +Engine: implement new system of engine features that can be enabled by Mod-Maker request
  359. +Engine: build BSP surface meshes for Mod-Makers. e.g. for build collision tree of VBO\VA custom rendering
  360. +Engine: allow support of large maps up to +\- 16384 units (need to edit delta.lst and enable feature in the engine)
  361. +Engine: rewrite MOVETYPE_TOSS, MOVETYPE_BOUNCE etc
  362. +Client: implement new draw type TRI_POINTS for TriAPI
  363. +Client: changed snapshot name from mapnameXXXX.bmp to mapname_XXXX.bmp (by Qwertyus request)
  364. +Client: write experimental code for interpolate bmodels movement (pev->animtime must not equal 0 for enable)
  365. +GameUI: allow scissor for enginefunc pfnDrawCharacter
  366. +Network: protocol changed. replace obsolete message svc_frame with message svc_restoresound
  367. +Client: remove pieces that stuck in the walls for TE_BREAKMODEL message
  368. +Render: fix mode r_lighting_extended 1 for prevent permanently black lighting in some cases
  369. +Render: global fog update. get the uniform color for all the underwater objects (thx n00b)
  370. +Render: fix issues with conveyor HD-textures (it can moves slower than physical conveyor speed)
  371. +Render: added support for HD-textures for normal sprite frames (non-HUD sprites)
  372. +Render: sorting meshes for studiomodel surfaces (draw "adiitive" surfaces at end of the list)
  373. +Render: release GL-context when engine is shutting down
  374. +Render: set gl_allow_static to zero as default
  375. +Sound: set s_cull to zero as default
  376. +Input: fix problems with call WC_SYSMENU instead of user-defined command when ALT is pressed
  377. +Console: add a new command that called "mapstats" and works like bspinfo.exe
  378. +Physic: added new meta-type SOLID_CUSTOM that could be traced in game dlls with physic API
  379. +Pmove: get to work PM_CheckStuck on a server-side
  380. +Server: added a new cvar that called a "sv_validate_changelevel" for skip any checks with changelevel problems
  381. +Server: make check for recursive changelevel (and ignore it)
  382. +Server: fix the problem with non-sended events when a player sight cross-line contents
  383. +Server: rewrite MOVETYPE_STEP and MOVETYPE_PUSHSTEP physics
  384. +Server: allow to MOVETYEP_PUSH blocking by dead bodies
  385. +Server: fix bug with MOVETYPE_FOLLOW
  386. +Server: added TriAPI through Server_PhysicsInterface for debug purposes
  387. +GameUI: replace broken letter 'ั‘' with 'ะต'
  388. +GameUI: don't draw logo.avi for mods without this file in gamedir
  389. +GameUI: fix buttons loader bug
  390. +GameUI: enable scissor for all ScrollList menus
  391. +GameUI: restore the menu buttons control from keyboard
  392. +Client: get walk animation support for 'wrong' player models that uses different skeleton
  393. +Server: ignore savegame during intermission (used for Quake remake)
  394. +Render: merge mirrors with same plane into one pass (perfomance option)
  395. +Render: fix errors in function GL_CleanupTextureUnits (it was cause problems in XashXT)
  396. +Render: allow decals on 'Solid" surfaces: grates, ladders etc (thx n00b)
  397. +Render: rewrite "r_lighting_extended 2" mode
  398. +Render: add optional texture sorting for models with Additive and Transparent textures (r_studio_sort_textures cvar)
  399. +Engine: makes AABB transform trace an option for switchable engine features
  400. +Engine: allow studiomodel textures up to 4096x4096 (for indexed images)
  401. +Server: merge PVS for looking for client through portal cameras
  402. +Server: fix bug with collect savegame info from basedir (e.g. valve)
  403. +
  404. +
  405. +build 1905
  406. +
  407. +Physic: fix trace bug when model is missing
  408. +Client: implement function TriScreenToWorld
  409. +Server: add local times for all the clients
  410. +Server: implement unlag system
  411. +Client: added ex_interp variable
  412. +GameUI: added support for playermodel images (preview thumbnails)
  413. +Engine: fix potentially crash in menu after calling Host_Error
  414. +Engine: fix crash on Cry Of Fear modification (memory corrupts)
  415. +Engine: first implementation of HLTV
  416. +Render: fix a little bug with engine mirrors
  417. +Sound: implement separate volume controls for background track and game sounds
  418. +Sound: fix wrong position for dynamic sounds in case parent entity never has updates on the client
  419. +Client: first implementation of extended engineinterface.
  420. +Server: fix bug with update movevars after the server initialization.
  421. +Input: cancel mouse movement while switches between menu\console and game
  422. +Render: added function R_EntityRemoveDecals into RendererInterface
  423. +Render: fixed bug with crash engine on custom resolutions while makes a screenshot (e.g. 1366x768)
  424. +
  425. +build 1850
  426. +
  427. +Physic: add check for liquid brushes that has only hull0
  428. +Render: draw decals without culling on the transparent surfaces
  429. +Engine: fix decal transition bug on global entities
  430. +Client: fix "r_drawentities 5" debug code in client.dll
  431. +Render: rewrited detail texture code for using detail scale for each diffuse texture instead of each detail texture
  432. +Render: custom render interface is changed to version 26
  433. +Engine: added custom studio decals serializtaion
  434. +Server: fixed check for russian letters in the commands "say" and "say_team"
  435. +Server: physics interface is changed to version 6
  436. +Client: allow console in multiplayer even while dev-mode is disabled
  437. +Engine: added new message SVC_STUDIODECAL that passed through engine and call function in extended rendered interface
  438. +Engine: hook PrintScreen and manually writing screenshot into clipboard
  439. +Render: fix decals drawing when rendermode is TransColor
  440. +Render: add support for cubemaps, 1D and 3D textures
  441. +Render: added some new internal textures that using by Xash-Mod 0.5
  442. +Render: fix reflection for Glow-Sprites and follow beams
  443. +Studio: fix poly-counter for studio models
  444. +Engine: add support for userconfig
  445. +Engine: allow letter 'ั‘' in console and chat-mode
  446. +Engine: fix REG_USER_MSG for messages that registering in-game
  447. +Server: clear savedir when new game is started
  448. +GameUI: loading maps.lst from basedir while mod doesn't contain multiplayer maps
  449. +Network: implemented QueryCvarValue and QueryCvarValue2
  450. +Physic: new pm-trace code, new server trace code, new studio hitbox trace code
  451. +Client: rewrite demo record and playback
  452. +Render: add support for STUDIO_NF_FULLBRIGHT
  453. +Physic: fix pmove trace bug
  454. +
  455. +build 1770
  456. +
  457. +Client: add command "on"-"off" for virtual CD-player
  458. +Client: add command "snapshot" that save screenshots into root folder
  459. +Client: add studiomodel missed flags like in Quake (EF_ROTATE, EF_ROCKET, EF_GIB etc)
  460. +Sound: clear LOOP flag for engine funcs PlaySoundByIndex and PlaySoundAtLocation
  461. +Render: fix r_wateralpha, move cvar to server and allow save-restore it
  462. +Render: fix old bug with surface->flags
  463. +Render: fix crash when studiomodel isn't loaded but trying to draw
  464. +Render: remove cvar gl_texturebits
  465. +Render: allow 16-bit color mode when decktop has same
  466. +Render: rename "vid_gamma" to "gamma", make backward compatibility with GoldSource config
  467. +Sound: get support for automatic ambient sounds like in Quake
  468. +Sound: add cvar "s_combine_channels" that trying to combine mutilpe channels with same sounds into one
  469. +Engine: add "secure" option support for both liblist.gam and gameinfo.txt
  470. +Engine: fix bug determine current directory
  471. +Server: fix bug when some sound messages can't be sended to client (e.g. not vised map)
  472. +Render: allow to load hi-res quake sky (two layers called as sky_solid and sky_alpha)
  473. +Physic: fix trace bug when bbox mins are 0 0 0 and bbox maxs are positive values (like quake boxes)
  474. +GameUI: add checkbox "allow materials" in menu Video Options.
  475. +Client: implement "viewsize" cvar
  476. +GameUI: add new function to inteface called as pfnProcessImage
  477. +Client: add support for default studiomodel flags like quake effects (light, smoke, blood etc)
  478. +Render: add engine mirrors (can be set on map with texture "decals.wad\reflect1")
  479. +Client: rewrite client font system to allow support for "hud_scale" feature
  480. +Client: re-enable client static entities (see engine function MAKE_STATIC for details)
  481. +Sound: clear "loop" flags for client engine functions PlaySoundByName and PlaySoundByIndex
  482. +Client: fix potentially crash in StudioRemap code
  483. +Client: finalize 'GlowShell' effect on StudioModels
  484. +Render: implement software gamma control that based on lightmap adjusting (gl_ignorehwgamma 1)
  485. +Render: restore projection and modelview matrices before call V_CalcRefdef to avoid errors on custom rendering (e.g. HLFX 0.5, Trinity Renderers)
  486. +Render: remove all stuff for 3dfx gamma control
  487. +Render: add missing function R_ScreenToWorld
  488. +Engine: add "icon" option support for both liblist.gam and gameinfo.txt
  489. +Render: get support for rotational skybox that can be saved and restored with current angle
  490. +Engine: fix bug with incorrect detecting Blue-Shift maps in some rare cases
  491. +Engine: add autocomplete for 'entpatch' command
  492. +Engine: fix Host_Error issues
  493. +Network: add IPX and IPX_BROADCAST for backward compatibility with GoldSrc
  494. +Engine: do revision for 'allow_studio_scale' cvar in trace code
  495. +GameUI: added support for Steam backgrounds
  496. +GameUI: hide input symbols for "password" field in "create server" menu page
  497. +Client: initial implementation of NetAPI
  498. +Render: clear decals code. Add transparent rendering for 'glass' decals
  499. +GameUI: added new argument for pfnPIC_Load.
  500. +GameUI: fix loading flipped Steam background images
  501. +Client: remove gravity for R_Implosion effect
  502. +Sound: add SND_MoveMouth16 for support 16-bit sounds lip-sync
  503. +Engine: fix potentially crash during parsing titles.txt when file is empty
  504. +Engine: increase MAX_VALUE field up to 2048 characters
  505. +Console: rename con_gamemaps to con_mapfilter
  506. +Sound: add check by PVS for dynamic entity channels
  507. +Sound: add sound culling by geometry (cvar 's_cull' for enable or disable)
  508. +Server: fix changelevel bug
  509. +Engine: fix sound pathes with backward slash
  510. +Engine: rewrite COM_LoadFile and LoadFileForMe for use malloc instead of engine Mem_Alloc
  511. +Server: check date for entitypatch to avoid loading too old pathes (when map is never than path)
  512. +Server: bug fixed in CreateNamedEntity (on create not existed entities).
  513. +Server: rewrite engine func pfnAlertMessage to avoid crash in AM:Rebrith
  514. +Server: align memory for edicts by 4 (this help to avoid crash in Poke646)
  515. +Render: bugfixed with rotational brush culling (perfomance)
  516. +Server: changelevel bug fixed (accumulate global entities)
  517. +Server: changelevel bug when entitypath on new level is too old (new level is never than him entitypath)
  518. +Server: physical inetrface for custom physic implementation is updated to version 5
  519. +Physic: fix bug with MOVETYPE_COMPOUND
  520. +Server: fix bug with force_retouch on start the level (to avoid crash in Todesangst2 on t2e1m10)
  521. +Render: fix rendering for FACE_UPRIGHT sprite types (doom-like sprite monsters)
  522. +Protocol: shifted up additional EF_ flags to avoid collisions with Trinity Renderers
  523. +Render: now hardware gamma-control is fixed
  524. +Client: implement new render interface for custom renderer implementation (current version is 12)
  525. +Client: added two new funcstions into event API (IndexForEvent and EventForIndex)
  526. +Client: added new function into IEngineStudio interface (StudioGetTexture) for custom rendering implementation
  527. +Client: passed server beam entity through client function HUD_AddEntity, make force to add menu entity (player setup)
  528. +Client: passed static client entities through client function HUD_AddEntity
  529. +Physic: add support for rotational water and triggers
  530. +
  531. +build 1662
  532. +
  533. +Client: implement StudioRemapColors function
  534. +Client: add simple shadows for stduiomodels (disabled like in GoldSrc)
  535. +Client: fix some Paranoia bugs when custom renderer is disabled
  536. +Client: implement overview tool (dev_overview)
  537. +Client: add debug commands linefile and pointfile
  538. +Client: get support for full-color external textures (tga format) - world, studiomodels and decals
  539. +Client: fixed some HLFX 0.6 bugs
  540. +Client: fixed follow studiomodels (like flags in CTF)
  541. +Server: add pfnGetApproxWavePlayLen
  542. +Sound: get support for mp3's with wav header
  543. +Server: fixed FIND_CLIENT_IN_PVS
  544. +Server: fixed PlaybackEvent, use camera PVS point when client see in
  545. +Render: enable lightmaps on a transparent surfaces like windows (r_lighting_extended 2)
  546. +Server: func_pushable can push players which standing on (sv_fix_pushstep)
  547. +Render: partially fix for underwater fog (temporary solution)
  548. +
  549. +build 1613
  550. +
  551. +Client: fix drawing beams for 'solid' mode
  552. +Image: fix BMP loader for 4-bit color bmp's
  553. +Client: fix lightlevel calculating for local client (remove 'ambient' base from final value)
  554. +GameUI: first implementation of custom strings and support 'strings.lst' parsing
  555. +GameUI: replace unneeded button 'credits' with button 'previews'
  556. +Render: fix sprite interpolation
  557. +Render: fix angled sprites offset
  558. +Render: implement detail textures like in Steam Half-Life (thx n00b)
  559. +Client: rework env_funnel effect
  560. +Engine: get full support for input, processing and drawing russian letters
  561. +Console: add console commands 'messagemode' and 'messagemode2'
  562. +Console: fix bug with autocomplete (enable sort for found cmds)
  563. +Client: added HUD_ChatInputPosition for CS 1.6
  564. +
  565. +build 1598
  566. +
  567. +Client: fix crosshair drawing
  568. +Sound: change libmad mp3 decoder on a mpg123
  569. +Client: fix gibs randomization for TE_BREAKMODEL
  570. +Engine: fix modelloader bug (engine crash after not found map)
  571. +Video: add resolution 1366x768
  572. +GameUI: fix skill select
  573. +Network: change 'svc_setangle' message, include rollangle
  574. +Render: fix chrome rendering on a studiomodels
  575. +Render: added video memory economy mode - cvar 'gl_luminance_textures'
  576. +GameDLL: first implementation of extended engineinterface. Metamod is supported now
  577. +
  578. +build 1557
  579. +
  580. +Sound: fixed wrong sound angles when client see in the camera
  581. +Render: fix crash on change gl_texturemode and gl_anisotropy.
  582. +Client: change relationsip for GetLocalPlayer. Now it's always valid.
  583. +Server: rewrite SV_Multicast for correct work with custom user cameras
  584. +Server: rewrite FIND_CLIENT_IN_PVS like in QW
  585. +
  586. +build 1540
  587. +
  588. +Fixed many-many small and large bugs before final release
  589. +
  590. +build 1529
  591. +
  592. +FS: add "fallback_dir" option
  593. +Server: fix func_pushable interaction with movers. Add new cvar "sv_allow_rotate_pushables"
  594. +Server: added support for 'SV_SaveGameComment' export
  595. +Server: fixed backup for quick.sav and autosave.save (quick01.sav and autosave01.sav)
  596. +Client: add commandline option "-nointro" to skip start movies
  597. +Pmove: add sv_clienttrace that shared across network
  598. +Render: implement "envshot" and "skyshot" commands for make cubemaps or skyboxes
  599. +Server: fix remote connection (rcon)
  600. +Render: add glare reduction option in menu
  601. +Server: fix FindEntityInSphere bug (satchel issues in multiplayer)
  602. +GameUI: added to scrollbar in srcoll lists (thx ADAMIX)
  603. +
  604. +build 1516
  605. +
  606. +Engine: fix Sys_Error blowout
  607. +GameUI: implement new credits effect in Half-Life (when game is end)
  608. +GameUI: use system cursor instead of emulated
  609. +
  610. +build 1515
  611. +
  612. +Engine: fix some bugs
  613. +
  614. +build 1507
  615. +
  616. +Console: implement Con_NPrintf and Con_NXPrintf
  617. +Render: adding better lighting for studiomodels (right lighting for long sequences e.g. forklift.mdl)
  618. +Network: clamp all integer values to prevent them out of range
  619. +Client: VGUI implementation
  620. +Render: fix decals loading
  621. +Server: fix NAN error on a crossbow launch
  622. +
  623. +build 1488
  624. +
  625. +Render: fix invisible sprites when game is paused
  626. +Render: implement new better sprites lighting
  627. +GameUI: HL-style buttons (old good menu form WON version)
  628. +Render: fix some rendering bugs
  629. +
  630. +build 1482
  631. +
  632. +Engine: fixed critical bug
  633. +Launch: remove all built-in tools
  634. +Engine: add underwater fog
  635. +Engine: add cvar to control studio model scaling (enable or disable)
  636. +Engine: fixed bug with mouse in multiplayer (not work in menu)
  637. +Engine: fixed lag on rpg laserspot
  638. +Engine: added weapon and movement prediction (may be bugly, use with caution)
  639. +GameUI: added pfnRandomLong and pfnRandomFloat built-ins (and keep compatibility with old versions)
  640. +Engine: added map_background (special command for loading background maps like in Source Engine)
  641. +GameUI: added support for chaptermapbackground.txt script-file (random choose background maps)
  642. +Render: fix some rendering bugs for mods with custom renderer (Paranoia, HLFX etc)
  643. +
  644. +build 1433
  645. +
  646. +Engine: rework hitbox trace
  647. +Engine: implement new check for blue-shift map format
  648. +Engine: fix PointContents for custom contents checking (spirit)
  649. +Engine: fix "angle" field on maps (typically for gearbox)
  650. +GameUI: implement 'mouse look' checkbox
  651. +
  652. +build 1430
  653. +
  654. +Engine: fix crash with invalid room_type set (more than 60)
  655. +Engine: fix stuck on elevators or tracktrains for clients
  656. +
  657. +build 1428
  658. +
  659. +Engine: fix trigger_camera serialization bug
  660. +Engine: many-many physics bugs fixed
  661. +Engine: reworking monster's movement and path finding
  662. +Engine: hlfx 0.6 is now working
  663. +FS: fix bug with game and base directory dectecting when they matches
  664. +FS: watch for changes in liblist.gam and update gameinfo.txt (feature)
  665. +Engine: fix some rendering bugs
  666. +GameUI: added 'suitvolume' control
  667. +GameUI: rewrite playeyrmodel drawing, so you can shows changes when hi\low resolution button is toggled
  668. +GameUI: remove choosing audio and video library (interface changed!)
  669. +Engine: fix train startup sound on new level
  670. +
  671. +build 1422
  672. +
  673. +Render: fix decals serialization bug
  674. +Engine: fix movie plaback bug (black screen)
  675. +Engine: fix crash on loading encrypted client.dll
  676. +GameUI: now recalc resolution when vid_mode is changed
  677. +Sound: fix musicvolume bug
  678. +Image: fix indexalpha palette bug
  679. +Physic: fix stuck on some items (weapons, ammo)
  680. +
  681. +build 1418
  682. +
  683. +Tools: move all tools into launch.dll
  684. +Sound: moving snd_dx.dll into engine.dll
  685. +Sound: implement CDAudio emulator with support mp3 tracks from original Half-Life
  686. +Sound: implement mp3 support
  687. +GameUI: GameUI.dll renamed to MainUI.dll to avoid conflict with original valve's GameUI.dll
  688. +Engine: support for StartupVids.txt
  689. +Engine: get full compatibility with hl.dll
  690. +FS: recode wad resource management (now support lumps from wads with same name)
  691. +Engine: trigger_camera is now correctly saved and restored
  692. +Render: add sorting for translucent surfaces
  693. +Render: make support for 'static' models (any opaque non-moving brushes engine automatically make as part of world)
  694. +Render: correct serialization for decals on bmodels
  695. +
  696. +build 1338
  697. +
  698. +Engine: fix a broken demos recording\playing
  699. +GameUI: get support for internal resources (built-in)
  700. +GameUI: make font.bmp, cursor.bmp and typing.bmp as part of GameUI.dll
  701. +GameUI: remove demo menus heads.
  702. +
  703. +build 1334
  704. +
  705. +Engine: prevent auto-repeat for most keys in-game
  706. +Engine: implement AVI movies support (instead of RoQ support)
  707. +Engine: enable logo.avi in main menu (see GameUI source for details)
  708. +
  709. +build 1313
  710. +
  711. +Launch: code revision, remove dead code, implement some missed functions
  712. +Sound: fix some errors and crash
  713. +Sound: implement music volume
  714. +Sound: reworking sound mixer
  715. +Sound: implement DSP
  716. +Engine: add support for five mouse extra-buttons
  717. +Engine: fix some physics bugs
  718. +SDK: add blue-shift game source to SDK (combined with main game source)
  719. +
  720. +build 1305
  721. +
  722. +Engine: implement bit-stream network buffer
  723. +Engine: implement custom delta-encoding with user defined script (delta.lst)
  724. +Engine: reworking client entity for get more compatibility with original HL client
  725. +Engine: make SDK compatible with HLSDK 2.3 on the server-side
  726. +Engine: fixup across transition time-bug
  727. +Engine: completely rewrite server trace
  728. +Engine: rewrite hitbox trace
  729. +Engine: rewrite SV_PointContents
  730. +Engine: implement a new movetype: compound for gluing two entities together (like movewith in spirit)
  731. +Engine: fix toss entities on conveyors
  732. +Engine: rewrite MOVETYPE_PUSH
  733. +Engine: rewrite monsters movement code
  734. +Engine: reworking client and game interfaces
  735. +Engine: fix camera bugs (no sounds when client see in the camera)
  736. +SDK: fix many-many small HL bugs in original sdk code
  737. +Engine: fix trigger retouching system
  738. +Engine: adjust beam visibility
  739. +
  740. +build 1271
  741. +
  742. +Engine: enable server.cfg, listenserver.cfg, mapcycle.txt etc
  743. +Engine: got to work mapcycle.txt
  744. +GameUI: implement redefine keys menu
  745. +Engine: added autocomplete for cmd 'exec'
  746. +Engine: added version info in menu
  747. +
  748. +build 1270
  749. +
  750. +SDK: Shared launcher code
  751. +Engine: Partially fix bmodel interpolation
  752. +Engine: use standard .cfg files instead of .rc files
  753. +
  754. +build 1269
  755. +
  756. +Render: cut invisible water polygons
  757. +Render: implement EF_NOWATERCSG for control func_water backface culling
  758. +Tools: fix wadlib and spritegen round bugs
  759. +FS: implement binary search for wadlumps
  760. +Engine: revert low-res timer
  761. +Network: fixup userinfo fields 'model' and 'name'
  762. +Sound: implement custom pause for various sources
  763. +Input: disable mouse events when level is loading
  764. +GameUI: adding some missed dialogs
  765. +Render: fix interpolation on flying monsters
  766. +Render: fix wrong sprite attachments
  767. +Render: fix invalid frustum culling for studiomodels ( e.g. barnacle.mdl )
  768. +Physic: fix trace for rotating bmodels
  769. +Engine: fixup physinfo save\restore bug
  770. +
  771. +build 1262
  772. +
  773. +Engine: add 'allow_levelshots' cvar (disabled by default) to switch between custom levelshots and normal 'loading' screen
  774. +Client: remove fmod.dll implementation
  775. +Engine: implement variable-sized fonts (console, menu hints)
  776. +Sound: added support for stereo wavs plays (menu sounds)
  777. +Render: enable custom game icons (game.ico in mod folder)
  778. +Engine: move menu code into new user dll called GameUI.dll (based on original q2e 0.40 menu code)
  779. +FS: implement simple converter liblist.gam to gameinfo.txt
  780. +
  781. +build 1254
  782. +
  783. +SoundLib: ogg loop points (LOOP_START comment)
  784. +Client: recalc fov y for more matched with original HL
  785. +Bshift: fix env_laser entity
  786. +Client: fix fadeout for break model pieces
  787. +Gfx: replace default.bmp font with fixed alpha-channel (thx LokiMb)
  788. +Render: fix invisible beams behind glass
  789. +Render: fix glow-sprites drawing through walls (see also r_cullflares cvar)
  790. +FS: implement filter wadlumps by wadname (e.g. gfx.wad/backtile)
  791. +Render: implement kRenderTransColor
  792. +Engine: completely moving particle code into the client.dll
  793. +Client: implement tracers for sparks, garg streaks and bullets
  794. +
  795. +build 1249
  796. +
  797. +ImageLib: added support for 4-bits and monochrome uncompressed BMPs.
  798. +ImageLib: fix data align for NPOT textures in menu (e.g. slider.bmp).
  799. +StdLib: skip empty symbols in numerical string for atoi and atof.
  800. +Render: implement LoadSprite for custom client sprites (e.g. hud)
  801. +Sound: fixed bug with background music looping
  802. +Fonts: implement Half-Life creditfonts
  803. +Client: move client.dll to valve folder
  804. \ No newline at end of file
  805. diff --git b/cl_dll/hud_servers.cpp a/cl_dll/hud_servers.cpp
  806. index 7a5a147..61f6454 100644
  807. --- b/cl_dll/hud_servers.cpp
  808. +++ a/cl_dll/hud_servers.cpp
  809. @@ -17,7 +17,7 @@
  810. static int context_id;
  811.  
  812. // Default master server address in case we can't read any from woncomm.lst file
  813. -#define VALVE_MASTER_ADDRESS "half-life.east.won.net"
  814. +#define VALVE_MASTER_ADDRESS "ms.xash.su"
  815. #define PORT_MASTER 27010
  816. #define PORT_SERVER 27015
  817.  
  818. @@ -902,7 +902,7 @@ void CHudServers::RequestList( void )
  819. NET_API->InitNetworking();
  820.  
  821. // Kill off left overs if any
  822. - NET_API->CancelAllRequests();
  823. + CancelRequest();
  824.  
  825. // Request Server List from master
  826. NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse );
  827. @@ -935,7 +935,7 @@ void CHudServers::RequestBroadcastList( int clearpending )
  828. if ( clearpending )
  829. {
  830. // Kill off left overs if any
  831. - NET_API->CancelAllRequests();
  832. + CancelRequest();
  833. }
  834.  
  835. adr.type = NA_BROADCAST;
  836. diff --git b/common/bspfile.h a/common/bspfile.h
  837. index 51452cd..12b8d65 100644
  838. --- b/common/bspfile.h
  839. +++ a/common/bspfile.h
  840. @@ -31,7 +31,8 @@ BRUSH MODELS
  841. #define XTBSP_VERSION 31 // extended lightmaps and expanded clipnodes limit
  842.  
  843. #define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH"
  844. -#define EXTRA_VERSION 2 // because version 1 was occupied by old versions of XashXT
  845. +#define EXTRA_VERSION 4 // ver. 1 was occupied by old versions of XashXT, ver. 2 was occupied by old vesrions of P2:savior
  846. + // ver. 3 was occupied by experimental versions of P2:savior change fmt
  847.  
  848. #define DELUXEMAP_VERSION 1
  849. #define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT"
  850. @@ -103,11 +104,19 @@ BRUSH MODELS
  851. #define LUMP_CLIPNODES3 16 // hull2 goes into LUMP_CLIPNODES2, hull3 goes into LUMP_CLIPNODES3
  852. #define HEADER_LUMPS_31 17
  853.  
  854. -#define LUMP_FACES_EXTRADATA 0 // extension of dface_t
  855. -#define LUMP_VERTS_EXTRADATA 1 // extension of dvertex_t
  856. -#define LUMP_CUBEMAPS 2 // cubemap description
  857. -
  858. -#define EXTRA_LUMPS 8 // g-cont. just for future expansions
  859. +#define LUMP_LIGHTVECS 0 // deluxemap data
  860. +#define LUMP_FACEINFO 1 // landscape and lightmap resolution info
  861. +#define LUMP_CUBEMAPS 2 // cubemap description
  862. +#define LUMP_VERTNORMALS 3 // phong shaded vertex normals
  863. +#define LUMP_LEAF_LIGHTING 4 // contain compressed light cubes per empty leafs
  864. +#define LUMP_WORLDLIGHTS 5 // list of all the virtual and real lights (used to relight models in-game)
  865. +#define LUMP_COLLISION 6 // physics engine collision hull dump
  866. +#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp
  867. +#define LUMP_UNUSED0 8 // one lump reserved for me
  868. +#define LUMP_UNUSED1 9 // one lump reserved for me
  869. +#define LUMP_UNUSED2 10 // one lump reserved for me
  870. +#define LUMP_UNUSED3 11 // one lump reserved for me
  871. +#define EXTRA_LUMPS 12 // count of the extra lumps
  872.  
  873. // texture flags
  874. #define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision
  875. @@ -216,9 +225,18 @@ typedef struct
  876. {
  877. float vecs[2][4]; // texmatrix [s/t][xyz offset]
  878. int miptex;
  879. - int flags;
  880. + short flags;
  881. + short faceinfo; // -1 no face info otherwise dfaceinfo_t
  882. } dtexinfo_t;
  883.  
  884. +typedef struct
  885. +{
  886. + char landname[16]; // name of decsription in mapname_land.txt
  887. + unsigned short texture_step; // default is 16, pixels\luxels ratio
  888. + unsigned short max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
  889. + short groupid; // to determine equal landscapes from various groups, -1 - no group
  890. +} dfaceinfo_t;
  891. +
  892. typedef word dmarkface_t; // leaf marksurfaces indexes
  893. typedef int dsurfedge_t; // map surfedges
  894.  
  895. diff --git b/common/com_model.h a/common/com_model.h
  896. index 709f23d..24077e0 100644
  897. --- b/common/com_model.h
  898. +++ a/common/com_model.h
  899. @@ -84,10 +84,20 @@ typedef struct texture_s
  900.  
  901. typedef struct
  902. {
  903. + char landname[16]; // name of decsription in mapname_land.txt
  904. + unsigned short texture_step; // default is 16, pixels\luxels ratio
  905. + unsigned short max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
  906. + short groupid; // to determine equal landscapes from various groups, -1 - no group
  907. +
  908. + int reserved[32]; // just for future expansions or mod-makers
  909. +} mfaceinfo_t;
  910. +
  911. +typedef struct
  912. +{
  913. float vecs[2][4]; // [s/t] unit vectors in world space.
  914. // [i][3] is the s/t offset relative to the origin.
  915. // s or t = dot( 3Dpoint, vecs[i] ) + vecs[i][3]
  916. - float mipadjust; // mipmap limits for very small surfaces
  917. + mfaceinfo_t *faceinfo; // pointer to landscape info and lightmap resolution (may be NULL)
  918. texture_t *texture;
  919. int flags; // sky or slime, no lightmap or 256 subdivision
  920. } mtexinfo_t;
  921. @@ -168,7 +178,7 @@ typedef struct mleaf_s
  922.  
  923. msurface_t **firstmarksurface;
  924. int nummarksurfaces;
  925. - byte *compressed_pas;
  926. + int cluster; // helper to acess to uncompressed visdata
  927. byte ambient_sound_level[NUM_AMBIENTS];
  928.  
  929. } mleaf_t;
  930. diff --git b/common/const.h a/common/const.h
  931. index e80c8a4..192b263 100644
  932. --- b/common/const.h
  933. +++ a/common/const.h
  934. @@ -50,6 +50,7 @@
  935. #define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction.
  936. #define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something)
  937. #define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc.
  938. +
  939. #define FL_CUSTOMENTITY (1<<29) // This is a custom entity
  940. #define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time
  941. #define FL_DORMANT (1<<31) // Entity is dormant, no updates to client
  942. diff --git b/common/cvardef.h a/common/cvardef.h
  943. index f822cc7..614c898 100644
  944. --- b/common/cvardef.h
  945. +++ a/common/cvardef.h
  946. @@ -25,6 +25,8 @@
  947. #define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
  948. #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
  949.  
  950. +#define FCVAR_GLCONFIG (1<<18) // write it into opengl.cfg
  951. +
  952. typedef struct cvar_s
  953. {
  954. char *name;
  955. diff --git b/common/entity_state.h a/common/entity_state.h
  956. index ef5448f..4d04e8f 100644
  957. --- b/common/entity_state.h
  958. +++ a/common/entity_state.h
  959. @@ -176,11 +176,13 @@ typedef struct clientdata_s
  960.  
  961. #include "weaponinfo.h"
  962.  
  963. +#define MAX_LOCAL_WEAPONS 64 // max weapons that can be predicted on the client
  964. +
  965. typedef struct local_state_s
  966. {
  967. entity_state_t playerstate;
  968. clientdata_t client;
  969. - weapon_data_t weapondata[64];
  970. + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
  971. } local_state_t;
  972.  
  973. #endif//ENTITY_STATE_H
  974. \ No newline at end of file
  975. diff --git b/common/features.h a/common/features.h
  976. index efc0bab..73f184e 100644
  977. --- b/common/features.h
  978. +++ a/common/features.h
  979. @@ -25,6 +25,6 @@ GNU General Public License for more details.
  980. #define ENGINE_COMPENSATE_QUAKE_BUG (1<<5) // compensate stupid quake bug (inverse pitch) for mods where this bug is fixed
  981. #define ENGINE_DISABLE_HDTEXTURES (1<<6) // disable support of HD-textures in case custom renderer have separate way to load them
  982. #define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
  983. -#define ENGINE_THREADED_MAIN_LOOP (1<<8) // simulate dedictated thread for main engine loop (prefomance)
  984. +#define ENGINE_FIXED_FRAMERATE (1<<8) // keep constant rate for client and server (but don't clamp renderer calls)
  985.  
  986. #endif//FEATURES_H
  987. \ No newline at end of file
  988. diff --git b/common/render_api.h a/common/render_api.h
  989. index 8f2b364..6bc60f9 100644
  990. --- b/common/render_api.h
  991. +++ a/common/render_api.h
  992. @@ -44,11 +44,11 @@ GNU General Public License for more details.
  993. #define PARM_TEX_TARGET 8
  994. #define PARM_TEX_TEXNUM 9
  995. #define PARM_TEX_FLAGS 10
  996. -#define PARM_TEX_TYPE 11
  997. +#define PARM_TEX_DEPTH 11 // 3D texture depth or 2D array num layers
  998. #define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload
  999. #define PARM_TEX_GLFORMAT 13 // get a texture GL-format
  1000. #define PARM_TEX_ENCODE 14 // custom encoding for DXT image
  1001. -// reserved
  1002. +#define PARM_TEX_MIPCOUNT 15 // count of mipmaps (0 - autogenerated, 1 - disabled of mipmapping)
  1003. #define PARM_WORLD_VERSION 16 // return the version of bsp
  1004. #define PARM_SKY_SPHERE 17 // sky is quake sphere ?
  1005. #define PARM_MAP_HAS_MIRRORS 18 // current map has mirorrs
  1006. @@ -65,6 +65,10 @@ GNU General Public License for more details.
  1007. #define PARM_MAX_IMAGE_UNITS 29
  1008. #define PARM_CLIENT_ACTIVE 30
  1009. #define PARM_REBUILD_GAMMA 31 // if true lightmaps rebuilding for gamma change
  1010. +#define PARM_DEDICATED_SERVER 32
  1011. +#define PARM_SURF_SAMPLESIZE 33 // lightmap resolution per face (second arg interpret as facenumber)
  1012. +#define PARM_GL_CONTEXT_TYPE 34 // opengl or opengles
  1013. +#define PARM_GLES_WRAPPER 35 //
  1014.  
  1015. enum
  1016. {
  1017. @@ -79,25 +83,6 @@ enum
  1018.  
  1019. typedef enum
  1020. {
  1021. - TEX_INVALID = 0, // free slot
  1022. - TEX_SYSTEM, // generated by engine
  1023. - TEX_NOMIP, // hud pics, menu etc
  1024. - TEX_BRUSH, // a map texture
  1025. - TEX_SPRITE, // sprite frames
  1026. - TEX_STUDIO, // studio skins
  1027. - TEX_LIGHTMAP, // lightmap textures
  1028. - TEX_DECAL, // decals
  1029. - TEX_VGUI, // vgui fonts or images
  1030. - TEX_CUBEMAP, // cubemap textures (sky)
  1031. - TEX_DETAIL, // detail textures
  1032. - TEX_REMAP, // local copy of remap texture
  1033. - TEX_SCREENCOPY, // keep screen copy e.g. for mirror
  1034. - TEX_CUSTOM, // user created texture
  1035. - TEX_DEPTHMAP // shadowmap texture
  1036. -} texType_t;
  1037. -
  1038. -typedef enum
  1039. -{
  1040. TF_NEAREST = (1<<0), // disable texfilter
  1041. TF_KEEP_RGBDATA = (1<<1), // some images keep source
  1042. TF_NOFLIP_TGA = (1<<2), // Steam background completely ignore tga attribute 0x20
  1043. @@ -106,7 +91,7 @@ typedef enum
  1044. TF_UNCOMPRESSED = (1<<5), // don't compress texture in video memory
  1045. TF_CUBEMAP = (1<<6), // it's cubemap texture
  1046. TF_DEPTHMAP = (1<<7), // custom texture filter used
  1047. - TF_INTENSITY = (1<<8), // monochrome intensity image
  1048. +// reserved
  1049. TF_LUMINANCE = (1<<9), // force image to grayscale
  1050. TF_SKYSIDE = (1<<10), // this is a part of skybox
  1051. TF_CLAMP = (1<<11), // clamp texcoords to [0..1] range
  1052. @@ -119,16 +104,29 @@ typedef enum
  1053. TF_TEXTURE_1D = (1<<18), // this is GL_TEXTURE_1D
  1054. TF_BORDER = (1<<19), // zero clamp for projected textures
  1055. TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D
  1056. - TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine)
  1057. +// reserved
  1058. TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE
  1059. - TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference)
  1060. -
  1061. - TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage
  1062. - TF_FLOAT = (1<<26), // float textures
  1063. +// reserved
  1064. + TF_TEXTURE_2D_ARRAY = (1<<24), // this is 2D texture array (multi-layers)
  1065. + TF_IMG_UPLOADED = (1<<25), // this is set for first time when called glTexImage, otherwise it will be call glTexSubImage
  1066. + TF_ARB_FLOAT = (1<<26), // float textures
  1067. TF_NOCOMPARE = (1<<27), // disable comparing for depth textures
  1068. - TF_FLOATDATA = (1<<28), // incoming dataType has type GL_FLOAT
  1069. + TF_ARB_16BIT = (1<<28), // keep image as 16-bit (not 24)
  1070. } texFlags_t;
  1071.  
  1072. +typedef enum
  1073. +{
  1074. + CONTEXT_TYPE_GL = 0,
  1075. + CONTEXT_TYPE_GLES_1_X,
  1076. + CONTEXT_TYPE_GLES_2_x
  1077. +} gl_context_type_t;
  1078. +
  1079. +typedef enum
  1080. +{
  1081. + GLES_WRAPPER_NONE = 0, // native GLES
  1082. + GLES_WRAPPER_NANOGL, // used on GLES platforms
  1083. +} gles_wrapper_t;
  1084. +
  1085. typedef struct beam_s BEAM;
  1086. typedef struct particle_s particle_t;
  1087.  
  1088. @@ -184,8 +182,8 @@ typedef struct render_api_s
  1089. const byte* (*GL_TextureData)( unsigned int texnum ); // may be NULL
  1090. int (*GL_LoadTexture)( const char *name, const byte *buf, size_t size, int flags );
  1091. int (*GL_CreateTexture)( const char *name, int width, int height, const void *buffer, int flags );
  1092. - void (*GL_SetTextureType)( unsigned int texnum, unsigned int type );
  1093. - void (*GL_TextureCacheFrame)( unsigned int texnum );
  1094. + int (*GL_LoadTextureArray)( const char **names, int flags );
  1095. + int (*GL_CreateTextureArray)( const char *name, int width, int height, int depth, const void *buffer, int flags );
  1096. void (*GL_FreeTexture)( unsigned int texnum );
  1097.  
  1098. // Decals manipulating (draw & remove)
  1099. @@ -211,11 +209,11 @@ typedef struct render_api_s
  1100. void (*GL_TexGen)( unsigned int coord, unsigned int mode );
  1101. void (*GL_TextureTarget)( unsigned int target ); // change texture unit mode without bind texture
  1102. void (*GL_TexCoordArrayMode)( unsigned int texmode );
  1103. + void* (*GL_GetProcAddress)( const char *name );
  1104. void (*GL_Reserved0)( void ); // for potential interface expansion without broken compatibility
  1105. void (*GL_Reserved1)( void );
  1106. void (*GL_Reserved2)( void );
  1107. - void (*GL_Reserved3)( void );
  1108. -
  1109. +
  1110. // Misc renderer functions
  1111. void (*GL_DrawParticles)( const float *vieworg, const float *fwd, const float *rt, const float *up, unsigned int clipFlags );
  1112. void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder
  1113. @@ -255,8 +253,10 @@ typedef struct render_interface_s
  1114. qboolean (*R_SpeedsMessage)( char *out, size_t size );
  1115. // replace with built-in R_DrawCubemapView for make skyshots or envshots
  1116. qboolean (*R_DrawCubemapView)( const float *origin, const float *angles, int size );
  1117. - // alloc or destroy studiomodel custom data
  1118. + // alloc or destroy model custom data
  1119. void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer );
  1120. + // alloc or destroy entity custom data
  1121. + void (*R_ProcessEntData)( qboolean allocate );
  1122. } render_interface_t;
  1123.  
  1124. #endif//RENDER_API_H
  1125. \ No newline at end of file
  1126. diff --git b/common/wadfile.h a/common/wadfile.h
  1127. index ae85648..a7e0231 100644
  1128. --- b/common/wadfile.h
  1129. +++ a/common/wadfile.h
  1130. @@ -20,7 +20,7 @@
  1131. ========================================================================
  1132. .WAD archive format (WhereAllData - WAD)
  1133.  
  1134. -List of compressed files, that can be identify only by TYPE_*
  1135. +List of compressed files, that can be identify only by TYP_*
  1136.  
  1137. <format>
  1138. header: dwadinfo_t[dwadinfo_t]
  1139. @@ -33,7 +33,7 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
  1140. ========================================================================
  1141. */
  1142.  
  1143. -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W')
  1144. +#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads
  1145.  
  1146. // dlumpinfo_t->attribs
  1147. #define ATTR_NONE 0 // allow to read-write
  1148. diff --git b/engine/cdll_exp.h a/engine/cdll_exp.h
  1149. index bf43654..c059231 100644
  1150. --- b/engine/cdll_exp.h
  1151. +++ a/engine/cdll_exp.h
  1152. @@ -64,6 +64,8 @@ typedef struct cldll_func_s
  1153. // Xash3D extension
  1154. int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback );
  1155. void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
  1156. + void (*pfnUpdateEntityState)( cl_entity_t *ent, entity_state_t *newstate, int noInterp ); // custom interp
  1157. + void (*pfnInterpolateEntity)( cl_entity_t *ent, float lerpFrac );
  1158. } cldll_func_t;
  1159.  
  1160. #endif//CDLL_EXP_H
  1161. \ No newline at end of file
  1162. diff --git b/engine/client/cl_cmds.c a/engine/client/cl_cmds.c
  1163. index af77f70..74b9e06 100644
  1164. --- b/engine/client/cl_cmds.c
  1165. +++ a/engine/client/cl_cmds.c
  1166. @@ -70,7 +70,8 @@ void CL_PlayCDTrack_f( void )
  1167. if( Cmd_Argc() < 2 ) return;
  1168. command = Cmd_Argv( 1 );
  1169.  
  1170. - if( !enabled && Q_stricmp( command, "on" )) return; // CD-player is disabled
  1171. + if( !enabled && Q_stricmp( command, "on" ))
  1172. + return; // CD-player is disabled
  1173.  
  1174. if( !Q_stricmp( command, "play" ))
  1175. {
  1176. @@ -135,15 +136,14 @@ void CL_PlayCDTrack_f( void )
  1177. CL_ScreenshotGetName
  1178. ==================
  1179. */
  1180. -void CL_ScreenshotGetName( int lastnum, char *filename )
  1181. +qboolean CL_ScreenshotGetName( int lastnum, char *filename )
  1182. {
  1183. int a, b, c, d;
  1184.  
  1185. if( lastnum < 0 || lastnum > 9999 )
  1186. {
  1187. - // bound
  1188. - Q_sprintf( filename, "scrshots/%s/!error.bmp", clgame.mapname );
  1189. - return;
  1190. + MsgDev( D_ERROR, "unable to write screenshot\n" );
  1191. + return false;
  1192. }
  1193.  
  1194. a = lastnum / 1000;
  1195. @@ -155,6 +155,8 @@ void CL_ScreenshotGetName( int lastnum, char *filename )
  1196. d = lastnum;
  1197.  
  1198. Q_sprintf( filename, "scrshots/%s_shot%i%i%i%i.bmp", clgame.mapname, a, b, c, d );
  1199. +
  1200. + return true;
  1201. }
  1202.  
  1203. /*
  1204. @@ -216,7 +218,9 @@ void CL_ScreenShot_f( void )
  1205. // scan for a free filename
  1206. for( i = 0; i < 9999; i++ )
  1207. {
  1208. - CL_ScreenshotGetName( i, checkname );
  1209. + if( !CL_ScreenshotGetName( i, checkname ))
  1210. + return; // no namespace
  1211. +
  1212. if( !FS_FileExists( checkname, false ))
  1213. break;
  1214. }
  1215. diff --git b/engine/client/cl_demo.c a/engine/client/cl_demo.c
  1216. index c2f8765..8aeee5c 100644
  1217. --- b/engine/client/cl_demo.c
  1218. +++ a/engine/client/cl_demo.c
  1219. @@ -30,7 +30,7 @@ GNU General Public License for more details.
  1220. #define DEMO_NORMAL 1 // this lump contains playback info of messages, etc., needed during playback.
  1221.  
  1222. #define IDEMOHEADER (('M'<<24)+('E'<<16)+('D'<<8)+'I') // little-endian "IDEM"
  1223. -#define DEMO_PROTOCOL 1
  1224. +#define DEMO_PROTOCOL 2
  1225.  
  1226. const char *demo_cmd[dem_lastcmd+1] =
  1227. {
  1228. @@ -49,6 +49,7 @@ typedef struct
  1229. int dem_protocol; // should be DEMO_PROTOCOL
  1230. int net_protocol; // should be PROTOCOL_VERSION
  1231. char mapname[64]; // name of map
  1232. + char comment[64]; // comment for demo
  1233. char gamedir[64]; // name of game directory (FS_Gamedir())
  1234. int directory_offset; // offset of Entry Directory.
  1235. } demoheader_t;
  1236. @@ -68,6 +69,13 @@ typedef struct
  1237. int numentries; // number of tracks
  1238. } demodirectory_t;
  1239.  
  1240. +// add angles
  1241. +typedef struct
  1242. +{
  1243. + float starttime;
  1244. + vec3_t viewangles;
  1245. +} demoangle_t;
  1246. +
  1247. // private demo states
  1248. struct
  1249. {
  1250. @@ -77,7 +85,13 @@ struct
  1251. int framecount;
  1252. float starttime;
  1253. float realstarttime;
  1254. + float timestamp;
  1255. + float lasttime;
  1256. int entryIndex;
  1257. +
  1258. + // interpolation stuff
  1259. + demoangle_t cmds[ANGLE_BACKUP];
  1260. + int angle_position;
  1261. } demo;
  1262.  
  1263. /*
  1264. @@ -261,11 +275,7 @@ void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg )
  1265. swlen = MSG_GetNumBytesWritten( msg ) - start;
  1266. if( swlen <= 0 ) return;
  1267.  
  1268. - if( !startup )
  1269. - {
  1270. - cls.demotime += host.frametime;
  1271. - demo.framecount++;
  1272. - }
  1273. + if( !startup ) demo.framecount++;
  1274.  
  1275. // demo playback should read this as an incoming message.
  1276. c = (cls.state != ca_active) ? dem_norewind : dem_read;
  1277. @@ -313,9 +323,9 @@ Write demo header
  1278. */
  1279. void CL_WriteDemoHeader( const char *name )
  1280. {
  1281. - fs_offset_t copysize;
  1282. - fs_offset_t savepos;
  1283. - fs_offset_t curpos;
  1284. + long copysize;
  1285. + long savepos;
  1286. + long curpos;
  1287.  
  1288. MsgDev( D_INFO, "recording to %s.\n", name );
  1289. cls.demofile = FS_Open( name, "wb", false );
  1290. @@ -336,6 +346,7 @@ void CL_WriteDemoHeader( const char *name )
  1291. demo.header.dem_protocol = DEMO_PROTOCOL;
  1292. demo.header.net_protocol = PROTOCOL_VERSION;
  1293. Q_strncpy( demo.header.mapname, clgame.mapname, sizeof( demo.header.mapname ));
  1294. + Q_strncpy( demo.header.comment, clgame.maptitle, sizeof( demo.header.comment ));
  1295. Q_strncpy( demo.header.gamedir, FS_Gamedir(), sizeof( demo.header.gamedir ));
  1296.  
  1297. // write header
  1298. @@ -420,9 +431,7 @@ void CL_StopRecord( void )
  1299. FS_Write( cls.demofile, &demo.directory.numentries, sizeof( int ));
  1300.  
  1301. for( i = 0; i < demo.directory.numentries; i++ )
  1302. - {
  1303. FS_Write( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t ));
  1304. - }
  1305.  
  1306. Mem_Free( demo.directory.entries );
  1307. demo.directory.numentries = 0;
  1308. @@ -438,7 +447,7 @@ void CL_StopRecord( void )
  1309. gameui.globals->demoname[0] = '\0';
  1310.  
  1311. Msg( "Completed demo\n" );
  1312. - MsgDev( D_INFO, "Recording time %.2f\n", cls.demotime );
  1313. + MsgDev( D_INFO, "Recording time: %02d:%02d", (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
  1314. cls.demotime = 0.0;
  1315. }
  1316.  
  1317. @@ -449,16 +458,17 @@ CL_DrawDemoRecording
  1318. */
  1319. void CL_DrawDemoRecording( void )
  1320. {
  1321. - char string[64];
  1322. - rgba_t color = { 255, 255, 255, 255 };
  1323. - fs_offset_t pos;
  1324. - int len;
  1325. + char string[64];
  1326. + rgba_t color = { 255, 255, 255, 255 };
  1327. + long pos;
  1328. + int len;
  1329.  
  1330. if(!( host.developer && cls.demorecording ))
  1331. return;
  1332.  
  1333. pos = FS_Tell( cls.demofile );
  1334. - Q_snprintf( string, sizeof( string ), "RECORDING %s: %ik", cls.demoname, pos / 1024 );
  1335. + Q_snprintf( string, sizeof( string ), "^1RECORDING:^7 %s: %s time: %02d:%02d", cls.demoname,
  1336. + Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
  1337.  
  1338. Con_DrawStringLen( string, &len, NULL );
  1339. Con_DrawString(( scr_width->integer - len) >> 1, scr_height->integer >> 2, string, color );
  1340. @@ -511,8 +521,9 @@ void CL_ReadDemoUserCmd( qboolean discard )
  1341.  
  1342. if( !discard )
  1343. {
  1344. - usercmd_t nullcmd;
  1345. - sizebuf_t buf;
  1346. + usercmd_t nullcmd;
  1347. + sizebuf_t buf;
  1348. + demoangle_t *a;
  1349.  
  1350. memset( &nullcmd, 0, sizeof( nullcmd ));
  1351. MSG_Init( &buf, "UserCmd", data, sizeof( data ));
  1352. @@ -530,6 +541,20 @@ void CL_ReadDemoUserCmd( qboolean discard )
  1353.  
  1354. MSG_ReadDeltaUsercmd( &buf, &nullcmd, cl.refdef.cmd );
  1355.  
  1356. + // make sure what interp info contain angles from different frames
  1357. + // or lerping will stop working
  1358. + if( demo.lasttime != demo.timestamp )
  1359. + {
  1360. + // select entry into circular buffer
  1361. + demo.angle_position = (demo.angle_position + 1) & ANGLE_MASK;
  1362. + a = &demo.cmds[demo.angle_position];
  1363. +
  1364. + // record update
  1365. + a->starttime = demo.timestamp;
  1366. + VectorCopy( cl.refdef.cmd->viewangles, a->viewangles );
  1367. + demo.lasttime = demo.timestamp;
  1368. + }
  1369. +
  1370. // NOTE: we need to have the current outgoing sequence correct
  1371. // so we can do prediction correctly during playback
  1372. cls.netchan.outgoing_sequence = outgoing_sequence;
  1373. @@ -674,7 +699,6 @@ reads demo data and write it to client
  1374. */
  1375. qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
  1376. {
  1377. - float f = 0.0f;
  1378. long curpos = 0;
  1379. float fElapsedTime = 0.0f;
  1380. qboolean swallowmessages = true;
  1381. @@ -690,8 +714,7 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
  1382. }
  1383.  
  1384. // HACKHACK: changedemo issues
  1385. - if( !cls.netchan.remote_address.type )
  1386. - cls.netchan.remote_address.type = NA_LOOPBACK;
  1387. + if( !cls.netchan.remote_address.type ) cls.netchan.remote_address.type = NA_LOOPBACK;
  1388.  
  1389. if(( !cl.background && ( cl.refdef.paused || cls.key_dest != key_game )) || cls.key_dest == key_console )
  1390. {
  1391. @@ -706,16 +729,14 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
  1392. if( !cls.demofile ) break;
  1393. curpos = FS_Tell( cls.demofile );
  1394.  
  1395. - CL_ReadDemoCmdHeader( &cmd, &f );
  1396. + CL_ReadDemoCmdHeader( &cmd, &demo.timestamp );
  1397.  
  1398. fElapsedTime = CL_GetDemoPlaybackClock() - demo.starttime;
  1399. - bSkipMessage = (f >= fElapsedTime) ? true : false;
  1400. + bSkipMessage = ((demo.timestamp - cl_serverframetime()) >= fElapsedTime) ? true : false;
  1401. + if( cls.changelevel ) demo.framecount = 1;
  1402.  
  1403. - if( cls.changelevel )
  1404. - demo.framecount = 1;
  1405. -
  1406. - // HACKHACK: changelevel issues
  1407. - if( demo.framecount <= 10 && ( fElapsedTime - f ) > host.frametime )
  1408. + // changelevel issues
  1409. + if( demo.framecount <= 2 && ( fElapsedTime - demo.timestamp ) > host.frametime )
  1410. demo.starttime = CL_GetDemoPlaybackClock();
  1411.  
  1412. // not ready for a message yet, put it back on the file.
  1413. @@ -778,6 +799,79 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
  1414. return CL_ReadRawNetworkData( buffer, length );
  1415. }
  1416.  
  1417. +void CL_DemoFindInterpolatedViewAngles( float t, float *frac, demoangle_t **prev, demoangle_t **next )
  1418. +{
  1419. + int i, i0, i1, imod;
  1420. + float at;
  1421. +
  1422. + imod = demo.angle_position - 1;
  1423. + i0 = (imod + 1) & ANGLE_MASK;
  1424. + i1 = (imod + 0) & ANGLE_MASK;
  1425. +
  1426. + if( demo.cmds[i0].starttime >= t )
  1427. + {
  1428. + for( i = 0; i < ANGLE_BACKUP - 2; i++ )
  1429. + {
  1430. + at = demo.cmds[imod & ANGLE_MASK].starttime;
  1431. + if( at == 0.0f ) break;
  1432. +
  1433. + if( at < t )
  1434. + {
  1435. + i0 = (imod + 1) & ANGLE_MASK;
  1436. + i1 = (imod + 0) & ANGLE_MASK;
  1437. + break;
  1438. + }
  1439. + imod--;
  1440. + }
  1441. + }
  1442. +
  1443. + *next = &demo.cmds[i0];
  1444. + *prev = &demo.cmds[i1];
  1445. +
  1446. + // avoid division by zero (probably this should never happens)
  1447. + if((*prev)->starttime == (*next)->starttime )
  1448. + {
  1449. + *prev = *next;
  1450. + *frac = 0.0f;
  1451. + return;
  1452. + }
  1453. +
  1454. + // time spans the two entries
  1455. + *frac = ( t - (*prev)->starttime ) / ((*next)->starttime - (*prev)->starttime );
  1456. + *frac = bound( 0.0f, *frac, 1.0f );
  1457. +}
  1458. +
  1459. +/*
  1460. +==============
  1461. +CL_DemoInterpolateAngles
  1462. +
  1463. +We can predict or inpolate player movement with standed client code
  1464. +but viewangles interpolate here
  1465. +==============
  1466. +*/
  1467. +void CL_DemoInterpolateAngles( void )
  1468. +{
  1469. + float curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime;
  1470. + demoangle_t *prev = NULL, *next = NULL;
  1471. + float frac = 0.0f;
  1472. +
  1473. + if( curtime > demo.timestamp )
  1474. + curtime = demo.timestamp; // don't run too far
  1475. +
  1476. + CL_DemoFindInterpolatedViewAngles( curtime, &frac, &prev, &next );
  1477. +
  1478. + if( prev && next )
  1479. + {
  1480. + vec4_t q, q1, q2;
  1481. +
  1482. + AngleQuaternion( next->viewangles, q1, false );
  1483. + AngleQuaternion( prev->viewangles, q2, false );
  1484. + QuaternionSlerp( q2, q1, frac, q );
  1485. + QuaternionAngle( q, cl.refdef.cl_viewangles );
  1486. + }
  1487. + else VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
  1488. +}
  1489. +
  1490. /*
  1491. ==============
  1492. CL_StopPlayback
  1493. @@ -804,16 +898,21 @@ void CL_StopPlayback( void )
  1494. cls.demoname[0] = '\0'; // clear demoname too
  1495. gameui.globals->demoname[0] = '\0';
  1496.  
  1497. - S_StopAllSounds();
  1498. - S_StopBackgroundTrack();
  1499. -
  1500. - if( !cls.changedemo )
  1501. + if( cls.changedemo )
  1502. + {
  1503. + S_StopAllSounds();
  1504. + S_StopBackgroundTrack();
  1505. + }
  1506. + else
  1507. {
  1508. // let game known about demo state
  1509. Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );
  1510. cls.state = ca_disconnected;
  1511. - cl.background = 0;
  1512. + cls.connect_time = 0;
  1513. cls.demonum = -1;
  1514. +
  1515. + // and finally clear the state
  1516. + CL_ClearState ();
  1517. }
  1518. }
  1519.  
  1520. @@ -876,7 +975,7 @@ qboolean CL_GetComment( const char *demoname, char *comment )
  1521.  
  1522. // split comment to sections
  1523. Q_strncpy( comment, demohdr.mapname, CS_SIZE );
  1524. - Q_strncpy( comment + CS_SIZE, "<No Title>", CS_SIZE ); // TODO: write titles or somewhat
  1525. + Q_strncpy( comment + CS_SIZE, demohdr.comment, CS_SIZE );
  1526. Q_strncpy( comment + CS_SIZE * 2, va( "%g sec", playtime ), CS_TIME );
  1527.  
  1528. // all done
  1529. @@ -889,8 +988,7 @@ qboolean CL_GetComment( const char *demoname, char *comment )
  1530. ==================
  1531. CL_NextDemo
  1532.  
  1533. -Called when a demo or cinematic finishes
  1534. -If the "nextdemo" cvar is set, that command will be issued
  1535. +Called when a demo finishes
  1536. ==================
  1537. */
  1538. qboolean CL_NextDemo( void )
  1539. @@ -1086,14 +1184,11 @@ void CL_PlayDemo_f( void )
  1540.  
  1541. if( demo.header.net_protocol != PROTOCOL_VERSION || demo.header.dem_protocol != DEMO_PROTOCOL )
  1542. {
  1543. - MsgDev( D_ERROR, "demo protocol outdated\n"
  1544. - "Demo file protocols Network(%i), Demo(%i)\n"
  1545. - "Server protocol is at Network(%i), Demo(%i)\n",
  1546. - demo.header.net_protocol,
  1547. - demo.header.dem_protocol,
  1548. - PROTOCOL_VERSION,
  1549. - DEMO_PROTOCOL
  1550. - );
  1551. + if( demo.header.dem_protocol != DEMO_PROTOCOL )
  1552. + MsgDev( D_ERROR, "playdemo: demo protocol outdated (%i should be %i)\n", demo.header.dem_protocol, DEMO_PROTOCOL );
  1553. +
  1554. + if( demo.header.net_protocol != PROTOCOL_VERSION )
  1555. + MsgDev( D_ERROR, "playdemo: net protocol outdated (%i should be %i)\n", demo.header.net_protocol, PROTOCOL_VERSION );
  1556.  
  1557. FS_Close( cls.demofile );
  1558. cls.demofile = NULL;
  1559. @@ -1129,7 +1224,7 @@ void CL_PlayDemo_f( void )
  1560. CL_Disconnect();
  1561. Host_ShutdownServer();
  1562.  
  1563. - Con_Close();
  1564. + Con_FastClose();
  1565. UI_SetActiveMenu( false );
  1566. }
  1567.  
  1568. @@ -1154,9 +1249,12 @@ void CL_PlayDemo_f( void )
  1569.  
  1570. Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableValue( "net_qport" ));
  1571.  
  1572. + memset( demo.cmds, 0, sizeof( demo.cmds ));
  1573. + demo.angle_position = 1;
  1574. demo.framecount = 0;
  1575. cls.lastoutgoingcommand = -1;
  1576. cls.nextcmdtime = host.realtime;
  1577. + cl.last_command_ack = -1;
  1578.  
  1579. // g-cont. is this need?
  1580. Q_strncpy( cls.servername, demoname, sizeof( cls.servername ));
  1581. diff --git b/engine/client/cl_events.c a/engine/client/cl_events.c
  1582. index 7b023c5..a6c9ee3 100644
  1583. --- b/engine/client/cl_events.c
  1584. +++ a/engine/client/cl_events.c
  1585. @@ -142,7 +142,7 @@ qboolean CL_FireEvent( event_info_t *ei )
  1586.  
  1587. if( !ev )
  1588. {
  1589. - idx = bound( 1, ei->index, MAX_EVENTS );
  1590. + idx = bound( 1, ei->index, ( MAX_EVENTS - 1 ));
  1591. MsgDev( D_ERROR, "CL_FireEvent: %s not precached\n", cl.event_precache[idx] );
  1592. break;
  1593. }
  1594. @@ -173,10 +173,9 @@ called right before draw frame
  1595. */
  1596. void CL_FireEvents( void )
  1597. {
  1598. - int i;
  1599. event_state_t *es;
  1600. event_info_t *ei;
  1601. - qboolean success;
  1602. + int i;
  1603.  
  1604. es = &cl.events;
  1605.  
  1606. @@ -191,7 +190,7 @@ void CL_FireEvents( void )
  1607. if( ei->fire_time && ( ei->fire_time > cl.time ))
  1608. continue;
  1609.  
  1610. - success = CL_FireEvent( ei );
  1611. + CL_FireEvent( ei );
  1612.  
  1613. // zero out the remaining fields
  1614. CL_ResetEvent( ei );
  1615. @@ -395,8 +394,15 @@ void CL_ParseEvent( sizebuf_t *msg )
  1616. args.angles[PITCH] = -state->angles[PITCH] * 3;
  1617. args.angles[YAW] = state->angles[YAW];
  1618. args.angles[ROLL] = 0; // no roll
  1619. +
  1620. + if( VectorIsNull( args.origin ))
  1621. + VectorCopy( state->origin, args.origin );
  1622. + if( VectorIsNull( args.velocity ))
  1623. + VectorCopy( state->velocity, args.velocity );
  1624. }
  1625. - }
  1626. +
  1627. + COM_NormalizeAngles( args.angles );
  1628. + }
  1629. else if( state )
  1630. {
  1631. if( VectorIsNull( args.origin ))
  1632. @@ -443,6 +449,13 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
  1633. MsgDev( D_ERROR, "CL_PlaybackEvent: invalid eventindex %i\n", eventindex );
  1634. return;
  1635. }
  1636. +
  1637. + if( flags & FEV_SERVER )
  1638. + {
  1639. + MsgDev( D_WARN, "CL_PlaybackEvent: event with FEV_SERVER flag!\n" );
  1640. + return;
  1641. + }
  1642. +
  1643. // check event for precached
  1644. if( !CL_EventIndex( cl.event_precache[eventindex] ))
  1645. {
  1646. @@ -459,15 +472,27 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
  1647. args.flags = 0;
  1648. args.entindex = invokerIndex;
  1649.  
  1650. -// TODO: restore checks when predicting will be done
  1651. -// if( !angles || VectorIsNull( angles ))
  1652. + if( !angles || VectorIsNull( angles ))
  1653. VectorCopy( cl.refdef.cl_viewangles, args.angles );
  1654. + else VectorCopy( angles, args.angles );
  1655.  
  1656. -// if( !origin || VectorIsNull( origin ))
  1657. - VectorCopy( cl.frame.client.origin, args.origin );
  1658. + if( !origin || VectorIsNull( origin ))
  1659. + {
  1660. + if( CL_IsPredicted( )) VectorCopy( cl.predicted.origin, args.origin );
  1661. + else VectorCopy( cl.frame.client.origin, args.origin );
  1662. + }
  1663. + else VectorCopy( origin, args.origin );
  1664.  
  1665. - VectorCopy( cl.frame.client.velocity, args.velocity );
  1666. - args.ducking = cl.frame.client.bInDuck;
  1667. + if( CL_IsPredicted( ))
  1668. + {
  1669. + VectorCopy( cl.predicted.velocity, args.velocity );
  1670. + args.ducking = (cl.predicted.usehull == 1);
  1671. + }
  1672. + else
  1673. + {
  1674. + VectorCopy( cl.frame.client.velocity, args.velocity );
  1675. + args.ducking = cl.frame.client.bInDuck;
  1676. + }
  1677.  
  1678. args.fparam1 = fparam1;
  1679. args.fparam2 = fparam2;
  1680. diff --git b/engine/client/cl_frame.c a/engine/client/cl_frame.c
  1681. index f1f1529..de18211 100644
  1682. --- b/engine/client/cl_frame.c
  1683. +++ a/engine/client/cl_frame.c
  1684. @@ -38,7 +38,7 @@ qboolean CL_IsPredicted( void )
  1685. if( !cl_predict->integer || !cl.frame.valid || cl.background )
  1686. return false;
  1687.  
  1688. - if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= ( CL_UPDATE_BACKUP - 1 ))
  1689. + if( !cl.validsequence || ( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
  1690. return false;
  1691.  
  1692. return true;
  1693. @@ -123,7 +123,7 @@ qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, float targettime, positi
  1694.  
  1695. int CL_InterpolateModel( cl_entity_t *e )
  1696. {
  1697. - position_history_t *ph0, *ph1;
  1698. + position_history_t *ph0 = NULL, *ph1 = NULL;
  1699. vec3_t origin, angles, delta;
  1700. float t, t1, t2, frac;
  1701. int i;
  1702. @@ -131,13 +131,20 @@ int CL_InterpolateModel( cl_entity_t *e )
  1703. VectorCopy( e->curstate.origin, e->origin );
  1704. VectorCopy( e->curstate.angles, e->angles );
  1705.  
  1706. - if( e->model == NULL || cl.maxclients <= 1 )
  1707. + if( cl.first_frame ) return 0;
  1708. +
  1709. + if( !e->model || ( e->model->name[0] == '*' && !cl_bmodelinterp->integer ) || RP_LOCALCLIENT( e ) || cl.maxclients <= 1 )
  1710. + return 1;
  1711. +
  1712. + if( cl.predicted.moving && cl.predicted.onground == e->index )
  1713. return 1;
  1714.  
  1715. + if( e->curstate.starttime != 0.0f && e->curstate.impacttime != 0.0f )
  1716. + return 1; // don't interpolate parametric entities
  1717. +
  1718. t = cl.time - cl_interp->value;
  1719.  
  1720. - if( !CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL ))
  1721. - return 0;
  1722. + CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL );
  1723.  
  1724. if( ph0 == NULL || ph1 == NULL )
  1725. return 0;
  1726. @@ -148,7 +155,7 @@ int CL_InterpolateModel( cl_entity_t *e )
  1727. if( t - t2 < 0.0f )
  1728. return 0;
  1729.  
  1730. - if( t2 == 0.0f || VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin ))
  1731. + if( t2 == 0.0f || ( VectorIsNull( ph1->origin ) && !VectorIsNull( ph0->origin )))
  1732. {
  1733. VectorCopy( ph0->origin, e->origin );
  1734. VectorCopy( ph0->angles, e->angles );
  1735. @@ -193,6 +200,36 @@ int CL_InterpolateModel( cl_entity_t *e )
  1736. return 1;
  1737. }
  1738.  
  1739. +void CL_InterpolateMovingEntity( cl_entity_t *ent )
  1740. +{
  1741. + float d, f = 0.0f;
  1742. + int i;
  1743. +
  1744. + // don't do it if the goalstarttime hasn't updated in a while.
  1745. + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
  1746. + // was increased to 1.0 s., which is 2x the max lag we are accounting for.
  1747. + if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
  1748. + f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );
  1749. +
  1750. + f = f - 1.0f;
  1751. +
  1752. + ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f;
  1753. + ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f;
  1754. + ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f;
  1755. +
  1756. + for( i = 0; i < 3; i++ )
  1757. + {
  1758. + float ang1, ang2;
  1759. +
  1760. + ang1 = ent->angles[i];
  1761. + ang2 = ent->latched.prevangles[i];
  1762. + d = ang1 - ang2;
  1763. + if( d > 180.0f ) d -= 360.0f;
  1764. + else if( d < -180.0f ) d += 360.0f;
  1765. + ent->angles[i] += d * f;
  1766. + }
  1767. +}
  1768. +
  1769. void CL_UpdateEntityFields( cl_entity_t *ent )
  1770. {
  1771. // parametric rockets code
  1772. @@ -217,8 +254,12 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
  1773. if( ent->player && RP_LOCALCLIENT( ent )) // stupid Half-Life bug
  1774. ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f;
  1775.  
  1776. - // make me lerp
  1777. - if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
  1778. + // make me lerp (multiplayer only. this code visually breaks XashXT parent system)
  1779. + if( ent->index == cl.predicted.onground && cl.predicted.moving && ( cl.maxclients > 1 ))
  1780. + {
  1781. + CL_InterpolateMovingEntity( ent );
  1782. + }
  1783. + else if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
  1784. {
  1785. float d, f = 0.0f;
  1786. int i;
  1787. @@ -324,7 +365,7 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
  1788. }
  1789. }
  1790.  
  1791. - // move code from StudioSetupTransform here
  1792. + // moved code from StudioSetupTransform here
  1793. if( host.features & ENGINE_COMPUTE_STUDIO_LERP )
  1794. {
  1795. ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
  1796. @@ -513,7 +554,8 @@ void CL_WeaponAnim( int iAnim, int body )
  1797. {
  1798. cl_entity_t *view = &clgame.viewent;
  1799.  
  1800. - view->curstate.modelindex = cl.frame.client.viewmodel;
  1801. + cl.weaponstarttime = 0;
  1802. + cl.weaponsequence = iAnim;
  1803.  
  1804. // anim is changed. update latchedvars
  1805. if( iAnim != view->curstate.sequence )
  1806. @@ -538,6 +580,9 @@ void CL_WeaponAnim( int iAnim, int body )
  1807. view->curstate.frame = 0.0f;
  1808. view->curstate.body = body;
  1809.  
  1810. + view->curstate.rendermode = kRenderNormal;
  1811. + view->curstate.renderamt = 255;
  1812. +
  1813. #if 0 // g-cont. for GlowShell testing
  1814. view->curstate.renderfx = kRenderFxGlowShell;
  1815. view->curstate.rendercolor.r = 255;
  1816. @@ -652,8 +697,16 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
  1817. qboolean newent = (old) ? false : true;
  1818. qboolean result = true;
  1819.  
  1820. - ent = CL_EDICT_NUM( newnum );
  1821. state = &cls.packet_entities[cls.next_client_entities % cls.num_client_entities];
  1822. +
  1823. + if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
  1824. + {
  1825. + if( !unchanged )
  1826. + MSG_ReadDeltaEntity( msg, old, state, newnum, CL_IsPlayerIndex( newnum ), cl.mtime[0] );
  1827. + return;
  1828. + }
  1829. +
  1830. + ent = CL_EDICT_NUM( newnum );
  1831. ent->index = newnum;
  1832.  
  1833. if( newent ) old = &ent->baseline;
  1834. @@ -663,7 +716,21 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
  1835.  
  1836. if( !result )
  1837. {
  1838. - if( newent ) Host_Error( "Cl_DeltaEntity: tried to release new entity\n" );
  1839. + if( newent )
  1840. + {
  1841. + MsgDev( D_WARN, "Cl_DeltaEntity: tried to release new entity\n" );
  1842. +
  1843. + // perform remove, entity was created and removed between packets
  1844. + if( state->number == -1 )
  1845. + {
  1846. + MsgDev( D_NOTE, "Entity %i was removed from server\n", newnum );
  1847. + ent->curstate.messagenum = 0;
  1848. + ent->baseline.number = 0;
  1849. + }
  1850. + else MsgDev( D_NOTE, "Entity %i was removed from delta-message\n", newnum );
  1851. +
  1852. + return;
  1853. + }
  1854.  
  1855. CL_KillDeadBeams( ent ); // release dead beams
  1856. #if 0
  1857. @@ -703,14 +770,21 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
  1858. ent->prevstate = ent->curstate;
  1859. }
  1860.  
  1861. - // NOTE: always check modelindex for new state not current
  1862. - if( Mod_GetType( state->modelindex ) == mod_studio )
  1863. + if( clgame.dllFuncs.pfnUpdateEntityState != NULL )
  1864. {
  1865. - CL_UpdateStudioVars( ent, state, newent );
  1866. + clgame.dllFuncs.pfnUpdateEntityState( ent, state, newent );
  1867. }
  1868. - else if( Mod_GetType( state->modelindex ) == mod_brush )
  1869. + else
  1870. {
  1871. - CL_UpdateBmodelVars( ent, state, newent );
  1872. + // NOTE: always check modelindex for new state not current
  1873. + if( Mod_GetType( state->modelindex ) == mod_studio )
  1874. + {
  1875. + CL_UpdateStudioVars( ent, state, newent );
  1876. + }
  1877. + else if( Mod_GetType( state->modelindex ) == mod_brush )
  1878. + {
  1879. + CL_UpdateBmodelVars( ent, state, newent );
  1880. + }
  1881. }
  1882.  
  1883. // set right current state
  1884. @@ -722,6 +796,8 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
  1885. /*
  1886. =================
  1887. CL_FlushEntityPacket
  1888. +
  1889. +Read and ignore whole entity packet.
  1890. =================
  1891. */
  1892. void CL_FlushEntityPacket( sizebuf_t *msg )
  1893. @@ -729,7 +805,6 @@ void CL_FlushEntityPacket( sizebuf_t *msg )
  1894. int newnum;
  1895. entity_state_t from, to;
  1896.  
  1897. - MsgDev( D_INFO, "FlushEntityPacket()\n" );
  1898. memset( &from, 0, sizeof( from ));
  1899.  
  1900. cl.frames[cl.parsecountmod].valid = false;
  1901. @@ -756,11 +831,13 @@ An svc_packetentities has just been parsed, deal with the
  1902. rest of the data stream.
  1903. ==================
  1904. */
  1905. -void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1906. +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1907. {
  1908. frame_t *newframe, *oldframe;
  1909. int oldindex, newnum, oldnum;
  1910. + int playerbytes = 0;
  1911. int oldpacket;
  1912. + int bufStart;
  1913. cl_entity_t *player;
  1914. entity_state_t *oldent;
  1915. int i, count;
  1916. @@ -778,6 +855,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1917. newframe->first_entity = cls.next_client_entities;
  1918. newframe->num_entities = 0;
  1919. newframe->valid = true; // assume valid
  1920. + memset( &newframe->graphdata, 0, sizeof( netbandwidthgraph_t ));
  1921.  
  1922. if( delta )
  1923. {
  1924. @@ -788,25 +866,29 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1925.  
  1926. if( subtracted == 0 )
  1927. {
  1928. - Host_Error( "CL_DeltaPacketEntities: update too old, connection dropped.\n" );
  1929. - return;
  1930. + MsgDev( D_NOTE, "CL_DeltaPacketEntities: update too old (flush)\n" );
  1931. + Con_NPrintf( 2, "^3Warning:^1 update too old\n^7\n" );
  1932. + CL_FlushEntityPacket( msg );
  1933. + return playerbytes;
  1934. }
  1935.  
  1936. if( subtracted >= CL_UPDATE_MASK )
  1937. {
  1938. // we can't use this, it is too old
  1939. + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old: overflow (flush)\n");
  1940. Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
  1941. CL_FlushEntityPacket( msg );
  1942. - return;
  1943. + return playerbytes;
  1944. }
  1945.  
  1946. oldframe = &cl.frames[oldpacket & CL_UPDATE_MASK];
  1947.  
  1948. if(( cls.next_client_entities - oldframe->first_entity ) > ( cls.num_client_entities - 128 ))
  1949. {
  1950. + MsgDev( D_NOTE, "CL_ParsePacketEntities: delta frame is too old (flush)\n");
  1951. Con_NPrintf( 2, "^3Warning:^1 delta frame is too old^7\n" );
  1952. CL_FlushEntityPacket( msg );
  1953. - return;
  1954. + return playerbytes;
  1955. }
  1956. }
  1957. else
  1958. @@ -814,7 +896,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1959. // this is a full update that we can start delta compressing from now
  1960. oldframe = NULL;
  1961. oldpacket = -1; // delta too old or is initial message
  1962. - cl.force_send_usercmd = true; // send reply
  1963. + cl.send_reply = true; // send reply
  1964. cls.demowaiting = false; // we can start recording now
  1965. }
  1966.  
  1967. @@ -851,8 +933,11 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1968.  
  1969. while( oldnum < newnum )
  1970. {
  1971. + bufStart = MSG_GetNumBytesRead( msg );
  1972. // one or more entities from the old packet are unchanged
  1973. CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
  1974. + if( CL_IsPlayerIndex( oldnum ) )
  1975. + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
  1976.  
  1977. oldindex++;
  1978.  
  1979. @@ -870,7 +955,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1980. if( oldnum == newnum )
  1981. {
  1982. // delta from previous state
  1983. + bufStart = MSG_GetNumBytesRead( msg );
  1984. CL_DeltaEntity( msg, newframe, newnum, oldent, false );
  1985. + if( CL_IsPlayerIndex( newnum ) )
  1986. + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
  1987. oldindex++;
  1988.  
  1989. if( oldindex >= oldframe->num_entities )
  1990. @@ -888,7 +976,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  1991. if( oldnum > newnum )
  1992. {
  1993. // delta from baseline ?
  1994. + bufStart = MSG_GetNumBytesRead( msg );
  1995. CL_DeltaEntity( msg, newframe, newnum, NULL, false );
  1996. + if( CL_IsPlayerIndex( newnum ) )
  1997. + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
  1998. continue;
  1999. }
  2000. }
  2001. @@ -897,7 +988,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  2002. while( oldnum != MAX_ENTNUMBER )
  2003. {
  2004. // one or more entities from the old packet are unchanged
  2005. + bufStart = MSG_GetNumBytesRead( msg );
  2006. CL_DeltaEntity( msg, newframe, oldnum, oldent, true );
  2007. + if( CL_IsPlayerIndex( oldnum ) )
  2008. + playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
  2009. oldindex++;
  2010.  
  2011. if( oldindex >= oldframe->num_entities )
  2012. @@ -916,7 +1010,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  2013.  
  2014. cl.frame = *newframe;
  2015.  
  2016. - if( !cl.frame.valid ) return;
  2017. + if( !cl.frame.valid ) return playerbytes; // frame is not valid but message was parsed
  2018.  
  2019. player = CL_GetLocalPlayer();
  2020.  
  2021. @@ -950,11 +1044,15 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
  2022.  
  2023. if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped )
  2024. SCR_EndLoadingPlaque(); // get rid of loading plaque
  2025. + cl.first_frame = true; // first server frame received
  2026. }
  2027. else
  2028. {
  2029. CL_CheckPredictionError();
  2030. + cl.first_frame = false;
  2031. }
  2032. +
  2033. + return playerbytes;
  2034. }
  2035.  
  2036. /*
  2037. @@ -972,23 +1070,34 @@ CL_SetIdealPitch
  2038. void CL_SetIdealPitch( void )
  2039. {
  2040. float angleval, sinval, cosval;
  2041. - vec3_t top, bottom;
  2042. - float z[MAX_FORWARD];
  2043. + float z[MAX_FORWARD], view_z;
  2044. + vec3_t top, bottom, origin;
  2045. int i, j;
  2046. int step, dir, steps;
  2047. pmtrace_t tr;
  2048.  
  2049. if( !( cl.frame.client.flags & FL_ONGROUND ))
  2050. return;
  2051. -
  2052. +
  2053. + if( CL_IsPredicted( ))
  2054. + {
  2055. + VectorCopy( cl.predicted.origin, origin );
  2056. + view_z = cl.predicted.viewofs[2];
  2057. + }
  2058. + else
  2059. + {
  2060. + VectorCopy( cl.frame.client.origin, origin );
  2061. + view_z = cl.frame.client.view_ofs[2];
  2062. + }
  2063. +
  2064. angleval = cl.frame.playerstate[cl.playernum].angles[YAW] * M_PI2 / 360.0f;
  2065. SinCos( angleval, &sinval, &cosval );
  2066.  
  2067. for( i = 0; i < MAX_FORWARD; i++ )
  2068. {
  2069. - top[0] = cl.frame.client.origin[0] + cosval * (i + 3.0f) * 12.0f;
  2070. - top[1] = cl.frame.client.origin[1] + sinval * (i + 3.0f) * 12.0f;
  2071. - top[2] = cl.frame.client.origin[2] + cl.frame.client.view_ofs[2];
  2072. + top[0] = origin[0] + cosval * (i + 3.0f) * 12.0f;
  2073. + top[1] = origin[1] + sinval * (i + 3.0f) * 12.0f;
  2074. + top[2] = origin[2] + view_z;
  2075.  
  2076. bottom[0] = top[0];
  2077. bottom[1] = top[1];
  2078. @@ -1052,7 +1161,9 @@ void CL_AddPacketEntities( frame_t *frame )
  2079. if( !ent || ent == clgame.entities )
  2080. continue;
  2081.  
  2082. - CL_UpdateEntityFields( ent );
  2083. + if( clgame.dllFuncs.pfnInterpolateEntity != NULL )
  2084. + clgame.dllFuncs.pfnInterpolateEntity( ent, cl.lerpFrac );
  2085. + else CL_UpdateEntityFields( ent );
  2086.  
  2087. if( ent->player ) entityType = ET_PLAYER;
  2088. else if( ent->curstate.entityType == ENTITY_BEAM )
  2089. diff --git b/engine/client/cl_game.c a/engine/client/cl_game.c
  2090. index 613cbc7..2d6b729 100644
  2091. --- b/engine/client/cl_game.c
  2092. +++ a/engine/client/cl_game.c
  2093. @@ -30,6 +30,7 @@ GNU General Public License for more details.
  2094. #include "vgui_draw.h"
  2095. #include "sound.h" // SND_STOP_LOOPING
  2096.  
  2097. +#define MAX_LINELENGTH 80
  2098. #define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels)
  2099. #define TEXT_MSGNAME "TextMessage%i"
  2100.  
  2101. @@ -88,6 +89,8 @@ static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher
  2102. { "HUD_GetRenderInterface", (void **)&clgame.dllFuncs.pfnGetRenderInterface }, // Xash3D ext
  2103. { "HUD_GetPlayerTeam", (void **)&clgame.dllFuncs.pfnGetPlayerTeam },
  2104. { "HUD_ClipMoveToEntity", (void **)&clgame.dllFuncs.pfnClipMoveToEntity }, // Xash3D ext
  2105. +{ "HUD_UpdateEntityState", (void **)&clgame.dllFuncs.pfnUpdateEntityState },
  2106. +{ "HUD_InterpolateEntity", (void **)&clgame.dllFuncs.pfnInterpolateEntity },
  2107. { NULL, NULL }
  2108. };
  2109.  
  2110. @@ -406,30 +409,6 @@ static void SPR_AdjustSize( float *x, float *y, float *w, float *h )
  2111.  
  2112. /*
  2113. ====================
  2114. -TextAdjustSize
  2115. -
  2116. -draw hudsprite routine
  2117. -====================
  2118. -*/
  2119. -void TextAdjustSize( int *x, int *y, int *w, int *h )
  2120. -{
  2121. - float xscale, yscale;
  2122. -
  2123. - if( !clgame.ds.adjust_size ) return;
  2124. - if( !x && !y && !w && !h ) return;
  2125. -
  2126. - // scale for screen sizes
  2127. - xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
  2128. - yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
  2129. -
  2130. - if( x ) *x *= xscale;
  2131. - if( y ) *y *= yscale;
  2132. - if( w ) *w *= xscale;
  2133. - if( h ) *h *= yscale;
  2134. -}
  2135. -
  2136. -/*
  2137. -====================
  2138. PictAdjustSize
  2139.  
  2140. draw hudsprite routine
  2141. @@ -573,7 +552,7 @@ void CL_DrawCenterPrint( void )
  2142. char *pText;
  2143. int i, j, x, y;
  2144. int width, lineLength;
  2145. - byte *colorDefault, line[80];
  2146. + byte *colorDefault, line[MAX_LINELENGTH];
  2147. int charWidth, charHeight;
  2148.  
  2149. if( !clgame.centerPrint.time )
  2150. @@ -596,7 +575,7 @@ void CL_DrawCenterPrint( void )
  2151. lineLength = 0;
  2152. width = 0;
  2153.  
  2154. - while( *pText && *pText != '\n' )
  2155. + while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH )
  2156. {
  2157. byte c = *pText;
  2158. line[lineLength] = c;
  2159. @@ -606,6 +585,9 @@ void CL_DrawCenterPrint( void )
  2160. pText++;
  2161. }
  2162.  
  2163. + if( lineLength == MAX_LINELENGTH )
  2164. + lineLength--;
  2165. +
  2166. pText++; // Skip LineFeed
  2167. line[lineLength] = 0;
  2168.  
  2169. @@ -1084,8 +1066,10 @@ void CL_InitEdicts( void )
  2170. {
  2171. ASSERT( clgame.entities == NULL );
  2172.  
  2173. + if( !clgame.mempool ) return; // Host_Error without client
  2174. +
  2175. CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
  2176. - cls.num_client_entities = CL_UPDATE_BACKUP * 64;
  2177. + cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
  2178. cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
  2179. clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
  2180. clgame.static_entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
  2181. @@ -1097,10 +1081,22 @@ void CL_InitEdicts( void )
  2182. clgame.maxRemapInfos = clgame.maxEntities + 1;
  2183. clgame.remap_info = (remap_info_t **)Mem_Alloc( clgame.mempool, sizeof( remap_info_t* ) * clgame.maxRemapInfos );
  2184. }
  2185. +
  2186. + if( clgame.drawFuncs.R_ProcessEntData != NULL )
  2187. + {
  2188. + // let the client.dll free custom data
  2189. + clgame.drawFuncs.R_ProcessEntData( true );
  2190. + }
  2191. }
  2192.  
  2193. void CL_FreeEdicts( void )
  2194. {
  2195. + if( clgame.drawFuncs.R_ProcessEntData != NULL )
  2196. + {
  2197. + // let the client.dll free custom data
  2198. + clgame.drawFuncs.R_ProcessEntData( false );
  2199. + }
  2200. +
  2201. if( clgame.entities )
  2202. Mem_Free( clgame.entities );
  2203. clgame.entities = NULL;
  2204. @@ -1208,7 +1204,8 @@ HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags )
  2205. // load new model
  2206. if( CL_LoadHudSprite( name, &clgame.sprites[i], false, texFlags ))
  2207. {
  2208. - clgame.sprites[i].needload = clgame.load_sequence;
  2209. + if( i < ( MAX_IMAGES - 1 ))
  2210. + clgame.sprites[i].needload = clgame.load_sequence;
  2211. return i;
  2212. }
  2213. return 0;
  2214. @@ -1414,11 +1411,11 @@ static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount )
  2215.  
  2216. /*
  2217. =============
  2218. -pfnFillRGBA
  2219. +CL_FillRGBA
  2220.  
  2221. =============
  2222. */
  2223. -static void pfnFillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
  2224. +void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
  2225. {
  2226. r = bound( 0, r, 255 );
  2227. g = bound( 0, g, 255 );
  2228. @@ -2098,7 +2095,7 @@ static void pfnHookEvent( const char *filename, pfnEventHook pfn )
  2229.  
  2230. if( !Q_stricmp( name, ev->name ) && ev->func != NULL )
  2231. {
  2232. - MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n" );
  2233. + MsgDev( D_WARN, "CL_HookEvent: %s already hooked!\n", name );
  2234. return;
  2235. }
  2236. }
  2237. @@ -2199,6 +2196,8 @@ pfnLocalPlayerDucking
  2238. */
  2239. int pfnLocalPlayerDucking( void )
  2240. {
  2241. + if( CL_IsPredicted( ))
  2242. + return (cl.predicted.usehull == 1);
  2243. return cl.frame.client.bInDuck;
  2244. }
  2245.  
  2246. @@ -2214,7 +2213,7 @@ void pfnLocalPlayerViewheight( float *view_ofs )
  2247. if( !view_ofs ) return;
  2248.  
  2249. if( CL_IsPredicted( ))
  2250. - VectorCopy( cl.predicted_viewofs, view_ofs );
  2251. + VectorCopy( cl.predicted.viewofs, view_ofs );
  2252. else VectorCopy( cl.frame.client.view_ofs, view_ofs );
  2253. }
  2254.  
  2255. @@ -2267,101 +2266,12 @@ physent_t *pfnGetPhysent( int idx )
  2256.  
  2257. /*
  2258. =============
  2259. -pfnSetUpPlayerPrediction
  2260. -
  2261. -FIXME: finalize
  2262. -=============
  2263. -*/
  2264. -void pfnSetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
  2265. -{
  2266. -#if 0
  2267. - entity_state_t *playerstate = cl.frames[cl.parsecountmod].playerstate;
  2268. - predicted_player_t *player = cls.predicted_players;
  2269. - cl_entity_t *clent;
  2270. - int j, v12;
  2271. -
  2272. - for( j = 0; j < MAX_CLIENTS; j++, player++, playerstate++ )
  2273. - {
  2274. - player->active = false;
  2275. -
  2276. - if( playerstate->messagenum != cl.parsecount )
  2277. - continue; // not present this frame
  2278. -
  2279. - if( !playerstate->modelindex )
  2280. - continue;
  2281. -
  2282. - // special for EF_NODRAW and local client?
  2283. - if(( playerstate->effects & EF_NODRAW ) && !bIncludeLocalClient )
  2284. - {
  2285. - // don't include local player?
  2286. - if( cl.playernum != j )
  2287. - {
  2288. - player->active = true;
  2289. - player->movetype = playerstate->movetype;
  2290. - player->solid = playerstate->solid;
  2291. - player->usehull = playerstate->usehull;
  2292. -
  2293. - clent = CL_EDICT_NUM( j + 1 );
  2294. -// CL_ComputePlayerOrigin( v9 );
  2295. - VectorCopy( clent->origin, player->origin );
  2296. - VectorCopy( clent->angles, player->angles );
  2297. - }
  2298. - else continue;
  2299. - }
  2300. - else
  2301. - {
  2302. - if( cl.playernum == j )
  2303. - continue;
  2304. -
  2305. - player->active = true;
  2306. - player->movetype = playerstate->movetype;
  2307. - player->solid = playerstate->solid;
  2308. - player->usehull = playerstate->usehull;
  2309. -
  2310. - v12 = 17080 * cl.parsecountmod + 340 * j;
  2311. - player->origin[0] = cl.frames[0].playerstate[0].origin[0] + v12;
  2312. - player->origin[1] = cl.frames[0].playerstate[0].origin[1] + v12;
  2313. - player->origin[2] = cl.frames[0].playerstate[0].origin[2] + v12;
  2314. -
  2315. - player->angles[0] = cl.frames[0].playerstate[0].angles[0] + v12;
  2316. - player->angles[1] = cl.frames[0].playerstate[0].angles[1] + v12;
  2317. - player->angles[2] = cl.frames[0].playerstate[0].angles[2] + v12;
  2318. - }
  2319. - }
  2320. -#endif
  2321. -}
  2322. -
  2323. -/*
  2324. -=============
  2325. -pfnPushPMStates
  2326. -
  2327. -=============
  2328. -*/
  2329. -void pfnPushPMStates( void )
  2330. -{
  2331. - clgame.oldcount = clgame.pmove->numphysent;
  2332. -}
  2333. -
  2334. -/*
  2335. -=============
  2336. -pfnPopPMStates
  2337. -
  2338. -=============
  2339. -*/
  2340. -void pfnPopPMStates( void )
  2341. -{
  2342. - clgame.pmove->numphysent = clgame.oldcount;
  2343. -}
  2344. -
  2345. -/*
  2346. -=============
  2347. pfnSetTraceHull
  2348.  
  2349. =============
  2350. */
  2351. void CL_SetTraceHull( int hull )
  2352. {
  2353. - clgame.old_trace_hull = clgame.pmove->usehull;
  2354. clgame.pmove->usehull = bound( 0, hull, 3 );
  2355.  
  2356. }
  2357. @@ -2376,7 +2286,6 @@ void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pm
  2358. {
  2359. if( !tr ) return;
  2360. *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, ignore_pe, NULL );
  2361. - clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull
  2362. }
  2363.  
  2364. /*
  2365. @@ -2389,7 +2298,6 @@ void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnor
  2366. {
  2367. if( !tr ) return;
  2368. *tr = PM_PlayerTraceExt( clgame.pmove, start, end, traceFlags, clgame.pmove->numphysent, clgame.pmove->physents, -1, pfnIgnore );
  2369. - clgame.pmove->usehull = clgame.old_trace_hull; // restore old trace hull
  2370. }
  2371.  
  2372. /*
  2373. @@ -2594,7 +2502,7 @@ const char *PlayerInfo_ValueForKey( int playerNum, const char *key )
  2374. if(( playerNum > cl.maxclients ) || ( playerNum < 1 ))
  2375. return NULL;
  2376.  
  2377. - if(( cl.players[playerNum-1].name == NULL ) || (*(cl.players[playerNum-1].name) == 0 ))
  2378. + if( !cl.players[playerNum-1].name[0] )
  2379. return NULL;
  2380.  
  2381. return Info_ValueForKey( cl.players[playerNum-1].userinfo, key );
  2382. @@ -2788,6 +2696,24 @@ void pfnSetLightmapScale( float scale )
  2383.  
  2384. /*
  2385. =============
  2386. +pfnParseFile
  2387. +
  2388. +handle colon separately
  2389. +=============
  2390. +*/
  2391. +char *pfnParseFile( char *data, char *token )
  2392. +{
  2393. + char *out;
  2394. +
  2395. + host.com_handlecolon = true;
  2396. + out = COM_ParseFile( data, token );
  2397. + host.com_handlecolon = false;
  2398. +
  2399. + return out;
  2400. +}
  2401. +
  2402. +/*
  2403. +=============
  2404. pfnSPR_DrawGeneric
  2405.  
  2406. =============
  2407. @@ -2808,7 +2734,11 @@ TODO: implement
  2408. */
  2409. int pfnDrawString( int x, int y, const char *str, int r, int g, int b )
  2410. {
  2411. - return 0;
  2412. + // draw the string until we hit the null character or a newline character
  2413. + for( ; *str != 0 && *str != '\n'; str++ )
  2414. + x += pfnDrawCharacter( x, y, (byte)*str, r, g, b );
  2415. +
  2416. + return x;
  2417. }
  2418.  
  2419. /*
  2420. @@ -2820,7 +2750,14 @@ TODO: implement
  2421. */
  2422. int pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b )
  2423. {
  2424. - return 0;
  2425. + char *szIt;
  2426. +
  2427. + // find the end of the string
  2428. + for( szIt = (char *)str; *szIt != 0; szIt++ )
  2429. + x -= clgame.scrInfo.charWidths[(byte)*szIt];
  2430. + pfnDrawString( x, y, str, r, g, b );
  2431. +
  2432. + return x;
  2433. }
  2434.  
  2435. /*
  2436. @@ -2920,11 +2857,11 @@ void pfnPlaySoundByNameAtPitch( char *filename, float volume, int pitch )
  2437.  
  2438. /*
  2439. =============
  2440. -pfnFillRGBABlend
  2441. +CL_FillRGBABlend
  2442.  
  2443. =============
  2444. */
  2445. -void pfnFillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a )
  2446. +void CL_FillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a )
  2447. {
  2448. r = bound( 0, r, 255 );
  2449. g = bound( 0, g, 255 );
  2450. @@ -2951,7 +2888,7 @@ pfnGetAppID
  2451. */
  2452. int pfnGetAppID( void )
  2453. {
  2454. - return 220; // standard Valve value
  2455. + return 130; // borrowed from SDLash3D
  2456. }
  2457.  
  2458. /*
  2459. @@ -3137,7 +3074,7 @@ void TriBrightness( float brightness )
  2460. rgba[1] = clgame.ds.triColor[1] * brightness;
  2461. rgba[2] = clgame.ds.triColor[2] * brightness;
  2462.  
  2463. - pglColor3ub( rgba[0], rgba[1], rgba[2] );
  2464. + pglColor4ub( rgba[0], rgba[1], rgba[2], clgame.ds.triColor[3] );
  2465. }
  2466.  
  2467. /*
  2468. @@ -3185,7 +3122,7 @@ int TriSpriteTexture( model_t *pSpriteModel, int frame )
  2469. if( psprite->texFormat == SPR_ALPHTEST )
  2470. {
  2471. pglEnable( GL_ALPHA_TEST );
  2472. - pglAlphaFunc( GL_GREATER, 0.0f );
  2473. + pglAlphaFunc( GL_GEQUAL, 0.5f );
  2474. }
  2475.  
  2476. GL_Bind( GL_TEXTURE0, gl_texturenum );
  2477. @@ -3322,7 +3259,8 @@ TriForParams
  2478. */
  2479. void TriFogParams( float flDensity, int iFogSkybox )
  2480. {
  2481. - // TODO: implement
  2482. + RI.fogDensity = flDensity;
  2483. + RI.fogCustom = iFogSkybox;
  2484. }
  2485.  
  2486. /*
  2487. @@ -3405,7 +3343,7 @@ void NetAPI_Status( net_status_t *status )
  2488. status->connected = NET_IsLocalAddress( cls.netchan.remote_address ) ? false : true;
  2489. status->connection_time = host.realtime - cls.netchan.connect_time;
  2490. status->remote_address = cls.netchan.remote_address;
  2491. - status->packet_loss = cls.packet_loss / 100; // percent
  2492. + status->packet_loss = cls.packet_loss / 100.0; // percent
  2493. status->latency = cl.frame.latency;
  2494. status->local_address = net_local;
  2495. status->rate = cls.netchan.rate;
  2496. @@ -3433,15 +3371,14 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
  2497. for( i = 0; i < MAX_REQUESTS; i++ )
  2498. {
  2499. nr = &clgame.net_requests[i];
  2500. - if( !nr->pfnFunc || nr->timeout < host.realtime )
  2501. - break;
  2502. + if( !nr->pfnFunc ) break;
  2503. }
  2504.  
  2505. if( i == MAX_REQUESTS )
  2506. {
  2507. double max_timeout = 0;
  2508.  
  2509. - // no free requests? use older
  2510. + // no free requests? use oldest
  2511. for( i = 0, nr = NULL; i < MAX_REQUESTS; i++ )
  2512. {
  2513. if(( host.realtime - clgame.net_requests[i].timesend ) > max_timeout )
  2514. @@ -3468,11 +3405,20 @@ void NetAPI_SendRequest( int context, int request, int flags, double timeout, ne
  2515.  
  2516. if( request == NETAPI_REQUEST_SERVERLIST )
  2517. {
  2518. - // UNDONE: build request for master-server
  2519. + char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
  2520. +
  2521. + // make sure what port is specified
  2522. + if( !nr->resp.remote_address.port ) nr->resp.remote_address.port = MSG_BigShort( PORT_MASTER );
  2523. +
  2524. + // grab the list from the master server
  2525. + Q_strcpy( &fullquery[22], GI->gamedir );
  2526. + NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 23, fullquery, nr->resp.remote_address );
  2527. + clgame.request_type = NET_REQUEST_CLIENT;
  2528. + clgame.master_request = nr; // holds the master request unitl the master acking
  2529. }
  2530. else
  2531. {
  2532. - // send request over the net
  2533. + // local servers request
  2534. Q_snprintf( req, sizeof( req ), "netinfo %i %i %i", PROTOCOL_VERSION, context, request );
  2535. Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, req );
  2536. }
  2537. @@ -3486,15 +3432,31 @@ NetAPI_CancelRequest
  2538. */
  2539. void NetAPI_CancelRequest( int context )
  2540. {
  2541. - int i;
  2542. + net_request_t *nr;
  2543. + int i;
  2544.  
  2545. // find a specified request
  2546. for( i = 0; i < MAX_REQUESTS; i++ )
  2547. {
  2548. + nr = &clgame.net_requests[i];
  2549. +
  2550. if( clgame.net_requests[i].resp.context == context )
  2551. {
  2552. - MsgDev( D_NOTE, "Request with context %i cancelled\n", context );
  2553. + if( nr->pfnFunc )
  2554. + {
  2555. + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
  2556. + nr->resp.ping = host.realtime - nr->timesend;
  2557. + nr->pfnFunc( &nr->resp );
  2558. + }
  2559. +
  2560. memset( &clgame.net_requests[i], 0, sizeof( net_request_t ));
  2561. +
  2562. + if( clgame.net_requests[i].resp.type == NETAPI_REQUEST_SERVERLIST && &clgame.net_requests[i] == clgame.master_request )
  2563. + {
  2564. + if( clgame.request_type == NET_REQUEST_CLIENT )
  2565. + clgame.request_type = NET_REQUEST_CANCEL;
  2566. + clgame.master_request = NULL;
  2567. + }
  2568. break;
  2569. }
  2570. }
  2571. @@ -3508,7 +3470,22 @@ NetAPI_CancelAllRequests
  2572. */
  2573. void NetAPI_CancelAllRequests( void )
  2574. {
  2575. + net_request_t *nr;
  2576. + int i;
  2577. +
  2578. + // tell the user about cancel
  2579. + for( i = 0; i < MAX_REQUESTS; i++ )
  2580. + {
  2581. + nr = &clgame.net_requests[i];
  2582. + if( !nr->pfnFunc ) continue; // not used
  2583. + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
  2584. + nr->resp.ping = host.realtime - nr->timesend;
  2585. + nr->pfnFunc( &nr->resp );
  2586. + }
  2587. +
  2588. memset( clgame.net_requests, 0, sizeof( clgame.net_requests ));
  2589. + clgame.request_type = NET_REQUEST_CANCEL;
  2590. + clgame.master_request = NULL;
  2591. }
  2592.  
  2593. /*
  2594. @@ -3758,9 +3735,9 @@ static event_api_t gEventApi =
  2595. pfnLocalPlayerBounds,
  2596. pfnIndexFromTrace,
  2597. pfnGetPhysent,
  2598. - pfnSetUpPlayerPrediction,
  2599. - pfnPushPMStates,
  2600. - pfnPopPMStates,
  2601. + CL_SetUpPlayerPrediction,
  2602. + CL_PushPMStates,
  2603. + CL_PopPMStates,
  2604. CL_SetSolidPlayers,
  2605. CL_SetTraceHull,
  2606. CL_PlayerTrace,
  2607. @@ -3823,13 +3800,13 @@ static cl_enginefunc_t gEngfuncs =
  2608. SPR_EnableScissor,
  2609. SPR_DisableScissor,
  2610. pfnSPR_GetList,
  2611. - pfnFillRGBA,
  2612. + CL_FillRGBA,
  2613. pfnGetScreenInfo,
  2614. pfnSetCrosshair,
  2615. - pfnCvar_RegisterVariable,
  2616. + pfnCvar_RegisterClientVariable,
  2617. Cvar_VariableValue,
  2618. Cvar_VariableString,
  2619. - pfnAddClientCommand,
  2620. + Cmd_AddClientCommand,
  2621. pfnHookUserMsg,
  2622. pfnServerCmd,
  2623. pfnClientCmd,
  2624. @@ -3892,7 +3869,7 @@ static cl_enginefunc_t gEngfuncs =
  2625. VGui_GetPanel,
  2626. VGui_ViewportPaintBackground,
  2627. COM_LoadFile,
  2628. - COM_ParseFile,
  2629. + pfnParseFile,
  2630. COM_FreeFile,
  2631. &gTriApi,
  2632. &gEfxApi,
  2633. @@ -3942,7 +3919,7 @@ static cl_enginefunc_t gEngfuncs =
  2634. pfnConstructTutorMessageDecayBuffer,
  2635. pfnResetTutorMessageDecayData,
  2636. pfnPlaySoundByNameAtPitch,
  2637. - pfnFillRGBABlend,
  2638. + CL_FillRGBABlend,
  2639. pfnGetAppID,
  2640. Cmd_AliasGetList,
  2641. pfnVguiWrap2_GetMouseDelta,
  2642. @@ -3972,7 +3949,7 @@ void CL_UnloadProgs( void )
  2643. Mem_FreePool( &clgame.mempool );
  2644. memset( &clgame, 0, sizeof( clgame ));
  2645.  
  2646. - Cvar_Unlink();
  2647. + Cvar_Unlink( CVAR_CLIENTDLL );
  2648. Cmd_Unlink( CMD_CLIENTDLL );
  2649. }
  2650.  
  2651. @@ -4073,8 +4050,8 @@ qboolean CL_LoadProgs( const char *name )
  2652. return false;
  2653. }
  2654.  
  2655. - Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE|CVAR_USERINFO, "disable client movement predicting" );
  2656. - Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
  2657. + Cvar_Get( "cl_nopred", "1", CVAR_ARCHIVE, "disable client movement predicting" );
  2658. + cl_lw = Cvar_Get( "cl_lw", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" );
  2659. Cvar_Get( "cl_lc", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable lag compensation" );
  2660. Cvar_FullSet( "host_clientloaded", "1", CVAR_INIT );
  2661.  
  2662. @@ -4086,13 +4063,12 @@ qboolean CL_LoadProgs( const char *name )
  2663. CL_InitParticles ();
  2664. CL_InitViewBeams ();
  2665. CL_InitTempEnts ();
  2666. - CL_InitEdicts (); // initailize local player and world
  2667. - CL_InitClientMove(); // initialize pm_shared
  2668.  
  2669. if( !R_InitRenderAPI()) // Xash3D extension
  2670. - {
  2671. MsgDev( D_WARN, "CL_LoadProgs: couldn't get render API\n" );
  2672. - }
  2673. +
  2674. + CL_InitEdicts (); // initailize local player and world
  2675. + CL_InitClientMove(); // initialize pm_shared
  2676.  
  2677. // initialize game
  2678. clgame.dllFuncs.pfnInit();
  2679. diff --git b/engine/client/cl_menu.c a/engine/client/cl_gameui.c
  2680. similarity index 98%
  2681. rename from engine/client/cl_menu.c
  2682. rename to engine/client/cl_gameui.c
  2683. index 5f77853..6c15883 100644
  2684. --- b/engine/client/cl_menu.c
  2685. +++ a/engine/client/cl_gameui.c
  2686. @@ -21,9 +21,9 @@ GNU General Public License for more details.
  2687. #include "input.h"
  2688.  
  2689. static MENUAPI GetMenuAPI;
  2690. -static void UI_UpdateUserinfo( void );
  2691. +static void UI_UpdateUserinfo( void );
  2692.  
  2693. -menu_static_t gameui;
  2694. +gameui_static_t gameui;
  2695.  
  2696. void UI_UpdateMenu( float realtime )
  2697. {
  2698. @@ -891,12 +891,12 @@ static ui_enginefuncs_t gEngfuncs =
  2699. pfnPIC_EnableScissor,
  2700. pfnPIC_DisableScissor,
  2701. pfnFillRGBA,
  2702. - pfnCvar_RegisterVariable,
  2703. + pfnCvar_RegisterGameUIVariable,
  2704. Cvar_VariableValue,
  2705. Cvar_VariableString,
  2706. Cvar_Set,
  2707. Cvar_SetFloat,
  2708. - pfnAddClientCommand,
  2709. + Cmd_AddGameUICommand,
  2710. pfnClientCmd,
  2711. Cmd_RemoveCommand,
  2712. Cmd_Argc,
  2713. @@ -968,9 +968,14 @@ void UI_UnloadProgs( void )
  2714. // deinitialize game
  2715. gameui.dllFuncs.pfnShutdown();
  2716.  
  2717. + Cvar_FullSet( "host_gameuiloaded", "0", CVAR_INIT );
  2718. +
  2719. Com_FreeLibrary( gameui.hInstance );
  2720. Mem_FreePool( &gameui.mempool );
  2721. memset( &gameui, 0, sizeof( gameui ));
  2722. +
  2723. + Cvar_Unlink( CVAR_GAMEUIDLL );
  2724. + Cmd_Unlink( CMD_GAMEUIDLL );
  2725. }
  2726.  
  2727. qboolean UI_LoadProgs( void )
  2728. @@ -1019,6 +1024,8 @@ qboolean UI_LoadProgs( void )
  2729. return false;
  2730. }
  2731.  
  2732. + Cvar_FullSet( "host_gameuiloaded", "1", CVAR_INIT );
  2733. +
  2734. // setup gameinfo
  2735. for( i = 0; i < SI.numgames; i++ )
  2736. {
  2737. @@ -1035,4 +1042,4 @@ qboolean UI_LoadProgs( void )
  2738. gameui.dllFuncs.pfnInit();
  2739.  
  2740. return true;
  2741. -}
  2742. +}
  2743. \ No newline at end of file
  2744. diff --git b/engine/client/cl_main.c a/engine/client/cl_main.c
  2745. index 9916d5f..7cf1978 100644
  2746. --- b/engine/client/cl_main.c
  2747. +++ a/engine/client/cl_main.c
  2748. @@ -22,15 +22,15 @@ GNU General Public License for more details.
  2749. #include "../cl_dll/kbutton.h"
  2750. #include "vgui_draw.h"
  2751.  
  2752. -#define MAX_TOTAL_CMDS 16
  2753. -#define MIN_CMD_RATE 10.0
  2754. -#define MAX_CMD_BUFFER 4000
  2755. +#define MAX_TOTAL_CMDS 32
  2756. +#define MAX_CMD_BUFFER 8000
  2757. #define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
  2758.  
  2759. convar_t *rcon_client_password;
  2760. convar_t *rcon_address;
  2761.  
  2762. -convar_t *cl_smooth;
  2763. +convar_t *cl_nosmooth;
  2764. +convar_t *cl_smoothtime;
  2765. convar_t *cl_timeout;
  2766. convar_t *cl_predict;
  2767. convar_t *cl_showfps;
  2768. @@ -38,13 +38,16 @@ convar_t *cl_nodelta;
  2769. convar_t *cl_crosshair;
  2770. convar_t *cl_cmdbackup;
  2771. convar_t *cl_showerror;
  2772. +convar_t *cl_bmodelinterp;
  2773. convar_t *cl_draw_particles;
  2774. convar_t *cl_lightstyle_lerping;
  2775. convar_t *cl_idealpitchscale;
  2776. convar_t *cl_solid_players;
  2777. convar_t *cl_draw_beams;
  2778. +convar_t *cl_updaterate;
  2779. convar_t *cl_cmdrate;
  2780. convar_t *cl_interp;
  2781. +convar_t *cl_lw;
  2782.  
  2783. //
  2784. // userinfo
  2785. @@ -170,8 +173,8 @@ qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset )
  2786. clgame.dllFuncs.IN_ActivateMouse();
  2787.  
  2788. // restore mlook state
  2789. - if( mlook_active ) Cmd_ExecuteString( "+mlook\n", src_command );
  2790. - if( jlook_active ) Cmd_ExecuteString( "+jlook\n", src_command );
  2791. + if( mlook_active ) Cmd_ExecuteString( "+mlook\n" );
  2792. + if( jlook_active ) Cmd_ExecuteString( "+jlook\n" );
  2793. return true;
  2794. }
  2795.  
  2796. @@ -190,7 +193,7 @@ static float CL_LerpPoint( void )
  2797. {
  2798. float f, frac;
  2799.  
  2800. - f = cl.mtime[0] - cl.mtime[1];
  2801. + f = cl_serverframetime();
  2802.  
  2803. if( !f || SV_Active( ))
  2804. {
  2805. @@ -284,6 +287,87 @@ CLIENT MOVEMENT COMMUNICATION
  2806. =======================================================================
  2807. */
  2808. /*
  2809. +===============
  2810. +CL_ProcessShowTexturesCmds
  2811. +
  2812. +navigate around texture atlas
  2813. +===============
  2814. +*/
  2815. +qboolean CL_ProcessShowTexturesCmds( usercmd_t *cmd )
  2816. +{
  2817. + static int oldbuttons;
  2818. + int changed;
  2819. + int pressed, released;
  2820. +
  2821. + if( !gl_showtextures->integer || gl_overview->integer )
  2822. + return false;
  2823. +
  2824. + changed = (oldbuttons ^ cmd->buttons);
  2825. + pressed = changed & cmd->buttons;
  2826. + released = changed & (~cmd->buttons);
  2827. +
  2828. + if( released & ( IN_RIGHT|IN_MOVERIGHT ))
  2829. + Cvar_SetFloat( "r_showtextures", gl_showtextures->integer + 1 );
  2830. + if( released & ( IN_LEFT|IN_MOVELEFT ))
  2831. + Cvar_SetFloat( "r_showtextures", max( 1, gl_showtextures->integer - 1 ));
  2832. + oldbuttons = cmd->buttons;
  2833. +
  2834. + return true;
  2835. +}
  2836. +
  2837. +/*
  2838. +===============
  2839. +CL_ProcessOverviewCmds
  2840. +
  2841. +Transform user movement into overview adjust
  2842. +===============
  2843. +*/
  2844. +qboolean CL_ProcessOverviewCmds( usercmd_t *cmd )
  2845. +{
  2846. + ref_overview_t *ov = &clgame.overView;
  2847. + int sign = 1;
  2848. + float size = world.size[!ov->rotated] / world.size[ov->rotated];
  2849. + float step = (2.0f / size) * host.realframetime;
  2850. + float step2 = step * 100.0f * (2.0f / ov->flZoom);
  2851. +
  2852. + if( !gl_overview->integer || gl_showtextures->integer )
  2853. + return false;
  2854. +
  2855. + if( ov->flZoom < 0.0f ) sign = -1;
  2856. +
  2857. + if( cmd->upmove > 0.0f ) ov->zNear += step;
  2858. + else if( cmd->upmove < 0.0f ) ov->zNear -= step;
  2859. +
  2860. + if( cmd->buttons & IN_JUMP ) ov->zFar += step;
  2861. + else if( cmd->buttons & IN_DUCK ) ov->zFar -= step;
  2862. +
  2863. + if( cmd->buttons & IN_FORWARD ) ov->origin[ov->rotated] -= sign * step2;
  2864. + else if( cmd->buttons & IN_BACK ) ov->origin[ov->rotated] += sign * step2;
  2865. +
  2866. + if( ov->rotated )
  2867. + {
  2868. + if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
  2869. + ov->origin[0] -= sign * step2;
  2870. + else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
  2871. + ov->origin[0] += sign * step2;
  2872. + }
  2873. + else
  2874. + {
  2875. + if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
  2876. + ov->origin[1] += sign * step2;
  2877. + else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
  2878. + ov->origin[1] -= sign * step2;
  2879. + }
  2880. +
  2881. + if( cmd->buttons & IN_ATTACK ) ov->flZoom += step;
  2882. + else if( cmd->buttons & IN_ATTACK2 ) ov->flZoom -= step;
  2883. +
  2884. + if( ov->flZoom == 0.0f ) ov->flZoom = 0.0001f; // to prevent disivion by zero
  2885. +
  2886. + return true;
  2887. +}
  2888. +
  2889. +/*
  2890. =================
  2891. CL_CreateCmd
  2892. =================
  2893. @@ -295,6 +379,7 @@ void CL_CreateCmd( void )
  2894. color24 color;
  2895. vec3_t angles;
  2896. qboolean active;
  2897. + int input_override;
  2898. int i, ms;
  2899.  
  2900. ms = host.frametime * 1000;
  2901. @@ -302,23 +387,23 @@ void CL_CreateCmd( void )
  2902. else if( ms <= 0 ) ms = 1; // keep time an actual
  2903.  
  2904. memset( &cmd, 0, sizeof( cmd ));
  2905. + input_override = 0;
  2906.  
  2907. - // build list of all solid entities per next frame (exclude clients)
  2908. - CL_SetSolidEntities ();
  2909. - CL_SetSolidPlayers ( cl.playernum );
  2910. + CL_PushPMStates();
  2911. + CL_SetSolidPlayers( cl.playernum );
  2912.  
  2913. VectorCopy( cl.refdef.cl_viewangles, angles );
  2914. VectorCopy( cl.frame.client.origin, cl.data.origin );
  2915. VectorCopy( cl.refdef.cl_viewangles, cl.data.viewangles );
  2916. cl.data.iWeaponBits = cl.frame.client.weapons;
  2917. - cl.data.fov = cl.frame.client.fov;
  2918. + cl.data.fov = cl.scr_fov;
  2919.  
  2920. - clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time );
  2921. -
  2922. - // grab changes
  2923. - VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
  2924. - cl.frame.client.weapons = cl.data.iWeaponBits;
  2925. - cl.frame.client.fov = cl.data.fov;
  2926. + if( clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time ))
  2927. + {
  2928. + // grab changes if successful
  2929. + VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
  2930. + cl.scr_fov = cl.data.fov;
  2931. + }
  2932.  
  2933. // allways dump the first ten messages,
  2934. // because it may contain leftover inputs
  2935. @@ -330,37 +415,45 @@ void CL_CreateCmd( void )
  2936. cl.refdef.cmd = &cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].cmd;
  2937. *cl.refdef.cmd = cmd;
  2938. }
  2939. +
  2940. + CL_PopPMStates();
  2941. return;
  2942. }
  2943.  
  2944. // message we are constructing.
  2945. i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK;
  2946. -
  2947. pcmd = &cl.commands[i];
  2948.  
  2949. - pcmd->senttime = cls.demoplayback ? 0.0 : host.realtime;
  2950. - memset( &pcmd->cmd, 0, sizeof( pcmd->cmd ));
  2951. - pcmd->receivedtime = -1.0;
  2952. - pcmd->processedfuncs = false;
  2953. - pcmd->heldback = false;
  2954. - pcmd->sendsize = 0;
  2955. + if( !cls.demoplayback )
  2956. + {
  2957. + pcmd->senttime = host.realtime;
  2958. + memset( &pcmd->cmd, 0, sizeof( pcmd->cmd ));
  2959. + pcmd->receivedtime = -1.0;
  2960. + pcmd->processedfuncs = false;
  2961. + pcmd->heldback = false;
  2962. + pcmd->sendsize = 0;
  2963. + }
  2964.  
  2965. active = ( cls.state == ca_active && !cl.refdef.paused && !cls.demoplayback );
  2966. clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &pcmd->cmd, active );
  2967. + CL_PopPMStates();
  2968.  
  2969. - R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f );
  2970. - pcmd->cmd.lightlevel = (color.r + color.g + color.b) / 3;
  2971. -
  2972. - // never let client.dll calc frametime for player
  2973. - // because is potential backdoor for cheating
  2974. - pcmd->cmd.msec = ms;
  2975. - pcmd->cmd.lerp_msec = cl_interp->value * 1000;
  2976. - pcmd->cmd.lerp_msec = bound( 0, cmd.lerp_msec, 250 );
  2977. + if( !cls.demoplayback )
  2978. + {
  2979. + R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f );
  2980. + pcmd->cmd.lightlevel = (color.r + color.g + color.b) / 3;
  2981. +
  2982. + // never let client.dll calc frametime for player
  2983. + // because is potential backdoor for cheating
  2984. + pcmd->cmd.msec = ms;
  2985. + pcmd->cmd.lerp_msec = cl_interp->value * 1000;
  2986. + pcmd->cmd.lerp_msec = bound( 0, cmd.lerp_msec, 250 );
  2987. + }
  2988.  
  2989. - V_ProcessOverviewCmds( &pcmd->cmd );
  2990. - V_ProcessShowTexturesCmds( &pcmd->cmd );
  2991. + input_override |= CL_ProcessOverviewCmds( &pcmd->cmd );
  2992. + input_override |= CL_ProcessShowTexturesCmds( &pcmd->cmd );
  2993.  
  2994. - if(( cl.background && !cls.demoplayback ) || gl_overview->integer || cls.changelevel )
  2995. + if(( cl.background && !cls.demoplayback ) || input_override || cls.changelevel )
  2996. {
  2997. VectorCopy( angles, cl.refdef.cl_viewangles );
  2998. VectorCopy( angles, pcmd->cmd.viewangles );
  2999. @@ -424,31 +517,34 @@ void CL_WritePacket( void )
  3000.  
  3001. CL_ComputePacketLoss ();
  3002.  
  3003. -#ifndef _DEBUG
  3004. - if( cl_cmdrate->value < MIN_CMD_RATE )
  3005. - {
  3006. - Cvar_SetFloat( "cl_cmdrate", MIN_CMD_RATE );
  3007. - }
  3008. -#endif
  3009. MSG_Init( &buf, "ClientData", data, sizeof( data ));
  3010.  
  3011. // Determine number of backup commands to send along
  3012. numbackup = bound( 0, cl_cmdbackup->integer, MAX_BACKUP_COMMANDS );
  3013. if( cls.state == ca_connected ) numbackup = 0;
  3014.  
  3015. + // clamp cmdrate
  3016. + if( cl_cmdrate->integer < 0 ) Cvar_Set( "cl_cmdrate", "0" );
  3017. + else if( cl_cmdrate->integer > 100 ) Cvar_Set( "cl_cmdrate", "100" );
  3018. +
  3019. // Check to see if we can actually send this command
  3020.  
  3021. + // always reply at end of frame during the connection process
  3022. + if( cls.state > ca_disconnected && cls.state < ca_active )
  3023. + send_command = true;
  3024. +
  3025. // In single player, send commands as fast as possible
  3026. // Otherwise, only send when ready and when not choking bandwidth
  3027. - if(( cl.maxclients == 1 ) || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer ))
  3028. + if( cl.maxclients == 1 || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer ))
  3029. send_command = true;
  3030. - else if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan ))
  3031. +
  3032. + if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan ))
  3033. send_command = true;
  3034.  
  3035. - if( cl.force_send_usercmd )
  3036. + if( cl.send_reply )
  3037. {
  3038. + cl.send_reply = false;
  3039. send_command = true;
  3040. - cl.force_send_usercmd = false;
  3041. }
  3042.  
  3043. if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
  3044. @@ -461,10 +557,8 @@ void CL_WritePacket( void )
  3045. }
  3046.  
  3047. if( cl_nodelta->integer )
  3048. - {
  3049. cl.validsequence = 0;
  3050. - }
  3051. -
  3052. +
  3053. // send a userinfo update if needed
  3054. if( userinfo->modified )
  3055. {
  3056. @@ -476,8 +570,8 @@ void CL_WritePacket( void )
  3057. {
  3058. int outgoing_sequence;
  3059.  
  3060. - if( cl_cmdrate->integer > 0 )
  3061. - cls.nextcmdtime = host.realtime + ( 1.0f / cl_cmdrate->value );
  3062. + if( cl_cmdrate->integer > 0 ) // clamped between 10 and 100 fps
  3063. + cls.nextcmdtime = host.realtime + bound( 0.1f, ( 1.0f / cl_cmdrate->value ), 0.01f );
  3064. else cls.nextcmdtime = host.realtime; // always able to send right away
  3065.  
  3066. if( cls.lastoutgoingcommand == -1 )
  3067. @@ -515,14 +609,13 @@ void CL_WritePacket( void )
  3068. for( i = numcmds - 1; i >= 0; i-- )
  3069. {
  3070. cmdnumber = ( cls.netchan.outgoing_sequence - i ) & CL_UPDATE_MASK;
  3071. - if( i == 0 ) cl.commands[cmdnumber].processedfuncs = true; // only last cmd allow to run funcs
  3072.  
  3073. to = cmdnumber;
  3074. CL_WriteUsercmd( &buf, from, to );
  3075. from = to;
  3076.  
  3077. if( MSG_CheckOverflow( &buf ))
  3078. - Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
  3079. + Host_Error( "CL_WritePacket: overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
  3080. }
  3081.  
  3082. // calculate a checksum over the move commands
  3083. @@ -547,9 +640,7 @@ void CL_WritePacket( void )
  3084. }
  3085.  
  3086. if( MSG_CheckOverflow( &buf ))
  3087. - {
  3088. - Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
  3089. - }
  3090. + Host_Error( "CL_WritePacket: overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER );
  3091.  
  3092. // remember outgoing command that we are sending
  3093. cls.lastoutgoingcommand = cls.netchan.outgoing_sequence;
  3094. @@ -714,7 +805,7 @@ void CL_Connect_f( void )
  3095. return;
  3096. }
  3097.  
  3098. - Q_strncpy( server, Cmd_Argv( 1 ), sizeof( cls.servername ));
  3099. + Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
  3100.  
  3101. if( Host_ServerState())
  3102. {
  3103. @@ -814,6 +905,9 @@ void CL_ClearState( void )
  3104. Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY );
  3105. cl.refdef.movevars = &clgame.movevars;
  3106. cl.maxclients = 1; // allow to drawing player in menu
  3107. + cl.mtime[0] = cl.mtime[1] = 1.0f; // because level starts from 1.0f second
  3108. + NetAPI_CancelAllRequests();
  3109. + cl.scr_fov = 90.0f;
  3110.  
  3111. Cvar_SetFloat( "scr_download", 0.0f );
  3112. Cvar_SetFloat( "scr_loading", 0.0f );
  3113. @@ -941,7 +1035,7 @@ CL_InternetServers_f
  3114. void CL_InternetServers_f( void )
  3115. {
  3116. netadr_t adr;
  3117. - char fullquery[512] = "\x31\xFF" "0.0.0.0:0\0" "\\gamedir\\";
  3118. + char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
  3119.  
  3120. MsgDev( D_INFO, "Scanning for servers on the internet area...\n" );
  3121. NET_Config( true ); // allow remote
  3122. @@ -949,9 +1043,14 @@ void CL_InternetServers_f( void )
  3123. if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
  3124. MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
  3125.  
  3126. - Q_strcpy( &fullquery[21], GI->gamedir );
  3127. + Q_strcpy( &fullquery[22], GI->gamedir );
  3128. +
  3129. + NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 23, fullquery, adr );
  3130.  
  3131. - NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 22, fullquery, adr );
  3132. + // now we clearing the vgui request
  3133. + if( clgame.master_request != NULL )
  3134. + memset( clgame.master_request, 0, sizeof( net_request_t ));
  3135. + clgame.request_type = NET_REQUEST_GAMEUI;
  3136. }
  3137.  
  3138. /*
  3139. @@ -983,11 +1082,11 @@ void CL_Packet_f( void )
  3140. return;
  3141. }
  3142.  
  3143. - if( !adr.port ) adr.port = MSG_BigShort( PORT_SERVER );
  3144. + if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
  3145.  
  3146. in = Cmd_Argv( 2 );
  3147. out = send + 4;
  3148. - send[0] = send[1] = send[2] = send[3] = (char)0xff;
  3149. + send[0] = send[1] = send[2] = send[3] = (char)0xFF;
  3150.  
  3151. l = Q_strlen( in );
  3152.  
  3153. @@ -1058,6 +1157,70 @@ void CL_Reconnect_f( void )
  3154.  
  3155. /*
  3156. =================
  3157. +CL_FixupColorStringsForInfoString
  3158. +
  3159. +all the keys and values must be ends with ^7
  3160. +=================
  3161. +*/
  3162. +void CL_FixupColorStringsForInfoString( const char *in, char *out )
  3163. +{
  3164. + qboolean hasPrefix = false;
  3165. + qboolean endOfKeyVal = false;
  3166. + int color = 7;
  3167. + int count = 0;
  3168. +
  3169. + if( *in == '\\' )
  3170. + {
  3171. + *out++ = *in++;
  3172. + count++;
  3173. + }
  3174. +
  3175. + while( *in && count < MAX_INFO_STRING )
  3176. + {
  3177. + if( IsColorString( in ))
  3178. + color = ColorIndex( *(in+1));
  3179. +
  3180. + // color the not reset while end of key (or value) was found!
  3181. + if( *in == '\\' && color != 7 )
  3182. + {
  3183. + if( IsColorString( out - 2 ))
  3184. + {
  3185. + *(out - 1) = '7';
  3186. + }
  3187. + else
  3188. + {
  3189. + *out++ = '^';
  3190. + *out++ = '7';
  3191. + count += 2;
  3192. + }
  3193. + color = 7;
  3194. + }
  3195. +
  3196. + *out++ = *in++;
  3197. + count++;
  3198. + }
  3199. +
  3200. + // check the remaining value
  3201. + if( color != 7 )
  3202. + {
  3203. + // if the ends with another color rewrite it
  3204. + if( IsColorString( out - 2 ))
  3205. + {
  3206. + *(out - 1) = '7';
  3207. + }
  3208. + else
  3209. + {
  3210. + *out++ = '^';
  3211. + *out++ = '7';
  3212. + count += 2;
  3213. + }
  3214. + }
  3215. +
  3216. + *out = '\0';
  3217. +}
  3218. +
  3219. +/*
  3220. +=================
  3221. CL_ParseStatusMessage
  3222.  
  3223. Handle a reply from a info
  3224. @@ -1065,10 +1228,15 @@ Handle a reply from a info
  3225. */
  3226. void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
  3227. {
  3228. - char *s;
  3229. + static char infostring[MAX_INFO_STRING+8];
  3230. + char *s = MSG_ReadString( msg );
  3231. +
  3232. + CL_FixupColorStringsForInfoString( s, infostring );
  3233.  
  3234. - s = MSG_ReadString( msg );
  3235. - UI_AddServerToList( from, s );
  3236. + // more info about servers
  3237. + MsgDev( D_INFO, "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
  3238. +
  3239. + UI_AddServerToList( from, infostring );
  3240. }
  3241.  
  3242. /*
  3243. @@ -1078,15 +1246,27 @@ CL_ParseNETInfoMessage
  3244. Handle a reply from a netinfo
  3245. =================
  3246. */
  3247. -void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg )
  3248. +void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg, const char *s )
  3249. {
  3250. - char *s;
  3251. net_request_t *nr;
  3252. + static char infostring[MAX_INFO_STRING+8];
  3253. int i, context, type;
  3254. + int errorBits = 0;
  3255. + char *val;
  3256.  
  3257. context = Q_atoi( Cmd_Argv( 1 ));
  3258. type = Q_atoi( Cmd_Argv( 2 ));
  3259. - s = Cmd_Argv( 3 );
  3260. + while( *s != '\\' ) s++; // fetching infostring
  3261. +
  3262. + // check for errors
  3263. + val = Info_ValueForKey( s, "neterror" );
  3264. +
  3265. + if( !Q_stricmp( val, "protocol" ))
  3266. + SetBits( errorBits, NET_ERROR_PROTO_UNSUPPORTED );
  3267. + else if( !Q_stricmp( val, "undefined" ))
  3268. + SetBits( errorBits, NET_ERROR_UNDEFINED );
  3269. +
  3270. + CL_FixupColorStringsForInfoString( s, infostring );
  3271.  
  3272. // find a request with specified context
  3273. for( i = 0; i < MAX_REQUESTS; i++ )
  3274. @@ -1095,28 +1275,81 @@ void CL_ParseNETInfoMessage( netadr_t from, sizebuf_t *msg )
  3275.  
  3276. if( nr->resp.context == context && nr->resp.type == type )
  3277. {
  3278. - if( nr->timeout > host.realtime )
  3279. - {
  3280. - // setup the answer
  3281. - nr->resp.response = s;
  3282. - nr->resp.remote_address = from;
  3283. - nr->resp.error = NET_SUCCESS;
  3284. - nr->resp.ping = host.realtime - nr->timesend;
  3285. - nr->pfnFunc( &nr->resp );
  3286. -
  3287. - if(!( nr->flags & FNETAPI_MULTIPLE_RESPONSE ))
  3288. - memset( nr, 0, sizeof( *nr )); // done
  3289. - }
  3290. - else
  3291. - {
  3292. - memset( nr, 0, sizeof( *nr ));
  3293. - }
  3294. + // setup the answer
  3295. + nr->resp.response = infostring;
  3296. + nr->resp.remote_address = from;
  3297. + nr->resp.error = NET_SUCCESS;
  3298. + nr->resp.ping = host.realtime - nr->timesend;
  3299. +
  3300. + if( nr->timeout <= host.realtime )
  3301. + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
  3302. + SetBits( nr->resp.error, errorBits ); // misc error bits
  3303. +
  3304. + nr->pfnFunc( &nr->resp );
  3305. +
  3306. + if( !FBitSet( nr->flags, FNETAPI_MULTIPLE_RESPONSE ))
  3307. + memset( nr, 0, sizeof( *nr )); // done
  3308. return;
  3309. }
  3310. }
  3311. }
  3312.  
  3313. +/*
  3314. +=================
  3315. +CL_ProcessNetRequests
  3316. +
  3317. +check for timeouts
  3318. +=================
  3319. +*/
  3320. +void CL_ProcessNetRequests( void )
  3321. +{
  3322. + net_request_t *nr;
  3323. + int i;
  3324. +
  3325. + // find a request with specified context
  3326. + for( i = 0; i < MAX_REQUESTS; i++ )
  3327. + {
  3328. + nr = &clgame.net_requests[i];
  3329. + if( !nr->pfnFunc ) continue; // not used
  3330. +
  3331. + if( nr->timeout <= host.realtime )
  3332. + {
  3333. + // setup the answer
  3334. + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
  3335. + nr->resp.ping = host.realtime - nr->timesend;
  3336. +
  3337. + nr->pfnFunc( &nr->resp );
  3338. + memset( nr, 0, sizeof( *nr )); // done
  3339. + }
  3340. + }
  3341. +}
  3342. +
  3343. //===================================================================
  3344. +/*
  3345. +===============
  3346. +CL_SetupOverviewParams
  3347. +
  3348. +Get initial overview values
  3349. +===============
  3350. +*/
  3351. +void CL_SetupOverviewParams( void )
  3352. +{
  3353. + ref_overview_t *ov = &clgame.overView;
  3354. + float mapAspect, screenAspect, aspect;
  3355. +
  3356. + ov->rotated = ( world.size[1] <= world.size[0] ) ? true : false;
  3357. +
  3358. + // calculate nearest aspect
  3359. + mapAspect = world.size[!ov->rotated] / world.size[ov->rotated];
  3360. + screenAspect = (float)glState.width / (float)glState.height;
  3361. + aspect = Q_max( mapAspect, screenAspect );
  3362. +
  3363. + ov->zNear = world.maxs[2];
  3364. + ov->zFar = world.mins[2];
  3365. + ov->flZoom = ( 8192.0f / world.size[ov->rotated] ) / aspect;
  3366. +
  3367. + VectorAverage( world.mins, world.maxs, ov->origin );
  3368. +}
  3369.  
  3370. /*
  3371. ======================
  3372. @@ -1144,26 +1377,6 @@ void CL_PrepSound( void )
  3373. }
  3374.  
  3375. S_EndRegistration();
  3376. -
  3377. - if( host.soundList )
  3378. - {
  3379. - // need to reapply all ambient sounds after restarting
  3380. - for( i = 0; i < host.numsounds; i++)
  3381. - {
  3382. - soundlist_t *entry = &host.soundList[i];
  3383. - if( entry->looping && entry->entnum != -1 )
  3384. - {
  3385. - MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name );
  3386. - S_AmbientSound( entry->origin, entry->entnum,
  3387. - S_RegisterSound( entry->name ), entry->volume, entry->attenuation,
  3388. - entry->pitch, 0 );
  3389. - }
  3390. - }
  3391. - }
  3392. -
  3393. - host.soundList = NULL;
  3394. - host.numsounds = 0;
  3395. -
  3396. cl.audio_prepped = true;
  3397. }
  3398.  
  3399. @@ -1220,7 +1433,7 @@ void CL_PrepVideo( void )
  3400.  
  3401. R_NewMap(); // tell the render about new map
  3402.  
  3403. - V_SetupOverviewState(); // set overview bounds
  3404. + CL_SetupOverviewParams(); // set overview bounds
  3405.  
  3406. // must be called after lightmap loading!
  3407. clgame.dllFuncs.pfnVidInit();
  3408. @@ -1237,44 +1450,6 @@ void CL_PrepVideo( void )
  3409.  
  3410. Cvar_SetFloat( "scr_loading", 100.0f ); // all done
  3411.  
  3412. - if( host.decalList )
  3413. - {
  3414. - // need to reapply all decals after restarting
  3415. - for( i = 0; i < host.numdecals; i++ )
  3416. - {
  3417. - decallist_t *entry = &host.decalList[i];
  3418. - cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex );
  3419. - int decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name ));
  3420. - int modelIndex = 0;
  3421. -
  3422. - if( pEdict ) modelIndex = pEdict->curstate.modelindex;
  3423. - CL_DecalShoot( decalIndex, entry->entityIndex, modelIndex, entry->position, entry->flags );
  3424. - }
  3425. - Z_Free( host.decalList );
  3426. - }
  3427. -
  3428. - host.decalList = NULL;
  3429. - host.numdecals = 0;
  3430. -
  3431. - if( host.soundList )
  3432. - {
  3433. - // need to reapply all ambient sounds after restarting
  3434. - for( i = 0; i < host.numsounds; i++ )
  3435. - {
  3436. - soundlist_t *entry = &host.soundList[i];
  3437. - if( entry->looping && entry->entnum != -1 )
  3438. - {
  3439. - MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name );
  3440. - S_AmbientSound( entry->origin, entry->entnum,
  3441. - S_RegisterSound( entry->name ), entry->volume, entry->attenuation,
  3442. - entry->pitch, 0 );
  3443. - }
  3444. - }
  3445. - }
  3446. -
  3447. - host.soundList = NULL;
  3448. - host.numsounds = 0;
  3449. -
  3450. if( host.developer <= 2 )
  3451. Con_ClearNotify(); // clear any lines of console text
  3452.  
  3453. @@ -1341,7 +1516,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
  3454. else if( !Q_strcmp( c, "netinfo" ))
  3455. {
  3456. // server responding to a status broadcast
  3457. - CL_ParseNETInfoMessage( from, msg );
  3458. + CL_ParseNETInfoMessage( from, msg, args );
  3459. }
  3460. else if( !Q_strcmp( c, "cmd" ))
  3461. {
  3462. @@ -1386,26 +1561,69 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
  3463. // dropped the connection but it is still getting packets from us
  3464. CL_Disconnect();
  3465. }
  3466. - 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 )
  3467. + else if( !Q_strcmp( c, "f" ))
  3468. {
  3469. - dataoffset = 6;
  3470. -
  3471. - while( 1 )
  3472. + // serverlist got from masterserver
  3473. + while( MSG_GetNumBitsLeft( msg ) > 8 )
  3474. {
  3475. + MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
  3476. + servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
  3477. servadr.type = NA_IP;
  3478. - memcpy( servadr.ip, &msg->pData[dataoffset], sizeof(servadr.ip));
  3479. - servadr.port = *(word *)&msg->pData[dataoffset + 4];
  3480.  
  3481. + // list is ends here
  3482. if( !servadr.port )
  3483. + {
  3484. + if( clgame.request_type == NET_REQUEST_CLIENT && clgame.master_request != NULL )
  3485. + {
  3486. + net_request_t *nr = clgame.master_request;
  3487. + net_adrlist_t *list, **prev;
  3488. +
  3489. + // setup the answer
  3490. + nr->resp.remote_address = from;
  3491. + nr->resp.error = NET_SUCCESS;
  3492. + nr->resp.ping = host.realtime - nr->timesend;
  3493. +
  3494. + if( nr->timeout <= host.realtime )
  3495. + SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
  3496. +
  3497. + MsgDev( D_INFO, "serverlist call: %s\n", NET_AdrToString( from ));
  3498. + nr->pfnFunc( &nr->resp );
  3499. +
  3500. + // throw the list, now it will be stored in user area
  3501. + prev = &((net_adrlist_t *)nr->resp.response);
  3502. +
  3503. + while( 1 )
  3504. + {
  3505. + list = *prev;
  3506. + if( !list ) break;
  3507. +
  3508. + // throw out any variables the game created
  3509. + *prev = list->next;
  3510. + Mem_Free( list );
  3511. + }
  3512. + memset( nr, 0, sizeof( *nr )); // done
  3513. + clgame.request_type = NET_REQUEST_CANCEL;
  3514. + clgame.master_request = NULL;
  3515. + }
  3516. break;
  3517. + }
  3518.  
  3519. - MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr ));
  3520. -
  3521. - NET_Config( true ); // allow remote
  3522. -
  3523. - Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
  3524. -
  3525. - dataoffset += 6;
  3526. + if( clgame.request_type == NET_REQUEST_CLIENT && clgame.master_request != NULL )
  3527. + {
  3528. + net_request_t *nr = clgame.master_request;
  3529. + net_adrlist_t *list;
  3530. +
  3531. + // adding addresses into list
  3532. + list = Z_Malloc( sizeof( *list ));
  3533. + list->remote_address = servadr;
  3534. + list->next = nr->resp.response;
  3535. + nr->resp.response = list;
  3536. + }
  3537. + else if( clgame.request_type == NET_REQUEST_GAMEUI )
  3538. + {
  3539. + NET_Config( true ); // allow remote
  3540. + Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
  3541. + }
  3542. }
  3543. }
  3544. else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
  3545. @@ -1477,6 +1695,7 @@ void CL_ReadNetMessage( void )
  3546. continue; // wasn't accepted for some reason
  3547.  
  3548. CL_ParseServerMessage( &net_message );
  3549. + cl.send_reply = true;
  3550. }
  3551.  
  3552. // check for fragmentation/reassembly related packets.
  3553. @@ -1499,6 +1718,9 @@ void CL_ReadNetMessage( void )
  3554. }
  3555.  
  3556. Netchan_UpdateProgress( &cls.netchan );
  3557. +
  3558. + // check requests for time-expire
  3559. + CL_ProcessNetRequests();
  3560. }
  3561.  
  3562. void CL_ReadPackets( void )
  3563. @@ -1516,6 +1738,9 @@ void CL_ReadPackets( void )
  3564. #endif
  3565. CL_UpdateFrameLerp ();
  3566.  
  3567. + // build list of all solid entities per next frame (exclude clients)
  3568. + CL_SetSolidEntities();
  3569. +
  3570. // singleplayer never has connection timeout
  3571. if( NET_IsLocalAddress( cls.netchan.remote_address ))
  3572. return;
  3573. @@ -1641,7 +1866,7 @@ void CL_InitLocal( void )
  3574. cls.state = ca_disconnected;
  3575.  
  3576. // register our variables
  3577. - cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE, "enable client movement prediction" );
  3578. + cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE|CVAR_USERINFO, "enable client movement prediction" );
  3579. cl_crosshair = Cvar_Get( "crosshair", "1", CVAR_ARCHIVE, "show weapon chrosshair" );
  3580. cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for usercommnds" );
  3581. cl_idealpitchscale = Cvar_Get( "cl_idealpitchscale", "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" );
  3582. @@ -1661,18 +1886,21 @@ void CL_InitLocal( void )
  3583. rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" );
  3584. hltv = Cvar_Get( "hltv", "0", CVAR_USERINFO|CVAR_LATCH, "HLTV mode" );
  3585. cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" );
  3586. - cl_smooth = Cvar_Get ("cl_smooth", "0", CVAR_ARCHIVE, "smooth up stair climbing and interpolate position in multiplayer" );
  3587. + cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", CVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" );
  3588. + cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", CVAR_ARCHIVE, "time to smooth up" );
  3589. cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", CVAR_ARCHIVE, "how many additional history commands are sent" );
  3590. cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", CVAR_ARCHIVE, "Max number of command packets sent to server per second" );
  3591. cl_draw_particles = Cvar_Get( "cl_draw_particles", "1", CVAR_ARCHIVE, "Disable any particle effects" );
  3592. cl_draw_beams = Cvar_Get( "cl_draw_beams", "1", CVAR_ARCHIVE, "Disable view beams" );
  3593. cl_lightstyle_lerping = Cvar_Get( "cl_lightstyle_lerping", "0", CVAR_ARCHIVE, "enables animated light lerping (perfomance option)" );
  3594. cl_showerror = Cvar_Get( "cl_showerror", "0", CVAR_ARCHIVE, "show prediction error" );
  3595. + cl_bmodelinterp = Cvar_Get( "cl_bmodelinterp", "1", CVAR_ARCHIVE, "enable bmodel interpolation" );
  3596.  
  3597. Cvar_Get( "hud_scale", "0", CVAR_ARCHIVE|CVAR_LATCH, "scale hud at current resolution" );
  3598. Cvar_Get( "skin", "", CVAR_USERINFO, "player skin" ); // XDM 3.3 want this cvar
  3599. - Cvar_Get( "cl_updaterate", "60", CVAR_USERINFO|CVAR_ARCHIVE, "refresh rate of server messages" );
  3600. + cl_updaterate = Cvar_Get( "cl_updaterate", "60", CVAR_USERINFO|CVAR_ARCHIVE, "refresh rate of server messages" );
  3601. Cvar_Get( "cl_background", "0", CVAR_READ_ONLY, "indicate what background map is running" );
  3602. + Cvar_Get( "cl_msglevel", "0", CVAR_USERINFO|CVAR_ARCHIVE, "message filter for server notifications" );
  3603.  
  3604. // these two added to shut up CS 1.5 about 'unknown' commands
  3605. Cvar_Get( "lightgamma", "1", CVAR_ARCHIVE, "ambient lighting level (legacy, unused)" );
  3606. @@ -1755,6 +1983,43 @@ void CL_SendCommand( void )
  3607.  
  3608. /*
  3609. ==================
  3610. +CL_PrepareFrame
  3611. +
  3612. +setup camera, update visible ents
  3613. +==================
  3614. +*/
  3615. +void CL_PrepareFrame( void )
  3616. +{
  3617. + if( cls.state != ca_active )
  3618. + return; // not in game
  3619. +
  3620. + if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
  3621. + return; // still loading
  3622. +
  3623. + if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
  3624. + {
  3625. + cl.force_refdef = false;
  3626. + V_SetupRefDef ();
  3627. + }
  3628. +}
  3629. +
  3630. +/*
  3631. +==================
  3632. +Host_RenderFrame
  3633. +
  3634. +==================
  3635. +*/
  3636. +void Host_RenderFrame( void )
  3637. +{
  3638. + // if client is not active, do nothing
  3639. + if( !cls.initialized ) return;
  3640. +
  3641. + // update the screen
  3642. + SCR_UpdateScreen ();
  3643. +}
  3644. +
  3645. +/*
  3646. +==================
  3647. Host_ClientFrame
  3648.  
  3649. ==================
  3650. @@ -1768,6 +2033,10 @@ void Host_ClientFrame( void )
  3651. cl.oldtime = cl.time;
  3652. cl.time += host.frametime;
  3653.  
  3654. + // demo time
  3655. + if( cls.demorecording && !cls.demowaiting )
  3656. + cls.demotime += host.frametime;
  3657. +
  3658. if( gameui.hInstance )
  3659. {
  3660. // menu time (not paused, not clamped)
  3661. @@ -1796,25 +2065,43 @@ void Host_ClientFrame( void )
  3662. if( !cl.audio_prepped ) CL_PrepSound();
  3663. }
  3664.  
  3665. - // update the screen
  3666. - SCR_UpdateScreen ();
  3667. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  3668. + {
  3669. + // send a new command message to the server
  3670. + CL_SendCommand();
  3671. +
  3672. + // predict all unacknowledged movements
  3673. + CL_PredictMovement();
  3674.  
  3675. - // update audio
  3676. - S_RenderFrame( &cl.refdef );
  3677. + // setup view, add visible ents
  3678. + CL_PrepareFrame();
  3679.  
  3680. - // send a new command message to the server
  3681. - CL_SendCommand();
  3682. + // update audio
  3683. + S_RenderFrame( &cl.refdef );
  3684. + }
  3685. + else
  3686. + {
  3687. + // update the screen
  3688. + SCR_UpdateScreen ();
  3689.  
  3690. - // predict all unacknowledged movements
  3691. - CL_PredictMovement();
  3692. + // update audio
  3693. + S_RenderFrame( &cl.refdef );
  3694. +
  3695. + // send a new command message to the server
  3696. + CL_SendCommand();
  3697. +
  3698. + // predict all unacknowledged movements
  3699. + CL_PredictMovement();
  3700. + }
  3701. +
  3702. + // animate lightestyles
  3703. + CL_RunLightStyles();
  3704.  
  3705. // decay dynamic lights
  3706. CL_DecayLights ();
  3707.  
  3708. SCR_RunCinematic();
  3709. Con_RunConsole();
  3710. -
  3711. - cls.framecount++;
  3712. }
  3713.  
  3714.  
  3715. @@ -1874,4 +2161,6 @@ void CL_Shutdown( void )
  3716. SCR_FreeCinematic (); // release AVI's *after* client.dll because custom renderer may use them
  3717. S_Shutdown ();
  3718. R_Shutdown ();
  3719. +
  3720. + Con_Shutdown ();
  3721. }
  3722. \ No newline at end of file
  3723. diff --git b/engine/client/cl_netgraph.c a/engine/client/cl_netgraph.c
  3724. new file mode 100644
  3725. index 0000000..f88456f
  3726. --- /dev/null
  3727. +++ a/engine/client/cl_netgraph.c
  3728. @@ -0,0 +1,511 @@
  3729. +/*
  3730. +cl_netgraph.c - Draw Net statistics (borrowed from Xash3D SDL code)
  3731. +Copyright (C) 2016 Uncle Mike
  3732. +
  3733. +This program is free software: you can redistribute it and/or modify
  3734. +it under the terms of the GNU General Public License as published by
  3735. +the Free Software Foundation, either version 3 of the License, or
  3736. +(at your option) any later version.
  3737. +
  3738. +This program is distributed in the hope that it will be useful,
  3739. +but WITHOUT ANY WARRANTY; without even the implied warranty of
  3740. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  3741. +GNU General Public License for more details.
  3742. +*/
  3743. +
  3744. +#include "common.h"
  3745. +#include "client.h"
  3746. +#include "gl_local.h"
  3747. +
  3748. +#define NET_TIMINGS 1024
  3749. +#define NET_TIMINGS_MASK (NET_TIMINGS - 1)
  3750. +#define LATENCY_AVG_FRAC 0.5
  3751. +#define PACKETLOSS_AVG_FRAC 0.5
  3752. +#define PACKETCHOKE_AVG_FRAC 0.5
  3753. +#define NETGRAPH_LERP_HEIGHT 24
  3754. +#define NUM_LATENCY_SAMPLES 8
  3755. +
  3756. +convar_t *net_graph;
  3757. +convar_t *net_graphpos;
  3758. +convar_t *net_graphwidth;
  3759. +convar_t *net_graphheight;
  3760. +convar_t *net_scale;
  3761. +convar_t *net_graphfillsegments;
  3762. +
  3763. +static struct packet_latency_t
  3764. +{
  3765. + int latency;
  3766. + int choked;
  3767. +} netstat_packet_latency[NET_TIMINGS];
  3768. +
  3769. +static struct cmdinfo_t
  3770. +{
  3771. + float cmd_lerp;
  3772. + int size;
  3773. + qboolean sent;
  3774. +} netstat_cmdinfo[NET_TIMINGS];
  3775. +
  3776. +static byte netcolors[NETGRAPH_LERP_HEIGHT+5][4] =
  3777. +{
  3778. + { 255, 0, 0, 255 },
  3779. + { 0, 0, 255, 255 },
  3780. + { 240, 127, 63, 255 },
  3781. + { 255, 255, 0, 255 },
  3782. + { 63, 255, 63, 150 }
  3783. + // other will be generated through NetGraph_InitColors()
  3784. +};
  3785. +
  3786. +static netbandwidthgraph_t netstat_graph[NET_TIMINGS];
  3787. +static float packet_loss;
  3788. +static float packet_choke;
  3789. +
  3790. +/*
  3791. +==========
  3792. +NetGraph_DrawLine
  3793. +
  3794. +CL_FillRGBA shortcut
  3795. +==========
  3796. +*/
  3797. +static void NetGraph_DrawRect( wrect_t *rect, byte colors[4] )
  3798. +{
  3799. + CL_FillRGBA( rect->left, rect->top, rect->right, rect->bottom, colors[0], colors[1], colors[2], colors[3] );
  3800. +}
  3801. +
  3802. +/*
  3803. +==========
  3804. +NetGraph_InitColors
  3805. +
  3806. +init netgraph colors
  3807. +==========
  3808. +*/
  3809. +void NetGraph_InitColors( void )
  3810. +{
  3811. + int i;
  3812. +
  3813. + for( i = 0; i < NETGRAPH_LERP_HEIGHT; i++ )
  3814. + {
  3815. + if( i <= NETGRAPH_LERP_HEIGHT / 3 )
  3816. + {
  3817. + netcolors[i + 5][0] = i * -7.875f + 63;
  3818. + netcolors[i + 5][1] = i * 7.875f;
  3819. + netcolors[i + 5][2] = i * 19.375f + 100;
  3820. + }
  3821. + else
  3822. + {
  3823. + netcolors[i + 5][0] = ( i - 8 ) * -0.3125f + 255;
  3824. + netcolors[i + 5][1] = ( i - 8 ) * -7.9375f + 127;
  3825. + netcolors[i + 5][2] = 0;
  3826. + }
  3827. + }
  3828. +}
  3829. +
  3830. +/*
  3831. +==========
  3832. +NetGraph_GetFrameData
  3833. +
  3834. +get frame data info, like chokes, packet losses, also update graph, packet and cmdinfo
  3835. +==========
  3836. +*/
  3837. +void NetGraph_GetFrameData( int *biggest_message, float *latency, int *latency_count )
  3838. +{
  3839. + int i, choke_count = 0, loss_count = 0;
  3840. + float loss, choke;
  3841. +
  3842. + *biggest_message = *latency_count = 0;
  3843. + *latency = 0.0f;
  3844. +
  3845. + for( i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ )
  3846. + {
  3847. + frame_t *f = cl.frames + ( i & CL_UPDATE_MASK );
  3848. + struct packet_latency_t *p = netstat_packet_latency + ( i & NET_TIMINGS_MASK );
  3849. + netbandwidthgraph_t *g = netstat_graph + ( i & NET_TIMINGS_MASK );
  3850. +
  3851. + p->choked = f->receivedtime == -2.0f ? true : false;
  3852. + if( p->choked )
  3853. + choke_count++;
  3854. +
  3855. + if( !f->valid || f->receivedtime == -2.0 )
  3856. + {
  3857. + p->latency = 9998; // broken delta
  3858. + }
  3859. + else if( f->receivedtime == -1.0 )
  3860. + {
  3861. + p->latency = 9999; // dropped
  3862. + loss_count++;
  3863. + }
  3864. + else
  3865. + {
  3866. + int frame_latency = Q_min( 1.0f, f->latency );
  3867. + p->latency = (( frame_latency + 0.1 ) / 1.1 ) * ( net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2 );
  3868. +
  3869. + if( i > cls.netchan.incoming_sequence - NUM_LATENCY_SAMPLES )
  3870. + {
  3871. + *latency += 1000.0f * f->latency;
  3872. + latency_count++;
  3873. + }
  3874. + }
  3875. +
  3876. + memcpy( g, &f->graphdata, sizeof( netbandwidthgraph_t ));
  3877. +
  3878. + if( *biggest_message < g->msgbytes )
  3879. + *biggest_message = g->msgbytes;
  3880. + }
  3881. +
  3882. + for( i = cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.outgoing_sequence; i++ )
  3883. + {
  3884. + netstat_cmdinfo[i & NET_TIMINGS_MASK].cmd_lerp = cl.commands[i & CL_UPDATE_MASK].frame_lerp;
  3885. + netstat_cmdinfo[i & NET_TIMINGS_MASK].sent = cl.commands[i & CL_UPDATE_MASK].heldback ? false : true;
  3886. + netstat_cmdinfo[i & NET_TIMINGS_MASK].size = cl.commands[i & CL_UPDATE_MASK].sendsize;
  3887. + }
  3888. +
  3889. + // packet loss
  3890. + loss = 100.0 * (float)loss_count / CL_UPDATE_BACKUP;
  3891. + packet_loss = PACKETLOSS_AVG_FRAC * packet_loss + ( 1.0 - PACKETLOSS_AVG_FRAC ) * loss;
  3892. +
  3893. + // packet choke
  3894. + choke = 100.0 * (float)choke_count / CL_UPDATE_BACKUP;
  3895. + packet_choke = PACKETCHOKE_AVG_FRAC * packet_choke + ( 1.0 - PACKETCHOKE_AVG_FRAC ) * choke;
  3896. +}
  3897. +
  3898. +/*
  3899. +===========
  3900. +NetGraph_DrawTimes
  3901. +
  3902. +===========
  3903. +*/
  3904. +void NetGraph_DrawTimes( wrect_t rect, int x, int w )
  3905. +{
  3906. + int i, j, extrap_point = NETGRAPH_LERP_HEIGHT / 3, a, h;
  3907. + POINT pt = { Q_max( x + w - 1 - 25, 1 ), Q_max( rect.top + rect.bottom - 4 - NETGRAPH_LERP_HEIGHT + 1, 1 ) };
  3908. + rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
  3909. + wrect_t fill;
  3910. +
  3911. + Con_DrawString( pt.x, pt.y, va( "%i/s", cl_cmdrate->integer ), colors );
  3912. +
  3913. + for( a = 0; a < w; a++ )
  3914. + {
  3915. + i = ( cls.netchan.outgoing_sequence - a ) & NET_TIMINGS_MASK;
  3916. + h = ( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT;
  3917. +
  3918. + fill.left = x + w - a - 1;
  3919. + fill.right = fill.bottom = 1;
  3920. + fill.top = rect.top + rect.bottom - 4;
  3921. +
  3922. + if( h >= extrap_point )
  3923. + {
  3924. + int start = 0;
  3925. +
  3926. + h -= extrap_point;
  3927. + fill.top = extrap_point;
  3928. +
  3929. + for( j = start; j < h; j++ )
  3930. + {
  3931. + memcpy( colors, netcolors[j + extrap_point], sizeof( byte ) * 3 );
  3932. + NetGraph_DrawRect( &fill, colors );
  3933. + fill.top--;
  3934. + }
  3935. + }
  3936. + else
  3937. + {
  3938. + int oldh = h;
  3939. +
  3940. + fill.top -= h;
  3941. + h = extrap_point - h;
  3942. +
  3943. + for( j = 0; j < h; j++ )
  3944. + {
  3945. + memcpy( colors, netcolors[j + oldh], sizeof( byte ) * 3 );
  3946. + NetGraph_DrawRect( &fill, colors );
  3947. + fill.top--;
  3948. + }
  3949. + }
  3950. +
  3951. + fill.top = rect.top + rect.bottom - 4 - extrap_point;
  3952. +
  3953. + CL_FillRGBA( fill.left, fill.top, fill.right, fill.bottom, 255, 255, 255, 255 );
  3954. +
  3955. + fill.top = rect.top + rect.bottom - 3;
  3956. +
  3957. + if( !netstat_cmdinfo[i].sent )
  3958. + CL_FillRGBA( fill.left, fill.top, fill.right, fill.bottom, 255, 0, 0, 255 );
  3959. + }
  3960. +}
  3961. +
  3962. +/*
  3963. +===========
  3964. +NetGraph_DrawHatches
  3965. +
  3966. +===========
  3967. +*/
  3968. +void NetGraph_DrawHatches( int x, int y, int maxmsgbytes )
  3969. +{
  3970. + int ystep = max((int)( 10.0 / net_scale->value ), 1 );
  3971. + wrect_t hatch = { x, 4, y, 1 };
  3972. + int starty;
  3973. +
  3974. + for( starty = hatch.top; hatch.top > 0 && ((starty - hatch.top) * net_scale->value < (maxmsgbytes + 50)); hatch.top -= ystep )
  3975. + {
  3976. + CL_FillRGBA( hatch.left, hatch.top, hatch.right, hatch.bottom, 63, 63, 0, 200 );
  3977. + }
  3978. +}
  3979. +
  3980. +/*
  3981. +===========
  3982. +NetGraph_DrawTextFields
  3983. +
  3984. +===========
  3985. +*/
  3986. +void NetGraph_DrawTextFields( int x, int y, int count, float avg, int packet_loss, int packet_choke )
  3987. +{
  3988. + static int lastout;
  3989. + rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
  3990. + int i = ( cls.netchan.outgoing_sequence - 1 ) & NET_TIMINGS_MASK;
  3991. + float latency = count > 0 ? Q_max( 0, avg / count - 0.5 * host.frametime - 1000.0 / cl_updaterate->value ) : 0;
  3992. + float framerate = 1.0 / host.realframetime;
  3993. +
  3994. + Con_DrawString( x, y - net_graphheight->integer, va( "%.1ffps" , framerate ), colors );
  3995. + Con_DrawString( x + 75, y - net_graphheight->integer, va( "%i ms" , (int)latency ), colors );
  3996. + Con_DrawString( x + 150, y - net_graphheight->integer, va( "%i/s" , cl_updaterate->integer ), colors );
  3997. +
  3998. + if( netstat_cmdinfo[i].size )
  3999. + lastout = netstat_cmdinfo[i].size;
  4000. +
  4001. + 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 );
  4002. +
  4003. + Con_DrawString( x, y - net_graphheight->integer + 30, va( "out: %i %.2f k/s", lastout, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
  4004. +
  4005. + if( net_graph->integer > 2 )
  4006. + Con_DrawString( x, y - net_graphheight->integer + 45, va( "loss: %i choke: %i", packet_loss, packet_choke ), colors );
  4007. +
  4008. +}
  4009. +
  4010. +/*
  4011. +===========
  4012. +NetGraph_DrawDataSegment
  4013. +
  4014. +===========
  4015. +*/
  4016. +int NetGraph_DrawDataSegment( wrect_t *fill, int bytes, byte r, byte g, byte b, byte a )
  4017. +{
  4018. + int h = bytes / net_scale->value;
  4019. + byte colors[4] = { r, g, b, a };
  4020. +
  4021. + fill->top -= h;
  4022. +
  4023. + if( net_graphfillsegments->integer )
  4024. + fill->bottom = h;
  4025. + else fill->bottom = 1;
  4026. +
  4027. + if( fill->top > 1 )
  4028. + {
  4029. + NetGraph_DrawRect( fill, colors );
  4030. + return 1;
  4031. + }
  4032. + return 0;
  4033. +}
  4034. +
  4035. +/*
  4036. +===========
  4037. +NetGraph_ColorForHeight
  4038. +
  4039. +color based on packet latency
  4040. +===========
  4041. +*/
  4042. +void NetGraph_ColorForHeight( struct packet_latency_t *packet, byte color[4], int *ping )
  4043. +{
  4044. + switch( packet->latency )
  4045. + {
  4046. + case 9999:
  4047. + memcpy( color, netcolors[0], sizeof( byte ) * 4 ); // dropped
  4048. + *ping = 0;
  4049. + break;
  4050. + case 9998:
  4051. + memcpy( color, netcolors[1], sizeof( byte ) * 4 ); // invalid
  4052. + *ping = 0;
  4053. + break;
  4054. + case 9997:
  4055. + memcpy( color, netcolors[2], sizeof( byte ) * 4 ); // skipped
  4056. + *ping = 0;
  4057. + break;
  4058. + default:
  4059. + *ping = 1;
  4060. + if( packet->choked )
  4061. + {
  4062. + memcpy( color, netcolors[3], sizeof( byte ) * 4 );
  4063. + }
  4064. + else
  4065. + {
  4066. + memcpy( color, netcolors[4], sizeof( byte ) * 4 );
  4067. + }
  4068. + }
  4069. +}
  4070. +
  4071. +/*
  4072. +===========
  4073. +NetGraph_DrawDataUsage
  4074. +
  4075. +===========
  4076. +*/
  4077. +void NetGraph_DrawDataUsage( int x, int y, int w, int maxmsgbytes )
  4078. +{
  4079. + int a, i, h, lastvalidh = 0, ping;
  4080. + wrect_t fill = { 0 };
  4081. + byte color[4];
  4082. +
  4083. + for( a = 0; a < w; a++ )
  4084. + {
  4085. + i = (cls.netchan.incoming_sequence - a) & NET_TIMINGS_MASK;
  4086. + h = netstat_packet_latency[i].latency;
  4087. +
  4088. + NetGraph_ColorForHeight( &netstat_packet_latency[i], color, &ping );
  4089. +
  4090. + if( !ping ) h = lastvalidh;
  4091. + else lastvalidh = h;
  4092. +
  4093. + if( h > net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2 )
  4094. + h = net_graphheight->value - NETGRAPH_LERP_HEIGHT - 2;
  4095. +
  4096. + fill.left = x + w - a - 1;
  4097. + fill.top = y - h;
  4098. + fill.right = 1;
  4099. + fill.bottom = ping ? 1: h;
  4100. +
  4101. + NetGraph_DrawRect( &fill, color );
  4102. +
  4103. + fill.top = y;
  4104. + fill.bottom = 1;
  4105. +
  4106. + color[0] = 0; color[1] = 255; color[2] = 0; color[3] = 160;
  4107. +
  4108. + NetGraph_DrawRect( &fill, color );
  4109. +
  4110. + if( net_graph->integer < 2 )
  4111. + continue;
  4112. +
  4113. + fill.top = y - net_graphheight->value - 1;
  4114. + fill.bottom = 1;
  4115. + color[0] = color[1] = color[2] = color[3] = 255;
  4116. +
  4117. + NetGraph_DrawRect( &fill, color );
  4118. +
  4119. + fill.top -= 1;
  4120. +
  4121. + if( netstat_packet_latency[i].latency > 9995 )
  4122. + continue; // skip invalid
  4123. +
  4124. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].client, 255, 0, 0, 128 ))
  4125. + continue;
  4126. +
  4127. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].players, 255, 255, 0, 128 ))
  4128. + continue;
  4129. +
  4130. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].entities, 255, 0, 255, 128 ))
  4131. + continue;
  4132. +
  4133. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].tentities, 0, 0, 255, 128 ))
  4134. + continue;
  4135. +
  4136. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].sound, 0, 255, 0, 128 ))
  4137. + continue;
  4138. +
  4139. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].event, 0, 255, 255, 128 ))
  4140. + continue;
  4141. +
  4142. + if( !NetGraph_DrawDataSegment( &fill, netstat_graph[i].usr, 200, 200, 200, 128 ))
  4143. + continue;
  4144. +
  4145. + // special case for absolute usage
  4146. + h = netstat_graph[i].msgbytes / net_scale->value;
  4147. +
  4148. + color[0] = color[1] = color[2] = 240; color[3] = 255;
  4149. +
  4150. + fill.bottom = 1;
  4151. + fill.top = y - net_graphheight->value - 1 - h;
  4152. +
  4153. + if( fill.top < 2 ) continue;
  4154. +
  4155. + NetGraph_DrawRect( &fill, color );
  4156. + }
  4157. +
  4158. + if( net_graph->integer >= 2 )
  4159. + NetGraph_DrawHatches( x, y - net_graphheight->value - 1, maxmsgbytes );
  4160. +}
  4161. +
  4162. +/*
  4163. +===========
  4164. +NetGraph_GetScreenPos
  4165. +
  4166. +===========
  4167. +*/
  4168. +void NetGraph_GetScreenPos( wrect_t *rect, int *w, int *x, int *y )
  4169. +{
  4170. + rect->left = rect->top = 0;
  4171. + rect->right = clgame.scrInfo.iWidth;
  4172. + rect->bottom = clgame.scrInfo.iHeight;
  4173. +
  4174. + *w = Q_min( NET_TIMINGS, net_graphwidth->integer );
  4175. + if( rect->right < *w + 10 )
  4176. + *w = rect->right - 10;
  4177. +
  4178. + // detect x and y position
  4179. + switch( net_graphpos->integer )
  4180. + {
  4181. + case 1: // right sided
  4182. + *x = rect->left + rect->right - 5 - *w;
  4183. + break;
  4184. + case 2: // center
  4185. + *x = rect->left + ( rect->right - 10 - *w ) / 2;
  4186. + break;
  4187. + default: // left sided
  4188. + *x = rect->left + 5;
  4189. + break;
  4190. + }
  4191. +
  4192. + *y = rect->bottom + rect->top - NETGRAPH_LERP_HEIGHT - 5;
  4193. +}
  4194. +
  4195. +/*
  4196. +===========
  4197. +SCR_DrawNetGraph
  4198. +
  4199. +===========
  4200. +*/
  4201. +void SCR_DrawNetGraph( void )
  4202. +{
  4203. + wrect_t rect;
  4204. + float avg_ping;
  4205. + int ping_count;
  4206. + int maxmsgbytes;
  4207. + int w, x, y;
  4208. +
  4209. + if( !net_graph->integer )
  4210. + return;
  4211. +
  4212. + if( net_scale->value <= 0 )
  4213. + Cvar_SetFloat( "net_scale", 0.1f );
  4214. +
  4215. + NetGraph_GetScreenPos( &rect, &w, &x, &y );
  4216. +
  4217. + NetGraph_GetFrameData( &maxmsgbytes, &avg_ping, &ping_count );
  4218. +
  4219. + if( net_graph->integer < 3 )
  4220. + {
  4221. + NetGraph_DrawTimes( rect, x, w );
  4222. + NetGraph_DrawDataUsage( x, y, w, maxmsgbytes );
  4223. + }
  4224. +
  4225. + NetGraph_DrawTextFields( x, y, ping_count, avg_ping, packet_loss, packet_choke );
  4226. +}
  4227. +
  4228. +void CL_InitNetgraph( void )
  4229. +{
  4230. + net_graph = Cvar_Get( "net_graph", "0", CVAR_ARCHIVE, "draw network usage graph" );
  4231. + net_graphpos = Cvar_Get( "net_graphpos", "1", CVAR_ARCHIVE, "network usage graph position" );
  4232. + net_scale = Cvar_Get( "net_scale", "5", CVAR_ARCHIVE, "network usage graph scale level" );
  4233. + net_graphwidth = Cvar_Get( "net_graphwidth", "192", CVAR_ARCHIVE, "network usage graph width" );
  4234. + net_graphheight = Cvar_Get( "net_graphheight", "64", CVAR_ARCHIVE, "network usage graph height" );
  4235. + net_graphfillsegments = Cvar_Get( "net_graphfillsegments", "1", CVAR_ARCHIVE, "fill segments in network usage graph" );
  4236. + packet_loss = packet_choke = 0.0;
  4237. +
  4238. + NetGraph_InitColors();
  4239. +}
  4240. \ No newline at end of file
  4241. diff --git b/engine/client/cl_parse.c a/engine/client/cl_parse.c
  4242. index 2cf84aa..08c1686 100644
  4243. --- b/engine/client/cl_parse.c
  4244. +++ a/engine/client/cl_parse.c
  4245. @@ -285,6 +285,9 @@ void CL_ParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
  4246. }
  4247. else handle = cl.sound_index[sound]; // see precached sound
  4248.  
  4249. + if( !cl.audio_prepped )
  4250. + return; // too early
  4251. +
  4252. if( is_ambient )
  4253. {
  4254. S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
  4255. @@ -354,6 +357,18 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
  4256.  
  4257. /*
  4258. ==================
  4259. +CL_ParseServerTime
  4260. +
  4261. +==================
  4262. +*/
  4263. +void CL_ParseServerTime( sizebuf_t *msg )
  4264. +{
  4265. + cl.mtime[1] = cl.mtime[0];
  4266. + cl.mtime[0] = MSG_ReadFloat( msg );
  4267. +}
  4268. +
  4269. +/*
  4270. +==================
  4271. CL_ParseMovevars
  4272.  
  4273. ==================
  4274. @@ -371,6 +386,7 @@ void CL_ParseMovevars( sizebuf_t *msg )
  4275. memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
  4276. // keep features an actual!
  4277. clgame.oldmovevars.features = clgame.movevars.features = host.features;
  4278. + clgame.entities->curstate.scale = cl.refdef.movevars->waveHeight;
  4279. }
  4280.  
  4281. /*
  4282. @@ -1444,7 +1460,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4283. char *s;
  4284. int i, j, cmd;
  4285. int param1, param2;
  4286. - int bufStart;
  4287. + int bufStart, playerbytes;
  4288.  
  4289. cls_message_debug.parsing = true; // begin parsing
  4290. starting_count = MSG_GetNumBytesRead( msg ); // updates each frame
  4291. @@ -1513,6 +1529,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4292. break;
  4293. case svc_sound:
  4294. CL_ParseSoundPacket( msg, false );
  4295. + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
  4296. break;
  4297. case svc_time:
  4298. // shuffle timestamps
  4299. @@ -1543,12 +1560,17 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4300. break;
  4301. case svc_clientdata:
  4302. CL_ParseClientData( msg );
  4303. + cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
  4304. break;
  4305. case svc_packetentities:
  4306. - CL_ParsePacketEntities( msg, false );
  4307. + playerbytes = CL_ParsePacketEntities( msg, false );
  4308. + cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
  4309. + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
  4310. break;
  4311. case svc_deltapacketentities:
  4312. - CL_ParsePacketEntities( msg, true );
  4313. + playerbytes = CL_ParsePacketEntities( msg, true );
  4314. + cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
  4315. + cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
  4316. break;
  4317. case svc_updatepings:
  4318. CL_UpdateUserPings( msg );
  4319. @@ -1561,12 +1583,14 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4320. break;
  4321. case svc_restoresound:
  4322. CL_ParseRestoreSoundPacket( msg );
  4323. + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
  4324. break;
  4325. case svc_spawnstatic:
  4326. CL_ParseStaticEntity( msg );
  4327. break;
  4328. case svc_ambientsound:
  4329. CL_ParseSoundPacket( msg, true );
  4330. + cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
  4331. break;
  4332. case svc_crosshairangle:
  4333. CL_ParseCrosshairAngle( msg );
  4334. @@ -1576,6 +1600,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4335. break;
  4336. case svc_temp_entity:
  4337. CL_ParseTempEntity( msg );
  4338. + cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
  4339. break;
  4340. case svc_setpause:
  4341. cl.refdef.paused = ( MSG_ReadOneBit( msg ) != 0 );
  4342. @@ -1591,9 +1616,11 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4343. break;
  4344. case svc_event:
  4345. CL_ParseEvent( msg );
  4346. + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
  4347. break;
  4348. case svc_event_reliable:
  4349. CL_ParseReliableEvent( msg );
  4350. + cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
  4351. break;
  4352. case svc_updateuserinfo:
  4353. CL_UpdateUserinfo( msg );
  4354. @@ -1667,6 +1694,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
  4355. break;
  4356. default:
  4357. CL_ParseUserMessage( msg, cmd );
  4358. + cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
  4359. break;
  4360. }
  4361. }
  4362. diff --git b/engine/client/cl_pmove.c a/engine/client/cl_pmove.c
  4363. index d736b64..f599843 100644
  4364. --- b/engine/client/cl_pmove.c
  4365. +++ a/engine/client/cl_pmove.c
  4366. @@ -29,6 +29,119 @@ void CL_ClearPhysEnts( void )
  4367. clgame.pmove->numphysent = 0;
  4368. }
  4369.  
  4370. +/*
  4371. +=============
  4372. +CL_PushPMStates
  4373. +
  4374. +=============
  4375. +*/
  4376. +void CL_PushPMStates( void )
  4377. +{
  4378. + if( clgame.pushed )
  4379. + {
  4380. + MsgDev( D_ERROR, "PushPMStates called with pushed stack\n");
  4381. + }
  4382. + else
  4383. + {
  4384. + clgame.oldphyscount = clgame.pmove->numphysent;
  4385. + clgame.oldviscount = clgame.pmove->numvisent;
  4386. + clgame.pushed = true;
  4387. + }
  4388. +
  4389. +}
  4390. +
  4391. +/*
  4392. +=============
  4393. +CL_PopPMStates
  4394. +
  4395. +=============
  4396. +*/
  4397. +void CL_PopPMStates( void )
  4398. +{
  4399. + if( clgame.pushed )
  4400. + {
  4401. + clgame.pmove->numphysent = clgame.oldphyscount;
  4402. + clgame.pmove->numvisent = clgame.oldviscount;
  4403. + clgame.pushed = false;
  4404. + }
  4405. + else
  4406. + {
  4407. + MsgDev( D_ERROR, "PopPMStates called without stack\n");
  4408. + }
  4409. +}
  4410. +
  4411. +/*
  4412. +=============
  4413. +CL_ComputePlayerOrigin
  4414. +
  4415. +FIXME: implement
  4416. +=============
  4417. +*/
  4418. +void CL_ComputePlayerOrigin( cl_entity_t *clent )
  4419. +{
  4420. +}
  4421. +
  4422. +/*
  4423. +=============
  4424. +CL_SetUpPlayerPrediction
  4425. +
  4426. +=============
  4427. +*/
  4428. +void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
  4429. +{
  4430. + entity_state_t *state;
  4431. + predicted_player_t *player;
  4432. + cl_entity_t *clent;
  4433. + int i;
  4434. +
  4435. + for( i = 0; i < MAX_CLIENTS; i++ )
  4436. + {
  4437. + state = &cl.frames[cl.parsecountmod].playerstate[i];
  4438. + player = &cls.predicted_players[i];
  4439. +
  4440. + player->active = false;
  4441. +
  4442. + if( state->messagenum != cl.parsecount )
  4443. + continue; // not present this frame
  4444. +
  4445. + if( !state->modelindex )
  4446. + continue;
  4447. +
  4448. + clent = CL_GetEntityByIndex( i + 1 );
  4449. +
  4450. + // special for EF_NODRAW and local client?
  4451. + if( FBitSet( state->effects, EF_NODRAW ) && !bIncludeLocalClient )
  4452. + {
  4453. + // don't include local player?
  4454. + if( cl.playernum == i ) continue;
  4455. +
  4456. + player->active = true;
  4457. + player->movetype = state->movetype;
  4458. + player->solid = state->solid;
  4459. + player->usehull = state->usehull;
  4460. +
  4461. + CL_ComputePlayerOrigin( clent );
  4462. +
  4463. + VectorCopy( clent->origin, player->origin );
  4464. + VectorCopy( clent->angles, player->angles );
  4465. + }
  4466. + else
  4467. + {
  4468. + player->active = true;
  4469. + player->movetype = state->movetype;
  4470. + player->solid = state->solid;
  4471. + player->usehull = state->usehull;
  4472. +
  4473. + // don't rewrite origin and angles of local client
  4474. + if( cl.playernum == i )
  4475. + continue;
  4476. +
  4477. + VectorCopy( state->origin, player->origin );
  4478. + VectorCopy( state->angles, player->angles );
  4479. + }
  4480. + }
  4481. +}
  4482. +
  4483. void CL_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr )
  4484. {
  4485. ASSERT( tr != NULL );
  4486. @@ -211,25 +324,35 @@ pmove must be setup with world and solid entity hulls before calling
  4487. */
  4488. void CL_SetSolidPlayers( int playernum )
  4489. {
  4490. - int j;
  4491. - extern vec3_t player_mins;
  4492. - extern vec3_t player_maxs;
  4493. + entity_state_t *state;
  4494. cl_entity_t *ent;
  4495. physent_t *pe;
  4496. + int i;
  4497.  
  4498. if( !cl_solid_players->integer )
  4499. return;
  4500.  
  4501. - for( j = 0; j < cl.maxclients; j++ )
  4502. + for( i = 0; i < cl.maxclients; i++ )
  4503. {
  4504. // the player object never gets added
  4505. - if( j == playernum ) continue;
  4506. + if( i == playernum ) continue;
  4507.  
  4508. - ent = CL_GetEntityByIndex( j + 1 );
  4509. + ent = CL_GetEntityByIndex( i + 1 );
  4510.  
  4511. if( !ent || !ent->player )
  4512. continue; // not present this frame
  4513.  
  4514. + state = cl.frames[cl.parsecountmod].playerstate + i;
  4515. +
  4516. + if( state->effects & EF_NODRAW )
  4517. + continue; // skip invisible
  4518. +
  4519. + if( !state->solid )
  4520. + continue; // not solid
  4521. +
  4522. + if( !state->movetype )
  4523. + continue; // dead
  4524. +
  4525. pe = &clgame.pmove->physents[clgame.pmove->numphysent];
  4526. if( CL_CopyEntityToPhysEnt( pe, ent ))
  4527. clgame.pmove->numphysent++;
  4528. @@ -550,9 +673,10 @@ static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
  4529.  
  4530. static void pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
  4531. {
  4532. - sound_t snd = S_RegisterSound( sample );
  4533. + if( !clgame.pmove->runfuncs )
  4534. + return;
  4535.  
  4536. - S_StartSound( NULL, clgame.pmove->player_index + 1, channel, snd, volume, attenuation, pitch, fFlags );
  4537. + S_StartSound( NULL, clgame.pmove->player_index + 1, channel, S_RegisterSound( sample ), volume, attenuation, pitch, fFlags );
  4538. }
  4539.  
  4540. static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, float delay, float *origin,
  4541. @@ -857,6 +981,10 @@ void CL_RunUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboole
  4542. // copy results back to client
  4543. CL_FinishPMove( clgame.pmove, to );
  4544.  
  4545. + cl.predicted.lastground = clgame.pmove->onground;
  4546. + if( cl.predicted.lastground > 0 && cl.predicted.lastground < clgame.pmove->numphysent )
  4547. + cl.predicted.lastground = clgame.pmove->physents[cl.predicted.lastground].info;
  4548. +
  4549. clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *time, random_seed );
  4550. *time += (double)cmd.msec / 1000.0;
  4551. }
  4552. @@ -878,26 +1006,30 @@ void CL_CheckPredictionError( void )
  4553. frame = ( cls.netchan.incoming_acknowledged ) & CL_UPDATE_MASK;
  4554.  
  4555. // compare what the server returned with what we had predicted it to be
  4556. - VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame], delta );
  4557. + VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame], delta );
  4558.  
  4559. maxspd = ( clgame.movevars.maxvelocity * host.frametime );
  4560. len = VectorLength( delta );
  4561.  
  4562. // save the prediction error for interpolation
  4563. - if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
  4564. +// if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
  4565. + if( len > 64.0f )
  4566. {
  4567. // a teleport or something or gamepaused
  4568. - VectorClear( cl.prediction_error );
  4569. + VectorClear( cl.predicted.error );
  4570. }
  4571. else
  4572. {
  4573. if( cl_showerror->value && len > 0.5f )
  4574. MsgDev( D_ERROR, "prediction error on %i: %g\n", cl.parsecount, len );
  4575.  
  4576. - VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame] );
  4577. + VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame] );
  4578. +
  4579. + // save for error interpolation
  4580. + VectorCopy( delta, cl.predicted.error );
  4581.  
  4582. - // save for error itnerpolation
  4583. - VectorCopy( delta, cl.prediction_error );
  4584. + if(( len > 0.25f ) && ( cl.maxclients > 1 ))
  4585. + cl.predicted.correction_time = cl_smoothtime->value;
  4586. }
  4587. }
  4588.  
  4589. @@ -912,6 +1044,8 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
  4590. {
  4591. local_state_t from, to;
  4592.  
  4593. + memset( &from, 0, sizeof( local_state_t ));
  4594. + memset( &to, 0, sizeof( local_state_t ));
  4595. memcpy( from.weapondata, cl.frame.weapondata, sizeof( from.weapondata ));
  4596. from.playerstate = cl.frame.playerstate[cl.playernum];
  4597. from.client = cl.frame.client;
  4598. @@ -922,6 +1056,35 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
  4599.  
  4600. /*
  4601. =================
  4602. +CL_FakeUsercmd
  4603. +
  4604. +Runs client weapons prediction code
  4605. +=================
  4606. +*/
  4607. +void CL_FakeUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboolean runfuncs, double *pfElapsed, unsigned int random_seed )
  4608. +{
  4609. + usercmd_t cmd;
  4610. + local_state_t temp;
  4611. + usercmd_t split;
  4612. +
  4613. + while( u->msec > 50 )
  4614. + {
  4615. + split = *u;
  4616. + split.msec /= 2;
  4617. + CL_FakeUsercmd( from, &temp, &split, runfuncs, pfElapsed, random_seed );
  4618. + from = &temp;
  4619. + u = &split;
  4620. + }
  4621. +
  4622. + cmd = *u;
  4623. + *to = *from;
  4624. +
  4625. + clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *pfElapsed, random_seed );
  4626. + *pfElapsed += cmd.msec / 1000.0;
  4627. +}
  4628. +
  4629. +/*
  4630. +=================
  4631. CL_PredictMovement
  4632.  
  4633. Sets cl.predicted_origin and cl.predicted_angles
  4634. @@ -941,22 +1104,66 @@ void CL_PredictMovement( void )
  4635. if( cls.state != ca_active ) return;
  4636.  
  4637. if( cls.demoplayback && cl.refdef.cmd != NULL )
  4638. - {
  4639. - // restore viewangles from cmd.angles
  4640. - VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
  4641. - }
  4642. + CL_DemoInterpolateAngles();
  4643.  
  4644. if( !CL_IsInGame( )) return;
  4645.  
  4646. + CL_SetUpPlayerPrediction( false, false );
  4647. +
  4648. // unpredicted pure angled values converted into axis
  4649. AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );
  4650.  
  4651. ASSERT( cl.refdef.cmd != NULL );
  4652.  
  4653. if( !CL_IsPredicted( ))
  4654. - {
  4655. - // run commands even if client predicting is disabled - client expected it
  4656. - CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );
  4657. + {
  4658. + // fake prediction code
  4659. + // we need to perform cl_lw prediction while cl_predict is disabled
  4660. + // because cl_lw is enabled by default in Half-Life
  4661. + if( !cl_lw->integer )
  4662. + {
  4663. + cl.predicted.viewmodel = cl.frame.client.viewmodel;
  4664. + return;
  4665. + }
  4666. +
  4667. + ack = cls.netchan.incoming_acknowledged;
  4668. + outgoing_command = cls.netchan.outgoing_sequence;
  4669. +
  4670. + from = &cl.predict[cl.parsecountmod];
  4671. + from->playerstate = cl.frame.playerstate[cl.playernum];
  4672. + from->client = cl.frame.client;
  4673. + memcpy( from->weapondata, cl.frame.weapondata, sizeof( from->weapondata ));
  4674. +
  4675. + time = cl.frame.time;
  4676. +
  4677. + while( 1 )
  4678. + {
  4679. + // we've run too far forward
  4680. + if( frame >= ( CL_UPDATE_BACKUP - 1 ))
  4681. + break;
  4682. +
  4683. + // Incoming_acknowledged is the last usercmd the server acknowledged having acted upon
  4684. + current_command = ack + frame;
  4685. + current_command_mod = current_command & CL_UPDATE_MASK;
  4686. +
  4687. + // we've caught up to the current command.
  4688. + if( current_command >= outgoing_command )
  4689. + break;
  4690. +
  4691. + to = &cl.predict[( cl.parsecountmod + frame ) & CL_UPDATE_MASK];
  4692. +
  4693. + CL_FakeUsercmd( from, to, &cl.commands[current_command_mod].cmd,
  4694. + !cl.commands[current_command_mod].processedfuncs,
  4695. + &time, cls.netchan.incoming_acknowledged + frame );
  4696. +
  4697. + cl.commands[current_command_mod].processedfuncs = true;
  4698. +
  4699. + from = to;
  4700. + frame++;
  4701. + }
  4702. +
  4703. + if( to )
  4704. + cl.predicted.viewmodel = to->client.viewmodel;
  4705. return;
  4706. }
  4707.  
  4708. @@ -970,7 +1177,6 @@ void CL_PredictMovement( void )
  4709.  
  4710. time = cl.frame.time;
  4711.  
  4712. - CL_SetSolidEntities();
  4713. CL_SetSolidPlayers( cl.playernum );
  4714.  
  4715. while( 1 )
  4716. @@ -995,7 +1201,7 @@ void CL_PredictMovement( void )
  4717. cl.commands[current_command_mod].processedfuncs = true;
  4718.  
  4719. // save for debug checking
  4720. - VectorCopy( to->playerstate.origin, cl.predicted_origins[current_command_mod] );
  4721. + VectorCopy( to->playerstate.origin, cl.predicted.origins[current_command_mod] );
  4722.  
  4723. from = to;
  4724. frame++;
  4725. @@ -1003,9 +1209,109 @@ void CL_PredictMovement( void )
  4726.  
  4727. if( to )
  4728. {
  4729. - VectorCopy( to->playerstate.origin, cl.predicted_origin );
  4730. - VectorCopy( to->client.velocity, cl.predicted_velocity );
  4731. - VectorCopy( to->client.view_ofs, cl.predicted_viewofs );
  4732. - VectorCopy( to->client.punchangle, cl.predicted_punchangle );
  4733. + float t0 = cl.commands[( cl.parsecountmod + frame - 1) & CL_UPDATE_MASK].senttime;
  4734. + float t1 = cl.commands[( cl.parsecountmod + frame ) & CL_UPDATE_MASK].senttime;
  4735. + float t;
  4736. +
  4737. + if( t0 == t1 )
  4738. + {
  4739. + t = 0.0f;
  4740. + }
  4741. + else
  4742. + {
  4743. + t = (host.realtime - t0) / (t1 - t0);
  4744. + t = bound( 0.0f, t, 1.0f );
  4745. + }
  4746. +
  4747. + // was teleported
  4748. + if( fabs( to->playerstate.origin[0] - from->playerstate.origin[0] ) > 128.0f ||
  4749. + fabs( to->playerstate.origin[1] - from->playerstate.origin[1] ) > 128.0f ||
  4750. + fabs( to->playerstate.origin[2] - from->playerstate.origin[2] ) > 128.0f )
  4751. + {
  4752. + VectorCopy( to->playerstate.origin, cl.predicted.origin );
  4753. + VectorCopy( to->client.velocity, cl.predicted.velocity );
  4754. + VectorCopy( to->client.punchangle, cl.predicted.punchangle );
  4755. + VectorCopy( to->client.view_ofs, cl.predicted.viewofs );
  4756. + }
  4757. + else
  4758. + {
  4759. + vec3_t delta_origin, delta_punch, delta_vel;
  4760. +
  4761. + VectorSubtract( to->playerstate.origin, from->playerstate.origin, delta_origin );
  4762. + VectorSubtract( to->client.velocity, from->client.velocity, delta_vel );
  4763. + VectorSubtract( to->client.punchangle, from->client.punchangle, delta_punch );
  4764. +
  4765. + VectorMA( from->playerstate.origin, t, delta_origin, cl.predicted.origin );
  4766. + VectorMA( from->client.velocity, t, delta_vel, cl.predicted.velocity );
  4767. + VectorMA( from->client.punchangle, t, delta_punch, cl.predicted.punchangle );
  4768. +
  4769. + if( from->playerstate.usehull == to->playerstate.usehull )
  4770. + {
  4771. + vec3_t delta_viewofs;
  4772. +
  4773. + VectorSubtract( to->client.view_ofs, from->client.view_ofs, delta_viewofs );
  4774. + VectorMA( from->client.view_ofs, t, delta_viewofs, cl.predicted.viewofs );
  4775. + }
  4776. + }
  4777. +
  4778. + cl.predicted.waterlevel = to->client.waterlevel;
  4779. + cl.predicted.viewmodel = to->client.viewmodel;
  4780. + cl.predicted.usehull = to->playerstate.usehull;
  4781. +
  4782. + if( to->client.flags & FL_ONGROUND )
  4783. + {
  4784. + cl_entity_t *ent = CL_GetEntityByIndex( cl.predicted.lastground );
  4785. +
  4786. + cl.predicted.onground = cl.predicted.lastground;
  4787. + cl.predicted.moving = 0;
  4788. +
  4789. + if( ent )
  4790. + {
  4791. + vec3_t delta;
  4792. + delta[0] = ent->curstate.origin[0] - ent->prevstate.origin[0];
  4793. + delta[1] = ent->curstate.origin[1] - ent->prevstate.origin[1];
  4794. + delta[2] = 0.0f;
  4795. +
  4796. + if( VectorLength( delta ) > 0.0f )
  4797. + {
  4798. + cl.predicted.correction_time = 0;
  4799. + cl.predicted.moving = 1;
  4800. + }
  4801. + }
  4802. + }
  4803. + else
  4804. + {
  4805. + cl.predicted.onground = -1;
  4806. + cl.predicted.moving = 0;
  4807. + }
  4808. +
  4809. + if ( cl.predicted.correction_time > 0.0 && !cl_nosmooth->value && cl_smoothtime->value )
  4810. + {
  4811. + float d;
  4812. + int i;
  4813. +
  4814. + cl.predicted.correction_time = cl.predicted.correction_time - host.frametime;
  4815. +
  4816. + if( cl_smoothtime->value <= 0 )
  4817. + Cvar_SetFloat( "cl_smoothtime", 0.1 );
  4818. +
  4819. + if( cl.predicted.correction_time < 0 )
  4820. + cl.predicted.correction_time = 0;
  4821. +
  4822. + if( cl_smoothtime->value <= cl.predicted.correction_time )
  4823. + cl.predicted.correction_time = cl_smoothtime->value;
  4824. +
  4825. + d = cl.predicted.correction_time / cl_smoothtime->value;
  4826. +
  4827. + for( i = 0; i < 3; i++ )
  4828. + {
  4829. + cl.predicted.origin[i] = cl.predicted.lastorigin[i] + ( cl.predicted.origin[i] - cl.predicted.lastorigin[i] ) * (1.0 - d);
  4830. + }
  4831. + }
  4832. +
  4833. + VectorCopy( cl.predicted.origin, cl.predicted.lastorigin );
  4834. + CL_SetIdealPitch();
  4835. }
  4836. +
  4837. + CL_CheckPredictionError();
  4838. }
  4839. \ No newline at end of file
  4840. diff --git b/engine/client/cl_remap.c a/engine/client/cl_remap.c
  4841. index ec5ff8e..869512e 100644
  4842. --- b/engine/client/cl_remap.c
  4843. +++ a/engine/client/cl_remap.c
  4844. @@ -127,7 +127,6 @@ void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomco
  4845.  
  4846. raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
  4847. ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR, NULL ); // do copy
  4848. - GL_SetTextureType( ptexture->index, TEX_REMAP );
  4849.  
  4850. // restore original palette
  4851. memcpy( pal, paletteBackup, 768 );
  4852. diff --git b/engine/client/cl_scrn.c a/engine/client/cl_scrn.c
  4853. index f4dd7bf..4fe17b7 100644
  4854. --- b/engine/client/cl_scrn.c
  4855. +++ a/engine/client/cl_scrn.c
  4856. @@ -44,21 +44,21 @@ static qboolean scr_init = false;
  4857. SCR_DrawFPS
  4858. ==============
  4859. */
  4860. -void SCR_DrawFPS( void )
  4861. +void SCR_DrawFPS( int height )
  4862. {
  4863. float calc;
  4864. rgba_t color;
  4865. + double newtime;
  4866. static double nexttime = 0, lasttime = 0;
  4867. static double framerate = 0;
  4868. static int framecount = 0;
  4869. static int minfps = 9999;
  4870. static int maxfps = 0;
  4871. - double newtime;
  4872. char fpsstring[64];
  4873. int offset;
  4874.  
  4875. - if( cls.state != ca_active ) return;
  4876. - if( !cl_showfps->integer || cl.background ) return;
  4877. + if( cls.state != ca_active || !cl_showfps->integer || cl.background )
  4878. + return;
  4879.  
  4880. switch( cls.scrshot_action )
  4881. {
  4882. @@ -74,12 +74,12 @@ void SCR_DrawFPS( void )
  4883. {
  4884. framerate = framecount / (newtime - lasttime);
  4885. lasttime = newtime;
  4886. - nexttime = max( nexttime + 1, lasttime - 1 );
  4887. + nexttime = Q_max( nexttime + 1.0, lasttime - 1.0 );
  4888. framecount = 0;
  4889. }
  4890.  
  4891. - framecount++;
  4892. calc = framerate;
  4893. + framecount++;
  4894.  
  4895. if( calc < 1.0f )
  4896. {
  4897. @@ -100,7 +100,7 @@ void SCR_DrawFPS( void )
  4898. }
  4899.  
  4900. Con_DrawStringLen( fpsstring, &offset, NULL );
  4901. - Con_DrawString( scr_width->integer - offset - 3, 4, fpsstring, color );
  4902. + Con_DrawString( scr_width->integer - offset - 4, height, fpsstring, color );
  4903. }
  4904.  
  4905. /*
  4906. @@ -116,42 +116,36 @@ void SCR_NetSpeeds( void )
  4907. int x, y, height;
  4908. char *p, *start, *end;
  4909. float time = cl.mtime[0];
  4910. + static int min_svfps = 100;
  4911. + static int max_svfps = 0;
  4912. + int cur_svfps = 0;
  4913. + static int min_clfps = 100;
  4914. + static int max_clfps = 0;
  4915. + int cur_clfps = 0;
  4916. rgba_t color;
  4917.  
  4918. - if( !net_speeds->integer ) return;
  4919. - if( cls.state != ca_active ) return;
  4920. + if( !net_speeds->integer || cls.demoplayback || cls.state != ca_active )
  4921. + return;
  4922.  
  4923. - switch( net_speeds->integer )
  4924. + if( cl_serverframetime() != 0 )
  4925. {
  4926. - case 1:
  4927. - if( cls.netchan.compress )
  4928. - {
  4929. - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal received from server:\n Huffman %s\nUncompressed %s\n",
  4930. - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_received ), Q_memprint( cls.netchan.total_received_uncompressed ));
  4931. - }
  4932. - else
  4933. - {
  4934. - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal received from server:\nUncompressed %s\n",
  4935. - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_received_uncompressed ));
  4936. - }
  4937. - break;
  4938. - case 2:
  4939. - if( cls.netchan.compress )
  4940. - {
  4941. - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal sended to server:\nHuffman %s\nUncompressed %s\n",
  4942. - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_sended ), Q_memprint( cls.netchan.total_sended_uncompressed ));
  4943. - }
  4944. - else
  4945. - {
  4946. - Q_snprintf( msg, sizeof( msg ), "Game Time: %02d:%02d\nTotal sended to server:\nUncompressed %s\n",
  4947. - (int)(time / 60.0f ), (int)fmod( time, 60.0f ), Q_memprint( cls.netchan.total_sended_uncompressed ));
  4948. - }
  4949. - break;
  4950. - default: return;
  4951. + cur_svfps = Q_rint( 1.0f / cl_serverframetime( ));
  4952. + if( cur_svfps < min_svfps ) min_svfps = cur_svfps;
  4953. + if( cur_svfps > max_svfps ) max_svfps = cur_svfps;
  4954. }
  4955.  
  4956. + if( cl_clientframetime() != 0 )
  4957. + {
  4958. + cur_clfps = Q_rint( 1.0f / cl_clientframetime( ));
  4959. + if( cur_clfps < min_clfps ) min_clfps = cur_clfps;
  4960. + if( cur_clfps > max_clfps ) max_clfps = cur_clfps;
  4961. + }
  4962. +
  4963. + 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",
  4964. + 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 ));
  4965. +
  4966. x = scr_width->integer - 320;
  4967. - y = 256;
  4968. + y = 384;
  4969.  
  4970. Con_DrawStringLen( NULL, NULL, &height );
  4971. MakeRGBA( color, 255, 255, 255, 255 );
  4972. @@ -258,7 +252,7 @@ void SCR_MakeScreenShot( void )
  4973. {
  4974. // snapshots don't writes message about image
  4975. if( cls.scrshot_action != scrshot_snapshot )
  4976. - MsgDev( D_AICONSOLE, "Write %s\n", cls.shotname );
  4977. + MsgDev( D_REPORT, "Write %s\n", cls.shotname );
  4978. }
  4979. else MsgDev( D_ERROR, "Unable to write %s\n", cls.shotname );
  4980.  
  4981. @@ -619,9 +613,9 @@ void SCR_Init( void )
  4982. Cmd_AddCommand( "sizeup", SCR_SizeUp_f, "screen size up to 10 points" );
  4983. Cmd_AddCommand( "sizedown", SCR_SizeDown_f, "screen size down to 10 points" );
  4984.  
  4985. - if( host.state != HOST_RESTART && !UI_LoadProgs( ))
  4986. + if( !UI_LoadProgs( ))
  4987. {
  4988. - Msg( "^1Error: ^7can't initialize menu.dll\n" ); // there is non fatal for us
  4989. + Msg( "^1Error: ^7can't initialize gameui.dll\n" ); // there is non fatal for us
  4990. if( !host.developer ) host.developer = 1; // we need console, because menu is missing
  4991. }
  4992.  
  4993. @@ -629,14 +623,12 @@ void SCR_Init( void )
  4994. SCR_InstallParticlePalette ();
  4995. SCR_RegisterTextures ();
  4996. SCR_InitCinematic();
  4997. + CL_InitNetgraph();
  4998. SCR_VidInit();
  4999.  
  5000. - if( host.state != HOST_RESTART )
  5001. - {
  5002. - if( host.developer && Sys_CheckParm( "-toconsole" ))
  5003. - Cbuf_AddText( "toggleconsole\n" );
  5004. - else UI_SetActiveMenu( true );
  5005. - }
  5006. + if( host.developer && Sys_CheckParm( "-toconsole" ))
  5007. + Cbuf_AddText( "toggleconsole\n" );
  5008. + else UI_SetActiveMenu( true );
  5009.  
  5010. scr_init = true;
  5011. }
  5012. @@ -650,9 +642,7 @@ void SCR_Shutdown( void )
  5013. Cmd_RemoveCommand( "skyname" );
  5014. Cmd_RemoveCommand( "viewpos" );
  5015. UI_SetActiveMenu( false );
  5016. -
  5017. - if( host.state != HOST_RESTART )
  5018. - UI_UnloadProgs();
  5019. + UI_UnloadProgs();
  5020.  
  5021. scr_init = false;
  5022. }
  5023. \ No newline at end of file
  5024. diff --git b/engine/client/cl_tent.c a/engine/client/cl_tent.c
  5025. index d047f9c..0681936 100644
  5026. --- b/engine/client/cl_tent.c
  5027. +++ a/engine/client/cl_tent.c
  5028. @@ -32,7 +32,7 @@ TEMPENTS MANAGEMENT
  5029.  
  5030. ==============================================================
  5031. */
  5032. -#define MAX_MUZZLEFLASH 4
  5033. +#define MAX_MUZZLEFLASH 3
  5034. #define SHARD_VOLUME 12.0f // on shard ever n^3 units
  5035. #define SF_FUNNEL_REVERSE 1
  5036.  
  5037. @@ -65,7 +65,6 @@ void CL_RegisterMuzzleFlashes( void )
  5038. cl_muzzleflash[0] = CL_FindModelIndex( "sprites/muzzleflash1.spr" );
  5039. cl_muzzleflash[1] = CL_FindModelIndex( "sprites/muzzleflash2.spr" );
  5040. cl_muzzleflash[2] = CL_FindModelIndex( "sprites/muzzleflash3.spr" );
  5041. - cl_muzzleflash[3] = CL_FindModelIndex( "sprites/muzzleflash.spr" );
  5042.  
  5043. // update registration for shellchrome
  5044. cls.hChromeSprite = pfnSPR_Load( "sprites/shellchrome.spr" );
  5045. @@ -442,6 +441,9 @@ void CL_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
  5046. if( !pent || Mod_GetType( modelIndex ) == mod_bad )
  5047. return;
  5048.  
  5049. + if( pent->curstate.modelindex <= 0 )
  5050. + return;
  5051. +
  5052. count = density + 1;
  5053. density = count * 3 + 6;
  5054.  
  5055. @@ -524,7 +526,7 @@ void CL_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIn
  5056.  
  5057. pTemp->x = origin[0];
  5058. pTemp->y = origin[1];
  5059. - angle = Com_RandomLong( -M_PI, M_PI );
  5060. + angle = Com_RandomFloat( -M_PI, M_PI );
  5061. SinCos( angle, &sine, &cosine );
  5062.  
  5063. zspeed = Com_RandomLong( 80, 140 );
  5064. @@ -569,7 +571,7 @@ void CL_BubbleTrail( const vec3_t start, const vec3_t end, float flWaterZ, int m
  5065.  
  5066. pTemp->x = origin[0];
  5067. pTemp->y = origin[1];
  5068. - angle = Com_RandomLong( -M_PI, M_PI );
  5069. + angle = Com_RandomFloat( -M_PI, M_PI );
  5070.  
  5071. zspeed = Com_RandomLong( 80, 140 );
  5072. VectorSet( pTemp->entity.baseline.origin, speed * cos( angle ), speed * sin( angle ), zspeed );
  5073. @@ -757,8 +759,8 @@ void CL_MuzzleFlash( const vec3_t pos, int type )
  5074. int index, modelIndex, frameCount;
  5075. float scale;
  5076.  
  5077. - index = bound( 0, type % 5, MAX_MUZZLEFLASH - 1 );
  5078. - scale = (type / 5) * 0.1f;
  5079. + index = ( type % 10 ) % MAX_MUZZLEFLASH;
  5080. + scale = ( type / 10 ) * 0.1f;
  5081. if( scale == 0.0f ) scale = 0.5f;
  5082.  
  5083. modelIndex = cl_muzzleflash[index];
  5084. @@ -2343,7 +2345,7 @@ void CL_SetLightstyle( int style, const char *s, float f )
  5085. break;
  5086. }
  5087. }
  5088. - MsgDev( D_AICONSOLE, "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
  5089. + MsgDev( D_REPORT, "Lightstyle %i (%s), interp %s\n", style, ls->pattern, ls->interp ? "Yes" : "No" );
  5090. }
  5091.  
  5092. /*
  5093. @@ -2650,7 +2652,7 @@ int CL_DecalIndexFromName( const char *name )
  5094. return 0;
  5095.  
  5096. // look through the loaded sprite name list for SpriteName
  5097. - for( i = 0; i < MAX_DECALS && host.draw_decals[i+1][0]; i++ )
  5098. + for( i = 0; i < (MAX_DECALS - 1) && host.draw_decals[i+1][0]; i++ )
  5099. {
  5100. if( !Q_stricmp( name, host.draw_decals[i+1] ))
  5101. return i+1;
  5102. diff --git b/engine/client/cl_video.c a/engine/client/cl_video.c
  5103. index 2160274..4a7dea0 100644
  5104. --- b/engine/client/cl_video.c
  5105. +++ a/engine/client/cl_video.c
  5106. @@ -59,14 +59,17 @@ qboolean SCR_NextMovie( void )
  5107. {
  5108. string str;
  5109.  
  5110. - S_StopAllSounds();
  5111. - SCR_StopCinematic();
  5112. -
  5113. if( cls.movienum == -1 )
  5114. + {
  5115. + S_StopAllSounds();
  5116. + SCR_StopCinematic();
  5117. return false; // don't play movies
  5118. + }
  5119.  
  5120. if( !cls.movies[cls.movienum][0] || cls.movienum == MAX_MOVIES )
  5121. {
  5122. + S_StopAllSounds();
  5123. + SCR_StopCinematic();
  5124. cls.movienum = -1;
  5125. return false;
  5126. }
  5127. @@ -146,7 +149,10 @@ void SCR_RunCinematic( void )
  5128. return;
  5129.  
  5130. if( !AVI_IsActive( cin_state ))
  5131. + {
  5132. + SCR_NextMovie( );
  5133. return;
  5134. + }
  5135.  
  5136. if( UI_IsVisible( ))
  5137. {
  5138. diff --git b/engine/client/cl_view.c a/engine/client/cl_view.c
  5139. index a587f65..221b49b 100644
  5140. --- b/engine/client/cl_view.c
  5141. +++ a/engine/client/cl_view.c
  5142. @@ -20,194 +20,6 @@ GNU General Public License for more details.
  5143. #include "gl_local.h"
  5144. #include "vgui_draw.h"
  5145.  
  5146. -/*
  5147. -===============
  5148. -V_SetupRefDef
  5149. -
  5150. -update refdef values each frame
  5151. -===============
  5152. -*/
  5153. -void V_SetupRefDef( void )
  5154. -{
  5155. - cl_entity_t *clent;
  5156. - int size;
  5157. - int sb_lines;
  5158. -
  5159. - clent = CL_GetLocalPlayer ();
  5160. -
  5161. - clgame.entities->curstate.scale = clgame.movevars.waveHeight;
  5162. - clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
  5163. - clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
  5164. - clgame.viewent.curstate.number = cl.playernum + 1;
  5165. - clgame.viewent.curstate.entityType = ET_NORMAL;
  5166. - clgame.viewent.index = cl.playernum + 1;
  5167. -
  5168. - cl.refdef.movevars = &clgame.movevars;
  5169. - cl.refdef.onground = ( cl.frame.client.flags & FL_ONGROUND ) ? 1 : 0;
  5170. - cl.refdef.health = cl.frame.client.health;
  5171. - cl.refdef.playernum = cl.playernum;
  5172. - cl.refdef.max_entities = clgame.maxEntities;
  5173. - cl.refdef.maxclients = cl.maxclients;
  5174. - cl.refdef.time = cl.time;
  5175. - cl.refdef.frametime = cl.time - cl.oldtime;
  5176. - cl.refdef.demoplayback = cls.demoplayback;
  5177. - cl.refdef.smoothing = cl_smooth->integer;
  5178. - cl.refdef.viewsize = scr_viewsize->integer;
  5179. - cl.refdef.waterlevel = cl.frame.client.waterlevel;
  5180. - cl.refdef.onlyClientDraw = 0; // reset clientdraw
  5181. - cl.refdef.hardware = true; // always true
  5182. - cl.refdef.spectator = (clent->curstate.spectator != 0);
  5183. - cl.refdef.nextView = 0;
  5184. -
  5185. - SCR_AddDirtyPoint( 0, 0 );
  5186. - SCR_AddDirtyPoint( scr_width->integer - 1, scr_height->integer - 1 );
  5187. -
  5188. - if( cl.refdef.viewsize >= 120 )
  5189. - sb_lines = 0; // no status bar at all
  5190. - else if( cl.refdef.viewsize >= 110 )
  5191. - sb_lines = 24; // no inventory
  5192. - else sb_lines = 48;
  5193. -
  5194. - size = min( scr_viewsize->integer, 100 );
  5195. -
  5196. - cl.refdef.viewport[2] = scr_width->integer * size / 100;
  5197. - cl.refdef.viewport[3] = scr_height->integer * size / 100;
  5198. -
  5199. - if( cl.refdef.viewport[3] > scr_height->integer - sb_lines )
  5200. - cl.refdef.viewport[3] = scr_height->integer - sb_lines;
  5201. - if( cl.refdef.viewport[3] > scr_height->integer )
  5202. - cl.refdef.viewport[3] = scr_height->integer;
  5203. -
  5204. - cl.refdef.viewport[0] = (scr_width->integer - cl.refdef.viewport[2]) / 2;
  5205. - cl.refdef.viewport[1] = (scr_height->integer - sb_lines - cl.refdef.viewport[3]) / 2;
  5206. -
  5207. - // calc FOV
  5208. - cl.refdef.fov_x = cl.data.fov; // this is a final fov value
  5209. - cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] );
  5210. -
  5211. - // adjust FOV for widescreen
  5212. - if( glState.wideScreen && r_adjust_fov->integer )
  5213. - V_AdjustFov( &cl.refdef.fov_x, &cl.refdef.fov_y, cl.refdef.viewport[2], cl.refdef.viewport[3], false );
  5214. -
  5215. - if( CL_IsPredicted( ) && !cl.refdef.demoplayback )
  5216. - {
  5217. - VectorMA( cl.predicted_origin, -cl.lerpBack, cl.prediction_error, cl.refdef.simorg );
  5218. - VectorCopy( cl.predicted_origin, cl.refdef.simorg );
  5219. - VectorCopy( cl.predicted_velocity, cl.refdef.simvel );
  5220. - VectorCopy( cl.predicted_viewofs, cl.refdef.viewheight );
  5221. - VectorCopy( cl.predicted_punchangle, cl.refdef.punchangle );
  5222. - }
  5223. - else
  5224. - {
  5225. - VectorCopy( cl.frame.client.origin, cl.refdef.simorg );
  5226. - VectorCopy( cl.frame.client.view_ofs, cl.refdef.viewheight );
  5227. - VectorCopy( cl.frame.client.velocity, cl.refdef.simvel );
  5228. - VectorCopy( cl.frame.client.punchangle, cl.refdef.punchangle );
  5229. - }
  5230. -}
  5231. -
  5232. -/*
  5233. -===============
  5234. -V_SetupOverviewState
  5235. -
  5236. -Get initial overview values
  5237. -===============
  5238. -*/
  5239. -void V_SetupOverviewState( void )
  5240. -{
  5241. - ref_overview_t *ov = &clgame.overView;
  5242. - float mapAspect, screenAspect, aspect;
  5243. -
  5244. - ov->rotated = ( world.size[1] <= world.size[0] ) ? true : false;
  5245. -
  5246. - // calculate nearest aspect
  5247. - mapAspect = world.size[!ov->rotated] / world.size[ov->rotated];
  5248. - screenAspect = (float)glState.width / (float)glState.height;
  5249. - aspect = max( mapAspect, screenAspect );
  5250. -
  5251. - ov->zNear = world.maxs[2];
  5252. - ov->zFar = world.mins[2];
  5253. - ov->flZoom = ( 8192.0f / world.size[ov->rotated] ) / aspect;
  5254. -
  5255. - VectorAverage( world.mins, world.maxs, ov->origin );
  5256. -}
  5257. -
  5258. -/*
  5259. -===============
  5260. -V_WriteOverviewScript
  5261. -
  5262. -Create overview scrip file
  5263. -===============
  5264. -*/
  5265. -void V_WriteOverviewScript( void )
  5266. -{
  5267. - ref_overview_t *ov = &clgame.overView;
  5268. - string filename;
  5269. - file_t *f;
  5270. -
  5271. - Q_snprintf( filename, sizeof( filename ), "overviews/%s.txt", clgame.mapname );
  5272. -
  5273. - f = FS_Open( filename, "w", false );
  5274. - if( !f ) return;
  5275. -
  5276. - FS_Printf( f, "// overview description file for %s.bsp\n\n", clgame.mapname );
  5277. - FS_Print( f, "global\n{\n" );
  5278. - FS_Printf( f, "\tZOOM\t%.2f\n", ov->flZoom );
  5279. - FS_Printf( f, "\tORIGIN\t%.f\t%.f\t%.f\n", ov->origin[0], ov->origin[1], ov->zFar + 1 );
  5280. - FS_Printf( f, "\tROTATED\t%i\n", ov->rotated ? 1 : 0 );
  5281. - FS_Print( f, "}\n\nlayer\n{\n" );
  5282. - FS_Printf( f, "\tIMAGE\t\"overviews/%s.bmp\"\n", clgame.mapname );
  5283. - FS_Printf( f, "\tHEIGHT\t%.f\n", ov->zFar + 1 ); // ???
  5284. - FS_Print( f, "}\n" );
  5285. -
  5286. - FS_Close( f );
  5287. -}
  5288. -
  5289. -/*
  5290. -===============
  5291. -V_ProcessOverviewCmds
  5292. -
  5293. -Transform user movement into overview adjust
  5294. -===============
  5295. -*/
  5296. -void V_ProcessOverviewCmds( usercmd_t *cmd )
  5297. -{
  5298. - ref_overview_t *ov = &clgame.overView;
  5299. - int sign = 1;
  5300. -
  5301. - if( !gl_overview->integer ) return;
  5302. -
  5303. - if( ov->flZoom < 0.0f ) sign = -1;
  5304. -
  5305. - if( cmd->upmove > 0.0f ) ov->zNear += 1.0f;
  5306. - else if( cmd->upmove < 0.0f ) ov->zNear -= 1.0f;
  5307. -
  5308. - if( cmd->buttons & IN_JUMP ) ov->zFar += 1.0f;
  5309. - else if( cmd->buttons & IN_DUCK ) ov->zFar -= 1.0f;
  5310. -
  5311. - if( cmd->buttons & IN_FORWARD ) ov->origin[ov->rotated] -= sign * 1.0f;
  5312. - else if( cmd->buttons & IN_BACK ) ov->origin[ov->rotated] += sign * 1.0f;
  5313. -
  5314. - if( ov->rotated )
  5315. - {
  5316. - if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
  5317. - ov->origin[0] -= sign * 1.0f;
  5318. - else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
  5319. - ov->origin[0] += sign * 1.0f;
  5320. - }
  5321. - else
  5322. - {
  5323. - if( cmd->buttons & ( IN_RIGHT|IN_MOVERIGHT ))
  5324. - ov->origin[1] += sign * 1.0f;
  5325. - else if( cmd->buttons & ( IN_LEFT|IN_MOVELEFT ))
  5326. - ov->origin[1] -= sign * 1.0f;
  5327. - }
  5328. -
  5329. - if( cmd->buttons & IN_ATTACK ) ov->flZoom += 0.01f;
  5330. - else if( cmd->buttons & IN_ATTACK2 ) ov->flZoom -= 0.01f;
  5331. -
  5332. - if( ov->flZoom == 0.0f ) ov->flZoom = 0.0001f; // to prevent disivion by zero
  5333. -}
  5334.  
  5335. /*
  5336. ===============
  5337. @@ -216,7 +28,7 @@ V_MergeOverviewRefdef
  5338. merge refdef with overview settings
  5339. ===============
  5340. */
  5341. -void V_MergeOverviewRefdef( ref_params_t *fd )
  5342. +void V_MergeOverviewRefdef( void )
  5343. {
  5344. ref_overview_t *ov = &clgame.overView;
  5345. float aspect;
  5346. @@ -243,99 +55,134 @@ void V_MergeOverviewRefdef( ref_params_t *fd )
  5347. ov->flZoom, ov->origin[0], ov->origin[1], ov->origin[2], ov->zNear, ov->zFar, ov->rotated );
  5348. }
  5349.  
  5350. - VectorCopy( ov->origin, fd->vieworg );
  5351. - fd->vieworg[2] = ov->zFar + ov->zNear;
  5352. - Vector2Copy( fd->vieworg, mins );
  5353. - Vector2Copy( fd->vieworg, maxs );
  5354. + VectorCopy( ov->origin, cl.refdef.vieworg );
  5355. + cl.refdef.vieworg[2] = ov->zFar + ov->zNear;
  5356. + Vector2Copy( cl.refdef.vieworg, mins );
  5357. + Vector2Copy( cl.refdef.vieworg, maxs );
  5358.  
  5359. mins[!ov->rotated] += ov->xLeft;
  5360. maxs[!ov->rotated] += ov->xRight;
  5361. mins[ov->rotated] += ov->xTop;
  5362. maxs[ov->rotated] += ov->xBottom;
  5363.  
  5364. - fd->viewangles[0] = 90.0f;
  5365. - fd->viewangles[1] = 90.0f;
  5366. - fd->viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
  5367. + cl.refdef.viewangles[0] = 90.0f;
  5368. + cl.refdef.viewangles[1] = 90.0f;
  5369. + cl.refdef.viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
  5370.  
  5371. Mod_SetOrthoBounds( mins, maxs );
  5372. }
  5373.  
  5374. /*
  5375. ===============
  5376. -V_ProcessShowTexturesCmds
  5377. +V_CalcViewRect
  5378.  
  5379. -navigate around texture atlas
  5380. +calc frame rectangle (Quake1 style)
  5381. ===============
  5382. */
  5383. -void V_ProcessShowTexturesCmds( usercmd_t *cmd )
  5384. +void V_CalcViewRect( void )
  5385. {
  5386. - static int oldbuttons;
  5387. - int changed;
  5388. - int pressed, released;
  5389. + int size, sb_lines;
  5390. +
  5391. + if( scr_viewsize->integer >= 120 )
  5392. + sb_lines = 0; // no status bar at all
  5393. + else if( scr_viewsize->integer >= 110 )
  5394. + sb_lines = 24; // no inventory
  5395. + else sb_lines = 48;
  5396.  
  5397. - if( !gl_showtextures->integer ) return;
  5398. + size = Q_min( scr_viewsize->integer, 100 );
  5399. +
  5400. + cl.refdef.viewport[2] = scr_width->integer * size / 100;
  5401. + cl.refdef.viewport[3] = scr_height->integer * size / 100;
  5402. +
  5403. + if( cl.refdef.viewport[3] > scr_height->integer - sb_lines )
  5404. + cl.refdef.viewport[3] = scr_height->integer - sb_lines;
  5405. + if( cl.refdef.viewport[3] > scr_height->integer )
  5406. + cl.refdef.viewport[3] = scr_height->integer;
  5407.  
  5408. - changed = (oldbuttons ^ cmd->buttons);
  5409. - pressed = changed & cmd->buttons;
  5410. - released = changed & (~cmd->buttons);
  5411. + cl.refdef.viewport[0] = ( scr_width->integer - cl.refdef.viewport[2] ) / 2;
  5412. + cl.refdef.viewport[1] = ( scr_height->integer - sb_lines - cl.refdef.viewport[3] ) / 2;
  5413.  
  5414. - if( released & ( IN_RIGHT|IN_MOVERIGHT ))
  5415. - Cvar_SetFloat( "r_showtextures", gl_showtextures->integer + 1 );
  5416. - if( released & ( IN_LEFT|IN_MOVELEFT ))
  5417. - Cvar_SetFloat( "r_showtextures", max( 1, gl_showtextures->integer - 1 ));
  5418. - oldbuttons = cmd->buttons;
  5419. }
  5420.  
  5421. /*
  5422. ===============
  5423. -V_CalcRefDef
  5424. +V_SetupRefDef
  5425.  
  5426. -sets cl.refdef view values
  5427. +update refdef values each frame
  5428. ===============
  5429. */
  5430. -void V_CalcRefDef( void )
  5431. +void V_SetupRefDef( void )
  5432. {
  5433. - R_Set2DMode( false );
  5434. - tr.framecount++; // g-cont. keep actual frame for all viewpasses
  5435. + cl_entity_t *clent;
  5436.  
  5437. - do
  5438. - {
  5439. - clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
  5440. - V_MergeOverviewRefdef( &cl.refdef );
  5441. - R_RenderFrame( &cl.refdef, true );
  5442. - cl.refdef.onlyClientDraw = false;
  5443. - } while( cl.refdef.nextView );
  5444. + // compute viewport rectangle
  5445. + V_CalcViewRect();
  5446.  
  5447. - // Xash3D extension. draw debug triangles on a server
  5448. - SV_DrawDebugTriangles ();
  5449. + clent = CL_GetLocalPlayer ();
  5450.  
  5451. - SCR_AddDirtyPoint( cl.refdef.viewport[0], cl.refdef.viewport[1] );
  5452. - SCR_AddDirtyPoint( cl.refdef.viewport[0] + cl.refdef.viewport[2] - 1, cl.refdef.viewport[1] + cl.refdef.viewport[3] - 1 );
  5453. -}
  5454. + clgame.entities->curstate.scale = clgame.movevars.waveHeight;
  5455.  
  5456. -//============================================================================
  5457. + cl.refdef.movevars = &clgame.movevars;
  5458. + cl.refdef.health = cl.frame.client.health;
  5459. + cl.refdef.playernum = cl.playernum;
  5460. + cl.refdef.max_entities = clgame.maxEntities;
  5461. + cl.refdef.maxclients = cl.maxclients;
  5462. + cl.refdef.time = cl.time;
  5463. + cl.refdef.frametime = cl.time - cl.oldtime;
  5464. + cl.refdef.demoplayback = cls.demoplayback;
  5465. + cl.refdef.viewsize = scr_viewsize->integer;
  5466. + cl.refdef.onlyClientDraw = 0; // reset clientdraw
  5467. + cl.refdef.hardware = true; // always true
  5468. + cl.refdef.spectator = (clent->curstate.spectator != 0);
  5469. + cl.refdef.smoothing = cl.first_frame; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
  5470. + cl.scr_fov = bound( 1.0f, cl.scr_fov, 179.0f );
  5471. + cl.refdef.nextView = 0;
  5472.  
  5473. -/*
  5474. -==================
  5475. -V_RenderView
  5476. + // calc FOV
  5477. + cl.refdef.fov_x = cl.scr_fov; // this is a final fov value
  5478. + cl.refdef.fov_y = V_CalcFov( &cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] );
  5479.  
  5480. -==================
  5481. -*/
  5482. -void V_RenderView( void )
  5483. -{
  5484. - if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
  5485. - return; // still loading
  5486. + // adjust FOV for widescreen
  5487. + if( glState.wideScreen && r_adjust_fov->integer )
  5488. + V_AdjustFov( &cl.refdef.fov_x, &cl.refdef.fov_y, cl.refdef.viewport[2], cl.refdef.viewport[3], false );
  5489. +
  5490. + if( CL_IsPredicted( ) && !cl.first_frame )
  5491. + {
  5492. + VectorCopy( cl.predicted.origin, cl.refdef.simorg );
  5493. + VectorCopy( cl.predicted.velocity, cl.refdef.simvel );
  5494. + VectorCopy( cl.predicted.viewofs, cl.refdef.viewheight );
  5495. + VectorCopy( cl.predicted.punchangle, cl.refdef.punchangle );
  5496. + cl.refdef.onground = ( cl.predicted.onground == -1 ) ? false : true;
  5497. + cl.refdef.waterlevel = cl.predicted.waterlevel;
  5498. + }
  5499. + else
  5500. + {
  5501. + VectorCopy( cl.frame.client.origin, cl.refdef.simorg );
  5502. + VectorCopy( cl.frame.client.view_ofs, cl.refdef.viewheight );
  5503. + VectorCopy( cl.frame.client.velocity, cl.refdef.simvel );
  5504. + VectorCopy( cl.frame.client.punchangle, cl.refdef.punchangle );
  5505. + cl.refdef.onground = (cl.frame.client.flags & FL_ONGROUND) ? 1 : 0;
  5506. + cl.refdef.waterlevel = cl.frame.client.waterlevel;
  5507. + }
  5508. +
  5509. + // setup the viewent variables
  5510. + if( cl_lw->value ) clgame.viewent.curstate.modelindex = cl.predicted.viewmodel;
  5511. + else clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
  5512. + clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
  5513. + clgame.viewent.curstate.number = cl.playernum + 1;
  5514. + clgame.viewent.curstate.entityType = ET_NORMAL;
  5515. + clgame.viewent.index = cl.playernum + 1;
  5516.  
  5517. - if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
  5518. + // calc refdef first so viewent can get an actual
  5519. + // player position, angles etc
  5520. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  5521. {
  5522. - cl.force_refdef = false;
  5523. + clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
  5524. + V_MergeOverviewRefdef();
  5525.  
  5526. R_ClearScene ();
  5527. CL_AddEntities ();
  5528. - V_SetupRefDef ();
  5529. }
  5530. -
  5531. - V_CalcRefDef ();
  5532. }
  5533.  
  5534. /*
  5535. @@ -361,7 +208,7 @@ qboolean V_PreRender( void )
  5536. {
  5537. if(( host.realtime - cls.disable_screen ) > cl_timeout->value )
  5538. {
  5539. - MsgDev( D_NOTE, "V_PreRender: loading plaque timed out.\n" );
  5540. + MsgDev( D_ERROR, "V_PreRender: loading plaque timed out\n" );
  5541. cls.disable_screen = 0.0f;
  5542. }
  5543. return false;
  5544. @@ -372,6 +219,53 @@ qboolean V_PreRender( void )
  5545. return true;
  5546. }
  5547.  
  5548. +//============================================================================
  5549. +
  5550. +/*
  5551. +==================
  5552. +V_RenderView
  5553. +
  5554. +==================
  5555. +*/
  5556. +void V_RenderView( void )
  5557. +{
  5558. + if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
  5559. + return; // still loading
  5560. +
  5561. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  5562. + {
  5563. + if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
  5564. + {
  5565. + cl.force_refdef = false;
  5566. +
  5567. + R_ClearScene ();
  5568. + CL_AddEntities ();
  5569. + V_SetupRefDef ();
  5570. + }
  5571. + }
  5572. +
  5573. + R_Set2DMode( false );
  5574. + SCR_AddDirtyPoint( 0, 0 );
  5575. + SCR_AddDirtyPoint( scr_width->integer - 1, scr_height->integer - 1 );
  5576. +
  5577. + tr.framecount++; // g-cont. keep actual frame for all viewpasses
  5578. +
  5579. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  5580. + {
  5581. + do
  5582. + {
  5583. + clgame.dllFuncs.pfnCalcRefdef( &cl.refdef );
  5584. + V_MergeOverviewRefdef();
  5585. + R_RenderFrame( &cl.refdef, true );
  5586. + cl.refdef.onlyClientDraw = false;
  5587. + } while( cl.refdef.nextView );
  5588. + }
  5589. + else R_RenderFrame( &cl.refdef, true );
  5590. +
  5591. + // draw debug triangles on a server
  5592. + SV_DrawDebugTriangles ();
  5593. +}
  5594. +
  5595. /*
  5596. ==================
  5597. V_PostRender
  5598. @@ -380,11 +274,12 @@ V_PostRender
  5599. */
  5600. void V_PostRender( void )
  5601. {
  5602. - qboolean draw_2d = false;
  5603. + static double oldtime;
  5604. + qboolean draw_2d = false;
  5605.  
  5606. R_Set2DMode( true );
  5607.  
  5608. - if( cls.state == ca_active )
  5609. + if( cls.state == ca_active && cls.scrshot_action != scrshot_mapshot )
  5610. {
  5611. SCR_TileClear();
  5612. CL_DrawHUD( CL_ACTIVE );
  5613. @@ -404,16 +299,28 @@ void V_PostRender( void )
  5614. {
  5615. SCR_RSpeeds();
  5616. SCR_NetSpeeds();
  5617. - SCR_DrawFPS();
  5618. + SCR_DrawNetGraph();
  5619. SV_DrawOrthoTriangles();
  5620. CL_DrawDemoRecording();
  5621. - R_ShowTextures();
  5622. CL_DrawHUD( CL_CHANGELEVEL );
  5623. + R_ShowTextures();
  5624. Con_DrawConsole();
  5625. UI_UpdateMenu( host.realtime );
  5626. Con_DrawVersion();
  5627. Con_DrawDebug(); // must be last
  5628. - S_ExtraUpdate();
  5629. +
  5630. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  5631. + S_ExtraUpdate();
  5632. + }
  5633. +
  5634. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  5635. + {
  5636. + // don't update sound too fast
  5637. + if(( host.realtime - oldtime ) >= HOST_FRAMETIME )
  5638. + {
  5639. + oldtime = host.realtime;
  5640. + CL_ExtraUpdate();
  5641. + }
  5642. }
  5643.  
  5644. SCR_MakeScreenShot();
  5645. diff --git b/engine/client/client.h a/engine/client/client.h
  5646. index 45f9b50..bc984ba 100644
  5647. --- b/engine/client/client.h
  5648. +++ a/engine/client/client.h
  5649. @@ -37,7 +37,7 @@ GNU General Public License for more details.
  5650. #define MAX_CDTRACKS 32
  5651. #define MAX_IMAGES 256 // SpriteTextures
  5652. #define MAX_EFRAGS 4096
  5653. -#define MAX_REQUESTS 32
  5654. +#define MAX_REQUESTS 64
  5655.  
  5656. // screenshot types
  5657. #define VID_SCREENSHOT 0
  5658. @@ -49,6 +49,19 @@ GNU General Public License for more details.
  5659. typedef int sound_t;
  5660.  
  5661. //=============================================================================
  5662. +typedef struct netbandwithgraph_s
  5663. +{
  5664. + word client;
  5665. + word players;
  5666. + word entities; // entities bytes, except for players
  5667. + word tentities;// temp entities
  5668. + word sound;
  5669. + word event;
  5670. + word usr;
  5671. + word msgbytes;
  5672. + word voicebytes;
  5673. +} netbandwidthgraph_t;
  5674. +
  5675. typedef struct frame_s
  5676. {
  5677. // received from server
  5678. @@ -58,7 +71,8 @@ typedef struct frame_s
  5679.  
  5680. clientdata_t client; // local client private data
  5681. entity_state_t playerstate[MAX_CLIENTS];
  5682. - weapon_data_t weapondata[64];
  5683. + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
  5684. + netbandwidthgraph_t graphdata;
  5685.  
  5686. int num_entities;
  5687. int first_entity; // into the circular cl_packet_entities[]
  5688. @@ -79,6 +93,9 @@ typedef struct runcmd_s
  5689. int sendsize;
  5690. } runcmd_t;
  5691.  
  5692. +#define ANGLE_BACKUP 16
  5693. +#define ANGLE_MASK (ANGLE_BACKUP - 1)
  5694. +
  5695. #define CMD_BACKUP MULTIPLAYER_BACKUP // allow a lot of command backups for very fast systems
  5696. #define CMD_MASK (CMD_BACKUP - 1)
  5697.  
  5698. @@ -87,6 +104,27 @@ extern int CL_UPDATE_BACKUP;
  5699.  
  5700. #define INVALID_HANDLE 0xFFFF // for XashXT cache system
  5701.  
  5702. +#define cl_serverframetime() (cl.mtime[0] - cl.mtime[1])
  5703. +#define cl_clientframetime() (host.frametime)
  5704. +
  5705. +typedef struct
  5706. +{
  5707. + vec3_t origin; // generated by CL_PredictMovement
  5708. + vec3_t viewofs;
  5709. + vec3_t velocity;
  5710. + vec3_t punchangle;
  5711. + vec3_t origins[CMD_BACKUP];
  5712. + vec3_t error;
  5713. + vec3_t lastorigin;
  5714. + double correction_time;
  5715. + int viewmodel;
  5716. + int onground;
  5717. + int waterlevel;
  5718. + int usehull;
  5719. + int moving;
  5720. + int lastground;
  5721. +} cl_predicted_data_t; // data we got from prediction system
  5722. +
  5723. // the client_t structure is wiped completely at every
  5724. // server map change
  5725. typedef struct
  5726. @@ -111,9 +149,10 @@ typedef struct
  5727. int last_command_ack;
  5728. int last_incoming_sequence;
  5729.  
  5730. - qboolean force_send_usercmd;
  5731. + qboolean send_reply;
  5732. qboolean thirdperson;
  5733. qboolean background; // not real game, just a background
  5734. + qboolean first_frame; // first rendering frame
  5735.  
  5736. uint checksum; // for catching cheater maps
  5737.  
  5738. @@ -140,12 +179,7 @@ typedef struct
  5739. event_state_t events;
  5740.  
  5741. // predicting stuff
  5742. - vec3_t predicted_origin; // generated by CL_PredictMovement
  5743. - vec3_t predicted_viewofs;
  5744. - vec3_t predicted_velocity;
  5745. - vec3_t predicted_punchangle;
  5746. - vec3_t predicted_origins[CMD_BACKUP];
  5747. - vec3_t prediction_error;
  5748. + cl_predicted_data_t predicted; // generated from CL_PredictMovement
  5749.  
  5750. // server state information
  5751. int playernum;
  5752. @@ -163,6 +197,11 @@ typedef struct
  5753.  
  5754. cl_entity_t *world;
  5755. model_t *worldmodel; // pointer to world
  5756. +
  5757. + // weapon predict stuff
  5758. + float scr_fov;
  5759. + float weaponstarttime;
  5760. + int weaponsequence;
  5761. } client_t;
  5762.  
  5763. /*
  5764. @@ -316,6 +355,13 @@ typedef struct
  5765. model_t *model; // for catch model changes
  5766. } remap_info_t;
  5767.  
  5768. +typedef enum
  5769. +{
  5770. + NET_REQUEST_CANCEL = 0, // request was cancelled for some reasons
  5771. + NET_REQUEST_GAMEUI, // called from GameUI
  5772. + NET_REQUEST_CLIENT, // called from Client
  5773. +} net_request_type_t;
  5774. +
  5775. typedef struct
  5776. {
  5777. net_response_t resp;
  5778. @@ -351,8 +397,9 @@ typedef struct
  5779. movevars_t oldmovevars;
  5780. playermove_t *pmove; // pmove state
  5781.  
  5782. - int old_trace_hull; // used by PM_Push\Pop state
  5783. - int oldcount; // used by PM_Push\Pop state
  5784. + qboolean pushed; // used by PM_Push\Pop state
  5785. + int oldviscount; // used by PM_Push\Pop state
  5786. + int oldphyscount; // used by PM_Push\Pop state
  5787.  
  5788. vec3_t player_mins[MAX_MAP_HULLS]; // 4 hulls allowed
  5789. vec3_t player_maxs[MAX_MAP_HULLS]; // 4 hulls allowed
  5790. @@ -376,7 +423,9 @@ typedef struct
  5791. client_textmessage_t *titles; // title messages, not network messages
  5792. int numTitles;
  5793.  
  5794. + net_request_type_t request_type; // filter the requests
  5795. net_request_t net_requests[MAX_REQUESTS]; // no reason to keep more
  5796. + net_request_t *master_request; // queued master request
  5797.  
  5798. efrag_t *free_efrags; // linked efrags
  5799. cl_entity_t viewent; // viewmodel
  5800. @@ -401,7 +450,7 @@ typedef struct
  5801. long logo_xres;
  5802. long logo_yres;
  5803. float logo_length;
  5804. -} menu_static_t;
  5805. +} gameui_static_t;
  5806.  
  5807. typedef struct
  5808. {
  5809. @@ -423,7 +472,6 @@ typedef struct
  5810.  
  5811. byte *mempool; // client premamnent pool: edicts etc
  5812.  
  5813. - int framecount;
  5814. int quakePort; // a 16 bit value that allows quake servers
  5815. // to work around address translating routers
  5816. // g-cont. this port allow many copies of engine in multiplayer game
  5817. @@ -502,7 +550,7 @@ extern "C" {
  5818. extern client_t cl;
  5819. extern client_static_t cls;
  5820. extern clgame_static_t clgame;
  5821. -extern menu_static_t gameui;
  5822. +extern gameui_static_t gameui;
  5823.  
  5824. #ifdef __cplusplus
  5825. }
  5826. @@ -512,15 +560,18 @@ extern menu_static_t gameui;
  5827. // cvars
  5828. //
  5829. extern convar_t *cl_predict;
  5830. -extern convar_t *cl_smooth;
  5831. extern convar_t *cl_showfps;
  5832. extern convar_t *cl_envshot_size;
  5833. extern convar_t *cl_timeout;
  5834. extern convar_t *cl_nodelta;
  5835. extern convar_t *cl_interp;
  5836. extern convar_t *cl_showerror;
  5837. +extern convar_t *cl_nosmooth;
  5838. +extern convar_t *cl_smoothtime;
  5839. extern convar_t *cl_crosshair;
  5840. extern convar_t *cl_testlights;
  5841. +extern convar_t *cl_cmdrate;
  5842. +extern convar_t *cl_updaterate;
  5843. extern convar_t *cl_solid_players;
  5844. extern convar_t *cl_idealpitchscale;
  5845. extern convar_t *cl_allow_levelshots;
  5846. @@ -528,6 +579,9 @@ extern convar_t *cl_lightstyle_lerping;
  5847. extern convar_t *cl_draw_particles;
  5848. extern convar_t *cl_levelshot_name;
  5849. extern convar_t *cl_draw_beams;
  5850. +extern convar_t *gl_showtextures;
  5851. +extern convar_t *cl_bmodelinterp;
  5852. +extern convar_t *cl_lw; // local weapons
  5853. extern convar_t *scr_centertime;
  5854. extern convar_t *scr_viewsize;
  5855. extern convar_t *scr_download;
  5856. @@ -586,6 +640,7 @@ void CL_WriteDemoUserCmd( int cmdnumber );
  5857. void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
  5858. void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
  5859. qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
  5860. +void CL_DemoInterpolateAngles( void );
  5861. void CL_WriteDemoJumpTime( void );
  5862. void CL_CloseDemoHeader( void );
  5863. void CL_StopPlayback( void );
  5864. @@ -632,11 +687,13 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize );
  5865. client_textmessage_t *CL_TextMessageGet( const char *pName );
  5866. int pfnDecalIndexFromName( const char *szDecalName );
  5867. int pfnIndexFromTrace( struct pmtrace_s *pTrace );
  5868. +void NetAPI_CancelAllRequests( void );
  5869. int CL_FindModelIndex( const char *m );
  5870. HSPRITE pfnSPR_Load( const char *szPicName );
  5871. HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
  5872. -void TextAdjustSize( int *x, int *y, int *w, int *h );
  5873. void PicAdjustSize( float *x, float *y, float *w, float *h );
  5874. +void CL_FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a );
  5875. +void CL_FillRGBABlend( int x, int y, int width, int height, int r, int g, int b, int a );
  5876. void CL_PlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr );
  5877. void CL_PlayerTraceExt( float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ), pmtrace_t *tr );
  5878. void CL_SetTraceHull( int hull );
  5879. @@ -672,7 +729,13 @@ void SCR_MakeScreenShot( void );
  5880. void SCR_MakeLevelShot( void );
  5881. void SCR_NetSpeeds( void );
  5882. void SCR_RSpeeds( void );
  5883. -void SCR_DrawFPS( void );
  5884. +void SCR_DrawFPS( int height );
  5885. +
  5886. +//
  5887. +// cl_netgraph.c
  5888. +//
  5889. +void CL_InitNetgraph( void );
  5890. +void SCR_DrawNetGraph( void );
  5891.  
  5892. //
  5893. // cl_view.c
  5894. @@ -683,11 +746,7 @@ void V_Shutdown( void );
  5895. qboolean V_PreRender( void );
  5896. void V_PostRender( void );
  5897. void V_RenderView( void );
  5898. -void V_SetupOverviewState( void );
  5899. -void V_ProcessOverviewCmds( usercmd_t *cmd );
  5900. -void V_MergeOverviewRefdef( ref_params_t *fd );
  5901. -void V_ProcessShowTexturesCmds( usercmd_t *cmd );
  5902. -void V_WriteOverviewScript( void );
  5903. +void V_SetupRefDef( void );
  5904.  
  5905. //
  5906. // cl_pmove.c
  5907. @@ -705,6 +764,9 @@ cl_entity_t *CL_GetWaterEntity( const float *rgflPos );
  5908. void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, qboolean runfuncs, double time );
  5909. pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
  5910. void CL_ClearPhysEnts( void );
  5911. +void CL_PushPMStates( void );
  5912. +void CL_PopPMStates( void );
  5913. +void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
  5914.  
  5915. //
  5916. // cl_studio.c
  5917. @@ -714,12 +776,13 @@ void CL_InitStudioAPI( void );
  5918. //
  5919. // cl_frame.c
  5920. //
  5921. -void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
  5922. +int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
  5923. qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
  5924. void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp );
  5925. qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius );
  5926. void CL_UpdateEntityFields( cl_entity_t *ent );
  5927. qboolean CL_IsPlayerIndex( int idx );
  5928. +void CL_SetIdealPitch( void );
  5929.  
  5930. //
  5931. // cl_remap.c
  5932. @@ -761,6 +824,7 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType );
  5933. void CL_RegisterMuzzleFlashes( void );
  5934. void CL_ReadPointFile_f( void );
  5935. void CL_ReadLineFile_f( void );
  5936. +void CL_RunLightStyles( void );
  5937.  
  5938. //
  5939. // console.c
  5940. @@ -769,6 +833,7 @@ extern convar_t *con_fontsize;
  5941. qboolean Con_Visible( void );
  5942. void Con_Init( void );
  5943. void Con_VidInit( void );
  5944. +void Con_Shutdown( void );
  5945. void Con_ToggleConsole_f( void );
  5946. void Con_ClearNotify( void );
  5947. void Con_DrawDebug( void );
  5948. @@ -786,7 +851,7 @@ void Con_CharEvent( int key );
  5949. void Con_RestoreFont( void );
  5950. void Key_Console( int key );
  5951. void Key_Message( int key );
  5952. -void Con_Close( void );
  5953. +void Con_FastClose( void );
  5954.  
  5955. //
  5956. // s_main.c
  5957. @@ -810,7 +875,7 @@ void S_RenderFrame( struct ref_params_s *fd );
  5958. void S_ExtraUpdate( void );
  5959.  
  5960. //
  5961. -// cl_menu.c
  5962. +// cl_gameui.c
  5963. //
  5964. void UI_UnloadProgs( void );
  5965. qboolean UI_LoadProgs( void );
  5966. diff --git b/engine/client/gl_backend.c a/engine/client/gl_backend.c
  5967. index f0188a5..6f477e3 100644
  5968. --- b/engine/client/gl_backend.c
  5969. +++ a/engine/client/gl_backend.c
  5970. @@ -76,7 +76,7 @@ void GL_BackendEndFrame( void )
  5971. break;
  5972. case 2:
  5973. Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "visible leafs:\n%3i leafs\ncurrent leaf %3i",
  5974. - r_stats.c_world_leafs, r_viewleaf - cl.worldmodel->leafs );
  5975. + r_stats.c_world_leafs, Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ) - cl.worldmodel->leafs );
  5976. break;
  5977. case 3:
  5978. Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i studio models drawn\n%3i sprites drawn",
  5979. @@ -182,10 +182,6 @@ void GL_SelectTexture( GLint tmu )
  5980. if( tmu < glConfig.max_texture_coords )
  5981. pglClientActiveTextureARB( tmu + GL_TEXTURE0_ARB );
  5982. }
  5983. - else if( pglSelectTextureSGIS )
  5984. - {
  5985. - pglSelectTextureSGIS( tmu + GL_TEXTURE0_SGIS );
  5986. - }
  5987. }
  5988.  
  5989. /*
  5990. @@ -228,20 +224,31 @@ void GL_CleanUpTextureUnits( int last )
  5991. }
  5992.  
  5993. /*
  5994. +==============
  5995. +GL_CleanupAllTextureUnits
  5996. +==============
  5997. +*/
  5998. +void GL_CleanupAllTextureUnits( void )
  5999. +{
  6000. + // force to cleanup all the units
  6001. + GL_SelectTexture( GL_MaxTextureUnits() - 1 );
  6002. + GL_CleanUpTextureUnits( 0 );
  6003. +}
  6004. +
  6005. +/*
  6006. =================
  6007. GL_MultiTexCoord2f
  6008. =================
  6009. */
  6010. void GL_MultiTexCoord2f( GLenum texture, GLfloat s, GLfloat t )
  6011. {
  6012. + if( !GL_Support( GL_ARB_MULTITEXTURE ))
  6013. + return;
  6014. +
  6015. if( pglMultiTexCoord2f )
  6016. {
  6017. pglMultiTexCoord2f( texture + GL_TEXTURE0_ARB, s, t );
  6018. }
  6019. - else if( pglMTexCoord2fSGIS )
  6020. - {
  6021. - pglMTexCoord2fSGIS( texture + GL_TEXTURE0_SGIS, s, t );
  6022. - }
  6023. }
  6024.  
  6025. /*
  6026. @@ -470,6 +477,37 @@ void VID_ImageAdjustGamma( byte *in, uint width, uint height )
  6027. }
  6028. }
  6029.  
  6030. +/*
  6031. +===============
  6032. +VID_WriteOverviewScript
  6033. +
  6034. +Create overview script file
  6035. +===============
  6036. +*/
  6037. +void VID_WriteOverviewScript( void )
  6038. +{
  6039. + ref_overview_t *ov = &clgame.overView;
  6040. + string filename;
  6041. + file_t *f;
  6042. +
  6043. + Q_snprintf( filename, sizeof( filename ), "overviews/%s.txt", clgame.mapname );
  6044. +
  6045. + f = FS_Open( filename, "w", false );
  6046. + if( !f ) return;
  6047. +
  6048. + FS_Printf( f, "// overview description file for %s.bsp\n\n", clgame.mapname );
  6049. + FS_Print( f, "global\n{\n" );
  6050. + FS_Printf( f, "\tZOOM\t%.2f\n", ov->flZoom );
  6051. + FS_Printf( f, "\tORIGIN\t%.2f\t%.2f\t%.2f\n", ov->origin[0], ov->origin[1], ov->origin[2] );
  6052. + FS_Printf( f, "\tROTATED\t%i\n", ov->rotated ? 1 : 0 );
  6053. + FS_Print( f, "}\n\nlayer\n{\n" );
  6054. + FS_Printf( f, "\tIMAGE\t\"overviews/%s.bmp\"\n", clgame.mapname );
  6055. + FS_Printf( f, "\tHEIGHT\t%.2f\n", ov->zFar ); // ???
  6056. + FS_Print( f, "}\n" );
  6057. +
  6058. + FS_Close( f );
  6059. +}
  6060. +
  6061. qboolean VID_ScreenShot( const char *filename, int shot_type )
  6062. {
  6063. rgbdata_t *r_shot;
  6064. @@ -519,7 +557,7 @@ qboolean VID_ScreenShot( const char *filename, int shot_type )
  6065. width = 320;
  6066. break;
  6067. case VID_MAPSHOT:
  6068. - V_WriteOverviewScript(); // store overview script too
  6069. + VID_WriteOverviewScript(); // store overview script too
  6070. flags |= IMAGE_RESAMPLE|IMAGE_QUANTIZE; // GoldSrc request overviews in 8-bit format
  6071. height = 768;
  6072. width = 1024;
  6073. @@ -637,8 +675,8 @@ void R_ShowTextures( void )
  6074. {
  6075. gltexture_t *image;
  6076. float x, y, w, h;
  6077. - int i, j, k, base_w, base_h;
  6078. int total, start, end;
  6079. + int i, j, k, base_w, base_h;
  6080. rgba_t color = { 192, 192, 192, 255 };
  6081. int charHeight, numTries = 0;
  6082. static qboolean showHelp = true;
  6083. @@ -649,15 +687,16 @@ void R_ShowTextures( void )
  6084.  
  6085. if( showHelp )
  6086. {
  6087. - CL_CenterPrint( "use '<-' and '->' keys for view all the textures", 0.25f );
  6088. + CL_CenterPrint( "use '<-' and '->' keys to change atlas page, ESC to quit", 0.25f );
  6089. showHelp = false;
  6090. }
  6091.  
  6092. + GL_SetRenderMode( kRenderNormal );
  6093. pglClear( GL_COLOR_BUFFER_BIT );
  6094. pglFinish();
  6095.  
  6096. - base_w = 8;
  6097. - base_h = 6;
  6098. + base_w = 8; // textures view by horizontal
  6099. + base_h = 6; // textures view by vertical
  6100.  
  6101. rebuild_page:
  6102. total = base_w * base_h;
  6103. @@ -698,27 +737,27 @@ rebuild_page:
  6104. pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
  6105. GL_Bind( GL_TEXTURE0, i ); // NOTE: don't use image->texnum here, because skybox has a 'wrong' indexes
  6106.  
  6107. - if(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE ))
  6108. + if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE ))
  6109. pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE );
  6110.  
  6111. pglBegin( GL_QUADS );
  6112. pglTexCoord2f( 0, 0 );
  6113. pglVertex2f( x, y );
  6114. - if( image->flags & TF_TEXTURE_RECTANGLE )
  6115. + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
  6116. pglTexCoord2f( image->width, 0 );
  6117. else pglTexCoord2f( 1, 0 );
  6118. pglVertex2f( x + w, y );
  6119. - if( image->flags & TF_TEXTURE_RECTANGLE )
  6120. + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
  6121. pglTexCoord2f( image->width, image->height );
  6122. else pglTexCoord2f( 1, 1 );
  6123. pglVertex2f( x + w, y + h );
  6124. - if( image->flags & TF_TEXTURE_RECTANGLE )
  6125. + if( image->target == GL_TEXTURE_RECTANGLE_EXT )
  6126. pglTexCoord2f( 0, image->height );
  6127. else pglTexCoord2f( 0, 1 );
  6128. pglVertex2f( x, y + h );
  6129. pglEnd();
  6130.  
  6131. - if(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE ))
  6132. + if( FBitSet( image->flags, TF_DEPTHMAP ) && !FBitSet( image->flags, TF_NOCOMPARE ))
  6133. pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
  6134.  
  6135. FS_FileBase( image->name, shortname );
  6136. @@ -735,6 +774,4 @@ rebuild_page:
  6137.  
  6138. CL_DrawCenterPrint ();
  6139. pglFinish();
  6140. -}
  6141. -
  6142. -//=======================================================
  6143. \ No newline at end of file
  6144. +}
  6145. \ No newline at end of file
  6146. diff --git b/engine/client/gl_beams.c a/engine/client/gl_beams.c
  6147. index 0697335..d601abf 100644
  6148. --- b/engine/client/gl_beams.c
  6149. +++ a/engine/client/gl_beams.c
  6150. @@ -33,7 +33,6 @@ typedef struct
  6151. vec3_t color;
  6152. float texcoord; // Y texture coordinate
  6153. float width;
  6154. - float alpha;
  6155. } beamseg_t;
  6156.  
  6157. static float rgNoise[NOISE_DIVISIONS+1]; // global noise array
  6158. @@ -88,24 +87,12 @@ static cl_entity_t *CL_GetBeamEntityByIndex( int index )
  6159. return ent;
  6160. }
  6161.  
  6162. -void BeamNormalizeColor( BEAM *pBeam, float r, float g, float b, float brightness )
  6163. +void BeamNormalizeColor( BEAM *pBeam, int r, int g, int b, float brightness )
  6164. {
  6165. - float max, scale;
  6166. -
  6167. - max = max( max( r, g ), b );
  6168. -
  6169. - if( max == 0 )
  6170. - {
  6171. - pBeam->r = pBeam->g = pBeam->b = 255.0f;
  6172. - pBeam->brightness = brightness;
  6173. - }
  6174. -
  6175. - scale = 255.0f / max;
  6176. -
  6177. - pBeam->r = r * scale;
  6178. - pBeam->g = g * scale;
  6179. - pBeam->b = b * scale;
  6180. - pBeam->brightness = ( brightness > 1.0f ) ? brightness : brightness * 255.0f;
  6181. + pBeam->r = (float)r;
  6182. + pBeam->g = (float)g;
  6183. + pBeam->b = (float)b;
  6184. + pBeam->brightness = brightness;
  6185. }
  6186.  
  6187. static qboolean ComputeBeamEntPosition( int beamEnt, vec3_t pt )
  6188. @@ -269,7 +256,6 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
  6189. vec3_t vPoint1, vPoint2;
  6190.  
  6191. ASSERT( noiseIndex < ( NOISE_DIVISIONS << 16 ));
  6192. - nextSeg.alpha = 1.0f;
  6193.  
  6194. fraction = i * div;
  6195.  
  6196. @@ -350,12 +336,12 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
  6197. VectorMA( curSeg.pos, ( curSeg.width * 0.5f ), vAveNormal, vPoint1 );
  6198. VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vAveNormal, vPoint2 );
  6199.  
  6200. - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
  6201. + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
  6202. pglTexCoord2f( 0.0f, curSeg.texcoord );
  6203. pglNormal3fv( vAveNormal );
  6204. pglVertex3fv( vPoint1 );
  6205.  
  6206. - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
  6207. + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
  6208. pglTexCoord2f( 1.0f, curSeg.texcoord );
  6209. pglNormal3fv( vAveNormal );
  6210. pglVertex3fv( vPoint2 );
  6211. @@ -371,12 +357,12 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3
  6212. VectorMA( curSeg.pos, (-curSeg.width * 0.5f ), vLastNormal, vPoint2 );
  6213.  
  6214. // specify the points.
  6215. - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
  6216. + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
  6217. pglTexCoord2f( 0.0f, curSeg.texcoord );
  6218. pglNormal3fv( vLastNormal );
  6219. pglVertex3fv( vPoint1 );
  6220.  
  6221. - pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], curSeg.alpha );
  6222. + pglColor4f( curSeg.color[0], curSeg.color[1], curSeg.color[2], 1.0f );
  6223. pglTexCoord2f( 1.0f, curSeg.texcoord );
  6224. pglNormal3fv( vLastNormal );
  6225. pglVertex3fv( vPoint2 );
  6226. @@ -1442,12 +1428,10 @@ void CL_DrawBeam( BEAM *pbeam )
  6227. pStart = CL_GetBeamEntityByIndex( pbeam->startEntity );
  6228. if( pStart && pStart->curstate.rendermode != kRenderNormal )
  6229. pbeam->brightness = pStart->curstate.renderamt;
  6230. - }
  6231. -
  6232. - VectorScale( color, ( pbeam->brightness / 255.0f ), color );
  6233. - VectorScale( color, ( 1.0f / 255.0f ), color );
  6234.  
  6235. - pglShadeModel( GL_SMOOTH );
  6236. + VectorScale( color, ( pbeam->brightness / 255.0f ), color );
  6237. + VectorScale( color, ( 1.0f / 255.0f ), color );
  6238. + }
  6239.  
  6240. switch( pbeam->type )
  6241. {
  6242. @@ -1478,7 +1462,6 @@ void CL_DrawBeam( BEAM *pbeam )
  6243. MsgDev( D_ERROR, "CL_DrawBeam: Unknown beam type %i\n", pbeam->type );
  6244. break;
  6245. }
  6246. - pglShadeModel( GL_FLAT );
  6247. }
  6248.  
  6249. /*
  6250. @@ -1517,9 +1500,9 @@ void CL_DrawCustomBeam( cl_entity_t *pbeam )
  6251. beam.width = pbeam->curstate.scale;
  6252. beam.amplitude = (float)(pbeam->curstate.body * 0.1f);
  6253. beam.brightness = pbeam->curstate.renderamt;
  6254. - beam.r = pbeam->curstate.rendercolor.r;
  6255. - beam.g = pbeam->curstate.rendercolor.g;
  6256. - beam.b = pbeam->curstate.rendercolor.b;
  6257. + beam.r = pbeam->curstate.rendercolor.r / 255.0f;
  6258. + beam.g = pbeam->curstate.rendercolor.g / 255.0f;
  6259. + beam.b = pbeam->curstate.rendercolor.b / 255.0f;
  6260. beam.flags = 0;
  6261.  
  6262. VectorSubtract( beam.target, beam.source, beam.delta );
  6263. @@ -1985,9 +1968,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
  6264. life = (float)(MSG_ReadByte( msg ) * 0.1f);
  6265. width = (float)(MSG_ReadByte( msg ) * 0.1f);
  6266. noise = (float)(MSG_ReadByte( msg ) * 0.1f);
  6267. - r = (float)MSG_ReadByte( msg );
  6268. - g = (float)MSG_ReadByte( msg );
  6269. - b = (float)MSG_ReadByte( msg );
  6270. + r = (float)MSG_ReadByte( msg ) / 255.0f;
  6271. + g = (float)MSG_ReadByte( msg ) / 255.0f;
  6272. + b = (float)MSG_ReadByte( msg ) / 255.0f;
  6273. brightness = (float)MSG_ReadByte( msg );
  6274. speed = (float)(MSG_ReadByte( msg ) * 0.1f);
  6275. CL_BeamPoints( start, end, modelIndex, life, width, noise, brightness, speed, startFrame,
  6276. @@ -2004,9 +1987,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
  6277. life = (float)(MSG_ReadByte( msg ) * 0.1f);
  6278. width = (float)(MSG_ReadByte( msg ) * 0.1f);
  6279. noise = (float)(MSG_ReadByte( msg ) * 0.01f);
  6280. - r = (float)MSG_ReadByte( msg );
  6281. - g = (float)MSG_ReadByte( msg );
  6282. - b = (float)MSG_ReadByte( msg );
  6283. + r = (float)MSG_ReadByte( msg ) / 255.0f;
  6284. + g = (float)MSG_ReadByte( msg ) / 255.0f;
  6285. + b = (float)MSG_ReadByte( msg ) / 255.0f;
  6286. brightness = (float)MSG_ReadByte( msg );
  6287. speed = (float)(MSG_ReadByte( msg ) * 0.1f);
  6288. CL_BeamEntPoint( startEnt, end, modelIndex, life, width, noise, brightness, speed, startFrame,
  6289. @@ -2034,9 +2017,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
  6290. life = (float)(MSG_ReadByte( msg ) * 0.1f);
  6291. width = (float)(MSG_ReadByte( msg ) * 0.1f);
  6292. noise = (float)(MSG_ReadByte( msg ) * 0.01f);
  6293. - r = (float)MSG_ReadByte( msg );
  6294. - g = (float)MSG_ReadByte( msg );
  6295. - b = (float)MSG_ReadByte( msg );
  6296. + r = (float)MSG_ReadByte( msg ) / 255.0f;
  6297. + g = (float)MSG_ReadByte( msg ) / 255.0f;
  6298. + b = (float)MSG_ReadByte( msg ) / 255.0f;
  6299. brightness = (float)MSG_ReadByte( msg );
  6300. speed = (float)(MSG_ReadByte( msg ) * 0.1f);
  6301. CL_BeamEnts( startEnt, endEnt, modelIndex, life, width, noise, brightness, speed, startFrame,
  6302. @@ -2071,9 +2054,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
  6303. life = (float)(MSG_ReadByte( msg ) * 0.1f);
  6304. width = (float)MSG_ReadByte( msg );
  6305. noise = (float)(MSG_ReadByte( msg ) * 0.1f);
  6306. - r = (float)MSG_ReadByte( msg );
  6307. - g = (float)MSG_ReadByte( msg );
  6308. - b = (float)MSG_ReadByte( msg );
  6309. + r = (float)MSG_ReadByte( msg ) / 255.0f;
  6310. + g = (float)MSG_ReadByte( msg ) / 255.0f;
  6311. + b = (float)MSG_ReadByte( msg ) / 255.0f;
  6312. brightness = (float)MSG_ReadByte( msg );
  6313. speed = (float)(MSG_ReadByte( msg ) * 0.1f);
  6314. CL_BeamCirclePoints( beamType, start, end, modelIndex, life, width, noise, brightness, speed,
  6315. @@ -2099,9 +2082,9 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType )
  6316. life = (float)(MSG_ReadByte( msg ) * 0.1f);
  6317. width = (float)(MSG_ReadByte( msg ) * 0.1f);
  6318. noise = (float)(MSG_ReadByte( msg ) * 0.1f);
  6319. - r = (float)MSG_ReadByte( msg );
  6320. - g = (float)MSG_ReadByte( msg );
  6321. - b = (float)MSG_ReadByte( msg );
  6322. + r = (float)MSG_ReadByte( msg ) / 255.0f;
  6323. + g = (float)MSG_ReadByte( msg ) / 255.0f;
  6324. + b = (float)MSG_ReadByte( msg ) / 255.0f;
  6325. brightness = (float)MSG_ReadByte( msg );
  6326. speed = (float)(MSG_ReadByte( msg ) * 0.1f);
  6327. CL_BeamRing( startEnt, endEnt, modelIndex, life, width, noise, brightness, speed, startFrame,
  6328. @@ -2166,7 +2149,7 @@ void CL_ReadLineFile_f( void )
  6329.  
  6330. if( token[0] != '-' )
  6331. {
  6332. - MsgDev( D_ERROR, "%s is corrupted\n" );
  6333. + MsgDev( D_ERROR, "%s is corrupted\n", filename );
  6334. break;
  6335. }
  6336.  
  6337. diff --git b/engine/client/gl_cull.c a/engine/client/gl_cull.c
  6338. index 806c6e7..72eb1cb 100644
  6339. --- b/engine/client/gl_cull.c
  6340. +++ a/engine/client/gl_cull.c
  6341. @@ -180,7 +180,7 @@ qboolean R_CullSurface( msurface_t *surf, uint clipflags )
  6342.  
  6343. if( r_faceplanecull->integer && glState.faceCull != 0 )
  6344. {
  6345. - if( RI.currentWaveHeight == 0.0f )
  6346. + if( e->curstate.scale == 0.0f )
  6347. {
  6348. if( !VectorIsNull( surf->plane->normal ))
  6349. {
  6350. diff --git b/engine/client/gl_decals.c a/engine/client/gl_decals.c
  6351. index 57fe7c6..20371da 100644
  6352. --- b/engine/client/gl_decals.c
  6353. +++ a/engine/client/gl_decals.c
  6354. @@ -404,22 +404,23 @@ static void R_DecalVertsLight( float *v, msurface_t *surf, int vertCount )
  6355. {
  6356. float s, t;
  6357. mtexinfo_t *tex;
  6358. - int j;
  6359. + int j, sample_size;
  6360.  
  6361. + sample_size = Mod_SampleSizeForFace( surf );
  6362. tex = surf->texinfo;
  6363.  
  6364. for( j = 0; j < vertCount; j++, v += VERTEXSIZE )
  6365. {
  6366. // lightmap texture coordinates
  6367. s = DotProduct( v, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
  6368. - s += surf->light_s * LM_SAMPLE_SIZE;
  6369. - s += LM_SAMPLE_SIZE >> 1;
  6370. - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
  6371. + s += surf->light_s * sample_size;
  6372. + s += sample_size >> 1;
  6373. + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
  6374.  
  6375. t = DotProduct( v, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
  6376. - t += surf->light_t * LM_SAMPLE_SIZE;
  6377. - t += LM_SAMPLE_SIZE >> 1;
  6378. - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
  6379. + t += surf->light_t * sample_size;
  6380. + t += sample_size >> 1;
  6381. + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
  6382.  
  6383. v[5] = s;
  6384. v[6] = t;
  6385. @@ -1232,7 +1233,11 @@ void R_DecalRemoveAll( int textureIndex )
  6386. {
  6387. pdecal = &gDecalPool[i];
  6388.  
  6389. - if( !textureIndex || pdecal->texture == textureIndex )
  6390. + // don't remove permanent decals
  6391. + if( pdecal->flags & FDECAL_PERMANENT )
  6392. + continue;
  6393. +
  6394. + if( !textureIndex || ( pdecal->texture == textureIndex ))
  6395. R_DecalUnlink( pdecal );
  6396. }
  6397. }
  6398. diff --git b/engine/client/gl_draw.c a/engine/client/gl_draw.c
  6399. index 9c8cf7c..d8620f4 100644
  6400. --- b/engine/client/gl_draw.c
  6401. +++ a/engine/client/gl_draw.c
  6402. @@ -231,7 +231,7 @@ void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height,
  6403. tex->height = rows;
  6404.  
  6405. pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw );
  6406. - GL_TexFilter( tex, false );
  6407. + GL_ApplyTextureParams( tex );
  6408. }
  6409.  
  6410. /*
  6411. diff --git b/engine/client/gl_export.h a/engine/client/gl_export.h
  6412. index 9aefb51..1422401 100644
  6413. --- b/engine/client/gl_export.h
  6414. +++ a/engine/client/gl_export.h
  6415. @@ -235,6 +235,29 @@ typedef float GLmatrix[16];
  6416. #define GL_PROXY_TEXTURE_2D 0x8064
  6417. #define GL_MAX_TEXTURE_SIZE 0x0D33
  6418.  
  6419. +#define GL_RG 0x8227
  6420. +#define GL_RG_INTEGER 0x8228
  6421. +#define GL_R8 0x8229
  6422. +#define GL_R16 0x822A
  6423. +#define GL_RG8 0x822B
  6424. +#define GL_RG16 0x822C
  6425. +#define GL_R16F 0x822D
  6426. +#define GL_R32F 0x822E
  6427. +#define GL_RG16F 0x822F
  6428. +#define GL_RG32F 0x8230
  6429. +#define GL_R8I 0x8231
  6430. +#define GL_R8UI 0x8232
  6431. +#define GL_R16I 0x8233
  6432. +#define GL_R16UI 0x8234
  6433. +#define GL_R32I 0x8235
  6434. +#define GL_R32UI 0x8236
  6435. +#define GL_RG8I 0x8237
  6436. +#define GL_RG8UI 0x8238
  6437. +#define GL_RG16I 0x8239
  6438. +#define GL_RG16UI 0x823A
  6439. +#define GL_RG32I 0x823B
  6440. +#define GL_RG32UI 0x823C
  6441. +
  6442. // texture coord name
  6443. #define GL_S 0x2000
  6444. #define GL_T 0x2001
  6445. @@ -433,7 +456,7 @@ typedef float GLmatrix[16];
  6446. #define GL_TEXTURE_WRAP_R 0x8072
  6447. #define GL_MAX_3D_TEXTURE_SIZE 0x8073
  6448. #define GL_TEXTURE_BINDING_3D 0x806A
  6449. -
  6450. +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
  6451. #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910
  6452. #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911
  6453. #define GL_STENCIL_BACK_FUNC 0x8800
  6454. @@ -441,6 +464,24 @@ typedef float GLmatrix[16];
  6455. #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
  6456. #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
  6457.  
  6458. +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
  6459. +#define GL_DRAW_BUFFER0_ARB 0x8825
  6460. +#define GL_DRAW_BUFFER1_ARB 0x8826
  6461. +#define GL_DRAW_BUFFER2_ARB 0x8827
  6462. +#define GL_DRAW_BUFFER3_ARB 0x8828
  6463. +#define GL_DRAW_BUFFER4_ARB 0x8829
  6464. +#define GL_DRAW_BUFFER5_ARB 0x882A
  6465. +#define GL_DRAW_BUFFER6_ARB 0x882B
  6466. +#define GL_DRAW_BUFFER7_ARB 0x882C
  6467. +#define GL_DRAW_BUFFER8_ARB 0x882D
  6468. +#define GL_DRAW_BUFFER9_ARB 0x882E
  6469. +#define GL_DRAW_BUFFER10_ARB 0x882F
  6470. +#define GL_DRAW_BUFFER11_ARB 0x8830
  6471. +#define GL_DRAW_BUFFER12_ARB 0x8831
  6472. +#define GL_DRAW_BUFFER13_ARB 0x8832
  6473. +#define GL_DRAW_BUFFER14_ARB 0x8833
  6474. +#define GL_DRAW_BUFFER15_ARB 0x8834
  6475. +
  6476. #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
  6477. #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C
  6478. #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D
  6479. @@ -614,6 +655,15 @@ typedef float GLmatrix[16];
  6480. #define GL_DOT3_RGB_ARB 0x86AE
  6481. #define GL_DOT3_RGBA_ARB 0x86AF
  6482.  
  6483. +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18
  6484. +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19
  6485. +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A
  6486. +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B
  6487. +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C
  6488. +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D
  6489. +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF
  6490. +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E
  6491. +
  6492. #define GL_MULTISAMPLE_ARB 0x809D
  6493. #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
  6494. #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
  6495. @@ -719,6 +769,29 @@ typedef float GLmatrix[16];
  6496. #define GL_MAX_TEXTURE_COORDS_ARB 0x8871
  6497. #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
  6498.  
  6499. +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
  6500. +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
  6501. +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
  6502. +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
  6503. +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
  6504. +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
  6505. +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
  6506. +#define GL_DEBUG_SOURCE_API_ARB 0x8246
  6507. +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
  6508. +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
  6509. +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
  6510. +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
  6511. +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
  6512. +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
  6513. +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
  6514. +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
  6515. +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
  6516. +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
  6517. +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
  6518. +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
  6519. +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
  6520. +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
  6521. +
  6522. #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
  6523. #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
  6524. #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
  6525. @@ -1153,6 +1226,10 @@ void ( APIENTRY *pglDisableVertexAttribArrayARB)(GLuint index);
  6526. void ( APIENTRY *pglBindAttribLocationARB)(GLhandleARB programObj, GLuint index, const GLcharARB *name);
  6527. void ( APIENTRY *pglGetActiveAttribARB)(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
  6528. GLint ( APIENTRY *pglGetAttribLocationARB)(GLhandleARB programObj, const GLcharARB *name);
  6529. +void ( APIENTRY *pglBindFragDataLocation)(GLuint programObj, GLuint index, const GLcharARB *name);
  6530. +void ( APIENTRY *pglVertexAttrib2fARB)( GLuint index, GLfloat x, GLfloat y );
  6531. +void ( APIENTRY *pglVertexAttrib2fvARB)( GLuint index, const GLfloat *v );
  6532. +void ( APIENTRY *pglVertexAttrib3fvARB)( GLuint index, const GLfloat *v );
  6533. void ( APIENTRY *pglBindBufferARB) (GLenum target, GLuint buffer);
  6534. void ( APIENTRY *pglDeleteBuffersARB) (GLsizei n, const GLuint *buffers);
  6535. void ( APIENTRY *pglGenBuffersARB) (GLsizei n, GLuint *buffers);
  6536. @@ -1169,8 +1246,36 @@ void ( APIENTRY *pglEndQueryARB) (GLenum target);
  6537. void ( APIENTRY *pglGetQueryivARB) (GLenum target, GLenum pname, GLint *params);
  6538. void ( APIENTRY *pglGetQueryObjectivARB) (GLuint id, GLenum pname, GLint *params);
  6539. void ( APIENTRY *pglGetQueryObjectuivARB) (GLuint id, GLenum pname, GLuint *params);
  6540. -void ( APIENTRY * pglSelectTextureSGIS) ( GLenum );
  6541. -void ( APIENTRY * pglMTexCoord2fSGIS) ( GLenum, GLfloat, GLfloat );
  6542. +typedef void ( APIENTRY *pglDebugProcARB)( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLcharARB* message, GLvoid* userParam );
  6543. +void ( APIENTRY *pglDebugMessageControlARB)( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled );
  6544. +void ( APIENTRY *pglDebugMessageInsertARB)( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* buf );
  6545. +void ( APIENTRY *pglDebugMessageCallbackARB)( pglDebugProcARB callback, void* userParam );
  6546. +GLuint ( APIENTRY *pglGetDebugMessageLogARB)( GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLuint* severities, GLsizei* lengths, char* messageLog );
  6547. +GLboolean ( APIENTRY *pglIsRenderbuffer )(GLuint renderbuffer);
  6548. +void ( APIENTRY *pglBindRenderbuffer )(GLenum target, GLuint renderbuffer);
  6549. +void ( APIENTRY *pglDeleteRenderbuffers )(GLsizei n, const GLuint *renderbuffers);
  6550. +void ( APIENTRY *pglGenRenderbuffers )(GLsizei n, GLuint *renderbuffers);
  6551. +void ( APIENTRY *pglRenderbufferStorage )(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
  6552. +void ( APIENTRY *pglRenderbufferStorageMultisample )(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
  6553. +void ( APIENTRY *pglGetRenderbufferParameteriv )(GLenum target, GLenum pname, GLint *params);
  6554. +GLboolean (APIENTRY *pglIsFramebuffer )(GLuint framebuffer);
  6555. +void ( APIENTRY *pglBindFramebuffer )(GLenum target, GLuint framebuffer);
  6556. +void ( APIENTRY *pglDeleteFramebuffers )(GLsizei n, const GLuint *framebuffers);
  6557. +void ( APIENTRY *pglGenFramebuffers )(GLsizei n, GLuint *framebuffers);
  6558. +GLenum ( APIENTRY *pglCheckFramebufferStatus )(GLenum target);
  6559. +void ( APIENTRY *pglFramebufferTexture1D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
  6560. +void ( APIENTRY *pglFramebufferTexture2D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
  6561. +void ( APIENTRY *pglFramebufferTexture3D )(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer);
  6562. +void ( APIENTRY *pglFramebufferTextureLayer )(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
  6563. +void ( APIENTRY *pglFramebufferRenderbuffer )(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
  6564. +void ( APIENTRY *pglGetFramebufferAttachmentParameteriv )(GLenum target, GLenum attachment, GLenum pname, GLint *params);
  6565. +void ( APIENTRY *pglBlitFramebuffer )(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
  6566. +void ( APIENTRY *pglDrawBuffersARB)( GLsizei n, const GLenum *bufs );
  6567. +void ( APIENTRY *pglGenerateMipmap )( GLenum target );
  6568. +void ( APIENTRY *pglBindVertexArray )( GLuint array );
  6569. +void ( APIENTRY *pglDeleteVertexArrays )( GLsizei n, const GLuint *arrays );
  6570. +void ( APIENTRY *pglGenVertexArrays )( GLsizei n, const GLuint *arrays );
  6571. +GLboolean ( APIENTRY *pglIsVertexArray )( GLuint array );
  6572. void ( APIENTRY * pglSwapInterval) ( int interval );
  6573. extern void *pglGetProcAddress( const GLubyte * );
  6574. BOOL ( WINAPI * pwglSwapBuffers)(HDC);
  6575. @@ -1191,5 +1296,6 @@ BOOL ( WINAPI * pwglRealizeLayerPalette)(HDC, int, BOOL);
  6576. BOOL ( WINAPI * pwglSwapLayerBuffers)(HDC, UINT);
  6577. BOOL ( WINAPI * pwglSwapIntervalEXT)( int interval );
  6578. HGLRC ( WINAPI * pwglCreateContextAttribsARB)( HDC hDC, HGLRC hShareContext, const int *attribList );
  6579. +const char *( WINAPI * pwglGetExtensionsStringEXT)( void );
  6580.  
  6581. #endif//GL_EXPORT_H
  6582. \ No newline at end of file
  6583. diff --git b/engine/client/gl_image.c a/engine/client/gl_image.c
  6584. index e93e5e7..46e9cf8 100644
  6585. --- b/engine/client/gl_image.c
  6586. +++ a/engine/client/gl_image.c
  6587. @@ -18,16 +18,13 @@ GNU General Public License for more details.
  6588. #include "gl_local.h"
  6589. #include "studio.h"
  6590.  
  6591. -#define TEXTURES_HASH_SIZE 64
  6592. +#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
  6593.  
  6594. -static int r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
  6595. -static int r_textureMagFilter = GL_LINEAR;
  6596. -static gltexture_t r_textures[MAX_TEXTURES];
  6597. -static gltexture_t *r_texturesHashTable[TEXTURES_HASH_SIZE];
  6598. -static int r_numTextures;
  6599. -static byte *scaledImage = NULL; // pointer to a scaled image
  6600. -static byte data2D[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; // intermediate texbuffer
  6601. -static rgbdata_t r_image; // generic pixelbuffer used for internal textures
  6602. +static gltexture_t r_textures[MAX_TEXTURES];
  6603. +static gltexture_t *r_texturesHashTable[TEXTURES_HASH_SIZE];
  6604. +static int r_numTextures;
  6605. +static byte data2D[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4]; // intermediate texbuffer
  6606. +static rgbdata_t r_image; // generic pixelbuffer used for internal textures
  6607.  
  6608. // internal tables
  6609. static vec3_t r_luminanceTable[256]; // RGB to luminance
  6610. @@ -43,7 +40,25 @@ static byte r_particleTexture[8][8] =
  6611. {0,0,0,0,0,0,0,0},
  6612. };
  6613.  
  6614. -const char *GL_Target( GLenum target )
  6615. +/*
  6616. +=================
  6617. +R_GetTexture
  6618. +
  6619. +acess to array elem
  6620. +=================
  6621. +*/
  6622. +gltexture_t *R_GetTexture( GLenum texnum )
  6623. +{
  6624. + ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
  6625. + return &r_textures[texnum];
  6626. +}
  6627. +
  6628. +/*
  6629. +=================
  6630. +GL_TargetToString
  6631. +=================
  6632. +*/
  6633. +static const char *GL_TargetToString( GLenum target )
  6634. {
  6635. switch( target )
  6636. {
  6637. @@ -55,6 +70,8 @@ const char *GL_Target( GLenum target )
  6638. return "3D";
  6639. case GL_TEXTURE_CUBE_MAP_ARB:
  6640. return "Cube";
  6641. + case GL_TEXTURE_2D_ARRAY_EXT:
  6642. + return "Array";
  6643. case GL_TEXTURE_RECTANGLE_EXT:
  6644. return "Rect";
  6645. }
  6646. @@ -69,6 +86,7 @@ GL_Bind
  6647. void GL_Bind( GLint tmu, GLenum texnum )
  6648. {
  6649. gltexture_t *texture;
  6650. + GLuint glTarget;
  6651.  
  6652. // missed texture ?
  6653. if( texnum <= 0 ) texnum = tr.defaultTexture;
  6654. @@ -79,12 +97,16 @@ void GL_Bind( GLint tmu, GLenum texnum )
  6655. else tmu = glState.activeTMU;
  6656.  
  6657. texture = &r_textures[texnum];
  6658. + glTarget = texture->target;
  6659. +
  6660. + if( glTarget == GL_TEXTURE_2D_ARRAY_EXT )
  6661. + glTarget = GL_TEXTURE_2D;
  6662.  
  6663. - if( glState.currentTextureTargets[tmu] != texture->target )
  6664. + if( glState.currentTextureTargets[tmu] != glTarget )
  6665. {
  6666. if( glState.currentTextureTargets[tmu] != GL_NONE )
  6667. pglDisable( glState.currentTextureTargets[tmu] );
  6668. - glState.currentTextureTargets[tmu] = texture->target;
  6669. + glState.currentTextureTargets[tmu] = glTarget;
  6670. pglEnable( glState.currentTextureTargets[tmu] );
  6671. }
  6672.  
  6673. @@ -97,125 +119,103 @@ void GL_Bind( GLint tmu, GLenum texnum )
  6674.  
  6675. /*
  6676. =================
  6677. -R_GetTexture
  6678. +GL_ApplyTextureParams
  6679. =================
  6680. */
  6681. -gltexture_t *R_GetTexture( GLenum texnum )
  6682. +void GL_ApplyTextureParams( gltexture_t *tex )
  6683. {
  6684. - ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
  6685. - return &r_textures[texnum];
  6686. -}
  6687. + vec4_t border = { 0.0f, 0.0f, 0.0f, 1.0f };
  6688.  
  6689. -/*
  6690. -=================
  6691. -GL_SetTextureType
  6692. -
  6693. -Just for debug (r_showtextures uses it)
  6694. -=================
  6695. -*/
  6696. -void GL_SetTextureType( GLenum texnum, GLenum type )
  6697. -{
  6698. - if( texnum <= 0 ) return;
  6699. - ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
  6700. - r_textures[texnum].texType = type;
  6701. -}
  6702. -
  6703. -/*
  6704. -=================
  6705. -GL_TexFilter
  6706. -=================
  6707. -*/
  6708. -void GL_TexFilter( gltexture_t *tex, qboolean update )
  6709. -{
  6710. - qboolean allowNearest;
  6711. - vec4_t zeroClampBorder = { 0.0f, 0.0f, 0.0f, 1.0f };
  6712. - vec4_t alphaZeroClampBorder = { 0.0f, 0.0f, 0.0f, 0.0f };
  6713. -
  6714. - switch( tex->texType )
  6715. - {
  6716. - case TEX_NOMIP:
  6717. - case TEX_CUBEMAP:
  6718. - case TEX_LIGHTMAP:
  6719. - allowNearest = false;
  6720. - break;
  6721. - default:
  6722. - allowNearest = true;
  6723. - break;
  6724. - }
  6725. + ASSERT( tex != NULL );
  6726.  
  6727. // set texture filter
  6728. - if( tex->flags & TF_DEPTHMAP )
  6729. + if( FBitSet( tex->flags, TF_DEPTHMAP ))
  6730. {
  6731. - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  6732. - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6733. -
  6734. - if( !( tex->flags & TF_NOCOMPARE ))
  6735. + if( !FBitSet( tex->flags, TF_NOCOMPARE ))
  6736. {
  6737. - pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
  6738. pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
  6739. + pglTexParameteri( tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
  6740. }
  6741.  
  6742. - if( tex->flags & TF_LUMINANCE )
  6743. + if( FBitSet( tex->flags, TF_LUMINANCE ))
  6744. pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE );
  6745. else pglTexParameteri( tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY );
  6746.  
  6747. + if( FBitSet( tex->flags, TF_NEAREST ))
  6748. + {
  6749. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  6750. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  6751. + }
  6752. + else
  6753. + {
  6754. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  6755. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6756. + }
  6757. +
  6758. + // allow max anisotropy as 1.0f on depth textures
  6759. if( GL_Support( GL_ANISOTROPY_EXT ))
  6760. pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f );
  6761. }
  6762. - else if( tex->flags & TF_NOMIPMAP )
  6763. + else if( FBitSet( tex->flags, TF_NOMIPMAP ) || tex->numMips <= 1 )
  6764. {
  6765. - if( tex->flags & TF_NEAREST )
  6766. + if( FBitSet( tex->flags, TF_NEAREST ))
  6767. {
  6768. pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  6769. pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  6770. }
  6771. else
  6772. {
  6773. - if( r_textureMagFilter == GL_NEAREST && allowNearest )
  6774. - {
  6775. - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMagFilter );
  6776. - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
  6777. - }
  6778. - else
  6779. - {
  6780. - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  6781. - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6782. - }
  6783. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  6784. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6785. }
  6786. }
  6787. else
  6788. {
  6789. - if( tex->flags & TF_NEAREST )
  6790. + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->integer )
  6791. {
  6792. pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
  6793. pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  6794. }
  6795. else
  6796. {
  6797. - pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, r_textureMinFilter );
  6798. - pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, r_textureMagFilter );
  6799. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  6800. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6801. }
  6802.  
  6803. // set texture anisotropy if available
  6804. - if( GL_Support( GL_ANISOTROPY_EXT ) && !( tex->flags & TF_ALPHACONTRAST ))
  6805. + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ))
  6806. pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value );
  6807.  
  6808. // set texture LOD bias if available
  6809. - if( GL_Support( GL_TEXTURE_LODBIAS ))
  6810. + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ))
  6811. pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value );
  6812. }
  6813.  
  6814. - if( update ) return;
  6815. -
  6816. - if( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT ))
  6817. + // check if border is not supported
  6818. + if( FBitSet( tex->flags, TF_BORDER ) && !GL_Support( GL_CLAMP_TEXBORDER_EXT ))
  6819. {
  6820. - // border is not support, use clamp instead
  6821. - tex->flags &= ~(TF_BORDER||TF_ALPHA_BORDER);
  6822. - tex->flags |= TF_CLAMP;
  6823. + ClearBits( tex->flags, TF_BORDER );
  6824. + SetBits( tex->flags, TF_CLAMP );
  6825. }
  6826.  
  6827. + // only seamless cubemaps allows wrap 'clamp_to_border"
  6828. + if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && FBitSet( tex->flags, TF_BORDER ))
  6829. + ClearBits( tex->flags, TF_BORDER );
  6830. +
  6831. // set texture wrap
  6832. - if( tex->flags & TF_CLAMP )
  6833. + if( FBitSet( tex->flags, TF_BORDER ))
  6834. + {
  6835. + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  6836. +
  6837. + if( tex->target != GL_TEXTURE_1D )
  6838. + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  6839. +
  6840. + if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB )
  6841. + pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER );
  6842. +
  6843. + pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, border );
  6844. + }
  6845. + else if( FBitSet( tex->flags, TF_CLAMP ))
  6846. {
  6847. if( GL_Support( GL_CLAMPTOEDGE_EXT ))
  6848. {
  6849. @@ -238,21 +238,6 @@ void GL_TexFilter( gltexture_t *tex, qboolean update )
  6850. pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP );
  6851. }
  6852. }
  6853. - else if( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER ))
  6854. - {
  6855. - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  6856. -
  6857. - if( tex->target != GL_TEXTURE_1D )
  6858. - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  6859. -
  6860. - if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_CUBE_MAP_ARB )
  6861. - pglTexParameteri( tex->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER );
  6862. -
  6863. - if( tex->flags & TF_BORDER )
  6864. - pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, zeroClampBorder );
  6865. - else if( tex->flags & TF_ALPHA_BORDER )
  6866. - pglTexParameterfv( tex->target, GL_TEXTURE_BORDER_COLOR, alphaZeroClampBorder );
  6867. - }
  6868. else
  6869. {
  6870. pglTexParameteri( tex->target, GL_TEXTURE_WRAP_S, GL_REPEAT );
  6871. @@ -267,53 +252,49 @@ void GL_TexFilter( gltexture_t *tex, qboolean update )
  6872.  
  6873. /*
  6874. =================
  6875. -R_SetTextureParameters
  6876. +GL_UpdateTextureParams
  6877. =================
  6878. */
  6879. -void R_SetTextureParameters( void )
  6880. +static void GL_UpdateTextureParams( int iTexture )
  6881. {
  6882. - gltexture_t *texture;
  6883. - int i;
  6884. + gltexture_t *tex = &r_textures[iTexture];
  6885.  
  6886. - if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST" ))
  6887. - {
  6888. - r_textureMinFilter = GL_NEAREST;
  6889. - r_textureMagFilter = GL_NEAREST;
  6890. - }
  6891. - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR" ))
  6892. - {
  6893. - r_textureMinFilter = GL_LINEAR;
  6894. - r_textureMagFilter = GL_LINEAR;
  6895. - }
  6896. - else if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST_MIPMAP_NEAREST" ))
  6897. - {
  6898. - r_textureMinFilter = GL_NEAREST_MIPMAP_NEAREST;
  6899. - r_textureMagFilter = GL_NEAREST;
  6900. - }
  6901. - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR_MIPMAP_NEAREST" ))
  6902. - {
  6903. - r_textureMinFilter = GL_LINEAR_MIPMAP_NEAREST;
  6904. - r_textureMagFilter = GL_LINEAR;
  6905. - }
  6906. - else if( !Q_stricmp( gl_texturemode->string, "GL_NEAREST_MIPMAP_LINEAR" ))
  6907. - {
  6908. - r_textureMinFilter = GL_NEAREST_MIPMAP_LINEAR;
  6909. - r_textureMagFilter = GL_NEAREST;
  6910. - }
  6911. - else if( !Q_stricmp( gl_texturemode->string, "GL_LINEAR_MIPMAP_LINEAR" ))
  6912. + ASSERT( tex != NULL );
  6913. +
  6914. + if( !tex->texnum ) return; // free slot
  6915. +
  6916. + GL_Bind( GL_TEXTURE0, iTexture );
  6917. +
  6918. + // set texture anisotropy if available
  6919. + if( GL_Support( GL_ANISOTROPY_EXT ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP ))
  6920. + pglTexParameterf( tex->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy->value );
  6921. +
  6922. + // set texture LOD bias if available
  6923. + if( GL_Support( GL_TEXTURE_LOD_BIAS ) && ( tex->numMips > 1 ) && !FBitSet( tex->flags, TF_DEPTHMAP ))
  6924. + pglTexParameterf( tex->target, GL_TEXTURE_LOD_BIAS_EXT, gl_texture_lodbias->value );
  6925. +
  6926. + if( tex->numMips <= 1 ) return;
  6927. +
  6928. + if( FBitSet( tex->flags, TF_NEAREST ) || gl_texture_nearest->integer )
  6929. {
  6930. - r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
  6931. - r_textureMagFilter = GL_LINEAR;
  6932. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
  6933. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  6934. }
  6935. else
  6936. {
  6937. - MsgDev( D_ERROR, "gl_texturemode invalid mode %s, defaulting to GL_LINEAR_MIPMAP_LINEAR\n", gl_texturemode->string );
  6938. - Cvar_Set( "gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
  6939. - r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR;
  6940. - r_textureMagFilter = GL_LINEAR;
  6941. + pglTexParameteri( tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  6942. + pglTexParameteri( tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  6943. }
  6944. +}
  6945.  
  6946. - gl_texturemode->modified = false;
  6947. +/*
  6948. +=================
  6949. +R_SetTextureParameters
  6950. +=================
  6951. +*/
  6952. +void R_SetTextureParameters( void )
  6953. +{
  6954. + int i;
  6955.  
  6956. if( GL_Support( GL_ANISOTROPY_EXT ))
  6957. {
  6958. @@ -323,222 +304,21 @@ void R_SetTextureParameters( void )
  6959. Cvar_SetFloat( "gl_anisotropy", 1.0f );
  6960. }
  6961.  
  6962. - gl_texture_anisotropy->modified = false;
  6963. -
  6964. - if( GL_Support( GL_TEXTURE_LODBIAS ))
  6965. + if( GL_Support( GL_TEXTURE_LOD_BIAS ))
  6966. {
  6967. - if( gl_texture_lodbias->value > glConfig.max_texture_lodbias )
  6968. - Cvar_SetFloat( "gl_texture_lodbias", glConfig.max_texture_lodbias );
  6969. - else if( gl_texture_lodbias->value < -glConfig.max_texture_lodbias )
  6970. - Cvar_SetFloat( "gl_texture_lodbias", -glConfig.max_texture_lodbias );
  6971. + if( gl_texture_lodbias->value < -glConfig.max_texture_lod_bias )
  6972. + Cvar_SetFloat( "gl_texture_lodbias", -glConfig.max_texture_lod_bias );
  6973. + else if( gl_texture_lodbias->value > glConfig.max_texture_lod_bias )
  6974. + Cvar_SetFloat( "gl_texture_lodbias", glConfig.max_texture_lod_bias );
  6975. }
  6976.  
  6977. + gl_texture_anisotropy->modified = false;
  6978. gl_texture_lodbias->modified = false;
  6979. + gl_texture_nearest->modified = false;
  6980.  
  6981. // change all the existing mipmapped texture objects
  6982. - for( i = 0, texture = r_textures; i < r_numTextures; i++, texture++ )
  6983. - {
  6984. - if( !texture->texnum ) continue; // free slot
  6985. - GL_Bind( GL_TEXTURE0, i );
  6986. - GL_TexFilter( texture, true );
  6987. - }
  6988. -}
  6989. -
  6990. -/*
  6991. -===============
  6992. -R_TextureList_f
  6993. -===============
  6994. -*/
  6995. -void R_TextureList_f( void )
  6996. -{
  6997. - gltexture_t *image;
  6998. - int i, texCount, bytes = 0;
  6999. -
  7000. - Msg( "\n" );
  7001. - Msg(" -w-- -h-- -size- -fmt- type -data-- -encode-- -wrap-- -name--------\n" );
  7002. -
  7003. - for( i = texCount = 0, image = r_textures; i < r_numTextures; i++, image++ )
  7004. - {
  7005. - if( !image->texnum ) continue;
  7006. -
  7007. - bytes += image->size;
  7008. - texCount++;
  7009. -
  7010. - Msg( "%4i: ", i );
  7011. - Msg( "%4i %4i ", image->width, image->height );
  7012. - Msg( "%5ik ", image->size >> 10 );
  7013. -
  7014. - switch( image->format )
  7015. - {
  7016. - case GL_COMPRESSED_RGBA_ARB:
  7017. - Msg( "CRGBA " );
  7018. - break;
  7019. - case GL_COMPRESSED_RGB_ARB:
  7020. - Msg( "CRGB " );
  7021. - break;
  7022. - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB:
  7023. - Msg( "CLA " );
  7024. - break;
  7025. - case GL_COMPRESSED_LUMINANCE_ARB:
  7026. - Msg( "CL " );
  7027. - break;
  7028. - case GL_COMPRESSED_ALPHA_ARB:
  7029. - Msg( "CA " );
  7030. - break;
  7031. - case GL_COMPRESSED_INTENSITY_ARB:
  7032. - Msg( "CI " );
  7033. - break;
  7034. - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  7035. - Msg( "DXT1c " );
  7036. - break;
  7037. - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  7038. - Msg( "DXT1a " );
  7039. - break;
  7040. - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  7041. - Msg( "DXT3 " );
  7042. - break;
  7043. - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  7044. - Msg( "DXT5 " );
  7045. - break;
  7046. - case GL_RGBA:
  7047. - Msg( "RGBA " );
  7048. - break;
  7049. - case GL_RGBA8:
  7050. - Msg( "RGBA8 " );
  7051. - break;
  7052. - case GL_RGBA4:
  7053. - Msg( "RGBA4 " );
  7054. - break;
  7055. - case GL_RGB:
  7056. - Msg( "RGB " );
  7057. - break;
  7058. - case GL_RGB8:
  7059. - Msg( "RGB8 " );
  7060. - break;
  7061. - case GL_RGB5:
  7062. - Msg( "RGB5 " );
  7063. - break;
  7064. - case GL_LUMINANCE4_ALPHA4:
  7065. - Msg( "L4A4 " );
  7066. - break;
  7067. - case GL_LUMINANCE_ALPHA:
  7068. - case GL_LUMINANCE8_ALPHA8:
  7069. - Msg( "L8A8 " );
  7070. - break;
  7071. - case GL_LUMINANCE4:
  7072. - Msg( "L4 " );
  7073. - break;
  7074. - case GL_LUMINANCE:
  7075. - case GL_LUMINANCE8:
  7076. - Msg( "L8 " );
  7077. - break;
  7078. - case GL_ALPHA8:
  7079. - Msg( "A8 " );
  7080. - break;
  7081. - case GL_INTENSITY8:
  7082. - Msg( "I8 " );
  7083. - break;
  7084. - case GL_DEPTH_COMPONENT:
  7085. - case GL_DEPTH_COMPONENT24:
  7086. - Msg( "DEPTH24" );
  7087. - break;
  7088. - case GL_DEPTH_COMPONENT32F:
  7089. - Msg( "DEPTH32" );
  7090. - break;
  7091. - case GL_LUMINANCE16F_ARB:
  7092. - Msg( "L16F " );
  7093. - break;
  7094. - case GL_LUMINANCE32F_ARB:
  7095. - Msg( "L32F " );
  7096. - break;
  7097. - case GL_LUMINANCE_ALPHA16F_ARB:
  7098. - Msg( "LA16F " );
  7099. - break;
  7100. - case GL_LUMINANCE_ALPHA32F_ARB:
  7101. - Msg( "LA32F " );
  7102. - break;
  7103. - case GL_RGB16F_ARB:
  7104. - Msg( "RGB16F" );
  7105. - break;
  7106. - case GL_RGB32F_ARB:
  7107. - Msg( "RGB32F" );
  7108. - break;
  7109. - case GL_RGBA16F_ARB:
  7110. - Msg( "RGBA16F" );
  7111. - break;
  7112. - case GL_RGBA32F_ARB:
  7113. - Msg( "RGBA32F" );
  7114. - break;
  7115. - default:
  7116. - Msg( "????? " );
  7117. - break;
  7118. - }
  7119. -
  7120. - switch( image->target )
  7121. - {
  7122. - case GL_TEXTURE_1D:
  7123. - Msg( " 1D " );
  7124. - break;
  7125. - case GL_TEXTURE_2D:
  7126. - Msg( " 2D " );
  7127. - break;
  7128. - case GL_TEXTURE_3D:
  7129. - Msg( " 3D " );
  7130. - break;
  7131. - case GL_TEXTURE_CUBE_MAP_ARB:
  7132. - Msg( "CUBE " );
  7133. - break;
  7134. - case GL_TEXTURE_RECTANGLE_EXT:
  7135. - Msg( "RECT " );
  7136. - break;
  7137. - default:
  7138. - Msg( "???? " );
  7139. - break;
  7140. - }
  7141. -
  7142. - if( image->flags & TF_NORMALMAP )
  7143. - Msg( "normal " );
  7144. - else Msg( "diffuse " );
  7145. -
  7146. - switch( image->encode )
  7147. - {
  7148. - case DXT_ENCODE_COLOR_YCoCg:
  7149. - Msg( "YCoCg " );
  7150. - break;
  7151. - case DXT_ENCODE_NORMAL_AG_ORTHO:
  7152. - Msg( "ortho " );
  7153. - break;
  7154. - case DXT_ENCODE_NORMAL_AG_STEREO:
  7155. - Msg( "stereo " );
  7156. - break;
  7157. - case DXT_ENCODE_NORMAL_AG_PARABOLOID:
  7158. - Msg( "parabolic " );
  7159. - break;
  7160. - case DXT_ENCODE_NORMAL_AG_QUARTIC:
  7161. - Msg( "quartic " );
  7162. - break;
  7163. - case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
  7164. - Msg( "azimuthal " );
  7165. - break;
  7166. - default:
  7167. - Msg( "default " );
  7168. - break;
  7169. - }
  7170. -
  7171. - if( image->flags & TF_CLAMP )
  7172. - Msg( "clamp " );
  7173. - else if( image->flags & TF_BORDER )
  7174. - Msg( "border " );
  7175. - else if( image->flags & TF_ALPHA_BORDER )
  7176. - Msg( "aborder" );
  7177. - else Msg( "repeat " );
  7178. - Msg( " %s\n", image->name );
  7179. - }
  7180. -
  7181. - Msg( "---------------------------------------------------------\n" );
  7182. - Msg( "%i total textures\n", texCount );
  7183. - Msg( "%s total memory used\n", Q_memprint( bytes ));
  7184. - Msg( "\n" );
  7185. + for( i = 0; i < r_numTextures; i++ )
  7186. + GL_UpdateTextureParams( i );
  7187. }
  7188.  
  7189. /*
  7190. @@ -546,259 +326,407 @@ void R_TextureList_f( void )
  7191. GL_CalcTextureSamples
  7192. ================
  7193. */
  7194. -int GL_CalcTextureSamples( int flags )
  7195. +static int GL_CalcTextureSamples( int flags )
  7196. {
  7197. - if( flags & IMAGE_HAS_COLOR )
  7198. - return (flags & IMAGE_HAS_ALPHA) ? 4 : 3;
  7199. - return (flags & IMAGE_HAS_ALPHA) ? 2 : 1;
  7200. + if( FBitSet( flags, IMAGE_HAS_COLOR ))
  7201. + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 4 : 3;
  7202. + return FBitSet( flags, IMAGE_HAS_ALPHA ) ? 2 : 1;
  7203. }
  7204.  
  7205. /*
  7206. -================
  7207. -GL_ImageFlagsFromSamples
  7208. -================
  7209. +==================
  7210. +GL_CalcImageSize
  7211. +==================
  7212. */
  7213. -int GL_ImageFlagsFromSamples( int samples )
  7214. +static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int depth )
  7215. {
  7216. - switch( samples )
  7217. + size_t size = 0;
  7218. +
  7219. + // check the depth error
  7220. + depth = Q_max( 1, depth );
  7221. +
  7222. + switch( format )
  7223. {
  7224. - case 2: return IMAGE_HAS_ALPHA;
  7225. - case 3: return IMAGE_HAS_COLOR;
  7226. - case 4: return (IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA);
  7227. + case PF_RGB_24:
  7228. + case PF_BGR_24:
  7229. + size = width * height * depth * 3;
  7230. + break;
  7231. + case PF_BGRA_32:
  7232. + case PF_RGBA_32:
  7233. + size = width * height * depth * 4;
  7234. + break;
  7235. + case PF_DXT1:
  7236. + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth;
  7237. + break;
  7238. + case PF_DXT3:
  7239. + case PF_DXT5:
  7240. + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth;
  7241. + break;
  7242. }
  7243.  
  7244. - return 0;
  7245. + return size;
  7246. }
  7247.  
  7248. /*
  7249. -================
  7250. -GL_CalcImageSamples
  7251. -================
  7252. +==================
  7253. +GL_CalcTextureSize
  7254. +==================
  7255. */
  7256. -int GL_CalcImageSamples( int s1, int s2 )
  7257. +static size_t GL_CalcTextureSize( GLenum format, int width, int height, int depth )
  7258. {
  7259. - int samples;
  7260. + size_t size = 0;
  7261.  
  7262. - if( s1 == 1 ) samples = s2;
  7263. - else if( s1 == 2 )
  7264. + // check the depth error
  7265. + depth = Q_max( 1, depth );
  7266. +
  7267. + switch( format )
  7268. {
  7269. - if( s2 == 3 || s2 == 4 )
  7270. - samples = 4;
  7271. - else samples = 2;
  7272. + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  7273. + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  7274. + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth;
  7275. + break;
  7276. + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  7277. + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  7278. + size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth;
  7279. + break;
  7280. + case GL_RGBA8:
  7281. + case GL_RGBA:
  7282. + size = width * height * depth * 4;
  7283. + break;
  7284. + case GL_RGB8:
  7285. + case GL_RGB:
  7286. + size = width * height * depth * 4;
  7287. + break;
  7288. + case GL_INTENSITY:
  7289. + case GL_LUMINANCE:
  7290. + case GL_INTENSITY8:
  7291. + case GL_LUMINANCE8:
  7292. + size = (width * height * depth);
  7293. + break;
  7294. + case GL_LUMINANCE_ALPHA:
  7295. + case GL_LUMINANCE8_ALPHA8:
  7296. + size = width * height * depth * 2;
  7297. + break;
  7298. + case GL_R8:
  7299. + size = width * height * depth;
  7300. + break;
  7301. + case GL_RG8:
  7302. + size = width * height * depth * 2;
  7303. + break;
  7304. + case GL_R16:
  7305. + size = width * height * depth * 2;
  7306. + break;
  7307. + case GL_RG16:
  7308. + size = width * height * depth * 4;
  7309. + break;
  7310. + case GL_R16F:
  7311. + case GL_LUMINANCE16F_ARB:
  7312. + size = width * height * depth * 2; // half-floats
  7313. + break;
  7314. + case GL_R32F:
  7315. + case GL_LUMINANCE32F_ARB:
  7316. + size = width * height * depth * 4;
  7317. + break;
  7318. + case GL_RG16F:
  7319. + case GL_LUMINANCE_ALPHA16F_ARB:
  7320. + size = width * height * depth * 4;
  7321. + break;
  7322. + case GL_RG32F:
  7323. + case GL_LUMINANCE_ALPHA32F_ARB:
  7324. + size = width * height * depth * 8;
  7325. + break;
  7326. + case GL_RGB16F_ARB:
  7327. + case GL_RGBA16F_ARB:
  7328. + size = width * height * depth * 8;
  7329. + break;
  7330. + case GL_RGB32F_ARB:
  7331. + case GL_RGBA32F_ARB:
  7332. + size = width * height * depth * 16;
  7333. + break;
  7334. + case GL_DEPTH_COMPONENT16:
  7335. + size = width * height * depth * 2;
  7336. + break;
  7337. + case GL_DEPTH_COMPONENT24:
  7338. + size = width * height * depth * 4;
  7339. + break;
  7340. + case GL_DEPTH_COMPONENT32F:
  7341. + size = width * height * depth * 4;
  7342. + break;
  7343. + default:
  7344. + Host_Error( "GL_CalcTextureSize: bad texture internal format (%u)\n", format );
  7345. + break;
  7346. }
  7347. - else if( s1 == 3 )
  7348. +
  7349. + return size;
  7350. +}
  7351. +
  7352. +static int GL_CalcMipmapCount( gltexture_t *tex, qboolean haveBuffer )
  7353. +{
  7354. + int width, height;
  7355. + int mipcount;
  7356. +
  7357. + ASSERT( tex != NULL );
  7358. +
  7359. + if( !haveBuffer || tex->target == GL_TEXTURE_3D )
  7360. + return 1;
  7361. +
  7362. + // generate mip-levels by user request
  7363. + if( FBitSet( tex->flags, TF_NOMIPMAP ))
  7364. + return 1;
  7365. +
  7366. + // mip-maps can't exceeds 16
  7367. + for( mipcount = 0; mipcount < 16; mipcount++ )
  7368. {
  7369. - if( s2 == 2 || s2 == 4 )
  7370. - samples = 4;
  7371. - else samples = 3;
  7372. + width = Q_max( 1, ( tex->width >> mipcount ));
  7373. + height = Q_max( 1, ( tex->height >> mipcount ));
  7374. + if( width == 1 && height == 1 )
  7375. + break;
  7376. }
  7377. - else samples = s1;
  7378.  
  7379. - return samples;
  7380. + return mipcount + 1;
  7381. }
  7382.  
  7383. /*
  7384. ================
  7385. -GL_RoundImageDimensions
  7386. +GL_SetTextureDimensions
  7387. ================
  7388. */
  7389. -void GL_RoundImageDimensions( word *width, word *height, texFlags_t flags, qboolean force )
  7390. +static void GL_SetTextureDimensions( gltexture_t *tex, int width, int height, int depth )
  7391. {
  7392. - int scaledWidth, scaledHeight;
  7393. -
  7394. - scaledWidth = *width;
  7395. - scaledHeight = *height;
  7396. + int maxTextureSize;
  7397. + int maxDepthSize = 1;
  7398.  
  7399. - if( flags & ( TF_TEXTURE_1D|TF_TEXTURE_3D )) return;
  7400. + ASSERT( tex != NULL );
  7401.  
  7402. - if( force || !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
  7403. + switch( tex->target )
  7404. {
  7405. - // find nearest power of two, rounding down if desired
  7406. - scaledWidth = NearestPOW( scaledWidth, gl_round_down->integer );
  7407. - scaledHeight = NearestPOW( scaledHeight, gl_round_down->integer );
  7408. + case GL_TEXTURE_1D:
  7409. + case GL_TEXTURE_2D:
  7410. + maxTextureSize = glConfig.max_2d_texture_size;
  7411. + break;
  7412. + case GL_TEXTURE_2D_ARRAY_EXT:
  7413. + maxDepthSize = glConfig.max_2d_texture_layers;
  7414. + maxTextureSize = glConfig.max_2d_texture_size;
  7415. + break;
  7416. + case GL_TEXTURE_RECTANGLE_EXT:
  7417. + maxTextureSize = glConfig.max_2d_rectangle_size;
  7418. + break;
  7419. + case GL_TEXTURE_CUBE_MAP_ARB:
  7420. + maxTextureSize = glConfig.max_cubemap_size;
  7421. + break;
  7422. + case GL_TEXTURE_3D:
  7423. + maxDepthSize = glConfig.max_3d_texture_size;
  7424. + maxTextureSize = glConfig.max_3d_texture_size;
  7425. + break;
  7426. }
  7427.  
  7428. - if( flags & TF_SKYSIDE )
  7429. - {
  7430. - // let people sample down the sky textures for speed
  7431. - scaledWidth >>= gl_skymip->integer;
  7432. - scaledHeight >>= gl_skymip->integer;
  7433. - }
  7434. - else if(!( flags & TF_NOPICMIP ))
  7435. + // store original sizes
  7436. + tex->srcWidth = width;
  7437. + tex->srcHeight = height;
  7438. +
  7439. + if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
  7440. {
  7441. - // let people sample down the world textures for speed
  7442. - scaledWidth >>= gl_picmip->integer;
  7443. - scaledHeight >>= gl_picmip->integer;
  7444. + width = (width + 3) & ~3;
  7445. + height = (height + 3) & ~3;
  7446. }
  7447.  
  7448. - if( flags & TF_CUBEMAP )
  7449. + if( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize )
  7450. {
  7451. - while( scaledWidth > glConfig.max_cubemap_size || scaledHeight > glConfig.max_cubemap_size )
  7452. + if( tex->target == GL_TEXTURE_1D )
  7453. {
  7454. - scaledWidth >>= 1;
  7455. - scaledHeight >>= 1;
  7456. + while( width > maxTextureSize )
  7457. + width >>= 1;
  7458. }
  7459. - }
  7460. - else
  7461. - {
  7462. - if( flags & TF_TEXTURE_RECTANGLE )
  7463. + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
  7464. {
  7465. - while( scaledWidth > glConfig.max_2d_rectangle_size || scaledHeight > glConfig.max_2d_rectangle_size )
  7466. + while( width > maxTextureSize || height > maxTextureSize || depth > maxDepthSize )
  7467. {
  7468. - scaledWidth >>= 1;
  7469. - scaledHeight >>= 1;
  7470. + width >>= 1;
  7471. + height >>= 1;
  7472. + depth >>= 1;
  7473. }
  7474. }
  7475. - else
  7476. + else // all remaining cases
  7477. {
  7478. - while( scaledWidth > glConfig.max_2d_texture_size || scaledHeight > glConfig.max_2d_texture_size )
  7479. + while( width > maxTextureSize || height > maxTextureSize )
  7480. {
  7481. - scaledWidth >>= 1;
  7482. - scaledHeight >>= 1;
  7483. + width >>= 1;
  7484. + height >>= 1;
  7485. }
  7486. }
  7487. }
  7488.  
  7489. - if( scaledWidth < 1 ) scaledWidth = 1;
  7490. - if( scaledHeight < 1 ) scaledHeight = 1;
  7491. + // apply custom downscales
  7492. + if( FBitSet( tex->flags, TF_SKYSIDE ))
  7493. + {
  7494. + // let people sample down the sky textures for speed
  7495. + width >>= gl_skymip->integer;
  7496. + height >>= gl_skymip->integer;
  7497. + }
  7498. + else if( !FBitSet( tex->flags, TF_NOPICMIP ))
  7499. + {
  7500. + // let people sample down the world textures for speed
  7501. + width >>= gl_picmip->integer;
  7502. + height >>= gl_picmip->integer;
  7503. + }
  7504.  
  7505. - *width = scaledWidth;
  7506. - *height = scaledHeight;
  7507. + // set the texture dimensions
  7508. + tex->width = Q_max( 1, width );
  7509. + tex->height = Q_max( 1, height );
  7510. + tex->depth = Q_max( 1, depth );
  7511. }
  7512.  
  7513. /*
  7514. ===============
  7515. -GL_TextureFormat
  7516. +GL_SetTextureTarget
  7517. ===============
  7518. */
  7519. -static GLenum GL_TextureFormat( gltexture_t *tex, int *samples )
  7520. +static void GL_SetTextureTarget( gltexture_t *tex, rgbdata_t *pic )
  7521. {
  7522. - qboolean compress;
  7523. - GLenum format;
  7524. + ASSERT( pic != NULL );
  7525. + ASSERT( tex != NULL );
  7526. +
  7527. + // correct depth size
  7528. + pic->depth = Q_max( 1, pic->depth );
  7529. + tex->numMips = 0; // begin counting
  7530. +
  7531. + // correct mip count
  7532. + pic->numMips = max( 1, pic->numMips );
  7533. +
  7534. + // trying to determine texture type
  7535. + if( pic->width > 1 && pic->height <= 1 )
  7536. + tex->target = GL_TEXTURE_1D;
  7537. + else if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
  7538. + tex->target = GL_TEXTURE_CUBE_MAP_ARB;
  7539. + else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 )
  7540. + tex->target = GL_TEXTURE_2D_ARRAY_EXT;
  7541. + else if( pic->width > 1 && pic->height > 1 && pic->depth > 1 )
  7542. + tex->target = GL_TEXTURE_3D;
  7543. + else if( FBitSet( tex->flags, TF_TEXTURE_RECTANGLE ) && pic->width == glState.width && pic->height == glState.height )
  7544. + tex->target = GL_TEXTURE_RECTANGLE_EXT;
  7545. + else tex->target = GL_TEXTURE_2D; // default case
  7546. +
  7547. + // check for hardware support
  7548. + if(( tex->target == GL_TEXTURE_CUBE_MAP_ARB ) && !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  7549. + tex->target = GL_NONE;
  7550. +
  7551. + if(( tex->target == GL_TEXTURE_RECTANGLE_EXT ) && !GL_Support( GL_TEXTURE_2D_RECT_EXT ))
  7552. + tex->target = GL_TEXTURE_2D; // fallback
  7553. +
  7554. + if(( tex->target == GL_TEXTURE_2D_ARRAY_EXT ) && !GL_Support( GL_TEXTURE_ARRAY_EXT ))
  7555. + tex->target = GL_NONE;
  7556. +
  7557. + if(( tex->target == GL_TEXTURE_3D ) && !GL_Support( GL_TEXTURE_3D_EXT ))
  7558. + tex->target = GL_NONE;
  7559. +
  7560. + // depth cubemaps only allowed when GL_EXT_gpu_shader4 is supported
  7561. + if( tex->target == GL_TEXTURE_CUBE_MAP_ARB && !GL_Support( GL_EXT_GPU_SHADER4 ) && FBitSet( tex->flags, TF_DEPTHMAP ))
  7562. + tex->target = GL_NONE;
  7563. +}
  7564.  
  7565. - // check if it should be compressed
  7566. - if( !gl_compress_textures->integer || ( tex->flags & TF_UNCOMPRESSED ))
  7567. - compress = false;
  7568. - else compress = GL_Support( GL_TEXTURE_COMPRESSION_EXT );
  7569. +/*
  7570. +===============
  7571. +GL_SetTextureFormat
  7572. +===============
  7573. +*/
  7574. +static void GL_SetTextureFormat( gltexture_t *tex, pixformat_t format, int channelMask )
  7575. +{
  7576. + qboolean haveColor = ( channelMask & IMAGE_HAS_COLOR );
  7577. + qboolean haveAlpha = ( channelMask & IMAGE_HAS_ALPHA );
  7578. + qboolean compressImage = false;
  7579.  
  7580. - // set texture format
  7581. - if( tex->flags & TF_DEPTHMAP )
  7582. + ASSERT( tex != NULL );
  7583. +
  7584. + if( !FBitSet( tex->flags, TF_UNCOMPRESSED ) && !ImageDXT( format ))
  7585. {
  7586. - if( tex->flags & TF_FLOAT && GL_Support( GL_ARB_DEPTH_FLOAT_EXT ))
  7587. - format = GL_DEPTH_COMPONENT32F;
  7588. - else format = GL_DEPTH_COMPONENT24;
  7589. - tex->flags &= ~TF_INTENSITY;
  7590. + // check if it should be compressed
  7591. + if( gl_compress_textures->integer && GL_Support( GL_TEXTURE_COMPRESSION_EXT ))
  7592. + compressImage = true;
  7593. }
  7594. - else if( tex->flags & TF_FLOAT && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT ))
  7595. - {
  7596. - int bits = glw_state.desktopBitsPixel;
  7597.  
  7598. - switch( *samples )
  7599. + if( ImageDXT( format ))
  7600. + {
  7601. + switch( format )
  7602. {
  7603. - case 1:
  7604. - switch( bits )
  7605. - {
  7606. - case 16: format = GL_LUMINANCE16F_ARB; break;
  7607. - default: format = GL_LUMINANCE32F_ARB; break;
  7608. - }
  7609. - break;
  7610. - case 2:
  7611. - switch( bits )
  7612. - {
  7613. - case 16: format = GL_LUMINANCE_ALPHA16F_ARB; break;
  7614. - default: format = GL_LUMINANCE_ALPHA32F_ARB; break;
  7615. - }
  7616. - break;
  7617. - case 3:
  7618. - switch( bits )
  7619. - {
  7620. - case 16: format = GL_RGB16F_ARB; break;
  7621. - default: format = GL_RGB32F_ARB; break;
  7622. - }
  7623. - break;
  7624. - case 4:
  7625. - default:
  7626. - switch( bits )
  7627. - {
  7628. - case 16: format = GL_RGBA16F_ARB; break;
  7629. - default: format = GL_RGBA32F_ARB; break;
  7630. - }
  7631. - break;
  7632. + case PF_DXT1: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; // never use DXT1 with 1-bit alpha
  7633. + case PF_DXT3: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
  7634. + case PF_DXT5: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
  7635. }
  7636. + return;
  7637. + }
  7638. + else if( FBitSet( tex->flags, TF_DEPTHMAP ))
  7639. + {
  7640. + if( FBitSet( tex->flags, TF_ARB_16BIT ))
  7641. + tex->format = GL_DEPTH_COMPONENT16;
  7642. + else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_DEPTH_FLOAT_EXT ))
  7643. + tex->format = GL_DEPTH_COMPONENT32F;
  7644. + else tex->format = GL_DEPTH_COMPONENT24;
  7645. }
  7646. - else if( compress )
  7647. + else if( FBitSet( tex->flags, TF_ARB_FLOAT ) && GL_Support( GL_ARB_TEXTURE_FLOAT_EXT ))
  7648. {
  7649. - switch( *samples )
  7650. + if( haveColor && haveAlpha )
  7651. {
  7652. - case 1: format = GL_COMPRESSED_LUMINANCE_ARB; break;
  7653. - case 2: format = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
  7654. - case 3: format = GL_COMPRESSED_RGB_ARB; break;
  7655. - case 4:
  7656. - default: format = GL_COMPRESSED_RGBA_ARB; break;
  7657. + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
  7658. + tex->format = GL_RGBA16F_ARB;
  7659. + else tex->format = GL_RGBA32F_ARB;
  7660. + }
  7661. + else if( haveColor )
  7662. + {
  7663. + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
  7664. + tex->format = GL_RGB16F_ARB;
  7665. + else tex->format = GL_RGB32F_ARB;
  7666. + }
  7667. + else if( haveAlpha )
  7668. + {
  7669. + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
  7670. + tex->format = GL_LUMINANCE_ALPHA16F_ARB;
  7671. + else tex->format = GL_LUMINANCE_ALPHA32F_ARB;
  7672. + }
  7673. + else
  7674. + {
  7675. + if( FBitSet( tex->flags, TF_ARB_16BIT ) || glw_state.desktopBitsPixel == 16 )
  7676. + tex->format = GL_LUMINANCE16F_ARB;
  7677. + else tex->format = GL_LUMINANCE32F_ARB;
  7678. + }
  7679. + }
  7680. + else if( compressImage )
  7681. + {
  7682. + switch( GL_CalcTextureSamples( channelMask ))
  7683. + {
  7684. + case 1: tex->format = GL_LUMINANCE8; break;
  7685. + case 2: tex->format = GL_LUMINANCE8_ALPHA8; break;
  7686. + case 3: tex->format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
  7687. + case 4: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
  7688. }
  7689. -
  7690. - if( tex->flags & TF_INTENSITY )
  7691. - format = GL_COMPRESSED_INTENSITY_ARB;
  7692. - tex->flags &= ~TF_INTENSITY;
  7693. }
  7694. else
  7695. {
  7696. + // NOTE: not all the types will be compressed
  7697. int bits = glw_state.desktopBitsPixel;
  7698.  
  7699. - switch( *samples )
  7700. + switch( GL_CalcTextureSamples( channelMask ) )
  7701. {
  7702. - case 1: format = GL_LUMINANCE8; break;
  7703. - case 2: format = GL_LUMINANCE8_ALPHA8; break;
  7704. + case 1: tex->format = GL_LUMINANCE8; break;
  7705. + case 2: tex->format = GL_LUMINANCE8_ALPHA8; break;
  7706. case 3:
  7707. - if( gl_luminance_textures->integer && !( tex->flags & TF_UNCOMPRESSED ))
  7708. - {
  7709. - switch( bits )
  7710. - {
  7711. - case 16: format = GL_LUMINANCE4; break;
  7712. - case 32: format = GL_LUMINANCE8; break;
  7713. - default: format = GL_LUMINANCE; break;
  7714. - }
  7715. - *samples = 1; // merge for right calc statistics
  7716. - }
  7717. - else
  7718. + switch( bits )
  7719. {
  7720. - switch( bits )
  7721. - {
  7722. - case 16: format = GL_RGB5; break;
  7723. - case 32: format = GL_RGB8; break;
  7724. - default: format = GL_RGB; break;
  7725. - }
  7726. + case 16: tex->format = GL_RGB5; break;
  7727. + case 32: tex->format = GL_RGB8; break;
  7728. + default: tex->format = GL_RGB; break;
  7729. }
  7730. - break;
  7731. + break;
  7732. case 4:
  7733. default:
  7734. - if( gl_luminance_textures->integer && !( tex->flags & TF_UNCOMPRESSED ))
  7735. - {
  7736. - switch( bits )
  7737. - {
  7738. - case 16: format = GL_LUMINANCE4_ALPHA4; break;
  7739. - case 32: format = GL_LUMINANCE8_ALPHA8; break;
  7740. - default: format = GL_LUMINANCE_ALPHA; break;
  7741. - }
  7742. - *samples = 2; // merge for right calc statistics
  7743. - }
  7744. - else
  7745. + switch( bits )
  7746. {
  7747. - switch( bits )
  7748. - {
  7749. - case 16: format = GL_RGBA4; break;
  7750. - case 32: format = GL_RGBA8; break;
  7751. - default: format = GL_RGBA; break;
  7752. - }
  7753. + case 16: tex->format = GL_RGBA4; break;
  7754. + case 32: tex->format = GL_RGBA8; break;
  7755. + default: tex->format = GL_RGBA; break;
  7756. }
  7757. break;
  7758. }
  7759. -
  7760. - if( tex->flags & TF_INTENSITY )
  7761. - format = GL_INTENSITY8;
  7762. - tex->flags &= ~TF_INTENSITY;
  7763. }
  7764. - return format;
  7765. }
  7766.  
  7767. /*
  7768. @@ -815,6 +743,7 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
  7769. uint p1[0x1000], p2[0x1000];
  7770. byte *pix1, *pix2, *pix3, *pix4;
  7771. uint *out, *inRow1, *inRow2;
  7772. + static byte *scaledImage = NULL; // pointer to a scaled image
  7773. vec3_t normal;
  7774. int i, x, y;
  7775.  
  7776. @@ -842,8 +771,8 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
  7777. {
  7778. for( y = 0; y < outHeight; y++, out += outWidth )
  7779. {
  7780. - inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight/outHeight);
  7781. - inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight/outHeight);
  7782. + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
  7783. + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
  7784.  
  7785. for( x = 0; x < outWidth; x++ )
  7786. {
  7787. @@ -852,16 +781,16 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
  7788. pix3 = (byte *)inRow2 + p1[x];
  7789. pix4 = (byte *)inRow2 + p2[x];
  7790.  
  7791. - 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);
  7792. - 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);
  7793. - 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);
  7794. + normal[0] = MAKE_SIGNED( pix1[0] ) + MAKE_SIGNED( pix2[0] ) + MAKE_SIGNED( pix3[0] ) + MAKE_SIGNED( pix4[0] );
  7795. + normal[1] = MAKE_SIGNED( pix1[1] ) + MAKE_SIGNED( pix2[1] ) + MAKE_SIGNED( pix3[1] ) + MAKE_SIGNED( pix4[1] );
  7796. + normal[2] = MAKE_SIGNED( pix1[2] ) + MAKE_SIGNED( pix2[2] ) + MAKE_SIGNED( pix3[2] ) + MAKE_SIGNED( pix4[2] );
  7797.  
  7798. if( !VectorNormalizeLength( normal ))
  7799. - VectorSet( normal, 0.0f, 0.0f, 1.0f );
  7800. + VectorSet( normal, 0.5f, 0.5f, 1.0f );
  7801.  
  7802. - ((byte *)(out+x))[0] = (byte)(128 + 127 * normal[0]);
  7803. - ((byte *)(out+x))[1] = (byte)(128 + 127 * normal[1]);
  7804. - ((byte *)(out+x))[2] = (byte)(128 + 127 * normal[2]);
  7805. + ((byte *)(out+x))[0] = 128 + (byte)(127.0f * normal[0]);
  7806. + ((byte *)(out+x))[1] = 128 + (byte)(127.0f * normal[1]);
  7807. + ((byte *)(out+x))[2] = 128 + (byte)(127.0f * normal[2]);
  7808. ((byte *)(out+x))[3] = 255;
  7809. }
  7810. }
  7811. @@ -870,8 +799,8 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
  7812. {
  7813. for( y = 0; y < outHeight; y++, out += outWidth )
  7814. {
  7815. - inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight/outHeight);
  7816. - inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight/outHeight);
  7817. + inRow1 = in + inWidth * (int)(((float)y + 0.25f) * inHeight / outHeight);
  7818. + inRow2 = in + inWidth * (int)(((float)y + 0.75f) * inHeight / outHeight);
  7819.  
  7820. for( x = 0; x < outWidth; x++ )
  7821. {
  7822. @@ -887,6 +816,7 @@ byte *GL_ResampleTexture( const byte *source, int inWidth, int inHeight, int out
  7823. }
  7824. }
  7825. }
  7826. +
  7827. return scaledImage;
  7828. }
  7829.  
  7830. @@ -922,96 +852,82 @@ GL_BuildMipMap
  7831. Operates in place, quartering the size of the texture
  7832. =================
  7833. */
  7834. -static void GL_BuildMipMap( byte *in, int width, int height, qboolean isNormalMap )
  7835. +static void GL_BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, qboolean isNormalMap )
  7836. {
  7837. byte *out = in;
  7838. + int instride = ALIGN( srcWidth * 4, 1 );
  7839. + int mipWidth, mipHeight, outpadding;
  7840. + int row, x, y, z;
  7841. vec3_t normal;
  7842. - int x, y;
  7843. -
  7844. - width <<= 2;
  7845. - height >>= 1;
  7846. -
  7847. - if( isNormalMap )
  7848. - {
  7849. - for( y = 0; y < height; y++, in += width )
  7850. - {
  7851. - for( x = 0; x < width; x += 8, in += 8, out += 4 )
  7852. - {
  7853. - 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);
  7854. - 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);
  7855. - 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);
  7856.  
  7857. - if( !VectorNormalizeLength( normal ))
  7858. - VectorSet( normal, 0.0f, 0.0f, 1.0f );
  7859. -
  7860. - out[0] = (byte)(128 + 127 * normal[0]);
  7861. - out[1] = (byte)(128 + 127 * normal[1]);
  7862. - out[2] = (byte)(128 + 127 * normal[2]);
  7863. - out[3] = 255;
  7864. - }
  7865. - }
  7866. - }
  7867. - else
  7868. - {
  7869. - for( y = 0; y < height; y++, in += width )
  7870. - {
  7871. - for( x = 0; x < width; x += 8, in += 8, out += 4 )
  7872. - {
  7873. - out[0] = (in[0] + in[4] + in[width+0] + in[width+4]) >> 2;
  7874. - out[1] = (in[1] + in[5] + in[width+1] + in[width+5]) >> 2;
  7875. - out[2] = (in[2] + in[6] + in[width+2] + in[width+6]) >> 2;
  7876. - out[3] = (in[3] + in[7] + in[width+3] + in[width+7]) >> 2;
  7877. - }
  7878. - }
  7879. - }
  7880. -}
  7881. -
  7882. -/*
  7883. -===============
  7884. -GL_GenerateMipmaps
  7885. -
  7886. -sgis generate mipmap
  7887. -===============
  7888. -*/
  7889. -void GL_GenerateMipmaps( byte *buffer, rgbdata_t *pic, gltexture_t *tex, GLenum glTarget, GLenum inFormat, int side, qboolean subImage )
  7890. -{
  7891. - int mipLevel;
  7892. - int dataType = GL_UNSIGNED_BYTE;
  7893. - int w, h;
  7894. -
  7895. - // not needs
  7896. - if( tex->flags & TF_NOMIPMAP )
  7897. - return;
  7898. -
  7899. - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
  7900. - {
  7901. - pglHint( GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST );
  7902. - pglTexParameteri( glTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
  7903. - pglGetError(); // clear error queue on mips generate
  7904. - return;
  7905. - }
  7906. -
  7907. - // screen texture?
  7908. - if( !buffer ) return;
  7909. -
  7910. - mipLevel = 0;
  7911. - w = tex->width;
  7912. - h = tex->height;
  7913. -
  7914. - // software mipmap generator
  7915. - while( w > 1 || h > 1 )
  7916. - {
  7917. - // build the mipmap
  7918. - if( tex->flags & TF_ALPHACONTRAST ) memset( buffer, pic->width >> mipLevel, w * h * 4 );
  7919. - else GL_BuildMipMap( buffer, w, h, ( tex->flags & TF_NORMALMAP ));
  7920. + if( !in ) return;
  7921.  
  7922. - w = (w+1)>>1;
  7923. - h = (h+1)>>1;
  7924. - mipLevel++;
  7925. + mipWidth = max( 1, ( srcWidth >> 1 ));
  7926. + mipHeight = max( 1, ( srcHeight >> 1 ));
  7927. + outpadding = ALIGN( mipWidth * 4, 1 ) - mipWidth * 4;
  7928. + row = srcWidth << 2;
  7929.  
  7930. - if( subImage ) pglTexSubImage2D( tex->target + side, mipLevel, 0, 0, w, h, inFormat, dataType, buffer );
  7931. - else pglTexImage2D( tex->target + side, mipLevel, tex->format, w, h, 0, inFormat, dataType, buffer );
  7932. - if( pglGetError( )) break; // can't create mip levels
  7933. + // move through all layers
  7934. + for( z = 0; z < srcDepth; z++ )
  7935. + {
  7936. + if( isNormalMap )
  7937. + {
  7938. + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding )
  7939. + {
  7940. + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in;
  7941. + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 )
  7942. + {
  7943. + if((( x << 1 ) + 1 ) < srcWidth )
  7944. + {
  7945. + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( in[row+4] )
  7946. + + MAKE_SIGNED( next[row+0] ) + MAKE_SIGNED( next[row+4] );
  7947. + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( in[row+5] )
  7948. + + MAKE_SIGNED( next[row+1] ) + MAKE_SIGNED( next[row+5] );
  7949. + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( in[row+6] )
  7950. + + MAKE_SIGNED( next[row+2] ) + MAKE_SIGNED( next[row+6] );
  7951. + }
  7952. + else
  7953. + {
  7954. + normal[0] = MAKE_SIGNED( in[row+0] ) + MAKE_SIGNED( next[row+0] );
  7955. + normal[1] = MAKE_SIGNED( in[row+1] ) + MAKE_SIGNED( next[row+1] );
  7956. + normal[2] = MAKE_SIGNED( in[row+2] ) + MAKE_SIGNED( next[row+2] );
  7957. + }
  7958. +
  7959. +
  7960. + if( !VectorNormalizeLength( normal ))
  7961. + VectorSet( normal, 0.5f, 0.5f, 1.0f );
  7962. +
  7963. + out[0] = 128 + (byte)(127.0f * normal[0]);
  7964. + out[1] = 128 + (byte)(127.0f * normal[1]);
  7965. + out[2] = 128 + (byte)(127.0f * normal[2]);
  7966. + out[3] = 255;
  7967. + }
  7968. + }
  7969. + }
  7970. + else
  7971. + {
  7972. + for( y = 0; y < mipHeight; y++, in += instride * 2, out += outpadding )
  7973. + {
  7974. + byte *next = ((( y << 1 ) + 1 ) < srcHeight ) ? ( in + instride ) : in;
  7975. + for( x = 0, row = 0; x < mipWidth; x++, row += 8, out += 4 )
  7976. + {
  7977. + if((( x << 1 ) + 1 ) < srcWidth )
  7978. + {
  7979. + out[0] = (in[row+0] + in[row+4] + next[row+0] + next[row+4]) >> 2;
  7980. + out[1] = (in[row+1] + in[row+5] + next[row+1] + next[row+5]) >> 2;
  7981. + out[2] = (in[row+2] + in[row+6] + next[row+2] + next[row+6]) >> 2;
  7982. + out[3] = (in[row+3] + in[row+7] + next[row+3] + next[row+7]) >> 2;
  7983. + }
  7984. + else
  7985. + {
  7986. + out[0] = (in[row+0] + next[row+0]) >> 1;
  7987. + out[1] = (in[row+1] + next[row+1]) >> 1;
  7988. + out[2] = (in[row+2] + next[row+2]) >> 1;
  7989. + out[3] = (in[row+3] + next[row+3]) >> 1;
  7990. + }
  7991. + }
  7992. + }
  7993. + }
  7994. }
  7995. }
  7996.  
  7997. @@ -1045,193 +961,85 @@ void GL_MakeLuminance( rgbdata_t *in )
  7998. }
  7999. }
  8000.  
  8001. -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 )
  8002. +static void GL_TextureImageRAW( gltexture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, GLint type, const void *data )
  8003. {
  8004. + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
  8005. + qboolean subImage = ( tex->flags & TF_IMG_UPLOADED );
  8006. + GLenum inFormat = PFDesc[type].glFormat;
  8007. GLint dataType = GL_UNSIGNED_BYTE;
  8008.  
  8009. - if( glTarget == GL_TEXTURE_1D )
  8010. + ASSERT( tex != NULL );
  8011. +
  8012. + if( tex->flags & TF_DEPTHMAP )
  8013. + inFormat = GL_DEPTH_COMPONENT;
  8014. +
  8015. + if( tex->target == GL_TEXTURE_1D )
  8016. {
  8017. - if( subImage ) pglTexSubImage1D( glTarget, level, 0, width, inFormat, dataType, data );
  8018. - else pglTexImage1D( glTarget, level, outFormat, width, 0, inFormat, dataType, data );
  8019. + if( subImage ) pglTexSubImage1D( tex->target, level, 0, width, inFormat, dataType, data );
  8020. + else pglTexImage1D( tex->target, level, tex->format, width, 0, inFormat, dataType, data );
  8021. }
  8022. - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
  8023. + else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB )
  8024. {
  8025. - if( subImage ) pglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, 0, 0, width, height, inFormat, dataType, data );
  8026. - else pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, outFormat, width, height, 0, inFormat, dataType, data );
  8027. + if( subImage ) pglTexSubImage2D( cubeTarget + side, level, 0, 0, width, height, inFormat, dataType, data );
  8028. + else pglTexImage2D( cubeTarget + side, level, tex->format, width, height, 0, inFormat, dataType, data );
  8029. }
  8030. - else if( glTarget == GL_TEXTURE_3D )
  8031. + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
  8032. {
  8033. - if( subImage ) pglTexSubImage3D( glTarget, level, 0, 0, 0, width, height, depth, inFormat, dataType, data );
  8034. - else pglTexImage3D( glTarget, level, outFormat, width, height, depth, 0, inFormat, dataType, data );
  8035. + if( subImage ) pglTexSubImage3D( tex->target, level, 0, 0, 0, width, height, depth, inFormat, dataType, data );
  8036. + else pglTexImage3D( tex->target, level, tex->format, width, height, depth, 0, inFormat, dataType, data );
  8037. }
  8038. - else
  8039. + else // 2D or RECT
  8040. {
  8041. - if( subImage ) pglTexSubImage2D( glTarget, level, 0, 0, width, height, inFormat, dataType, data );
  8042. - else pglTexImage2D( glTarget, level, outFormat, width, height, 0, inFormat, dataType, data );
  8043. + if( subImage ) pglTexSubImage2D( tex->target, level, 0, 0, width, height, inFormat, dataType, data );
  8044. + else pglTexImage2D( tex->target, level, tex->format, width, height, 0, inFormat, dataType, data );
  8045. }
  8046. }
  8047.  
  8048. -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 )
  8049. +static void GL_TextureImageDXT( gltexture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data )
  8050. {
  8051. - if( glTarget == GL_TEXTURE_1D )
  8052. + GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
  8053. + qboolean subImage = ( tex->flags & TF_IMG_UPLOADED );
  8054. +
  8055. + ASSERT( tex != NULL );
  8056. +
  8057. + if( tex->target == GL_TEXTURE_1D )
  8058. {
  8059. - if( subImage ) pglCompressedTexSubImage1DARB( glTarget, level, 0, width, format, size, data );
  8060. - else pglCompressedTexImage1DARB( glTarget, level, format, width, 0, size, data );
  8061. + if( subImage ) pglCompressedTexSubImage1DARB( tex->target, level, 0, width, tex->format, size, data );
  8062. + else pglCompressedTexImage1DARB( tex->target, level, tex->format, width, 0, size, data );
  8063. }
  8064. - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
  8065. + else if( tex->target == GL_TEXTURE_CUBE_MAP_ARB )
  8066. {
  8067. - if( subImage ) pglCompressedTexSubImage2DARB( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, 0, 0, width, height, format, size, data );
  8068. - else pglCompressedTexImage2DARB( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, level, format, width, height, 0, size, data );
  8069. + if( subImage ) pglCompressedTexSubImage2DARB( cubeTarget + side, level, 0, 0, width, height, tex->format, size, data );
  8070. + else pglCompressedTexImage2DARB( cubeTarget + side, level, tex->format, width, height, 0, size, data );
  8071. }
  8072. - else if( glTarget == GL_TEXTURE_3D )
  8073. + else if( tex->target == GL_TEXTURE_3D || tex->target == GL_TEXTURE_2D_ARRAY_EXT )
  8074. {
  8075. - if( subImage ) pglCompressedTexSubImage3DARB( glTarget, level, 0, 0, 0, width, height, depth, format, size, data );
  8076. - else pglCompressedTexImage3DARB( glTarget, level, format, width, height, depth, 0, size, data );
  8077. + if( subImage ) pglCompressedTexSubImage3DARB( tex->target, level, 0, 0, 0, width, height, depth, tex->format, size, data );
  8078. + else pglCompressedTexImage3DARB( tex->target, level, tex->format, width, height, depth, 0, size, data );
  8079. }
  8080. else // 2D or RECT
  8081. {
  8082. - if( subImage ) pglCompressedTexSubImage2DARB( glTarget, level, 0, 0, width, height, format, size, data );
  8083. - else pglCompressedTexImage2DARB( glTarget, level, format, width, height, 0, size, data );
  8084. + if( subImage ) pglCompressedTexSubImage2DARB( tex->target, level, 0, 0, width, height, tex->format, size, data );
  8085. + else pglCompressedTexImage2DARB( tex->target, level, tex->format, width, height, 0, size, data );
  8086. }
  8087. }
  8088.  
  8089. /*
  8090. ===============
  8091. -GL_UploadTextureDXT
  8092. +GL_CheckTexImageError
  8093.  
  8094. -upload compressed texture into video memory
  8095. +show GL-errors on load images
  8096. ===============
  8097. */
  8098. -static void GL_UploadTextureDXT( rgbdata_t *pic, gltexture_t *tex, qboolean subImage, imgfilter_t *filter )
  8099. +static void GL_CheckTexImageError( gltexture_t *tex )
  8100. {
  8101. - byte *buf;
  8102. - const byte *bufend;
  8103. - GLenum inFormat, glTarget;
  8104. - uint width, height, depth;
  8105. - int texsize = 0, samples;
  8106. - uint i, j, s, numSides;
  8107. - int numMips, err;
  8108. -
  8109. - ASSERT( pic != NULL && tex != NULL );
  8110. -
  8111. - tex->srcWidth = tex->width = pic->width;
  8112. - tex->srcHeight = tex->height = pic->height;
  8113. - s = tex->srcWidth * tex->srcHeight;
  8114. -
  8115. - tex->fogParams[0] = pic->fogParams[0];
  8116. - tex->fogParams[1] = pic->fogParams[1];
  8117. - tex->fogParams[2] = pic->fogParams[2];
  8118. - tex->fogParams[3] = pic->fogParams[3];
  8119. -
  8120. - // NOTE: normalmaps must be power of two or software mip generator will stop working
  8121. - GL_RoundImageDimensions( &tex->width, &tex->height, tex->flags, ( tex->flags & TF_NORMALMAP ));
  8122. -
  8123. - if( s&3 )
  8124. - {
  8125. - // will be resample, just tell me for debug targets
  8126. - MsgDev( D_NOTE, "GL_Upload: %s s&3 [%d x %d]\n", tex->name, tex->srcWidth, tex->srcHeight );
  8127. - }
  8128. -
  8129. - // clear all the unsupported flags
  8130. - tex->flags &= ~TF_KEEP_8BIT;
  8131. - tex->flags &= ~TF_KEEP_RGBDATA;
  8132. - tex->flags |= TF_NOPICMIP;
  8133. - tex->encode = pic->encode; // share encode method
  8134. -
  8135. - samples = GL_CalcTextureSamples( pic->flags );
  8136. -
  8137. - if( pic->flags & IMAGE_HAS_ALPHA )
  8138. - tex->flags |= TF_HAS_ALPHA;
  8139. -
  8140. - if( !pic->numMips ) tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request
  8141. -
  8142. - // determine format
  8143. - inFormat = PFDesc[pic->type].glFormat;
  8144. -
  8145. - if( ImageDXT( pic->type ))
  8146. - tex->format = inFormat;
  8147. - else tex->format = GL_TextureFormat( tex, &samples );
  8148. -
  8149. - if( !( tex->flags & TF_HAS_ALPHA ) && inFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )
  8150. - tex->format = inFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // OpenGL hint
  8151. -
  8152. - // determine target
  8153. - tex->target = glTarget = GL_TEXTURE_2D;
  8154. -
  8155. - numMips = (pic->numMips > 0) ? pic->numMips : 1;
  8156. - numSides = 1;
  8157. -
  8158. - if( pic->flags & IMAGE_CUBEMAP )
  8159. - {
  8160. - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8161. - {
  8162. - numSides = 6;
  8163. - tex->target = glTarget = GL_TEXTURE_CUBE_MAP_ARB;
  8164. - tex->flags |= TF_CUBEMAP;
  8165. -
  8166. - if( !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && ( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER )))
  8167. - {
  8168. - // don't use border for cubemaps (but allow for seamless cubemaps)
  8169. - tex->flags &= ~(TF_BORDER|TF_ALPHA_BORDER);
  8170. - tex->flags |= TF_CLAMP;
  8171. - }
  8172. - }
  8173. - else
  8174. - {
  8175. - MsgDev( D_WARN, "GL_UploadTexture: cubemaps isn't supported, %s ignored\n", tex->name );
  8176. - tex->flags &= ~TF_CUBEMAP;
  8177. - }
  8178. - }
  8179. - else if( tex->flags & TF_TEXTURE_1D || pic->height <= 1 )
  8180. - {
  8181. - // determine target
  8182. - tex->target = glTarget = GL_TEXTURE_1D;
  8183. - }
  8184. - else if( tex->flags & TF_TEXTURE_RECTANGLE )
  8185. - {
  8186. - if( glConfig.max_2d_rectangle_size )
  8187. - tex->target = glTarget = glConfig.texRectangle;
  8188. - // or leave as GL_TEXTURE_2D
  8189. - }
  8190. - else if( tex->flags & TF_TEXTURE_3D )
  8191. - {
  8192. - // determine target
  8193. - tex->target = glTarget = GL_TEXTURE_3D;
  8194. - }
  8195. -
  8196. - pglBindTexture( tex->target, tex->texnum );
  8197. -
  8198. - buf = pic->buffer;
  8199. - bufend = pic->buffer + pic->size;
  8200. - tex->size = pic->size;
  8201. -
  8202. - // uploading texture into video memory
  8203. - for( i = 0; i < numSides; i++ )
  8204. - {
  8205. - if( buf != NULL && buf >= bufend )
  8206. - Host_Error( "GL_UploadTextureDXT: %s image buffer overflow\n", tex->name );
  8207. -
  8208. - width = pic->width;
  8209. - height = pic->height;
  8210. - depth = pic->depth;
  8211. -
  8212. - for( j = 0; j < numMips; j++ )
  8213. - {
  8214. - width = max( 1, ( pic->width >> j ));
  8215. - height = max( 1, ( pic->height >> j ));
  8216. - texsize = Image_DXTGetLinearSize( pic->type, width, height, depth );
  8217. - if( ImageDXT( pic->type ))
  8218. - GL_TextureImageDXT( inFormat, glTarget, i, j, width, height, depth, subImage, texsize, buf );
  8219. - else GL_TextureImage( inFormat, tex->format, glTarget, i, j, width, height, depth, subImage, texsize, buf );
  8220. -
  8221. - buf += texsize; // move pointer
  8222. + int err;
  8223.  
  8224. - // catch possible errors
  8225. - if(( err = pglGetError()) != GL_NO_ERROR )
  8226. - MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_Target( glTarget ));
  8227. + ASSERT( tex != NULL );
  8228.  
  8229. - }
  8230. - }
  8231. + // catch possible errors
  8232. + if(( err = pglGetError()) != GL_NO_ERROR )
  8233. + MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_TargetToString( tex->target ));
  8234. }
  8235.  
  8236. /*
  8237. @@ -1241,211 +1049,192 @@ GL_UploadTexture
  8238. upload texture into video memory
  8239. ===============
  8240. */
  8241. -static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImage, imgfilter_t *filter )
  8242. +static qboolean GL_UploadTexture( gltexture_t *tex, rgbdata_t *pic )
  8243. {
  8244. byte *buf, *data;
  8245. + size_t texsize, size;
  8246. + uint width, height;
  8247. + uint i, j, numSides;
  8248. + uint offset = 0;
  8249. + qboolean normalMap;
  8250. const byte *bufend;
  8251. - GLenum outFormat, inFormat, glTarget;
  8252. - uint i, s, numSides, offset = 0, err;
  8253. - int texsize = 0, img_flags = 0, samples;
  8254. - GLint dataType = GL_UNSIGNED_BYTE;
  8255.  
  8256. - ASSERT( pic != NULL && tex != NULL );
  8257. + ASSERT( pic != NULL );
  8258. + ASSERT( tex != NULL );
  8259.  
  8260. - if( pic->flags & IMAGE_DDS_FORMAT )
  8261. + GL_SetTextureTarget( tex, pic ); // must be first
  8262. +
  8263. + // make sure what target is correct
  8264. + if( tex->target == GL_NONE )
  8265. {
  8266. - // special case for DDS textures
  8267. - GL_UploadTextureDXT( pic, tex, subImage, filter );
  8268. - return;
  8269. + MsgDev( D_ERROR, "GL_UploadTexture: %s is not supported by your hardware\n", tex->name );
  8270. + return false;
  8271. }
  8272.  
  8273. - tex->srcWidth = tex->width = pic->width;
  8274. - tex->srcHeight = tex->height = pic->height;
  8275. - s = tex->srcWidth * tex->srcHeight;
  8276. + GL_SetTextureDimensions( tex, pic->width, pic->height, pic->depth );
  8277. + GL_SetTextureFormat( tex, pic->type, pic->flags );
  8278.  
  8279. tex->fogParams[0] = pic->fogParams[0];
  8280. tex->fogParams[1] = pic->fogParams[1];
  8281. tex->fogParams[2] = pic->fogParams[2];
  8282. tex->fogParams[3] = pic->fogParams[3];
  8283.  
  8284. - // NOTE: normalmaps must be power of two or software mip generator will stop working
  8285. - GL_RoundImageDimensions( &tex->width, &tex->height, tex->flags, ( tex->flags & TF_NORMALMAP ));
  8286. -
  8287. - if( s&3 )
  8288. - {
  8289. - // will be resample, just tell me for debug targets
  8290. - MsgDev( D_NOTE, "GL_Upload: %s s&3 [%d x %d]\n", tex->name, tex->srcWidth, tex->srcHeight );
  8291. - }
  8292. -
  8293. - // copy flag about luma pixels
  8294. - if( pic->flags & IMAGE_HAS_LUMA )
  8295. - tex->flags |= TF_HAS_LUMA;
  8296. -
  8297. - // create luma texture from quake texture
  8298. - if( tex->flags & TF_MAKELUMA )
  8299. + if(( pic->width * pic->height ) & 3 )
  8300. {
  8301. - img_flags |= IMAGE_MAKE_LUMA;
  8302. - tex->flags &= ~TF_MAKELUMA;
  8303. + // will be resampled, just tell me for debug targets
  8304. + MsgDev( D_NOTE, "GL_UploadTexture: %s s&3 [%d x %d]\n", tex->name, pic->width, pic->height );
  8305. }
  8306.  
  8307. - if( !subImage && tex->flags & TF_KEEP_8BIT )
  8308. - tex->original = FS_CopyImage( pic ); // because current pic will be expanded to rgba
  8309. -
  8310. - if( !subImage && tex->flags & TF_KEEP_RGBDATA )
  8311. - tex->original = pic; // no need to copy
  8312. -
  8313. - // we need to expand image into RGBA buffer
  8314. - if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
  8315. - img_flags |= IMAGE_FORCE_RGBA;
  8316. + buf = pic->buffer;
  8317. + bufend = pic->buffer + pic->size; // total image size include all the layers, cube sides, mipmaps
  8318. + offset = GL_CalcImageSize( pic->type, pic->width, pic->height, pic->depth );
  8319. + texsize = GL_CalcTextureSize( tex->format, tex->width, tex->height, tex->depth );
  8320. + normalMap = ( tex->flags & TF_NORMALMAP ) ? true : false;
  8321. + numSides = ( pic->flags & IMAGE_CUBEMAP ) ? 6 : 1;
  8322.  
  8323. - // processing image before uploading (force to rgba, make luma etc)
  8324. - if( pic->buffer ) Image_Process( &pic, 0, 0, 0.0f, img_flags, filter );
  8325. + // uploading texture into video memory
  8326. + pglBindTexture( tex->target, tex->texnum );
  8327.  
  8328. - if( tex->flags & TF_LUMINANCE )
  8329. + for( i = 0; i < numSides; i++ )
  8330. {
  8331. - if( !( tex->flags & TF_DEPTHMAP ))
  8332. + // track the buffer bounds
  8333. + if( buf != NULL && buf >= bufend )
  8334. + Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name );
  8335. +
  8336. + if( ImageDXT( pic->type ))
  8337. {
  8338. - GL_MakeLuminance( pic );
  8339. - tex->flags &= ~TF_LUMINANCE;
  8340. + for( j = 0; j < max( 1, pic->numMips ); j++ )
  8341. + {
  8342. + width = max( 1, ( tex->width >> j ));
  8343. + height = max( 1, ( tex->height >> j ));
  8344. + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
  8345. + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
  8346. + GL_TextureImageDXT( tex, i, j, width, height, tex->depth, size, buf );
  8347. + tex->size += texsize;
  8348. + buf += size; // move pointer
  8349. + tex->numMips++;
  8350. +
  8351. + GL_CheckTexImageError( tex );
  8352. + }
  8353. }
  8354. - pic->flags &= ~IMAGE_HAS_COLOR;
  8355. - }
  8356. -
  8357. - samples = GL_CalcTextureSamples( pic->flags );
  8358. -
  8359. - if( pic->flags & IMAGE_HAS_ALPHA )
  8360. - tex->flags |= TF_HAS_ALPHA;
  8361. -
  8362. - // determine format
  8363. - inFormat = PFDesc[pic->type].glFormat;
  8364. - outFormat = GL_TextureFormat( tex, &samples );
  8365. - tex->format = outFormat;
  8366. + else if( max( 1, pic->numMips ) > 1 ) // not-compressed DDS
  8367. + {
  8368. + for( j = 0; j < max( 1, pic->numMips ); j++ )
  8369. + {
  8370. + width = max( 1, ( tex->width >> j ));
  8371. + height = max( 1, ( tex->height >> j ));
  8372. + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
  8373. + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
  8374. + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, buf );
  8375. + tex->size += texsize;
  8376. + buf += size; // move pointer
  8377. + tex->numMips++;
  8378.  
  8379. - // determine target
  8380. - tex->target = glTarget = GL_TEXTURE_2D;
  8381. - numSides = 1;
  8382. + GL_CheckTexImageError( tex );
  8383.  
  8384. - if( tex->flags & TF_FLOATDATA )
  8385. - dataType = GL_FLOAT;
  8386. + }
  8387. + }
  8388. + else // RGBA32
  8389. + {
  8390. + int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL ));
  8391.  
  8392. - if( tex->flags & TF_DEPTHMAP )
  8393. - inFormat = GL_DEPTH_COMPONENT;
  8394. + // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
  8395. + if(( tex->depth == 1 ) && ( pic->width != tex->width ) || ( pic->height != tex->height ))
  8396. + data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap );
  8397. + else data = buf;
  8398.  
  8399. - if( pic->flags & IMAGE_CUBEMAP )
  8400. - {
  8401. - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8402. - {
  8403. - numSides = 6;
  8404. - tex->target = glTarget = GL_TEXTURE_CUBE_MAP_ARB;
  8405. - tex->flags |= TF_CUBEMAP;
  8406. + if( !glConfig.deviceSupportsGamma )
  8407. + {
  8408. + if( !ImageDXT( pic->type ) && !( tex->flags & TF_NOMIPMAP ) && !( tex->flags & TF_SKYSIDE ))
  8409. + data = GL_ApplyGamma( data, tex->width * tex->height * tex->depth, ( tex->flags & TF_NORMALMAP ));
  8410. + }
  8411.  
  8412. - if( !GL_Support( GL_ARB_SEAMLESS_CUBEMAP ) && ( tex->flags & ( TF_BORDER|TF_ALPHA_BORDER )))
  8413. + // mips will be auto-generated if desired
  8414. + for( j = 0; j < mipCount; j++ )
  8415. {
  8416. - // don't use border for cubemaps
  8417. - tex->flags &= ~(TF_BORDER|TF_ALPHA_BORDER);
  8418. - tex->flags |= TF_CLAMP;
  8419. + width = max( 1, ( tex->width >> j ));
  8420. + height = max( 1, ( tex->height >> j ));
  8421. + texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
  8422. + size = GL_CalcImageSize( pic->type, width, height, tex->depth );
  8423. + GL_TextureImageRAW( tex, i, j, width, height, tex->depth, pic->type, data );
  8424. + if( mipCount > 1 )
  8425. + GL_BuildMipMap( data, width, height, tex->depth, normalMap );
  8426. + tex->size += texsize;
  8427. + tex->numMips++;
  8428. +
  8429. + GL_CheckTexImageError( tex );
  8430. }
  8431. +
  8432. + // move to next side
  8433. + if( numSides > 1 && ( buf != NULL ))
  8434. + buf += GL_CalcImageSize( pic->type, pic->width, pic->height, 1 );
  8435. }
  8436. - else
  8437. - {
  8438. - MsgDev( D_WARN, "GL_UploadTexture: cubemaps isn't supported, %s ignored\n", tex->name );
  8439. - tex->flags &= ~TF_CUBEMAP;
  8440. - }
  8441. - }
  8442. - else if( tex->flags & TF_TEXTURE_1D )
  8443. - {
  8444. - // determine target
  8445. - tex->target = glTarget = GL_TEXTURE_1D;
  8446. - }
  8447. - else if( tex->flags & TF_TEXTURE_RECTANGLE )
  8448. - {
  8449. - if( glConfig.max_2d_rectangle_size )
  8450. - tex->target = glTarget = glConfig.texRectangle;
  8451. - // or leave as GL_TEXTURE_2D
  8452. - }
  8453. - else if( tex->flags & TF_TEXTURE_3D )
  8454. - {
  8455. - // determine target
  8456. - tex->target = glTarget = GL_TEXTURE_3D;
  8457. }
  8458.  
  8459. - pglBindTexture( tex->target, tex->texnum );
  8460. + tex->flags |= TF_IMG_UPLOADED; // done
  8461.  
  8462. - buf = pic->buffer;
  8463. - bufend = pic->buffer + pic->size;
  8464. - offset = pic->width * pic->height * PFDesc[pic->type].bpp;
  8465. + return true;
  8466. +}
  8467.  
  8468. - // NOTE: probably this code relies when gl_compressed_textures is enabled
  8469. - texsize = tex->width * tex->height * samples;
  8470. +/*
  8471. +===============
  8472. +GL_ProcessImage
  8473.  
  8474. - // determine some texTypes
  8475. - if( tex->flags & TF_NOPICMIP )
  8476. - tex->texType = TEX_NOMIP;
  8477. - else if( tex->flags & TF_CUBEMAP )
  8478. - tex->texType = TEX_CUBEMAP;
  8479. - else if(( tex->flags & TF_DECAL ) == TF_DECAL )
  8480. - tex->texType = TEX_DECAL;
  8481. +do specified actions on pixels
  8482. +===============
  8483. +*/
  8484. +static void GL_ProcessImage( gltexture_t *tex, rgbdata_t *pic, imgfilter_t *filter )
  8485. +{
  8486. + uint img_flags = 0;
  8487.  
  8488. - // uploading texture into video memory
  8489. - for( i = 0; i < numSides; i++ )
  8490. - {
  8491. - if( buf != NULL && buf >= bufend )
  8492. - Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name );
  8493. + // force upload texture as RGB or RGBA (detail textures requires this)
  8494. + if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
  8495. + if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA;
  8496.  
  8497. - // copy or resample the texture
  8498. - if(( tex->width == tex->srcWidth && tex->height == tex->srcHeight ) || ( tex->flags & ( TF_TEXTURE_1D|TF_TEXTURE_3D )))
  8499. - {
  8500. - data = buf;
  8501. - }
  8502. - else
  8503. - {
  8504. - data = GL_ResampleTexture( buf, tex->srcWidth, tex->srcHeight, tex->width, tex->height, ( tex->flags & TF_NORMALMAP ));
  8505. - }
  8506. + tex->encode = pic->encode; // share encode method
  8507.  
  8508. - if( !glConfig.deviceSupportsGamma )
  8509. - {
  8510. - if(!( tex->flags & TF_NOMIPMAP ) && !( tex->flags & TF_SKYSIDE ) && !( tex->flags & TF_TEXTURE_3D ))
  8511. - data = GL_ApplyGamma( data, tex->width * tex->height, ( tex->flags & TF_NORMALMAP ));
  8512. - }
  8513. + if( ImageDXT( pic->type ))
  8514. + {
  8515. + if( !pic->numMips )
  8516. + tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request
  8517.  
  8518. - if( glTarget == GL_TEXTURE_1D )
  8519. - {
  8520. - if( subImage ) pglTexSubImage1D( tex->target, 0, 0, tex->width, inFormat, dataType, data );
  8521. - else pglTexImage1D( tex->target, 0, outFormat, tex->width, 0, inFormat, dataType, data );
  8522. - }
  8523. - else if( glTarget == GL_TEXTURE_CUBE_MAP_ARB )
  8524. - {
  8525. - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & TF_NORMALMAP ))
  8526. - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
  8527. - if( subImage ) pglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, 0, 0, 0, tex->width, tex->height, inFormat, dataType, data );
  8528. - else pglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, 0, outFormat, tex->width, tex->height, 0, inFormat, dataType, data );
  8529. - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ) || ( tex->flags & TF_NORMALMAP ))
  8530. - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
  8531. - }
  8532. - else if( glTarget == GL_TEXTURE_3D )
  8533. - {
  8534. - if( subImage ) pglTexSubImage3D( tex->target, 0, 0, 0, 0, tex->width, tex->height, pic->depth, inFormat, dataType, data );
  8535. - else pglTexImage3D( tex->target, 0, outFormat, tex->width, tex->height, pic->depth, 0, inFormat, dataType, data );
  8536. - }
  8537. - else
  8538. + // clear all the unsupported flags
  8539. + tex->flags &= ~TF_KEEP_8BIT;
  8540. + tex->flags &= ~TF_KEEP_RGBDATA;
  8541. + tex->flags |= TF_NOPICMIP;
  8542. + }
  8543. + else
  8544. + {
  8545. + // copy flag about luma pixels
  8546. + if( pic->flags & IMAGE_HAS_LUMA )
  8547. + tex->flags |= TF_HAS_LUMA;
  8548. +
  8549. + // create luma texture from quake texture
  8550. + if( tex->flags & TF_MAKELUMA )
  8551. {
  8552. - if( GL_Support( GL_SGIS_MIPMAPS_EXT ) && !( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
  8553. - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
  8554. - if( subImage ) pglTexSubImage2D( tex->target, 0, 0, 0, tex->width, tex->height, inFormat, dataType, data );
  8555. - else pglTexImage2D( tex->target, 0, outFormat, tex->width, tex->height, 0, inFormat, dataType, data );
  8556. - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ) || ( tex->flags & ( TF_NORMALMAP|TF_ALPHACONTRAST )))
  8557. - GL_GenerateMipmaps( data, pic, tex, glTarget, inFormat, i, subImage );
  8558. + img_flags |= IMAGE_MAKE_LUMA;
  8559. + tex->flags &= ~TF_MAKELUMA;
  8560. }
  8561.  
  8562. - if( numSides > 1 && buf != NULL )
  8563. - buf += offset;
  8564. - tex->size += texsize;
  8565. + if( !( tex->flags & TF_IMG_UPLOADED ) && ( tex->flags & ( TF_KEEP_8BIT|TF_KEEP_RGBDATA )))
  8566. + tex->original = FS_CopyImage( pic ); // because current pic will be expanded to rgba
  8567. +
  8568. + // we need to expand image into RGBA buffer
  8569. + if( pic->type == PF_INDEXED_24 || pic->type == PF_INDEXED_32 )
  8570. + img_flags |= IMAGE_FORCE_RGBA;
  8571.  
  8572. - // catch possible errors
  8573. - err = pglGetError();
  8574. + // processing image before uploading (force to rgba, make luma etc)
  8575. + if( pic->buffer ) Image_Process( &pic, 0, 0, 0.0f, img_flags, filter );
  8576.  
  8577. - if( err != GL_NO_ERROR )
  8578. - MsgDev( D_ERROR, "GL_UploadTexture: error %x while uploading %s [%s]\n", err, tex->name, GL_Target( glTarget ));
  8579. + if( tex->flags & TF_LUMINANCE )
  8580. + {
  8581. + if( !( tex->flags & TF_DEPTHMAP ))
  8582. + {
  8583. + GL_MakeLuminance( pic );
  8584. + tex->flags &= ~TF_LUMINANCE;
  8585. + }
  8586. + pic->flags &= ~IMAGE_HAS_COLOR;
  8587. + }
  8588. }
  8589. }
  8590.  
  8591. @@ -1499,9 +1288,6 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i
  8592. pic = FS_LoadImage( name, buf, size );
  8593. if( !pic ) return 0; // couldn't loading image
  8594.  
  8595. - // force upload texture as RGB or RGBA (detail textures requires this)
  8596. - if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
  8597. -
  8598. // find a free texture slot
  8599. if( r_numTextures == MAX_TEXTURES )
  8600. Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
  8601. @@ -1525,11 +1311,192 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i
  8602. tex->texnum = tr.skyboxbasenum++;
  8603. else tex->texnum = i; // texnum is used for fast acess into r_textures array too
  8604.  
  8605. - GL_UploadTexture( pic, tex, false, filter );
  8606. - GL_TexFilter( tex, false ); // update texture filter, wrap etc
  8607. + GL_ProcessImage( tex, pic, filter );
  8608. +
  8609. + if( !GL_UploadTexture( tex, pic ))
  8610. + {
  8611. + memset( tex, 0, sizeof( gltexture_t ));
  8612. + FS_FreeImage( pic ); // release source texture
  8613. + return 0;
  8614. + }
  8615. +
  8616. + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
  8617. + FS_FreeImage( pic ); // release source texture
  8618. +
  8619. + // add to hash table
  8620. + hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE );
  8621. + tex->nextHash = r_texturesHashTable[hash];
  8622. + r_texturesHashTable[hash] = tex;
  8623. +
  8624. + // NOTE: always return texnum as index in array or engine will stop work !!!
  8625. + return i;
  8626. +}
  8627. +
  8628. +/*
  8629. +================
  8630. +GL_LoadTextureArray
  8631. +================
  8632. +*/
  8633. +int GL_LoadTextureArray( const char **names, int flags, imgfilter_t *filter )
  8634. +{
  8635. + gltexture_t *tex;
  8636. + rgbdata_t *pic, *src;
  8637. + char basename[256];
  8638. + uint numLayers = 0;
  8639. + uint picFlags = 0;
  8640. + char name[256];
  8641. + uint i, j, hash;
  8642. +
  8643. + if( !names || !names[0] || !glw_state.initialized )
  8644. + return 0;
  8645. +
  8646. + // count layers (g-cont. this is pontentially unsafe loop)
  8647. + for( i = 0; i < glConfig.max_2d_texture_layers && ( *names[i] != '\0' ); i++ )
  8648. + numLayers++;
  8649. + name[0] = '\0';
  8650. +
  8651. + if( numLayers <= 0 ) return 0;
  8652. +
  8653. + // create complexname from layer names
  8654. + for( i = 0; i < numLayers; i++ )
  8655. + {
  8656. + FS_FileBase( names[i], basename );
  8657. + Q_strncat( name, va( "%s", basename ), sizeof( name ));
  8658. + if( i != ( numLayers - 1 )) Q_strncat( name, "|", sizeof( name ));
  8659. + }
  8660. +
  8661. + Q_strncat( name, va( "[%i]", numLayers ), sizeof( name ));
  8662. +
  8663. + if( Q_strlen( name ) >= sizeof( r_textures->name ))
  8664. + {
  8665. + MsgDev( D_ERROR, "GL_LoadTextureArray: too long name %s\n", name );
  8666. + return 0;
  8667. + }
  8668. +
  8669. + // see if already loaded
  8670. + hash = Com_HashKey( name, TEXTURES_HASH_SIZE );
  8671. +
  8672. + for( tex = r_texturesHashTable[hash]; tex != NULL; tex = tex->nextHash )
  8673. + {
  8674. + if( !Q_stricmp( tex->name, name ))
  8675. + {
  8676. + // prolonge registration
  8677. + tex->cacheframe = world.load_sequence;
  8678. + return (tex - r_textures);
  8679. + }
  8680. + }
  8681. +
  8682. + // load all the images and pack it into single image
  8683. + for( i = 0, pic = NULL; i < numLayers; i++ )
  8684. + {
  8685. + size_t srcsize, dstsize, mipsize;
  8686. +
  8687. + src = FS_LoadImage( names[i], NULL, 0 );
  8688. + if( !src ) break; // coldn't find layer
  8689. +
  8690. + if( pic )
  8691. + {
  8692. + // mixed mode: DXT + RGB
  8693. + if( pic->type != src->type )
  8694. + {
  8695. + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch image format for %s and %s\n", names[0], names[i] );
  8696. + break;
  8697. + }
  8698. +
  8699. + // different mipcount
  8700. + if( pic->numMips != src->numMips )
  8701. + {
  8702. + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch mip count for %s and %s\n", names[0], names[i] );
  8703. + break;
  8704. + }
  8705. +
  8706. + if( pic->encode != src->encode )
  8707. + {
  8708. + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch custom encoding for %s and %s\n", names[0], names[i] );
  8709. + break;
  8710. + }
  8711. +
  8712. + // but allow to rescale raw images
  8713. + if( ImageRAW( pic->type ) && ImageRAW( src->type ) && ( pic->width != src->width || pic->height != src->height ))
  8714. + Image_Process( &src, pic->width, pic->height, 0.0f, IMAGE_RESAMPLE, NULL );
  8715. +
  8716. + if( pic->size != src->size )
  8717. + {
  8718. + MsgDev( D_ERROR, "GL_LoadTextureArray: mismatch image size for %s and %s\n", names[0], names[i] );
  8719. + break;
  8720. + }
  8721. + }
  8722. + else
  8723. + {
  8724. + // create new image
  8725. + pic = Mem_Alloc( host.imagepool, sizeof( rgbdata_t ));
  8726. + memcpy( pic, src, sizeof( rgbdata_t ));
  8727. +
  8728. + // expand pic buffer for all layers
  8729. + pic->buffer = Mem_Alloc( host.imagepool, pic->size * numLayers );
  8730. + pic->depth = 0;
  8731. + }
  8732. +
  8733. + mipsize = srcsize = dstsize = 0;
  8734. +
  8735. + for( j = 0; j < max( 1, pic->numMips ); j++ )
  8736. + {
  8737. + int width = max( 1, ( pic->width >> j ));
  8738. + int height = max( 1, ( pic->height >> j ));
  8739. + mipsize = GL_CalcImageSize( pic->type, width, height, 1 );
  8740. + memcpy( pic->buffer + dstsize + mipsize * i, src->buffer + srcsize, mipsize );
  8741. + dstsize += mipsize * numLayers;
  8742. + srcsize += mipsize;
  8743. + }
  8744. +
  8745. + FS_FreeImage( src );
  8746. +
  8747. + // increase layers
  8748. + pic->depth++;
  8749. + }
  8750. +
  8751. + // there were errors
  8752. + if( !pic || ( pic->depth != numLayers ))
  8753. + {
  8754. + MsgDev( D_ERROR, "GL_LoadTextureArray: not all layers were loaded. Texture array is not created\n" );
  8755. + if( pic ) FS_FreeImage( pic );
  8756. + return 0;
  8757. + }
  8758. +
  8759. + // it's multilayer image!
  8760. + pic->flags |= IMAGE_MULTILAYER;
  8761. + pic->size *= numLayers;
  8762. +
  8763. + // find a free texture slot
  8764. + if( r_numTextures == MAX_TEXTURES )
  8765. + Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
  8766. +
  8767. + // find a free texture_t slot
  8768. + for( i = 0, tex = r_textures; i < r_numTextures; i++, tex++ )
  8769. + if( !tex->name[0] ) break;
  8770. +
  8771. + if( i == r_numTextures )
  8772. + {
  8773. + if( r_numTextures == MAX_TEXTURES )
  8774. + Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
  8775. + r_numTextures++;
  8776. + }
  8777. +
  8778. + tex = &r_textures[i];
  8779. + Q_strncpy( tex->name, name, sizeof( tex->name ));
  8780. + tex->flags = flags;
  8781. + tex->texnum = i; // texnum is used for fast acess into r_textures array too
  8782.  
  8783. - if(!( flags & ( TF_KEEP_8BIT|TF_KEEP_RGBDATA )))
  8784. + GL_ProcessImage( tex, pic, filter );
  8785. + if( !GL_UploadTexture( tex, pic ))
  8786. + {
  8787. + memset( tex, 0, sizeof( gltexture_t ));
  8788. FS_FreeImage( pic ); // release source texture
  8789. + return 0;
  8790. + }
  8791. +
  8792. + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
  8793. + FS_FreeImage( pic ); // release source texture
  8794.  
  8795. // add to hash table
  8796. hash = Com_HashKey( tex->name, TEXTURES_HASH_SIZE );
  8797. @@ -1579,9 +1546,6 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
  8798. Host_Error( "Couldn't find texture %s for update\n", name );
  8799. }
  8800.  
  8801. - // force upload texture as RGB or RGBA (detail textures requires this)
  8802. - if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR;
  8803. -
  8804. // find a free texture slot
  8805. if( r_numTextures == MAX_TEXTURES )
  8806. Host_Error( "GL_LoadTexture: MAX_TEXTURES limit exceeds\n" );
  8807. @@ -1610,8 +1574,15 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
  8808. tex->flags |= flags;
  8809. }
  8810.  
  8811. - GL_UploadTexture( pic, tex, update, NULL );
  8812. - GL_TexFilter( tex, update ); // update texture filter, wrap etc
  8813. + GL_ProcessImage( tex, pic, NULL );
  8814. + if( !GL_UploadTexture( tex, pic ))
  8815. + {
  8816. + memset( tex, 0, sizeof( gltexture_t ));
  8817. + FS_FreeImage( pic ); // release source texture
  8818. + return 0;
  8819. + }
  8820. +
  8821. + GL_ApplyTextureParams( tex ); // update texture filter, wrap etc
  8822.  
  8823. if( !update )
  8824. {
  8825. @@ -1628,7 +1599,7 @@ int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags,
  8826. ================
  8827. GL_CreateTexture
  8828.  
  8829. -creates an empty 32-bit texture (just reserve slot)
  8830. +creates texture from buffer
  8831. ================
  8832. */
  8833. int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
  8834. @@ -1654,7 +1625,7 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
  8835. if( !GL_Support( GL_TEXTURE_3D_EXT ))
  8836. return 0;
  8837.  
  8838. - r_empty.depth = r_empty.width;
  8839. + r_empty.depth = r_empty.width; // HACKHACK
  8840. r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4;
  8841. }
  8842. else if( flags & TF_CUBEMAP )
  8843. @@ -1666,9 +1637,43 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
  8844.  
  8845. texture = GL_LoadTextureInternal( name, &r_empty, flags, false );
  8846.  
  8847. - if( flags & TF_DEPTHMAP )
  8848. - GL_SetTextureType( texture, TEX_DEPTHMAP );
  8849. - else GL_SetTextureType( texture, TEX_CUSTOM );
  8850. + return texture;
  8851. +}
  8852. +
  8853. +/*
  8854. +================
  8855. +GL_CreateTextureArray
  8856. +
  8857. +creates texture array from buffer
  8858. +================
  8859. +*/
  8860. +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags )
  8861. +{
  8862. + rgbdata_t r_empty;
  8863. + int texture;
  8864. +
  8865. + memset( &r_empty, 0, sizeof( r_empty ));
  8866. + r_empty.width = width;
  8867. + r_empty.height = height;
  8868. + r_empty.depth = depth;
  8869. + r_empty.type = PF_RGBA_32;
  8870. + r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4;
  8871. + r_empty.flags = IMAGE_HAS_COLOR | (( flags & TF_HAS_ALPHA ) ? IMAGE_HAS_ALPHA : 0 );
  8872. + r_empty.buffer = (byte *)buffer;
  8873. +
  8874. + if( flags & TF_TEXTURE_3D )
  8875. + {
  8876. + if( !GL_Support( GL_TEXTURE_3D_EXT ))
  8877. + return 0;
  8878. + }
  8879. + else
  8880. + {
  8881. + if( !GL_Support( GL_TEXTURE_ARRAY_EXT ))
  8882. + return 0;
  8883. + r_empty.flags |= IMAGE_MULTILAYER;
  8884. + }
  8885. +
  8886. + texture = GL_LoadTextureInternal( name, &r_empty, flags, false );
  8887.  
  8888. return texture;
  8889. }
  8890. @@ -1703,7 +1708,7 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
  8891. return;
  8892. }
  8893.  
  8894. - if(!( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT)) || !image->original )
  8895. + if( !image->original )
  8896. {
  8897. MsgDev( D_ERROR, "GL_ProcessTexture: no input data for %s\n", image->name );
  8898. return;
  8899. @@ -1719,8 +1724,8 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
  8900. pic = FS_CopyImage( image->original );
  8901. Image_Process( &pic, topColor, bottomColor, gamma, flags, NULL );
  8902.  
  8903. - GL_UploadTexture( pic, image, true, NULL );
  8904. - GL_TexFilter( image, true ); // update texture filter, wrap etc
  8905. + GL_UploadTexture( image, pic );
  8906. + GL_ApplyTextureParams( image ); // update texture filter, wrap etc
  8907.  
  8908. FS_FreeImage( pic );
  8909. }
  8910. @@ -1777,7 +1782,7 @@ void GL_FreeImage( const char *name )
  8911.  
  8912. if( Q_strlen( name ) >= sizeof( r_textures->name ))
  8913. {
  8914. - MsgDev( D_ERROR, "GL_FreeImage: too long name %s\n", name, sizeof( r_textures->name ));
  8915. + MsgDev( D_ERROR, "GL_FreeImage: too long name %s\n", name );
  8916. return;
  8917. }
  8918.  
  8919. @@ -1847,7 +1852,7 @@ void R_FreeImage( gltexture_t *image )
  8920. }
  8921.  
  8922. // release source
  8923. - if( image->flags & (TF_KEEP_RGBDATA|TF_KEEP_8BIT) && image->original )
  8924. + if( image->original )
  8925. FS_FreeImage( image->original );
  8926.  
  8927. pglDeleteTextures( 1, &image->texnum );
  8928. @@ -2272,7 +2277,7 @@ static rgbdata_t *R_InitNormalizeCubemap( texFlags_t *flags )
  8929. float s, t;
  8930. vec3_t normal;
  8931.  
  8932. - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8933. + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  8934. return NULL;
  8935.  
  8936. // normal cube map texture
  8937. @@ -2328,7 +2333,7 @@ static rgbdata_t *R_InitDlightCubemap( texFlags_t *flags )
  8938. byte *dataCM = data2D;
  8939. int dx2, dy, d;
  8940.  
  8941. - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8942. + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  8943. return NULL;
  8944.  
  8945. // normal cube map texture
  8946. @@ -2372,7 +2377,7 @@ static rgbdata_t *R_InitGrayCubemap( texFlags_t *flags )
  8947. int size = 4;
  8948. byte *dataCM = data2D;
  8949.  
  8950. - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8951. + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  8952. return NULL;
  8953.  
  8954. // gray cubemap - just stub for pointlights
  8955. @@ -2399,7 +2404,7 @@ static rgbdata_t *R_InitWhiteCubemap( texFlags_t *flags )
  8956. int size = 4;
  8957. byte *dataCM = data2D;
  8958.  
  8959. - if( !GL_Support( GL_TEXTURECUBEMAP_EXT ))
  8960. + if( !GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  8961. return NULL;
  8962.  
  8963. // white cubemap - just stub for pointlights
  8964. @@ -2418,29 +2423,6 @@ static rgbdata_t *R_InitWhiteCubemap( texFlags_t *flags )
  8965.  
  8966. /*
  8967. ==================
  8968. -R_InitAlphaContrast
  8969. -==================
  8970. -*/
  8971. -static rgbdata_t *R_InitAlphaContrast( texFlags_t *flags )
  8972. -{
  8973. - int size = 64;
  8974. - byte *data = data2D;
  8975. -
  8976. - *flags = (TF_NOPICMIP|TF_UNCOMPRESSED|TF_ALPHACONTRAST|TF_INTENSITY);
  8977. -
  8978. - r_image.width = r_image.height = 64;
  8979. - r_image.size = r_image.width * r_image.height * 4;
  8980. -
  8981. - memset( data, size, r_image.size );
  8982. -
  8983. - r_image.buffer = data2D;
  8984. - r_image.type = PF_RGBA_32;
  8985. -
  8986. - return &r_image;
  8987. -}
  8988. -
  8989. -/*
  8990. -==================
  8991. R_InitVSDCTCubemap
  8992. ==================
  8993. */
  8994. @@ -2488,33 +2470,32 @@ static void R_InitBuiltinTextures( void )
  8995. char *name;
  8996. int *texnum;
  8997. rgbdata_t *(*init)( texFlags_t *flags );
  8998. - int texType;
  8999. }
  9000. +
  9001. textures[] =
  9002. {
  9003. - { "*default", &tr.defaultTexture, R_InitDefaultTexture, TEX_SYSTEM },
  9004. - { "*white", &tr.whiteTexture, R_InitWhiteTexture, TEX_SYSTEM },
  9005. - { "*gray", &tr.grayTexture, R_InitGrayTexture, TEX_SYSTEM },
  9006. - { "*black", &tr.blackTexture, R_InitBlackTexture, TEX_SYSTEM },
  9007. - { "*particle", &tr.particleTexture, R_InitParticleTexture, TEX_SYSTEM },
  9008. - { "*particle2", &tr.particleTexture2, R_InitParticleTexture2, TEX_SYSTEM },
  9009. - { "*cintexture", &tr.cinTexture, R_InitCinematicTexture, TEX_NOMIP }, // force linear filter
  9010. - { "*dlight", &tr.dlightTexture, R_InitDlightTexture, TEX_LIGHTMAP },
  9011. - { "*dlight2", &tr.dlightTexture2, R_InitDlightTexture2, TEX_LIGHTMAP },
  9012. - { "*atten", &tr.attenuationTexture, R_InitAttenuationTexture, TEX_SYSTEM },
  9013. - { "*atten2", &tr.attenuationTexture2, R_InitAttenuationTexture2, TEX_SYSTEM },
  9014. - { "*atten3", &tr.attenuationTexture3, R_InitAttenuationTexture3, TEX_SYSTEM },
  9015. - { "*attnno", &tr.attenuationStubTexture, R_InitAttenuationTextureNoAtten, TEX_SYSTEM },
  9016. - { "*normalize", &tr.normalizeTexture, R_InitNormalizeCubemap, TEX_CUBEMAP },
  9017. - { "*blankbump", &tr.blankbumpTexture, R_InitBlankBumpTexture, TEX_SYSTEM },
  9018. - { "*blankdeluxe", &tr.blankdeluxeTexture, R_InitBlankDeluxeTexture, TEX_SYSTEM },
  9019. - { "*lightCube", &tr.dlightCubeTexture, R_InitDlightCubemap, TEX_CUBEMAP },
  9020. - { "*grayCube", &tr.grayCubeTexture, R_InitGrayCubemap, TEX_CUBEMAP },
  9021. - { "*whiteCube", &tr.whiteCubeTexture, R_InitWhiteCubemap, TEX_CUBEMAP },
  9022. - { "*atten3D", &tr.attenuationTexture3D, R_InitAttenTexture3D, TEX_SYSTEM },
  9023. - { "*sky", &tr.skyTexture, R_InitSkyTexture, TEX_SYSTEM },
  9024. - { "*alphaContrast", &tr.acontTexture, R_InitAlphaContrast, TEX_SYSTEM },
  9025. - { "*vsdct", &tr.vsdctCubeTexture, R_InitVSDCTCubemap, TEX_SYSTEM },
  9026. + { "*default", &tr.defaultTexture, R_InitDefaultTexture },
  9027. + { "*white", &tr.whiteTexture, R_InitWhiteTexture },
  9028. + { "*gray", &tr.grayTexture, R_InitGrayTexture },
  9029. + { "*black", &tr.blackTexture, R_InitBlackTexture },
  9030. + { "*particle", &tr.particleTexture, R_InitParticleTexture },
  9031. + { "*particle2", &tr.particleTexture2, R_InitParticleTexture2 },
  9032. + { "*cintexture", &tr.cinTexture, R_InitCinematicTexture }, // force linear filter
  9033. + { "*dlight", &tr.dlightTexture, R_InitDlightTexture },
  9034. + { "*dlight2", &tr.dlightTexture2, R_InitDlightTexture2 },
  9035. + { "*atten", &tr.attenuationTexture, R_InitAttenuationTexture },
  9036. + { "*atten2", &tr.attenuationTexture2, R_InitAttenuationTexture2 },
  9037. + { "*atten3", &tr.attenuationTexture3, R_InitAttenuationTexture3 },
  9038. + { "*attnno", &tr.attenuationStubTexture, R_InitAttenuationTextureNoAtten },
  9039. + { "*normalize", &tr.normalizeTexture, R_InitNormalizeCubemap },
  9040. + { "*blankbump", &tr.blankbumpTexture, R_InitBlankBumpTexture },
  9041. + { "*blankdeluxe", &tr.blankdeluxeTexture, R_InitBlankDeluxeTexture },
  9042. + { "*lightCube", &tr.dlightCubeTexture, R_InitDlightCubemap },
  9043. + { "*grayCube", &tr.grayCubeTexture, R_InitGrayCubemap },
  9044. + { "*whiteCube", &tr.whiteCubeTexture, R_InitWhiteCubemap },
  9045. + { "*atten3D", &tr.attenuationTexture3D, R_InitAttenTexture3D },
  9046. + { "*sky", &tr.skyTexture, R_InitSkyTexture },
  9047. + { "*vsdct", &tr.vsdctCubeTexture, R_InitVSDCTCubemap },
  9048. { NULL, NULL, NULL }
  9049. };
  9050. size_t i, num_builtin_textures = sizeof( textures ) / sizeof( textures[0] ) - 1;
  9051. @@ -2527,9 +2508,206 @@ static void R_InitBuiltinTextures( void )
  9052. pic = textures[i].init( &flags );
  9053. if( pic == NULL ) continue;
  9054. *textures[i].texnum = GL_LoadTextureInternal( textures[i].name, pic, flags, false );
  9055. + }
  9056. +}
  9057. +
  9058. +/*
  9059. +===============
  9060. +R_TextureList_f
  9061. +===============
  9062. +*/
  9063. +void R_TextureList_f( void )
  9064. +{
  9065. + gltexture_t *image;
  9066. + int i, texCount, bytes = 0;
  9067. +
  9068. + Msg( "\n" );
  9069. + Msg(" -w-- -h-- -size- -fmt- type -data-- -encode-- -wrap-- -depth- -name--------\n" );
  9070. +
  9071. + for( i = texCount = 0, image = r_textures; i < r_numTextures; i++, image++ )
  9072. + {
  9073. + if( !image->texnum ) continue;
  9074. +
  9075. + bytes += image->size;
  9076. + texCount++;
  9077. +
  9078. + Msg( "%4i: ", i );
  9079. + Msg( "%4i %4i ", image->width, image->height );
  9080. + Msg( "%5ik ", image->size >> 10 );
  9081. +
  9082. + switch( image->format )
  9083. + {
  9084. + case GL_COMPRESSED_RGBA_ARB:
  9085. + Msg( "CRGBA " );
  9086. + break;
  9087. + case GL_COMPRESSED_RGB_ARB:
  9088. + Msg( "CRGB " );
  9089. + break;
  9090. + case GL_COMPRESSED_LUMINANCE_ALPHA_ARB:
  9091. + Msg( "CLA " );
  9092. + break;
  9093. + case GL_COMPRESSED_LUMINANCE_ARB:
  9094. + Msg( "CL " );
  9095. + break;
  9096. + case GL_COMPRESSED_ALPHA_ARB:
  9097. + Msg( "CA " );
  9098. + break;
  9099. + case GL_COMPRESSED_INTENSITY_ARB:
  9100. + Msg( "CI " );
  9101. + break;
  9102. + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  9103. + Msg( "DXT1c " );
  9104. + break;
  9105. + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  9106. + Msg( "DXT1a " );
  9107. + break;
  9108. + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  9109. + Msg( "DXT3 " );
  9110. + break;
  9111. + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  9112. + Msg( "DXT5 " );
  9113. + break;
  9114. + case GL_RGBA:
  9115. + Msg( "RGBA " );
  9116. + break;
  9117. + case GL_RGBA8:
  9118. + Msg( "RGBA8 " );
  9119. + break;
  9120. + case GL_RGBA4:
  9121. + Msg( "RGBA4 " );
  9122. + break;
  9123. + case GL_RGB:
  9124. + Msg( "RGB " );
  9125. + break;
  9126. + case GL_RGB8:
  9127. + Msg( "RGB8 " );
  9128. + break;
  9129. + case GL_RGB5:
  9130. + Msg( "RGB5 " );
  9131. + break;
  9132. + case GL_LUMINANCE4_ALPHA4:
  9133. + Msg( "L4A4 " );
  9134. + break;
  9135. + case GL_LUMINANCE_ALPHA:
  9136. + case GL_LUMINANCE8_ALPHA8:
  9137. + Msg( "L8A8 " );
  9138. + break;
  9139. + case GL_LUMINANCE4:
  9140. + Msg( "L4 " );
  9141. + break;
  9142. + case GL_LUMINANCE:
  9143. + case GL_LUMINANCE8:
  9144. + Msg( "L8 " );
  9145. + break;
  9146. + case GL_ALPHA8:
  9147. + Msg( "A8 " );
  9148. + break;
  9149. + case GL_INTENSITY8:
  9150. + Msg( "I8 " );
  9151. + break;
  9152. + case GL_DEPTH_COMPONENT:
  9153. + case GL_DEPTH_COMPONENT24:
  9154. + Msg( "DPTH24" );
  9155. + break;
  9156. + case GL_DEPTH_COMPONENT32F:
  9157. + Msg( "DPTH32" );
  9158. + break;
  9159. + case GL_LUMINANCE16F_ARB:
  9160. + Msg( "L16F " );
  9161. + break;
  9162. + case GL_LUMINANCE32F_ARB:
  9163. + Msg( "L32F " );
  9164. + break;
  9165. + case GL_LUMINANCE_ALPHA16F_ARB:
  9166. + Msg( "LA16F " );
  9167. + break;
  9168. + case GL_LUMINANCE_ALPHA32F_ARB:
  9169. + Msg( "LA32F " );
  9170. + break;
  9171. + case GL_RGB16F_ARB:
  9172. + Msg( "RGB16F" );
  9173. + break;
  9174. + case GL_RGB32F_ARB:
  9175. + Msg( "RGB32F" );
  9176. + break;
  9177. + case GL_RGBA16F_ARB:
  9178. + Msg( "RGBA16F" );
  9179. + break;
  9180. + case GL_RGBA32F_ARB:
  9181. + Msg( "RGBA32F" );
  9182. + break;
  9183. + default:
  9184. + Msg( "????? " );
  9185. + break;
  9186. + }
  9187. +
  9188. + switch( image->target )
  9189. + {
  9190. + case GL_TEXTURE_1D:
  9191. + Msg( " 1D " );
  9192. + break;
  9193. + case GL_TEXTURE_2D:
  9194. + Msg( " 2D " );
  9195. + break;
  9196. + case GL_TEXTURE_3D:
  9197. + Msg( " 3D " );
  9198. + break;
  9199. + case GL_TEXTURE_CUBE_MAP_ARB:
  9200. + Msg( "CUBE " );
  9201. + break;
  9202. + case GL_TEXTURE_RECTANGLE_EXT:
  9203. + Msg( "RECT " );
  9204. + break;
  9205. + case GL_TEXTURE_2D_ARRAY_EXT:
  9206. + Msg( "ARRAY " );
  9207. + break;
  9208. + default:
  9209. + Msg( "???? " );
  9210. + break;
  9211. + }
  9212. +
  9213. + if( image->flags & TF_NORMALMAP )
  9214. + Msg( "normal " );
  9215. + else Msg( "diffuse " );
  9216. +
  9217. + switch( image->encode )
  9218. + {
  9219. + case DXT_ENCODE_COLOR_YCoCg:
  9220. + Msg( "YCoCg " );
  9221. + break;
  9222. + case DXT_ENCODE_NORMAL_AG_ORTHO:
  9223. + Msg( "ortho " );
  9224. + break;
  9225. + case DXT_ENCODE_NORMAL_AG_STEREO:
  9226. + Msg( "stereo " );
  9227. + break;
  9228. + case DXT_ENCODE_NORMAL_AG_PARABOLOID:
  9229. + Msg( "parabolic " );
  9230. + break;
  9231. + case DXT_ENCODE_NORMAL_AG_QUARTIC:
  9232. + Msg( "quartic " );
  9233. + break;
  9234. + case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
  9235. + Msg( "azimuthal " );
  9236. + break;
  9237. + default:
  9238. + Msg( "default " );
  9239. + break;
  9240. + }
  9241.  
  9242. - GL_SetTextureType( *textures[i].texnum, textures[i].texType );
  9243. + if( image->flags & TF_CLAMP )
  9244. + Msg( "clamp " );
  9245. + else if( image->flags & TF_BORDER )
  9246. + Msg( "border " );
  9247. + else Msg( "repeat " );
  9248. + Msg( " %d ", image->depth );
  9249. + Msg( " %s\n", image->name );
  9250. }
  9251. +
  9252. + Msg( "---------------------------------------------------------\n" );
  9253. + Msg( "%i total textures\n", texCount );
  9254. + Msg( "%s total memory used\n", Q_memprint( bytes ));
  9255. + Msg( "\n" );
  9256. }
  9257.  
  9258. /*
  9259. @@ -2542,10 +2720,9 @@ void R_InitImages( void )
  9260. uint i, hash;
  9261. float f;
  9262.  
  9263. - r_numTextures = 0;
  9264. - scaledImage = NULL;
  9265. memset( r_textures, 0, sizeof( r_textures ));
  9266. memset( r_texturesHashTable, 0, sizeof( r_texturesHashTable ));
  9267. + r_numTextures = 0;
  9268.  
  9269. // create unused 0-entry
  9270. Q_strncpy( r_textures->name, "*unused*", sizeof( r_textures->name ));
  9271. @@ -2568,6 +2745,7 @@ void R_InitImages( void )
  9272. R_InitBuiltinTextures();
  9273.  
  9274. R_ParseTexFilters( "scripts/texfilter.txt" );
  9275. + Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
  9276. }
  9277.  
  9278. /*
  9279. @@ -2582,23 +2760,11 @@ void R_ShutdownImages( void )
  9280.  
  9281. if( !glw_state.initialized ) return;
  9282.  
  9283. - for( i = ( MAX_TEXTURE_UNITS - 1); i >= 0; i-- )
  9284. - {
  9285. - if( i >= GL_MaxTextureUnits( ))
  9286. - continue;
  9287. -
  9288. - GL_SelectTexture( i );
  9289. - pglBindTexture( GL_TEXTURE_2D, 0 );
  9290. -
  9291. - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
  9292. - pglBindTexture( GL_TEXTURE_CUBE_MAP_ARB, 0 );
  9293. - }
  9294. + Cmd_RemoveCommand( "texturelist" );
  9295. + GL_CleanupAllTextureUnits();
  9296.  
  9297. for( i = 0, image = r_textures; i < r_numTextures; i++, image++ )
  9298. - {
  9299. - if( !image->texnum ) continue;
  9300. - GL_FreeTexture( i );
  9301. - }
  9302. + R_FreeImage( image );
  9303.  
  9304. memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
  9305. memset( r_texturesHashTable, 0, sizeof( r_texturesHashTable ));
  9306. diff --git b/engine/client/gl_local.h a/engine/client/gl_local.h
  9307. index 1a9deb1..314c199 100644
  9308. --- b/engine/client/gl_local.h
  9309. +++ a/engine/client/gl_local.h
  9310. @@ -48,7 +48,7 @@ extern byte *r_temppool;
  9311. #define RP_FLIPFRONTFACE BIT( 4 ) // e.g. for mirrors drawing
  9312.  
  9313. #define RP_NONVIEWERREF (RP_MIRRORVIEW|RP_ENVVIEW)
  9314. -#define R_StudioOpaque( e ) ( e->curstate.rendermode == kRenderNormal || e->curstate.rendermode == kRenderTransAlpha )
  9315. +#define R_StudioOpaque( rm ) ( rm == kRenderNormal || rm == kRenderTransAlpha )
  9316. #define RP_LOCALCLIENT( e ) (CL_GetLocalPlayer() && ((e)->index == CL_GetLocalPlayer()->index && e->curstate.entityType == ET_PLAYER ))
  9317. #define RP_NORMALPASS() ((RI.params & RP_NONVIEWERREF) == 0 )
  9318.  
  9319. @@ -64,6 +64,8 @@ typedef struct gltexture_s
  9320. word srcHeight;
  9321. word width; // upload width\height
  9322. word height;
  9323. + word depth; // texture depth or count of layers for 2D_ARRAY
  9324. + byte numMips; // mipmap count
  9325.  
  9326. uint cacheframe; // worldmodel->load_sequence
  9327.  
  9328. @@ -78,7 +80,6 @@ typedef struct gltexture_s
  9329. rgbdata_t *original; // keep original image
  9330.  
  9331. // debug info
  9332. - byte texType; // used for gl_showtextures
  9333. size_t size; // upload size for debug targets
  9334.  
  9335. // detail textures stuff
  9336. @@ -113,6 +114,8 @@ typedef struct
  9337. int viewport[4];
  9338. mplane_t frustum[6];
  9339.  
  9340. + mleaf_t *viewleaf;
  9341. + mleaf_t *oldviewleaf;
  9342. vec3_t pvsorigin;
  9343. vec3_t vieworg; // locked vieworigin
  9344. vec3_t vforward;
  9345. @@ -135,9 +138,6 @@ typedef struct
  9346. float fogEnd;
  9347. int cached_contents; // in water
  9348.  
  9349. - float waveHeight; // global waveHeight
  9350. - float currentWaveHeight; // current entity waveHeight
  9351. -
  9352. float skyMins[2][6];
  9353. float skyMaxs[2][6];
  9354.  
  9355. @@ -147,8 +147,7 @@ typedef struct
  9356.  
  9357. matrix4x4 projectionMatrix;
  9358. matrix4x4 worldviewProjectionMatrix; // worldviewMatrix * projectionMatrix
  9359. - int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
  9360. - float lightcache[MAX_LIGHTSTYLES];
  9361. + byte visbytes[(MAX_MAP_LEAFS+7)/8];// actual PVS for current frame
  9362.  
  9363. float viewplanedist;
  9364. mplane_t clipPlane;
  9365. @@ -161,7 +160,6 @@ typedef struct
  9366. int whiteTexture;
  9367. int grayTexture;
  9368. int blackTexture;
  9369. - int acontTexture;
  9370. int defaultTexture; // use for bad textures
  9371. int particleTexture; // particle texture
  9372. int particleTexture2; // unsmoothed particle texture
  9373. @@ -211,6 +209,9 @@ typedef struct
  9374. int realframecount; // not including passes
  9375. int framecount;
  9376.  
  9377. + int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536
  9378. + float lightcache[MAX_LIGHTSTYLES];
  9379. +
  9380. // cull info
  9381. vec3_t modelorg; // relative to viewpoint
  9382. } ref_globals_t;
  9383. @@ -265,6 +266,7 @@ void GL_LoadTexMatrixExt( const float *glmatrix );
  9384. void GL_LoadMatrix( const matrix4x4 source );
  9385. void GL_TexGen( GLenum coord, GLenum mode );
  9386. void GL_SelectTexture( GLint texture );
  9387. +void GL_CleanupAllTextureUnits( void );
  9388. void GL_LoadIdentityTexMatrix( void );
  9389. void GL_DisableAllTexGens( void );
  9390. void GL_SetRenderMode( int mode );
  9391. @@ -302,13 +304,14 @@ void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height,
  9392. //
  9393. void R_SetTextureParameters( void );
  9394. gltexture_t *R_GetTexture( GLenum texnum );
  9395. -void GL_SetTextureType( GLenum texnum, GLenum type );
  9396. int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, imgfilter_t *filter );
  9397. +int GL_LoadTextureArray( const char **names, int flags, imgfilter_t *filter );
  9398. int GL_LoadTextureInternal( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
  9399. byte *GL_ResampleTexture( const byte *source, int in_w, int in_h, int out_w, int out_h, qboolean isNormalMap );
  9400. int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
  9401. +int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
  9402. void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor );
  9403. -void GL_TexFilter( gltexture_t *tex, qboolean update );
  9404. +void GL_ApplyTextureParams( gltexture_t *tex );
  9405. void R_FreeImage( gltexture_t *image );
  9406. int GL_FindTexture( const char *name );
  9407. void GL_FreeTexture( GLenum texnum );
  9408. @@ -422,16 +425,15 @@ void R_InitSky( struct mip_s *mt, struct texture_s *tx );
  9409. void R_AddSkyBoxSurface( msurface_t *fa );
  9410. void R_ClearSkyBox( void );
  9411. void R_DrawSkyBox( void );
  9412. -void EmitSkyLayers( msurface_t *fa );
  9413. -void EmitSkyPolys( msurface_t *fa );
  9414. -void EmitWaterPolys( glpoly_t *polys, qboolean noCull );
  9415. -void R_DrawSkyChain( msurface_t *s );
  9416. +void R_DrawClouds( void );
  9417. +void EmitWaterPolys( glpoly_t *polys, qboolean noCull, qboolean direction );
  9418.  
  9419. //
  9420. // gl_vidnt.c
  9421. //
  9422. #define GL_CheckForErrors() GL_CheckForErrors_( __FILE__, __LINE__ )
  9423. void GL_CheckForErrors_( const char *filename, const int fileline );
  9424. +void *GL_GetProcAddress( const char *name );
  9425. void GL_UpdateSwapInterval( void );
  9426. void GL_UpdateGammaRamp( void );
  9427. qboolean GL_DeleteContext( void );
  9428. @@ -492,40 +494,36 @@ void R_NewMap( void );
  9429. enum
  9430. {
  9431. GL_OPENGL_110 = 0, // base
  9432. + GL_WGL_EXTENSIONS,
  9433. GL_WGL_SWAPCONTROL,
  9434. GL_WGL_PROCADDRESS,
  9435. - GL_HARDWARE_GAMMA_CONTROL,
  9436. GL_ARB_VERTEX_BUFFER_OBJECT_EXT,
  9437. - GL_ENV_COMBINE_EXT,
  9438. + GL_ARB_VERTEX_ARRAY_OBJECT_EXT,
  9439. GL_ARB_MULTITEXTURE,
  9440. - GL_TEXTURECUBEMAP_EXT,
  9441. - GL_DOT3_ARB_EXT,
  9442. + GL_TEXTURE_CUBEMAP_EXT,
  9443. GL_ANISOTROPY_EXT,
  9444. - GL_TEXTURE_LODBIAS,
  9445. + GL_TEXTURE_LOD_BIAS,
  9446. GL_OCCLUSION_QUERIES_EXT,
  9447. GL_TEXTURE_COMPRESSION_EXT,
  9448. GL_SHADER_GLSL100_EXT,
  9449. - GL_SGIS_MIPMAPS_EXT,
  9450. GL_DRAW_RANGEELEMENTS_EXT,
  9451. - GL_LOCKARRAYS_EXT,
  9452. + GL_TEXTURE_2D_RECT_EXT,
  9453. + GL_TEXTURE_ARRAY_EXT,
  9454. GL_TEXTURE_3D_EXT,
  9455. GL_CLAMPTOEDGE_EXT,
  9456. - GL_BLEND_MINMAX_EXT,
  9457. - GL_STENCILTWOSIDE_EXT,
  9458. - GL_BLEND_SUBTRACT_EXT,
  9459. GL_SHADER_OBJECTS_EXT,
  9460. - GL_VERTEX_SHADER_EXT, // glsl vertex program
  9461. - GL_FRAGMENT_SHADER_EXT, // glsl fragment program
  9462. - GL_EXT_POINTPARAMETERS,
  9463. - GL_SEPARATESTENCIL_EXT,
  9464. GL_ARB_TEXTURE_NPOT_EXT,
  9465. - GL_CUSTOM_VERTEX_ARRAY_EXT,
  9466. - GL_TEXTURE_ENV_ADD_EXT,
  9467. GL_CLAMP_TEXBORDER_EXT,
  9468. GL_ARB_TEXTURE_FLOAT_EXT,
  9469. + GL_ARB_HALF_FLOAT_EXT,
  9470. GL_ARB_DEPTH_FLOAT_EXT,
  9471. GL_ARB_SEAMLESS_CUBEMAP,
  9472. + GL_FRAMEBUFFER_OBJECT,
  9473. + GL_DRAW_BUFFERS_EXT,
  9474. + GL_EXT_GPU_SHADER4, // shaders only
  9475. + GL_ARB_TEXTURE_RG,
  9476. GL_DEPTH_TEXTURE,
  9477. + GL_DEBUG_OUTPUT,
  9478. GL_SHADOW_EXT,
  9479. GL_EXTCOUNT, // must be last
  9480. };
  9481. @@ -540,14 +538,24 @@ enum
  9482. MAX_TEXTURE_UNITS = 32 // can't acess to all over units without GLSL or cg
  9483. };
  9484.  
  9485. +typedef enum
  9486. +{
  9487. + GLHW_GENERIC, // where everthing works the way it should
  9488. + GLHW_RADEON, // where you don't have proper GLSL support
  9489. + GLHW_NVIDIA // Geforce 8/9 class DX10 hardware
  9490. +} glHWType_t;
  9491. +
  9492. typedef struct
  9493. {
  9494. const char *renderer_string; // ptrs to OpenGL32.dll, use with caution
  9495. const char *vendor_string;
  9496. const char *version_string;
  9497.  
  9498. + glHWType_t hardware_type;
  9499. +
  9500. // list of supported extensions
  9501. const char *extensions_string;
  9502. + const char *wgl_extensions_string;
  9503. byte extension[GL_EXTCOUNT];
  9504.  
  9505. int max_texture_units;
  9506. @@ -555,12 +563,13 @@ typedef struct
  9507. int max_teximage_units;
  9508. GLint max_2d_texture_size;
  9509. GLint max_2d_rectangle_size;
  9510. + GLint max_2d_texture_layers;
  9511. GLint max_3d_texture_size;
  9512. GLint max_cubemap_size;
  9513. - GLint texRectangle;
  9514. + GLint max_draw_buffers;
  9515.  
  9516. GLfloat max_texture_anisotropy;
  9517. - GLfloat max_texture_lodbias;
  9518. + GLfloat max_texture_lod_bias;
  9519.  
  9520. GLint max_vertex_uniforms;
  9521. GLint max_vertex_attribs;
  9522. @@ -570,6 +579,9 @@ typedef struct
  9523. int depth_bits;
  9524. int stencil_bits;
  9525.  
  9526. + gl_context_type_t context;
  9527. + gles_wrapper_t wrapper;
  9528. +
  9529. qboolean softwareGammaUpdate;
  9530. qboolean deviceSupportsGamma;
  9531. int prev_mode;
  9532. @@ -608,8 +620,8 @@ typedef struct
  9533. int desktopWidth;
  9534. int desktopHeight;
  9535.  
  9536. - qboolean software; // OpenGL software emulation
  9537. qboolean initialized; // OpenGL subsystem started
  9538. + qboolean extended; // extended context allows to GL_Debug
  9539. } glwstate_t;
  9540.  
  9541. extern glconfig_t glConfig;
  9542. @@ -619,7 +631,6 @@ extern glwstate_t glw_state;
  9543. //
  9544. // renderer cvars
  9545. //
  9546. -extern convar_t *gl_allow_software;
  9547. extern convar_t *gl_texture_anisotropy;
  9548. extern convar_t *gl_extensions;
  9549. extern convar_t *gl_stencilbits;
  9550. @@ -627,11 +638,9 @@ extern convar_t *gl_ignorehwgamma;
  9551. extern convar_t *gl_swapInterval;
  9552. extern convar_t *gl_check_errors;
  9553. extern convar_t *gl_round_down;
  9554. -extern convar_t *gl_texturemode;
  9555. extern convar_t *gl_texture_lodbias;
  9556. -extern convar_t *gl_showtextures;
  9557. +extern convar_t *gl_texture_nearest;
  9558. extern convar_t *gl_compress_textures;
  9559. -extern convar_t *gl_luminance_textures;
  9560. extern convar_t *gl_compensate_gamma_screenshots;
  9561. extern convar_t *gl_keeptjunctions;
  9562. extern convar_t *gl_detailscale;
  9563. @@ -672,7 +681,6 @@ extern convar_t *r_fastsky;
  9564. extern convar_t *vid_displayfrequency;
  9565. extern convar_t *vid_fullscreen;
  9566. extern convar_t *vid_gamma;
  9567. -extern convar_t *vid_texgamma;
  9568. extern convar_t *vid_mode;
  9569.  
  9570. #endif//GL_LOCAL_H
  9571. \ No newline at end of file
  9572. diff --git b/engine/client/gl_mirror.c a/engine/client/gl_mirror.c
  9573. index 797ed0c..72983dc 100644
  9574. --- b/engine/client/gl_mirror.c
  9575. +++ a/engine/client/gl_mirror.c
  9576. @@ -160,7 +160,6 @@ int R_AllocateMirrorTexture( void )
  9577. r_screen.flags = IMAGE_HAS_COLOR;
  9578. r_screen.buffer = NULL; // create empty texture for now
  9579. tr.mirrorTextures[i] = GL_LoadTextureInternal( txName, &r_screen, TF_IMAGE, false );
  9580. - GL_SetTextureType( tr.mirrorTextures[i], TEX_SCREENCOPY );
  9581. texture = tr.mirrorTextures[i];
  9582. }
  9583.  
  9584. @@ -291,10 +290,6 @@ void R_DrawMirrors( void )
  9585.  
  9586. VectorCopy( origin, RI.pvsorigin );
  9587.  
  9588. - // combine two leafs from client and mirror views
  9589. - r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes );
  9590. - r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
  9591. -
  9592. if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
  9593. {
  9594. // allow screen size
  9595. @@ -341,7 +336,6 @@ void R_DrawMirrors( void )
  9596. tr.mirror_entities[i].ent = NULL;
  9597. }
  9598.  
  9599. - r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame
  9600. tr.framecount = oldframecount; // restore real framecount
  9601. tr.num_mirror_entities = 0;
  9602. tr.num_mirrors_used = 0;
  9603. diff --git b/engine/client/gl_rlight.c a/engine/client/gl_rlight.c
  9604. index 9e7a28a..19048eb 100644
  9605. --- b/engine/client/gl_rlight.c
  9606. +++ a/engine/client/gl_rlight.c
  9607. @@ -29,11 +29,11 @@ DYNAMIC LIGHTS
  9608. */
  9609. /*
  9610. ==================
  9611. -R_AnimateLight
  9612. +CL_RunLightStyles
  9613.  
  9614. ==================
  9615. */
  9616. -void R_AnimateLight( void )
  9617. +void CL_RunLightStyles( void )
  9618. {
  9619. int i, k, flight, clight;
  9620. float l, c, lerpfrac, backlerp;
  9621. @@ -51,36 +51,36 @@ void R_AnimateLight( void )
  9622. {
  9623. if( r_fullbright->integer || !cl.worldmodel->lightdata )
  9624. {
  9625. - RI.lightstylevalue[i] = 256 * 256;
  9626. - RI.lightcache[i] = 3.0f;
  9627. + tr.lightstylevalue[i] = 256 * 256;
  9628. + tr.lightcache[i] = 3.0f;
  9629. continue;
  9630. }
  9631.  
  9632. if( !RI.refdef.paused && RI.refdef.frametime <= 0.1f )
  9633. ls->time += RI.refdef.frametime; // evaluate local time
  9634.  
  9635. - flight = (int)floor( ls->time * 10 );
  9636. - clight = (int)ceil( ls->time * 10 );
  9637. + flight = (int)Q_floor( ls->time * 10 );
  9638. + clight = (int)Q_ceil( ls->time * 10 );
  9639. lerpfrac = ( ls->time * 10 ) - flight;
  9640. backlerp = 1.0f - lerpfrac;
  9641.  
  9642. if( !ls->length )
  9643. {
  9644. - RI.lightstylevalue[i] = 256 * scale;
  9645. - RI.lightcache[i] = 3.0f * scale;
  9646. + tr.lightstylevalue[i] = 256 * scale;
  9647. + tr.lightcache[i] = 3.0f * scale;
  9648. continue;
  9649. }
  9650. else if( ls->length == 1 )
  9651. {
  9652. // single length style so don't bother interpolating
  9653. - RI.lightstylevalue[i] = ls->map[0] * 22 * scale;
  9654. - RI.lightcache[i] = ( ls->map[0] / 12.0f ) * 3.0f * scale;
  9655. + tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
  9656. + tr.lightcache[i] = ( ls->map[0] / 12.0f ) * 3.0f * scale;
  9657. continue;
  9658. }
  9659. else if( !ls->interp || !cl_lightstyle_lerping->integer )
  9660. {
  9661. - RI.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
  9662. - RI.lightcache[i] = ( ls->map[flight%ls->length] / 12.0f ) * 3.0f * scale;
  9663. + tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
  9664. + tr.lightcache[i] = ( ls->map[flight%ls->length] / 12.0f ) * 3.0f * scale;
  9665. continue;
  9666. }
  9667.  
  9668. @@ -95,8 +95,8 @@ void R_AnimateLight( void )
  9669. l += (float)( k * 22.0f ) * lerpfrac;
  9670. c += (float)( k / 12.0f ) * lerpfrac;
  9671.  
  9672. - RI.lightstylevalue[i] = (int)l * scale;
  9673. - RI.lightcache[i] = c * 3.0f * scale;
  9674. + tr.lightstylevalue[i] = (int)l * scale;
  9675. + tr.lightcache[i] = c * 3.0f * scale;
  9676. }
  9677. }
  9678.  
  9679. @@ -237,6 +237,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
  9680. {
  9681. float front, back, frac;
  9682. int i, map, side, size, s, t;
  9683. + int sample_size;
  9684. msurface_t *surf;
  9685. mtexinfo_t *tex;
  9686. color24 *lm;
  9687. @@ -269,6 +270,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
  9688.  
  9689. // check for impact on this node
  9690. surf = model->surfaces + node->firstsurface;
  9691. + sample_size = Mod_SampleSizeForFace( surf );
  9692.  
  9693. for( i = 0; i < node->numsurfaces; i++, surf++ )
  9694. {
  9695. @@ -283,20 +285,20 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3
  9696. if(( s < 0 || s > surf->extents[0] ) || ( t < 0 || t > surf->extents[1] ))
  9697. continue;
  9698.  
  9699. - s /= LM_SAMPLE_SIZE;
  9700. - t /= LM_SAMPLE_SIZE;
  9701. + s /= sample_size;
  9702. + t /= sample_size;
  9703.  
  9704. if( !surf->samples )
  9705. return true;
  9706.  
  9707. VectorClear( r_pointColor );
  9708.  
  9709. - lm = surf->samples + (t * ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) + s);
  9710. - size = ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) * ((surf->extents[1] / LM_SAMPLE_SIZE) + 1);
  9711. + lm = surf->samples + (t * ((surf->extents[0] / sample_size) + 1) + s);
  9712. + size = ((surf->extents[0] / sample_size) + 1) * ((surf->extents[1] / sample_size) + 1);
  9713.  
  9714. for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
  9715. {
  9716. - uint scale = RI.lightstylevalue[surf->styles[map]];
  9717. + uint scale = tr.lightstylevalue[surf->styles[map]];
  9718.  
  9719. r_pointColor[0] += TextureToTexGamma( lm->r ) * scale;
  9720. r_pointColor[1] += TextureToTexGamma( lm->g ) * scale;
  9721. diff --git b/engine/client/gl_rmain.c a/engine/client/gl_rmain.c
  9722. index 8ac980b..6b5592e 100644
  9723. --- b/engine/client/gl_rmain.c
  9724. +++ a/engine/client/gl_rmain.c
  9725. @@ -30,9 +30,6 @@ float gldepthmin, gldepthmax;
  9726. ref_params_t r_lastRefdef;
  9727. ref_instance_t RI, prevRI;
  9728.  
  9729. -mleaf_t *r_viewleaf, *r_oldviewleaf;
  9730. -mleaf_t *r_viewleaf2, *r_oldviewleaf2;
  9731. -
  9732. static int R_RankForRenderMode( cl_entity_t *ent )
  9733. {
  9734. switch( ent->curstate.rendermode )
  9735. @@ -370,16 +367,16 @@ int R_ComputeFxBlend( cl_entity_t *e )
  9736. break;
  9737. }
  9738.  
  9739. - if( e->model->type != mod_brush )
  9740. + if( e->model && e->model->type != mod_brush )
  9741. {
  9742. // NOTE: never pass sprites with rendercolor '0 0 0' it's a stupid Valve Hammer Editor bug
  9743. if( !e->curstate.rendercolor.r && !e->curstate.rendercolor.g && !e->curstate.rendercolor.b )
  9744. e->curstate.rendercolor.r = e->curstate.rendercolor.g = e->curstate.rendercolor.b = 255;
  9745. - }
  9746.  
  9747. - // apply scale to studiomodels and sprites only
  9748. - if( e->model && e->model->type != mod_brush && !e->curstate.scale )
  9749. - e->curstate.scale = 1.0f;
  9750. + // apply scale to studiomodels and sprites only
  9751. + if( !e->curstate.scale )
  9752. + e->curstate.scale = 1.0f;
  9753. + }
  9754.  
  9755. blend = bound( 0, blend, 255 );
  9756.  
  9757. @@ -745,35 +742,8 @@ R_FindViewLeaf
  9758. */
  9759. void R_FindViewLeaf( void )
  9760. {
  9761. - float height;
  9762. - mleaf_t *leaf;
  9763. - vec3_t tmp;
  9764. -
  9765. - r_oldviewleaf = r_viewleaf;
  9766. - r_oldviewleaf2 = r_viewleaf2;
  9767. - leaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
  9768. - r_viewleaf2 = r_viewleaf = leaf;
  9769. - height = RI.waveHeight ? RI.waveHeight : 16;
  9770. -
  9771. - // check above and below so crossing solid water doesn't draw wrong
  9772. - if( leaf->contents == CONTENTS_EMPTY )
  9773. - {
  9774. - // look down a bit
  9775. - VectorCopy( RI.pvsorigin, tmp );
  9776. - tmp[2] -= height;
  9777. - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes );
  9778. - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 ))
  9779. - r_viewleaf2 = leaf;
  9780. - }
  9781. - else
  9782. - {
  9783. - // look up a bit
  9784. - VectorCopy( RI.pvsorigin, tmp );
  9785. - tmp[2] += height;
  9786. - leaf = Mod_PointInLeaf( tmp, cl.worldmodel->nodes );
  9787. - if(( leaf->contents != CONTENTS_SOLID ) && ( leaf != r_viewleaf2 ))
  9788. - r_viewleaf2 = leaf;
  9789. - }
  9790. + RI.oldviewleaf = RI.viewleaf;
  9791. + RI.viewleaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
  9792. }
  9793.  
  9794. /*
  9795. @@ -805,7 +775,6 @@ static void R_SetupFrame( void )
  9796. VectorCopy( RI.vup, RI.cull_vup );
  9797. }
  9798.  
  9799. - R_AnimateLight();
  9800. R_RunViewmodelEvents();
  9801.  
  9802. // sort opaque entities by model type to avoid drawing model shadows under alpha-surfaces
  9803. @@ -820,11 +789,8 @@ static void R_SetupFrame( void )
  9804. // current viewleaf
  9805. if( RI.drawWorld )
  9806. {
  9807. - RI.waveHeight = cl.refdef.movevars->waveHeight * 2.0f; // set global waveheight
  9808. RI.isSkyVisible = false; // unknown at this moment
  9809. -
  9810. - if(!( RI.params & RP_OLDVIEWLEAF ))
  9811. - R_FindViewLeaf();
  9812. + R_FindViewLeaf();
  9813. }
  9814. }
  9815.  
  9816. @@ -999,13 +965,13 @@ static void R_CheckFog( void )
  9817.  
  9818. RI.fogEnabled = false;
  9819.  
  9820. - if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !r_viewleaf )
  9821. + if( RI.refdef.waterlevel < 2 || !RI.drawWorld || !RI.viewleaf )
  9822. return;
  9823.  
  9824. ent = CL_GetWaterEntity( RI.vieworg );
  9825. if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 )
  9826. cnt = ent->curstate.skin;
  9827. - else cnt = r_viewleaf->contents;
  9828. + else cnt = RI.viewleaf->contents;
  9829.  
  9830. if( IsLiquidContents( RI.cached_contents ) && !IsLiquidContents( cnt ))
  9831. {
  9832. @@ -1038,8 +1004,8 @@ static void R_CheckFog( void )
  9833. }
  9834. else
  9835. {
  9836. - tex = R_RecursiveFindWaterTexture( r_viewleaf->parent, NULL, false );
  9837. - if( tex ) RI.cached_contents = r_viewleaf->contents;
  9838. + tex = R_RecursiveFindWaterTexture( RI.viewleaf->parent, NULL, false );
  9839. + if( tex ) RI.cached_contents = RI.viewleaf->contents;
  9840. }
  9841.  
  9842. if( !tex ) return; // no valid fogs
  9843. @@ -1167,7 +1133,10 @@ void R_DrawEntitiesOnList( void )
  9844. }
  9845.  
  9846. if( RI.drawWorld )
  9847. + {
  9848. + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  9849. clgame.dllFuncs.pfnDrawTransparentTriangles ();
  9850. + }
  9851.  
  9852. if( !RI.refdef.onlyClientDraw )
  9853. {
  9854. @@ -1185,7 +1154,8 @@ void R_DrawEntitiesOnList( void )
  9855.  
  9856. R_DrawViewModel();
  9857.  
  9858. - CL_ExtraUpdate();
  9859. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  9860. + CL_ExtraUpdate();
  9861. }
  9862.  
  9863. /*
  9864. @@ -1213,7 +1183,8 @@ void R_RenderScene( const ref_params_t *fd )
  9865. R_CheckFog();
  9866. R_DrawWorld();
  9867.  
  9868. - CL_ExtraUpdate (); // don't let sound get messed up if going slow
  9869. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  9870. + CL_ExtraUpdate (); // don't let sound get messed up if going slow
  9871.  
  9872. R_DrawEntitiesOnList();
  9873.  
  9874. @@ -1248,7 +1219,7 @@ void R_BeginFrame( qboolean clearScene )
  9875. else
  9876. {
  9877. glConfig.softwareGammaUpdate = true;
  9878. - BuildGammaTable( vid_gamma->value, vid_texgamma->value );
  9879. + BuildGammaTable( vid_gamma->value, GAMMA );
  9880. GL_RebuildLightmaps();
  9881. glConfig.softwareGammaUpdate = false;
  9882. }
  9883. @@ -1259,15 +1230,15 @@ void R_BeginFrame( qboolean clearScene )
  9884. // draw buffer stuff
  9885. pglDrawBuffer( GL_BACK );
  9886.  
  9887. - // texturemode stuff
  9888. // update texture parameters
  9889. - if( gl_texturemode->modified || gl_texture_anisotropy->modified || gl_texture_lodbias->modified )
  9890. + if( gl_texture_nearest->modified || gl_texture_anisotropy->modified || gl_texture_lodbias->modified )
  9891. R_SetTextureParameters();
  9892.  
  9893. // swapinterval stuff
  9894. GL_UpdateSwapInterval();
  9895.  
  9896. - CL_ExtraUpdate ();
  9897. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  9898. + CL_ExtraUpdate ();
  9899. }
  9900.  
  9901. /*
  9902. @@ -1343,7 +1314,10 @@ void R_EndFrame( void )
  9903. R_Set2DMode( false );
  9904.  
  9905. if( !pwglSwapBuffers( glw_state.hDC ))
  9906. - Sys_Error( "wglSwapBuffers() failed!\n" );
  9907. + {
  9908. + Msg( "Error: WGL: failed to swap buffers\n" );
  9909. + Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" );
  9910. + }
  9911. }
  9912.  
  9913. /*
  9914. @@ -1382,7 +1356,7 @@ void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size )
  9915.  
  9916. R_RenderScene( fd );
  9917.  
  9918. - r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame
  9919. + RI.oldviewleaf = RI.viewleaf = NULL; // force markleafs next frame
  9920. }
  9921.  
  9922. static int GL_RenderGetParm( int parm, int arg )
  9923. @@ -1409,6 +1383,12 @@ static int GL_RenderGetParm( int parm, int arg )
  9924. case PARM_TEX_ENCODE:
  9925. glt = R_GetTexture( arg );
  9926. return glt->encode;
  9927. + case PARM_TEX_MIPCOUNT:
  9928. + glt = R_GetTexture( arg );
  9929. + return glt->numMips;
  9930. + case PARM_TEX_DEPTH:
  9931. + glt = R_GetTexture( arg );
  9932. + return glt->depth;
  9933. case PARM_TEX_SKYBOX:
  9934. ASSERT( arg >= 0 && arg < 6 );
  9935. return tr.skyboxTextures[arg];
  9936. @@ -1418,7 +1398,7 @@ static int GL_RenderGetParm( int parm, int arg )
  9937. ASSERT( arg >= 0 && arg < MAX_LIGHTMAPS );
  9938. return tr.lightmapTextures[arg];
  9939. case PARM_SKY_SPHERE:
  9940. - return world.sky_sphere;
  9941. + return world.sky_sphere && !world.custom_skybox;
  9942. case PARM_WORLD_VERSION:
  9943. if( cls.state != ca_active )
  9944. return bmodel_version;
  9945. @@ -1455,9 +1435,6 @@ static int GL_RenderGetParm( int parm, int arg )
  9946. return glt->cacheframe;
  9947. case PARM_MAP_HAS_DELUXE:
  9948. return (world.deluxedata != NULL);
  9949. - case PARM_TEX_TYPE:
  9950. - glt = R_GetTexture( arg );
  9951. - return glt->texType;
  9952. case PARM_CACHEFRAME:
  9953. return world.load_sequence;
  9954. case PARM_MAX_IMAGE_UNITS:
  9955. @@ -1466,6 +1443,16 @@ static int GL_RenderGetParm( int parm, int arg )
  9956. return (cls.state == ca_active);
  9957. case PARM_REBUILD_GAMMA:
  9958. return glConfig.softwareGammaUpdate;
  9959. + case PARM_DEDICATED_SERVER:
  9960. + return (host.type == HOST_DEDICATED);
  9961. + case PARM_SURF_SAMPLESIZE:
  9962. + if( arg >= 0 && arg < cl.worldmodel->numsurfaces )
  9963. + return Mod_SampleSizeForFace( &cl.worldmodel->surfaces[arg] );
  9964. + return LM_SAMPLE_SIZE;
  9965. + case PARM_GL_CONTEXT_TYPE:
  9966. + return glConfig.context;
  9967. + case PARM_GLES_WRAPPER:
  9968. + return glConfig.wrapper;
  9969. }
  9970. return 0;
  9971. }
  9972. @@ -1604,6 +1591,11 @@ static int GL_LoadTextureNoFilter( const char *name, const byte *buf, size_t siz
  9973. return GL_LoadTexture( name, buf, size, flags, NULL );
  9974. }
  9975.  
  9976. +static int GL_LoadTextureArrayNoFilter( const char **names, int flags )
  9977. +{
  9978. + return GL_LoadTextureArray( names, flags, NULL );
  9979. +}
  9980. +
  9981. static const ref_overview_t *GL_GetOverviewParms( void )
  9982. {
  9983. return &clgame.overView;
  9984. @@ -1616,6 +1608,7 @@ static void *R_Mem_Alloc( size_t cb, const char *filename, const int fileline )
  9985.  
  9986. static void R_Mem_Free( void *mem, const char *filename, const int fileline )
  9987. {
  9988. + if( !mem ) return;
  9989. _Mem_Free( mem, filename, fileline );
  9990. }
  9991.  
  9992. @@ -1662,8 +1655,8 @@ static render_api_t gRenderAPI =
  9993. GL_TextureData,
  9994. GL_LoadTextureNoFilter,
  9995. GL_CreateTexture,
  9996. - GL_SetTextureType,
  9997. - GL_TextureUpdateCache,
  9998. + GL_LoadTextureArrayNoFilter,
  9999. + GL_CreateTextureArray,
  10000. GL_FreeTexture,
  10001. DrawSingleDecal,
  10002. R_DecalSetupVerts,
  10003. @@ -1683,7 +1676,7 @@ static render_api_t gRenderAPI =
  10004. GL_TexGen,
  10005. GL_TextureTarget,
  10006. GL_SetTexCoordArrayMode,
  10007. - NULL,
  10008. + GL_GetProcAddress,
  10009. NULL,
  10010. NULL,
  10011. NULL,
  10012. @@ -1718,7 +1711,7 @@ qboolean R_InitRenderAPI( void )
  10013. {
  10014. if( clgame.dllFuncs.pfnGetRenderInterface( CL_RENDER_INTERFACE_VERSION, &gRenderAPI, &clgame.drawFuncs ))
  10015. {
  10016. - MsgDev( D_AICONSOLE, "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
  10017. + MsgDev( D_REPORT, "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
  10018. return true;
  10019. }
  10020.  
  10021. diff --git b/engine/client/gl_rmisc.c a/engine/client/gl_rmisc.c
  10022. index a1160b5..bf8624c 100644
  10023. --- b/engine/client/gl_rmisc.c
  10024. +++ a/engine/client/gl_rmisc.c
  10025. @@ -291,7 +291,6 @@ void R_ParseDetailTextures( const char *filename )
  10026. {
  10027. gltexture_t *glt;
  10028.  
  10029. - GL_SetTextureType( tex->dt_texturenum, TEX_DETAIL );
  10030. glt = R_GetTexture( tex->gl_texturenum );
  10031. glt->xscale = xScale;
  10032. glt->yscale = yScale;
  10033. @@ -460,7 +459,6 @@ void R_NewMap( void )
  10034. cl.worldmodel->leafs[i+1].efrags = NULL;
  10035.  
  10036. tr.skytexturenum = -1;
  10037. - r_viewleaf = r_oldviewleaf = NULL;
  10038.  
  10039. // clearing texture chains
  10040. for( i = 0; i < cl.worldmodel->numtextures; i++ )
  10041. diff --git b/engine/client/gl_rpart.c a/engine/client/gl_rpart.c
  10042. index e42d40c..5fb971f 100644
  10043. --- b/engine/client/gl_rpart.c
  10044. +++ a/engine/client/gl_rpart.c
  10045. @@ -843,20 +843,64 @@ void CL_BloodStream( const vec3_t org, const vec3_t dir, int pcolor, int speed )
  10046. {
  10047. particle_t *p;
  10048. int i, j;
  10049. + float arc;
  10050.  
  10051. - for( i = 0; i < speed * 20; i++ )
  10052. + for( arc = 0.05f, i = 0; i < 100; i++, arc -= 0.005f )
  10053. {
  10054. p = CL_AllocParticle( NULL );
  10055. +
  10056. if( !p ) return;
  10057.  
  10058. - p->die += Com_RandomFloat( 0.2f, 0.8f );
  10059. + p->die += 2.0f;
  10060. p->type = pt_vox_grav;
  10061. - p->color = pcolor;
  10062. + p->color = pcolor + Com_RandomLong( 0, 9 );
  10063.  
  10064. - for( j = 0; j < 3; j++ )
  10065. + VectorCopy( org, p->org );
  10066. + VectorCopy( dir, p->vel );
  10067. +
  10068. + p->vel[2] -= arc;
  10069. + arc -= 0.005f;
  10070. +
  10071. + VectorScale( p->vel, speed, p->vel );
  10072. + }
  10073. +
  10074. + for( arc = 0.075f, i = 0; i < speed / 2; i++, arc -= 0.005f )
  10075. + {
  10076. + float num;
  10077. +
  10078. + p = CL_AllocParticle( NULL );
  10079. + if( !p ) return;
  10080. +
  10081. + p->die += 3.0f;
  10082. + p->color = pcolor + Com_RandomLong( 0, 9 );
  10083. + p->type = pt_vox_slowgrav;
  10084. +
  10085. + VectorCopy( org, p->org );
  10086. + VectorCopy( dir, p->vel );
  10087. +
  10088. + p->vel[2] -= arc;
  10089. +
  10090. + num = Com_RandomFloat( 0.0f, 1.0f );
  10091. + num = 1.7f * num * (int)(num * speed);
  10092. + VectorScale( p->vel, num, p->vel );
  10093. +
  10094. + for( j = 0; j < 2; j++ )
  10095. {
  10096. - p->org[j] = org[j];
  10097. - p->vel[j] = dir[j] * speed;
  10098. + p = CL_AllocParticle( NULL );
  10099. + if( !p ) return;
  10100. +
  10101. + p->die += 3.0f;
  10102. + p->color = pcolor + Com_RandomLong( 0, 9 );
  10103. + p->type = pt_vox_slowgrav;
  10104. +
  10105. + p->org[0] = org[0] + Com_RandomFloat( -1.0f, 1.0f );
  10106. + p->org[1] = org[1] + Com_RandomFloat( -1.0f, 1.0f );
  10107. + p->org[2] = org[2] + Com_RandomFloat( -1.0f, 1.0f );
  10108. +
  10109. + VectorCopy( dir, p->vel );
  10110. + p->vel[2] -= arc;
  10111. +
  10112. + VectorScale( p->vel, num, p->vel );
  10113. }
  10114. }
  10115. }
  10116. diff --git b/engine/client/gl_rsurf.c a/engine/client/gl_rsurf.c
  10117. index a8ede91..2391c3a 100644
  10118. --- b/engine/client/gl_rsurf.c
  10119. +++ a/engine/client/gl_rsurf.c
  10120. @@ -31,7 +31,6 @@ typedef struct
  10121. static int nColinElim; // stats
  10122. static vec2_t world_orthocenter;
  10123. static vec2_t world_orthohalf;
  10124. -static byte visbytes[MAX_MAP_LEAFS/8];
  10125. static uint r_blocklights[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*3];
  10126. static glpoly_t *fullbright_polys[MAX_TEXTURES];
  10127. static qboolean draw_fullbrights = false;
  10128. @@ -44,7 +43,7 @@ static void LM_UploadBlock( int lightmapnum );
  10129.  
  10130. byte *Mod_GetCurrentVis( void )
  10131. {
  10132. - return Mod_LeafPVS( r_viewleaf, cl.worldmodel );
  10133. + return RI.visbytes;
  10134. }
  10135.  
  10136. void Mod_SetOrthoBounds( float *mins, float *maxs )
  10137. @@ -79,6 +78,7 @@ static void BoundPoly( int numverts, float *verts, vec3_t mins, vec3_t maxs )
  10138. static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts )
  10139. {
  10140. int i, j, k, f, b;
  10141. + int sample_size;
  10142. vec3_t mins, maxs;
  10143. float m, frac, s, t, *v, vertsDiv;
  10144. vec3_t front[SUBDIVIDE_SIZE], back[SUBDIVIDE_SIZE], total;
  10145. @@ -88,6 +88,7 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
  10146. if( numverts > ( SUBDIVIDE_SIZE - 4 ))
  10147. Host_Error( "Mod_SubdividePolygon: too many vertexes on face ( %i )\n", numverts );
  10148.  
  10149. + sample_size = Mod_SampleSizeForFace( warpface );
  10150. BoundPoly( numverts, verts, mins, maxs );
  10151.  
  10152. for( i = 0; i < 3; i++ )
  10153. @@ -182,15 +183,15 @@ static void SubdividePolygon_r( msurface_t *warpface, int numverts, float *verts
  10154. // lightmap texture coordinates
  10155. s = DotProduct( verts, warpface->texinfo->vecs[0] ) + warpface->texinfo->vecs[0][3];
  10156. s -= warpface->texturemins[0];
  10157. - s += warpface->light_s * LM_SAMPLE_SIZE;
  10158. - s += LM_SAMPLE_SIZE >> 1;
  10159. - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
  10160. + s += warpface->light_s * sample_size;
  10161. + s += sample_size >> 1;
  10162. + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
  10163.  
  10164. t = DotProduct( verts, warpface->texinfo->vecs[1] ) + warpface->texinfo->vecs[1][3];
  10165. t -= warpface->texturemins[1];
  10166. - t += warpface->light_t * LM_SAMPLE_SIZE;
  10167. - t += LM_SAMPLE_SIZE >> 1;
  10168. - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
  10169. + t += warpface->light_t * sample_size;
  10170. + t += sample_size >> 1;
  10171. + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
  10172.  
  10173. poly->verts[i+1][5] = s;
  10174. poly->verts[i+1][6] = t;
  10175. @@ -285,8 +286,8 @@ GL_BuildPolygonFromSurface
  10176. void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
  10177. {
  10178. int i, lindex, lnumverts;
  10179. + int vertpage, sample_size;
  10180. medge_t *pedges, *r_pedge;
  10181. - int vertpage;
  10182. texture_t *tex;
  10183. gltexture_t *glt;
  10184. float *vec;
  10185. @@ -310,6 +311,8 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
  10186. glt->srcHeight = tex->height;
  10187. }
  10188.  
  10189. + sample_size = Mod_SampleSizeForFace( fa );
  10190. +
  10191. // reconstruct the polygon
  10192. pedges = mod->edges;
  10193. lnumverts = fa->numedges;
  10194. @@ -350,15 +353,15 @@ void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa )
  10195. // lightmap texture coordinates
  10196. s = DotProduct( vec, fa->texinfo->vecs[0] ) + fa->texinfo->vecs[0][3];
  10197. s -= fa->texturemins[0];
  10198. - s += fa->light_s * LM_SAMPLE_SIZE;
  10199. - s += LM_SAMPLE_SIZE >> 1;
  10200. - s /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->width;
  10201. + s += fa->light_s * sample_size;
  10202. + s += sample_size >> 1;
  10203. + s /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->width;
  10204.  
  10205. t = DotProduct( vec, fa->texinfo->vecs[1] ) + fa->texinfo->vecs[1][3];
  10206. t -= fa->texturemins[1];
  10207. - t += fa->light_t * LM_SAMPLE_SIZE;
  10208. - t += LM_SAMPLE_SIZE >> 1;
  10209. - t /= BLOCK_SIZE * LM_SAMPLE_SIZE; //fa->texinfo->texture->height;
  10210. + t += fa->light_t * sample_size;
  10211. + t += sample_size >> 1;
  10212. + t /= BLOCK_SIZE * sample_size; //fa->texinfo->texture->height;
  10213.  
  10214. poly->verts[i][5] = s;
  10215. poly->verts[i][6] = t;
  10216. @@ -467,6 +470,7 @@ void R_AddDynamicLights( msurface_t *surf )
  10217. int lnum, s, t, sd, td, smax, tmax;
  10218. float sl, tl, sacc, tacc;
  10219. vec3_t impact, origin_l;
  10220. + int sample_size;
  10221. mtexinfo_t *tex;
  10222. dlight_t *dl;
  10223. uint *bl;
  10224. @@ -474,8 +478,9 @@ void R_AddDynamicLights( msurface_t *surf )
  10225. // no dlighted surfaces here
  10226. if( !R_CountSurfaceDlights( surf )) return;
  10227.  
  10228. - smax = (surf->extents[0] / LM_SAMPLE_SIZE) + 1;
  10229. - tmax = (surf->extents[1] / LM_SAMPLE_SIZE) + 1;
  10230. + sample_size = Mod_SampleSizeForFace( surf );
  10231. + smax = (surf->extents[0] / sample_size) + 1;
  10232. + tmax = (surf->extents[1] / sample_size) + 1;
  10233. tex = surf->texinfo;
  10234.  
  10235. for( lnum = 0; lnum < MAX_DLIGHTS; lnum++ )
  10236. @@ -512,12 +517,12 @@ void R_AddDynamicLights( msurface_t *surf )
  10237. tl = DotProduct( impact, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
  10238.  
  10239. bl = r_blocklights;
  10240. - for( t = 0, tacc = 0; t < tmax; t++, tacc += LM_SAMPLE_SIZE )
  10241. + for( t = 0, tacc = 0; t < tmax; t++, tacc += sample_size )
  10242. {
  10243. td = tl - tacc;
  10244. if( td < 0 ) td = -td;
  10245.  
  10246. - for( s = 0, sacc = 0; s < smax; s++, sacc += LM_SAMPLE_SIZE, bl += 3 )
  10247. + for( s = 0, sacc = 0; s < smax; s++, sacc += sample_size, bl += 3 )
  10248. {
  10249. sd = sl - sacc;
  10250. if( sd < 0 ) sd = -sd;
  10251. @@ -547,7 +552,7 @@ void R_SetCacheState( msurface_t *surf )
  10252.  
  10253. for( maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++ )
  10254. {
  10255. - surf->cached_light[maps] = RI.lightstylevalue[surf->styles[maps]];
  10256. + surf->cached_light[maps] = tr.lightstylevalue[surf->styles[maps]];
  10257. }
  10258. }
  10259.  
  10260. @@ -637,7 +642,6 @@ static void LM_UploadBlock( qboolean dynamic )
  10261. r_lightmap.flags = ( world.version == Q1BSP_VERSION ) ? 0 : IMAGE_HAS_COLOR;
  10262. r_lightmap.buffer = gl_lms.lightmap_buffer;
  10263. tr.lightmapTextures[i] = GL_LoadTextureInternal( lmName, &r_lightmap, TF_FONT, false );
  10264. - GL_SetTextureType( tr.lightmapTextures[i], TEX_LIGHTMAP );
  10265.  
  10266. if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
  10267. Host_Error( "AllocBlock: full\n" );
  10268. @@ -657,10 +661,12 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
  10269. int smax, tmax;
  10270. uint *bl, scale;
  10271. int i, map, size, s, t;
  10272. + int sample_size;
  10273. color24 *lm;
  10274.  
  10275. - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
  10276. - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
  10277. + sample_size = Mod_SampleSizeForFace( surf );
  10278. + smax = ( surf->extents[0] / sample_size ) + 1;
  10279. + tmax = ( surf->extents[1] / sample_size ) + 1;
  10280. size = smax * tmax;
  10281.  
  10282. lm = surf->samples;
  10283. @@ -670,7 +676,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
  10284. // add all the lightmaps
  10285. for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255 && lm; map++ )
  10286. {
  10287. - scale = RI.lightstylevalue[surf->styles[map]];
  10288. + scale = tr.lightstylevalue[surf->styles[map]];
  10289.  
  10290. for( i = 0, bl = r_blocklights; i < size; i++, bl += 3, lm++ )
  10291. {
  10292. @@ -716,6 +722,8 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
  10293. cl_entity_t *e = RI.currententity;
  10294. int i, hasScale = false;
  10295.  
  10296. + if( !p ) return;
  10297. +
  10298. // special hack for non-lightmapped surfaces
  10299. if( p->flags & SURF_DRAWTILED )
  10300. GL_ResetFogColor();
  10301. @@ -879,10 +887,12 @@ void R_BlendLightmaps( void )
  10302. for( surf = gl_lms.dynamic_surfaces; surf != NULL; surf = surf->lightmapchain )
  10303. {
  10304. int smax, tmax;
  10305. + int sample_size;
  10306. byte *base;
  10307.  
  10308. - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
  10309. - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
  10310. + sample_size = Mod_SampleSizeForFace( surf );
  10311. + smax = ( surf->extents[0] / sample_size ) + 1;
  10312. + tmax = ( surf->extents[1] / sample_size ) + 1;
  10313. info = SURF_INFO( surf, RI.currentmodel );
  10314.  
  10315. if( LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
  10316. @@ -996,7 +1006,7 @@ void R_RenderFullbrights( void )
  10317. for( p = fullbright_polys[i]; p; p = p->next )
  10318. {
  10319. if( p->flags & SURF_DRAWTURB )
  10320. - EmitWaterPolys( p, ( p->flags & SURF_NOCULL ));
  10321. + EmitWaterPolys( p, ( p->flags & SURF_NOCULL ), false );
  10322. else DrawGLPoly( p, 0.0f, 0.0f );
  10323. }
  10324.  
  10325. @@ -1086,15 +1096,8 @@ void R_RenderBrushPoly( msurface_t *fa )
  10326. else r_stats.c_brush_polys++;
  10327.  
  10328. if( fa->flags & SURF_DRAWSKY )
  10329. - {
  10330. - if( world.sky_sphere )
  10331. - {
  10332. - // warp texture, no lightmaps
  10333. - EmitSkyLayers( fa );
  10334. - }
  10335. - return;
  10336. - }
  10337. -
  10338. + return; // already handled
  10339. +
  10340. t = R_TextureAnimation( fa->texinfo->texture, fa - RI.currententity->model->surfaces );
  10341.  
  10342. if( RP_NORMALPASS() && fa->flags & SURF_REFLECT )
  10343. @@ -1122,13 +1125,13 @@ void R_RenderBrushPoly( msurface_t *fa )
  10344. if( fa->flags & SURF_DRAWTURB )
  10345. {
  10346. // warp texture, no lightmaps
  10347. - EmitWaterPolys( fa->polys, ( fa->flags & SURF_NOCULL ));
  10348. + EmitWaterPolys( fa->polys, ( fa->flags & SURF_NOCULL ), false );
  10349. if( is_mirror ) R_EndDrawMirror();
  10350. // END WATER STUFF
  10351. return;
  10352. }
  10353.  
  10354. - if( t->fb_texturenum )
  10355. + if( t->fb_texturenum && fa->polys )
  10356. {
  10357. // HACKHACK: store fullbrights in poly->next (only for non-water surfaces)
  10358. fa->polys->next = fullbright_polys[t->fb_texturenum];
  10359. @@ -1182,7 +1185,7 @@ void R_RenderBrushPoly( msurface_t *fa )
  10360. // check for lightmap modification
  10361. for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
  10362. {
  10363. - if( RI.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
  10364. + if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] )
  10365. goto dynamic;
  10366. }
  10367.  
  10368. @@ -1199,10 +1202,12 @@ dynamic:
  10369. if(( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != tr.framecount ))
  10370. {
  10371. byte temp[132*132*4];
  10372. + int sample_size;
  10373. int smax, tmax;
  10374.  
  10375. - smax = ( fa->extents[0] / LM_SAMPLE_SIZE ) + 1;
  10376. - tmax = ( fa->extents[1] / LM_SAMPLE_SIZE ) + 1;
  10377. + sample_size = Mod_SampleSizeForFace( fa );
  10378. + smax = ( fa->extents[0] / sample_size ) + 1;
  10379. + tmax = ( fa->extents[1] / sample_size ) + 1;
  10380.  
  10381. R_BuildLightMap( fa, temp, smax * 4, true );
  10382. R_SetCacheState( fa );
  10383. @@ -1249,31 +1254,40 @@ void R_DrawTextureChains( void )
  10384. RI.currententity = clgame.entities;
  10385. RI.currentmodel = RI.currententity->model;
  10386.  
  10387. + if( world.sky_sphere && !world.custom_skybox )
  10388. + {
  10389. + pglDisable( GL_TEXTURE_2D );
  10390. + pglColor3f( 1.0f, 1.0f, 1.0f );
  10391. + }
  10392. +
  10393. // clip skybox surfaces
  10394. for( s = skychain; s != NULL; s = s->texturechain )
  10395. R_AddSkyBoxSurface( s );
  10396.  
  10397. + if( world.sky_sphere && !world.custom_skybox )
  10398. + {
  10399. + pglEnable( GL_TEXTURE_2D );
  10400. +
  10401. + if( skychain )
  10402. + R_DrawClouds();
  10403. + skychain = NULL;
  10404. + }
  10405. +
  10406. for( i = 0; i < cl.worldmodel->numtextures; i++ )
  10407. {
  10408. t = cl.worldmodel->textures[i];
  10409. if( !t ) continue;
  10410.  
  10411. s = t->texturechain;
  10412. - if( !s ) continue;
  10413.  
  10414. - if( i == tr.skytexturenum )
  10415. - {
  10416. - if( world.sky_sphere )
  10417. - R_DrawSkyChain( s );
  10418. - }
  10419. - else
  10420. - {
  10421. - if(( s->flags & SURF_DRAWTURB ) && cl.refdef.movevars->wateralpha < 1.0f )
  10422. - continue; // draw translucent water later
  10423. + if( !s || ( i == tr.skytexturenum ))
  10424. + continue;
  10425.  
  10426. - for( ; s != NULL; s = s->texturechain )
  10427. - R_RenderBrushPoly( s );
  10428. - }
  10429. + if(( s->flags & SURF_DRAWTURB ) && cl.refdef.movevars->wateralpha < 1.0f )
  10430. + continue; // draw translucent water later
  10431. +
  10432. + for( ; s != NULL; s = s->texturechain )
  10433. + R_RenderBrushPoly( s );
  10434. t->texturechain = NULL;
  10435. }
  10436.  
  10437. @@ -1298,6 +1312,10 @@ void R_DrawWaterSurfaces( void )
  10438. if( cl.refdef.movevars->wateralpha >= 1.0f )
  10439. return;
  10440.  
  10441. + // restore worldmodel
  10442. + RI.currententity = clgame.entities;
  10443. + RI.currentmodel = RI.currententity->model;
  10444. +
  10445. // go back to the world matrix
  10446. R_LoadIdentity();
  10447.  
  10448. @@ -1323,7 +1341,7 @@ void R_DrawWaterSurfaces( void )
  10449. GL_Bind( GL_TEXTURE0, t->gl_texturenum );
  10450.  
  10451. for( ; s; s = s->texturechain )
  10452. - EmitWaterPolys( s->polys, ( s->flags & SURF_NOCULL ));
  10453. + EmitWaterPolys( s->polys, ( s->flags & SURF_NOCULL ), false );
  10454.  
  10455. t->texturechain = NULL;
  10456. }
  10457. @@ -1389,7 +1407,6 @@ void R_DrawBrushModel( cl_entity_t *e )
  10458. if( !RI.drawWorld ) return;
  10459.  
  10460. clmodel = e->model;
  10461. - RI.currentWaveHeight = RI.currententity->curstate.scale * 32.0f;
  10462.  
  10463. // don't reflect this entity in mirrors
  10464. if( e->curstate.effects & EF_NOREFLECT && RI.params & RP_MIRRORVIEW )
  10465. @@ -1551,7 +1568,7 @@ void R_DrawStaticModel( cl_entity_t *e )
  10466. if( R_CullSurface( psurf, RI.clipFlags ))
  10467. continue;
  10468.  
  10469. - if( psurf->flags & SURF_DRAWSKY && !world.sky_sphere )
  10470. + if( psurf->flags & SURF_DRAWSKY )
  10471. {
  10472. // make sky chain to right clip the skybox
  10473. psurf->texturechain = skychain;
  10474. @@ -1677,7 +1694,7 @@ void R_RecursiveWorldNode( mnode_t *node, uint clipflags )
  10475. if( R_CullSurface( surf, clipflags ))
  10476. continue;
  10477.  
  10478. - if( surf->flags & SURF_DRAWSKY && !world.sky_sphere )
  10479. + if( surf->flags & SURF_DRAWSKY )
  10480. {
  10481. // make sky chain to right clip the skybox
  10482. surf->texturechain = skychain;
  10483. @@ -1900,7 +1917,6 @@ void R_DrawWorld( void )
  10484. memset( fullbright_polys, 0, sizeof( fullbright_polys ));
  10485. memset( detail_surfaces, 0, sizeof( detail_surfaces ));
  10486.  
  10487. - RI.currentWaveHeight = RI.waveHeight;
  10488. GL_SetRenderMode( kRenderNormal );
  10489. gl_lms.dynamic_surfaces = NULL;
  10490.  
  10491. @@ -1941,7 +1957,6 @@ Mark the leaves and nodes that are in the PVS for the current leaf
  10492. */
  10493. void R_MarkLeaves( void )
  10494. {
  10495. - byte *vis;
  10496. mnode_t *node;
  10497. int i;
  10498.  
  10499. @@ -1952,21 +1967,20 @@ void R_MarkLeaves( void )
  10500. // force recalc viewleaf
  10501. r_novis->modified = false;
  10502. tr.fResetVis = false;
  10503. - r_viewleaf = NULL;
  10504. + RI.viewleaf = NULL;
  10505. }
  10506.  
  10507. - if( r_viewleaf == r_oldviewleaf && r_viewleaf2 == r_oldviewleaf2 && !r_novis->integer && r_viewleaf != NULL )
  10508. + if( RI.viewleaf == RI.oldviewleaf && !r_novis->integer && RI.viewleaf != NULL )
  10509. return;
  10510.  
  10511. // development aid to let you run around
  10512. // and see exactly where the pvs ends
  10513. if( r_lockpvs->integer ) return;
  10514.  
  10515. + RI.oldviewleaf = RI.viewleaf;
  10516. tr.visframecount++;
  10517. - r_oldviewleaf = r_viewleaf;
  10518. - r_oldviewleaf2 = r_viewleaf2;
  10519. -
  10520. - if( r_novis->integer || RI.drawOrtho || !r_viewleaf || !cl.worldmodel->visdata )
  10521. +
  10522. + if( r_novis->integer || RI.drawOrtho || !RI.viewleaf || !cl.worldmodel->visdata )
  10523. {
  10524. // mark everything
  10525. for( i = 0; i < cl.worldmodel->numleafs; i++ )
  10526. @@ -1976,26 +1990,11 @@ void R_MarkLeaves( void )
  10527. return;
  10528. }
  10529.  
  10530. - // may have to combine two clusters
  10531. - // because of solid water boundaries
  10532. - vis = Mod_LeafPVS( r_viewleaf, cl.worldmodel );
  10533. -
  10534. - if( r_viewleaf != r_viewleaf2 )
  10535. - {
  10536. - int longs = ( cl.worldmodel->numleafs + 31 ) >> 5;
  10537. -
  10538. - memcpy( visbytes, vis, longs << 2 );
  10539. - vis = Mod_LeafPVS( r_viewleaf2, cl.worldmodel );
  10540. -
  10541. - for( i = 0; i < longs; i++ )
  10542. - ((int *)visbytes)[i] |= ((int *)vis)[i];
  10543. -
  10544. - vis = visbytes;
  10545. - }
  10546. + Mod_FatPVS( RI.pvsorigin, REFPVS_RADIUS, RI.visbytes, world.visbytes, FBitSet( RI.params, RP_OLDVIEWLEAF ), r_novis->integer );
  10547.  
  10548. for( i = 0; i < cl.worldmodel->numleafs; i++ )
  10549. {
  10550. - if( vis[i>>3] & ( 1<<( i & 7 )))
  10551. + if( CHECKVISBIT( RI.visbytes, i ))
  10552. {
  10553. node = (mnode_t *)&cl.worldmodel->leafs[i+1];
  10554. do
  10555. @@ -2017,14 +2016,16 @@ GL_CreateSurfaceLightmap
  10556. void GL_CreateSurfaceLightmap( msurface_t *surf )
  10557. {
  10558. int smax, tmax;
  10559. + int sample_size;
  10560. byte *base;
  10561.  
  10562. if( !cl.worldmodel->lightdata ) return;
  10563. if( surf->flags & SURF_DRAWTILED )
  10564. return;
  10565.  
  10566. - smax = ( surf->extents[0] / LM_SAMPLE_SIZE ) + 1;
  10567. - tmax = ( surf->extents[1] / LM_SAMPLE_SIZE ) + 1;
  10568. + sample_size = Mod_SampleSizeForFace( surf );
  10569. + smax = ( surf->extents[0] / sample_size ) + 1;
  10570. + tmax = ( surf->extents[1] / sample_size ) + 1;
  10571.  
  10572. if( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ))
  10573. {
  10574. @@ -2075,7 +2076,7 @@ void GL_RebuildLightmaps( void )
  10575. gl_lms.current_lightmap_texture = 0;
  10576.  
  10577. // setup all the lightstyles
  10578. - R_AnimateLight();
  10579. + CL_RunLightStyles();
  10580.  
  10581. LM_InitBlock();
  10582.  
  10583. @@ -2131,7 +2132,7 @@ void GL_BuildLightmaps( void )
  10584. memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
  10585. memset( tr.mirror_entities, 0, sizeof( tr.mirror_entities ));
  10586. memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures ));
  10587. - memset( visbytes, 0x00, sizeof( visbytes ));
  10588. + memset( &RI, 0, sizeof( RI ));
  10589.  
  10590. skychain = NULL;
  10591.  
  10592. @@ -2142,7 +2143,7 @@ void GL_BuildLightmaps( void )
  10593. nColinElim = 0;
  10594.  
  10595. // setup all the lightstyles
  10596. - R_AnimateLight();
  10597. + CL_RunLightStyles();
  10598.  
  10599. LM_InitBlock();
  10600.  
  10601. @@ -2166,9 +2167,6 @@ void GL_BuildLightmaps( void )
  10602. if( m->surfaces[j].flags & SURF_DRAWTURB )
  10603. continue;
  10604.  
  10605. - if( m->surfaces[j].flags & SURF_DRAWSKY && world.sky_sphere )
  10606. - continue;
  10607. -
  10608. GL_BuildPolygonFromSurface( m, m->surfaces + j );
  10609. }
  10610.  
  10611. diff --git b/engine/client/gl_sprite.c a/engine/client/gl_sprite.c
  10612. index 331e5d6..e07dc25 100644
  10613. --- b/engine/client/gl_sprite.c
  10614. +++ a/engine/client/gl_sprite.c
  10615. @@ -104,8 +104,6 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t
  10616. pspriteframe->gl_texturenum = gl_texturenum;
  10617. *ppframe = pspriteframe;
  10618.  
  10619. - GL_SetTextureType( pspriteframe->gl_texturenum, TEX_SPRITE );
  10620. -
  10621. return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height );
  10622. }
  10623.  
  10624. @@ -200,10 +198,10 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
  10625. psprite->radius = pin->boundingradius;
  10626. psprite->synctype = pin->synctype;
  10627.  
  10628. - mod->mins[0] = mod->mins[1] = -pin->bounds[0] / 2;
  10629. - mod->maxs[0] = mod->maxs[1] = pin->bounds[0] / 2;
  10630. - mod->mins[2] = -pin->bounds[1] / 2;
  10631. - mod->maxs[2] = pin->bounds[1] / 2;
  10632. + mod->mins[0] = mod->mins[1] = -pin->bounds[0] * 0.5f;
  10633. + mod->maxs[0] = mod->maxs[1] = pin->bounds[0] * 0.5f;
  10634. + mod->mins[2] = -pin->bounds[1] * 0.5f;
  10635. + mod->maxs[2] = pin->bounds[1] * 0.5f;
  10636. numi = (short *)(pin + 1);
  10637.  
  10638. if( host.type == HOST_DEDICATED )
  10639. @@ -336,7 +334,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
  10640. psprite->type = SPR_FWD_PARALLEL_ORIENTED;
  10641. psprite->texFormat = SPR_ALPHTEST;
  10642. psprite->numframes = mod->numframes = numframes;
  10643. - psprite->radius = sqrt((( w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1)));
  10644. + psprite->radius = sqrt(((w >> 1) * (w >> 1)) + ((h >> 1) * (h >> 1)));
  10645.  
  10646. mod->mins[0] = mod->mins[1] = -w / 2;
  10647. mod->maxs[0] = mod->maxs[1] = w / 2;
  10648. @@ -384,8 +382,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
  10649. pspriteframe->down = ( h >> 1 ) - h;
  10650. pspriteframe->right = w + -( w >> 1 );
  10651. pspriteframe->gl_texturenum = GL_LoadTextureInternal( texname, &temp, TF_IMAGE, false );
  10652. - GL_SetTextureType( pspriteframe->gl_texturenum, TEX_NOMIP );
  10653. -
  10654. +
  10655. xl += w;
  10656. if( xl >= pix->width )
  10657. {
  10658. @@ -462,13 +459,16 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
  10659. mspritegroup_t *pspritegroup;
  10660. mspriteframe_t *pspriteframe = NULL;
  10661. float *pintervals, fullinterval;
  10662. - float targettime, time;
  10663. int i, numframes;
  10664. + float targettime;
  10665.  
  10666. ASSERT( pModel );
  10667. psprite = pModel->cache.data;
  10668.  
  10669. - if( frame < 0 ) frame = 0;
  10670. + if( frame < 0 )
  10671. + {
  10672. + frame = 0;
  10673. + }
  10674. else if( frame >= psprite->numframes )
  10675. {
  10676. MsgDev( D_WARN, "R_GetSpriteFrame: no such frame %d (%s)\n", frame, pModel->name );
  10677. @@ -485,11 +485,10 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
  10678. pintervals = pspritegroup->intervals;
  10679. numframes = pspritegroup->numframes;
  10680. fullinterval = pintervals[numframes-1];
  10681. - time = cl.time;
  10682.  
  10683. // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
  10684. // are positive, so we don't have to worry about division by zero
  10685. - targettime = time - ((int)(time / fullinterval)) * fullinterval;
  10686. + targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
  10687.  
  10688. for( i = 0; i < (numframes - 1); i++ )
  10689. {
  10690. @@ -520,98 +519,89 @@ between frames where are we lerping
  10691. */
  10692. float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe, mspriteframe_t **curframe )
  10693. {
  10694. - msprite_t *psprite;
  10695. - mspritegroup_t *pspritegroup;
  10696. - int i, j, numframes, frame;
  10697. - float lerpFrac, time, jtime, jinterval;
  10698. - float *pintervals, fullinterval, targettime;
  10699. - int m_fDoInterp;
  10700. + msprite_t *psprite;
  10701. + float lerpFrac = 1.0f, frame;
  10702. + int m_fDoInterp, oldf, newf;
  10703. + float frametime = 0.0f;
  10704. + int i, j, iframe;
  10705.  
  10706. psprite = ent->model->cache.data;
  10707. - frame = (int)ent->curstate.frame;
  10708. - lerpFrac = 1.0f;
  10709. +
  10710. + if( ent->curstate.framerate > 0.0f )
  10711. + frametime = (1.0f / ent->curstate.framerate);
  10712. +
  10713. + frame = Q_max( 0.0f, ent->curstate.frame - host.frametime * ent->curstate.framerate );
  10714. + iframe = (int)frame;
  10715.  
  10716. // misc info
  10717. - if( r_sprite_lerping->integer )
  10718. + if( r_sprite_lerping->integer && psprite->numframes > 1 )
  10719. m_fDoInterp = (ent->curstate.effects & EF_NOINTERP) ? false : true;
  10720. else m_fDoInterp = false;
  10721.  
  10722. - if( frame < 0 )
  10723. + if( m_fDoInterp == false )
  10724. {
  10725. - frame = 0;
  10726. - }
  10727. - else if( frame >= psprite->numframes )
  10728. + // interpolation disabled for some reasons
  10729. + *oldframe = *curframe = R_GetSpriteFrame( ent->model, ent->curstate.frame, ent->angles[YAW] );
  10730. + return lerpFrac;
  10731. + }
  10732. +
  10733. + if( iframe < 0 )
  10734. + {
  10735. + iframe = 0;
  10736. + }
  10737. + else if( iframe >= psprite->numframes )
  10738. {
  10739. MsgDev( D_WARN, "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name );
  10740. - frame = psprite->numframes - 1;
  10741. + iframe = psprite->numframes - 1;
  10742. }
  10743.  
  10744. - if( psprite->frames[frame].type == FRAME_SINGLE )
  10745. + // calc interpolant range
  10746. + oldf = (int)Q_floor( frame );
  10747. + newf = (int)Q_ceil( frame );
  10748. +
  10749. + // allow interp between first and last frame
  10750. + oldf = oldf % ( psprite->numframes - 1 );
  10751. + newf = newf % ( psprite->numframes - 1 );
  10752. +
  10753. + // NOTE: we allow interpolation between single and angled frames e.g. for Doom monsters
  10754. + if( psprite->frames[iframe].type == FRAME_SINGLE || psprite->frames[iframe].type == FRAME_ANGLED )
  10755. {
  10756. - if( m_fDoInterp )
  10757. - {
  10758. - if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_SINGLE )
  10759. - {
  10760. - // this can be happens when rendering switched between single and angled frames
  10761. - // or change model on replace delta-entity
  10762. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10763. - ent->latched.prevanimtime = RI.refdef.time;
  10764. - lerpFrac = 1.0f;
  10765. - }
  10766. -
  10767. - if( ent->latched.prevanimtime < RI.refdef.time )
  10768. - {
  10769. - if( frame != ent->latched.prevblending[1] )
  10770. - {
  10771. - ent->latched.prevblending[0] = ent->latched.prevblending[1];
  10772. - ent->latched.prevblending[1] = frame;
  10773. - ent->latched.prevanimtime = RI.refdef.time;
  10774. - lerpFrac = 0.0f;
  10775. - }
  10776. - else lerpFrac = (RI.refdef.time - ent->latched.prevanimtime) * 10;
  10777. - }
  10778. - else
  10779. - {
  10780. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10781. - ent->latched.prevanimtime = RI.refdef.time;
  10782. - lerpFrac = 0.0f;
  10783. - }
  10784. - }
  10785. - else
  10786. + // frame was changed
  10787. + if( newf != ent->latched.prevframe )
  10788. {
  10789. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10790. - lerpFrac = 1.0f;
  10791. + ent->latched.prevanimtime = cl.time + frametime;
  10792. + ent->latched.prevframe = newf;
  10793. + lerpFrac = 1.0f; // reset lerp
  10794. }
  10795. +
  10796. + if( ent->latched.prevanimtime != 0.0f && ent->latched.prevanimtime > cl.time )
  10797. + lerpFrac = (ent->latched.prevanimtime - cl.time) * ent->curstate.framerate;
  10798.  
  10799. - if( ent->latched.prevblending[0] >= psprite->numframes )
  10800. - {
  10801. - // reset interpolation on change model
  10802. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10803. - ent->latched.prevanimtime = RI.refdef.time;
  10804. - lerpFrac = 0.0f;
  10805. - }
  10806. + // compute lerp factor
  10807. + lerpFrac = (int)(10000 * lerpFrac) / 10000.0f;
  10808. + lerpFrac = bound( 0.0f, 1.0f - lerpFrac, 1.0f );
  10809.  
  10810. // get the interpolated frames
  10811. - if( oldframe ) *oldframe = psprite->frames[ent->latched.prevblending[0]].frameptr;
  10812. - if( curframe ) *curframe = psprite->frames[frame].frameptr;
  10813. + if( oldframe ) *oldframe = R_GetSpriteFrame( ent->model, oldf, ent->angles[YAW] );
  10814. + if( curframe ) *curframe = R_GetSpriteFrame( ent->model, newf, ent->angles[YAW] );
  10815. }
  10816. - else if( psprite->frames[frame].type == FRAME_GROUP )
  10817. + else if( psprite->frames[iframe].type == FRAME_GROUP )
  10818. {
  10819. - pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
  10820. - pintervals = pspritegroup->intervals;
  10821. - numframes = pspritegroup->numframes;
  10822. - fullinterval = pintervals[numframes-1];
  10823. + mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[iframe].frameptr;
  10824. + float *pintervals = pspritegroup->intervals;
  10825. + float fullinterval, targettime, jinterval;
  10826. + float jtime = 0.0f;
  10827. +
  10828. + fullinterval = pintervals[pspritegroup->numframes-1];
  10829. jinterval = pintervals[1] - pintervals[0];
  10830. - time = RI.refdef.time;
  10831. - jtime = 0.0f;
  10832.  
  10833. // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
  10834. // are positive, so we don't have to worry about division by zero
  10835. - targettime = time - ((int)(time / fullinterval)) * fullinterval;
  10836. + targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
  10837.  
  10838. // LordHavoc: since I can't measure the time properly when it loops from numframes - 1 to 0,
  10839. // i instead measure the time of the first frame, hoping it is consistent
  10840. - for( i = 0, j = numframes - 1; i < (numframes - 1); i++ )
  10841. + for( i = 0, j = (pspritegroup->numframes - 1); i < (pspritegroup->numframes - 1); i++ )
  10842. {
  10843. if( pintervals[i] > targettime )
  10844. break;
  10845. @@ -620,61 +610,12 @@ float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe,
  10846. jtime = pintervals[i];
  10847. }
  10848.  
  10849. - if( m_fDoInterp )
  10850. - lerpFrac = (targettime - jtime) / jinterval;
  10851. - else j = i; // no lerping
  10852. + lerpFrac = (targettime - jtime) / jinterval;
  10853.  
  10854. // get the interpolated frames
  10855. if( oldframe ) *oldframe = pspritegroup->frames[j];
  10856. if( curframe ) *curframe = pspritegroup->frames[i];
  10857. }
  10858. - else if( psprite->frames[frame].type == FRAME_ANGLED )
  10859. - {
  10860. - // e.g. doom-style sprite monsters
  10861. - float yaw = ent->angles[YAW];
  10862. - int angleframe = (int)(Q_rint(( RI.refdef.viewangles[1] - yaw + 45.0f ) / 360 * 8) - 4) & 7;
  10863. -
  10864. - if( m_fDoInterp )
  10865. - {
  10866. - if( ent->latched.prevblending[0] >= psprite->numframes || psprite->frames[ent->latched.prevblending[0]].type != FRAME_ANGLED )
  10867. - {
  10868. - // this can be happens when rendering switched between single and angled frames
  10869. - // or change model on replace delta-entity
  10870. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10871. - ent->latched.prevanimtime = RI.refdef.time;
  10872. - lerpFrac = 1.0f;
  10873. - }
  10874. -
  10875. - if( ent->latched.prevanimtime < RI.refdef.time )
  10876. - {
  10877. - if( frame != ent->latched.prevblending[1] )
  10878. - {
  10879. - ent->latched.prevblending[0] = ent->latched.prevblending[1];
  10880. - ent->latched.prevblending[1] = frame;
  10881. - ent->latched.prevanimtime = RI.refdef.time;
  10882. - lerpFrac = 0.0f;
  10883. - }
  10884. - else lerpFrac = (RI.refdef.time - ent->latched.prevanimtime) * ent->curstate.framerate;
  10885. - }
  10886. - else
  10887. - {
  10888. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10889. - ent->latched.prevanimtime = RI.refdef.time;
  10890. - lerpFrac = 0.0f;
  10891. - }
  10892. - }
  10893. - else
  10894. - {
  10895. - ent->latched.prevblending[0] = ent->latched.prevblending[1] = frame;
  10896. - lerpFrac = 1.0f;
  10897. - }
  10898. -
  10899. - pspritegroup = (mspritegroup_t *)psprite->frames[ent->latched.prevblending[0]].frameptr;
  10900. - if( oldframe ) *oldframe = pspritegroup->frames[angleframe];
  10901. -
  10902. - pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
  10903. - if( curframe ) *curframe = pspritegroup->frames[angleframe];
  10904. - }
  10905.  
  10906. return lerpFrac;
  10907. }
  10908. diff --git b/engine/client/gl_studio.c a/engine/client/gl_studio.c
  10909. index 8f6fbf0..0bb18c4 100644
  10910. --- b/engine/client/gl_studio.c
  10911. +++ a/engine/client/gl_studio.c
  10912. @@ -28,7 +28,7 @@ GNU General Public License for more details.
  10913. #define STUDIO_MERGE_TEXTURES
  10914.  
  10915. #define EVENT_CLIENT 5000 // less than this value it's a server-side studio events
  10916. -#define MAXARRAYVERTS 20000 // used for draw shadows
  10917. +#define MAXARRAYVERTS 32768 // used for draw shadows
  10918. #define LEGS_BONES_COUNT 8
  10919.  
  10920. static vec3_t hullcolor[8] =
  10921. @@ -138,7 +138,7 @@ R_StudioInit
  10922. */
  10923. void R_StudioInit( void )
  10924. {
  10925. - float pixelAspect;
  10926. + float pixelAspect, fov_x = 90.0f, fov_y;
  10927.  
  10928. r_studio_lambert = Cvar_Get( "r_studio_lambert", "2", CVAR_ARCHIVE, "bonelighting lambert value" );
  10929. r_studio_lerping = Cvar_Get( "r_studio_lerping", "1", CVAR_ARCHIVE, "enables studio animation lerping" );
  10930. @@ -156,7 +156,8 @@ void R_StudioInit( void )
  10931. pixelAspect *= (320.0f / 240.0f);
  10932. else pixelAspect *= (640.0f / 480.0f);
  10933.  
  10934. - aliasXscale = (float)scr_width->integer / RI.refdef.fov_y;
  10935. + fov_y = V_CalcFov( &fov_x, scr_width->integer, scr_height->integer );
  10936. + aliasXscale = (float)scr_width->integer / fov_y; // stub
  10937. aliasYscale = aliasXscale * pixelAspect;
  10938.  
  10939. Matrix3x4_LoadIdentity( g_aliastransform );
  10940. @@ -257,10 +258,22 @@ static qboolean R_StudioComputeBBox( cl_entity_t *e, vec3_t bbox[8] )
  10941.  
  10942. // rotate the bounding box
  10943. VectorCopy( e->angles, angles );
  10944. -
  10945. +#if 0
  10946. if( e->player ) angles[PITCH] = 0.0f; // don't rotate player model, only aim
  10947. AngleVectors( angles, vectors[0], vectors[1], vectors[2] );
  10948. +#else
  10949. + vectors[0][0] = g_rotationmatrix[0][0];
  10950. + vectors[0][1] = g_rotationmatrix[1][0];
  10951. + vectors[0][2] = g_rotationmatrix[2][0];
  10952. +
  10953. + vectors[1][0] = g_rotationmatrix[0][1];
  10954. + vectors[1][1] = g_rotationmatrix[1][1];
  10955. + vectors[1][2] = g_rotationmatrix[2][1];
  10956.  
  10957. + vectors[2][0] = g_rotationmatrix[0][2];
  10958. + vectors[2][1] = g_rotationmatrix[1][2];
  10959. + vectors[2][2] = g_rotationmatrix[2][2];
  10960. +#endif
  10961. // compute a full bounding box
  10962. for( i = 0; i < 8; i++ )
  10963. {
  10964. @@ -270,7 +283,7 @@ static qboolean R_StudioComputeBBox( cl_entity_t *e, vec3_t bbox[8] )
  10965.  
  10966. // rotate by YAW
  10967. p2[0] = DotProduct( p1, vectors[0] );
  10968. - p2[1] = DotProduct( p1, vectors[1] );
  10969. + p2[1] = -DotProduct( p1, vectors[1] );
  10970. p2[2] = DotProduct( p1, vectors[2] );
  10971.  
  10972. if( bbox ) VectorAdd( p2, e->origin, bbox[i] );
  10973. @@ -736,7 +749,7 @@ StudioCalcBoneAdj
  10974. void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen )
  10975. {
  10976. mstudiobonecontroller_t *pbonecontroller;
  10977. - float value;
  10978. + float value = 0.0f;
  10979. int i, j;
  10980.  
  10981. pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex);
  10982. @@ -875,13 +888,13 @@ void R_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudi
  10983.  
  10984. if( !VectorCompare( angle1, angle2 ))
  10985. {
  10986. - AngleQuaternion( angle1, q1 );
  10987. - AngleQuaternion( angle2, q2 );
  10988. + AngleQuaternion( angle1, q1, true );
  10989. + AngleQuaternion( angle2, q2, true );
  10990. QuaternionSlerp( q1, q2, s, q );
  10991. }
  10992. else
  10993. {
  10994. - AngleQuaternion( angle1, q );
  10995. + AngleQuaternion( angle1, q, true );
  10996. }
  10997. }
  10998.  
  10999. @@ -2017,10 +2030,10 @@ static void R_StudioDrawPoints( void )
  11000. pglColor4ub( clr->r, clr->g, clr->b, 255 );
  11001. alpha = 1.0f;
  11002. }
  11003. - else if( g_nFaceFlags & STUDIO_NF_TRANSPARENT && R_StudioOpaque( RI.currententity ))
  11004. + else if( g_nFaceFlags & STUDIO_NF_TRANSPARENT && R_StudioOpaque( g_iRenderMode ))
  11005. {
  11006. GL_SetRenderMode( kRenderTransAlpha );
  11007. - pglAlphaFunc( GL_GREATER, 0.0f );
  11008. + pglAlphaFunc( GL_GEQUAL, 0.5f );
  11009. alpha = 1.0f;
  11010. }
  11011. else if( g_nFaceFlags & STUDIO_NF_ADDITIVE )
  11012. @@ -2443,7 +2456,7 @@ static model_t *R_StudioSetupPlayerModel( int index )
  11013.  
  11014. if( cls.key_dest == key_menu && !index )
  11015. {
  11016. - // we are in menu.
  11017. + // we are in gameui.
  11018. info = &gameui.playerinfo;
  11019. }
  11020. else
  11021. @@ -2565,15 +2578,16 @@ R_StudioSetupRenderer
  11022. */
  11023. static void R_StudioSetupRenderer( int rendermode )
  11024. {
  11025. + if( rendermode > kRenderTransAdd ) rendermode = 0;
  11026. g_iRenderMode = bound( 0, rendermode, kRenderTransAdd );
  11027. - pglShadeModel( GL_SMOOTH ); // enable gouraud shading
  11028. if( clgame.ds.cullMode != GL_NONE ) GL_Cull( GL_FRONT );
  11029.  
  11030. // enable depthmask on studiomodels
  11031. if( glState.drawTrans && g_iRenderMode != kRenderTransAdd )
  11032. pglDepthMask( GL_TRUE );
  11033.  
  11034. - pglAlphaFunc( GL_GREATER, 0.0f );
  11035. + pglAlphaFunc( GL_GEQUAL, 0.5f );
  11036. + pglShadeModel( GL_SMOOTH );
  11037.  
  11038. if( g_iBackFaceCull )
  11039. GL_FrontFace( true );
  11040. @@ -2588,7 +2602,6 @@ R_StudioRestoreRenderer
  11041. static void R_StudioRestoreRenderer( void )
  11042. {
  11043. pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
  11044. - pglShadeModel( GL_FLAT );
  11045.  
  11046. // restore depthmask state for sprites etc
  11047. if( glState.drawTrans && g_iRenderMode != kRenderTransAdd )
  11048. @@ -2948,7 +2961,7 @@ R_StudioDrawPlayer
  11049. static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer )
  11050. {
  11051. int m_nPlayerIndex;
  11052. - float gaitframe, gaityaw;
  11053. + float gaitframe = 0.0f, gaityaw = 0.0f;
  11054. vec3_t dir, prevgaitorigin;
  11055. alight_t lighting;
  11056.  
  11057. @@ -3305,6 +3318,10 @@ void R_RunViewmodelEvents( void )
  11058. RI.currentmodel = RI.currententity->model;
  11059. if( !RI.currentmodel ) return;
  11060.  
  11061. + if( !cl.weaponstarttime ) cl.weaponstarttime = cl.time;
  11062. + RI.currententity->curstate.animtime = cl.weaponstarttime;
  11063. + RI.currententity->curstate.sequence = cl.weaponsequence;
  11064. +
  11065. pStudioDraw->StudioDrawModel( STUDIO_EVENTS );
  11066.  
  11067. RI.currententity = NULL;
  11068. @@ -3344,6 +3361,10 @@ void R_DrawViewModel( void )
  11069. if( r_lefthand->integer == 1 || g_iBackFaceCull )
  11070. GL_FrontFace( !glState.frontFace );
  11071.  
  11072. + if( !cl.weaponstarttime ) cl.weaponstarttime = cl.time;
  11073. + RI.currententity->curstate.animtime = cl.weaponstarttime;
  11074. + RI.currententity->curstate.sequence = cl.weaponsequence;
  11075. +
  11076. pStudioDraw->StudioDrawModel( STUDIO_RENDER );
  11077.  
  11078. // restore depth range
  11079. @@ -3433,7 +3454,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
  11080. filter = R_FindTexFilter( va( "%s.mdl/%s", mdlname, name )); // grab texture filter
  11081.  
  11082. // NOTE: colormaps must have the palette for properly work. Ignore it.
  11083. - if( Mod_AllowMaterials( ) && !( ptexture->flags & STUDIO_NF_COLORMAP ))
  11084. + if( Mod_AllowMaterials( ) && !FBitSet( ptexture->flags, STUDIO_NF_COLORMAP ))
  11085. {
  11086. int gl_texturenum = 0;
  11087.  
  11088. @@ -3455,7 +3476,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
  11089. ptexture->index = (int)((byte *)phdr) + ptexture->index;
  11090. size = sizeof( mstudiotexture_t ) + ptexture->width * ptexture->height + 768;
  11091.  
  11092. - if( host.features & ENGINE_DISABLE_HDTEXTURES && ptexture->flags & STUDIO_NF_TRANSPARENT )
  11093. + if( FBitSet( host.features, ENGINE_DISABLE_HDTEXTURES ) && FBitSet( ptexture->flags, STUDIO_NF_TRANSPARENT ))
  11094. flags |= TF_KEEP_8BIT; // Paranoia2 alpha-tracing
  11095.  
  11096. // build the texname
  11097. @@ -3473,7 +3494,6 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
  11098. {
  11099. // duplicate texnum for easy acess
  11100. if( tx ) tx->gl_texturenum = ptexture->index;
  11101. - GL_SetTextureType( ptexture->index, TEX_STUDIO );
  11102. }
  11103. }
  11104.  
  11105. diff --git b/engine/client/gl_vidnt.c a/engine/client/gl_vidnt.c
  11106. index 482bed3..96700ce 100644
  11107. --- b/engine/client/gl_vidnt.c
  11108. +++ a/engine/client/gl_vidnt.c
  11109. @@ -22,35 +22,28 @@ GNU General Public License for more details.
  11110. #define VID_AUTOMODE "-1"
  11111. #define VID_DEFAULTMODE 2.0f
  11112. #define DISP_CHANGE_BADDUALVIEW -6 // MSVC 6.0 doesn't
  11113. -#define num_vidmodes ( sizeof( vidmode ) / sizeof( vidmode[0] ))
  11114. +#define num_vidmodes ARRAYSIZE( vidmode )
  11115. #define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_SYSMENU|WS_CAPTION|WS_VISIBLE)
  11116. #define WINDOW_EX_STYLE (0)
  11117. -#define WINDOW_NAME "Xash Window" // Half-Life
  11118. -
  11119. -#ifdef WIN32
  11120. -// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
  11121. -__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
  11122. -#endif
  11123. +#define WINDOW_NAME "Xash3D Window" // Half-Life
  11124.  
  11125. convar_t *renderinfo;
  11126. -convar_t *gl_allow_software;
  11127. convar_t *gl_extensions;
  11128. convar_t *gl_alphabits;
  11129. convar_t *gl_stencilbits;
  11130. convar_t *gl_ignorehwgamma;
  11131. convar_t *gl_texture_anisotropy;
  11132. +convar_t *gl_texture_lodbias;
  11133. +convar_t *gl_texture_nearest;
  11134. convar_t *gl_compress_textures;
  11135. -convar_t *gl_luminance_textures;
  11136. convar_t *gl_compensate_gamma_screenshots;
  11137. convar_t *gl_keeptjunctions;
  11138. -convar_t *gl_texture_lodbias;
  11139. convar_t *gl_showtextures;
  11140. convar_t *gl_detailscale;
  11141. convar_t *gl_swapInterval;
  11142. convar_t *gl_check_errors;
  11143. convar_t *gl_allow_static;
  11144. convar_t *gl_allow_mirrors;
  11145. -convar_t *gl_texturemode;
  11146. convar_t *gl_wireframe;
  11147. convar_t *gl_round_down;
  11148. convar_t *gl_overview;
  11149. @@ -90,7 +83,6 @@ convar_t *r_fastsky;
  11150. convar_t *vid_displayfrequency;
  11151. convar_t *vid_fullscreen;
  11152. convar_t *vid_gamma;
  11153. -convar_t *vid_texgamma;
  11154. convar_t *vid_mode;
  11155.  
  11156. byte *r_temppool;
  11157. @@ -147,328 +139,403 @@ vidmode_t vidmode[] =
  11158.  
  11159. static dllfunc_t opengl_110funcs[] =
  11160. {
  11161. -{ "glClearColor" , (void **)&pglClearColor },
  11162. -{ "glClear" , (void **)&pglClear },
  11163. -{ "glAlphaFunc" , (void **)&pglAlphaFunc },
  11164. -{ "glBlendFunc" , (void **)&pglBlendFunc },
  11165. -{ "glCullFace" , (void **)&pglCullFace },
  11166. -{ "glDrawBuffer" , (void **)&pglDrawBuffer },
  11167. -{ "glReadBuffer" , (void **)&pglReadBuffer },
  11168. -{ "glEnable" , (void **)&pglEnable },
  11169. -{ "glDisable" , (void **)&pglDisable },
  11170. -{ "glEnableClientState" , (void **)&pglEnableClientState },
  11171. -{ "glDisableClientState" , (void **)&pglDisableClientState },
  11172. -{ "glGetBooleanv" , (void **)&pglGetBooleanv },
  11173. -{ "glGetDoublev" , (void **)&pglGetDoublev },
  11174. -{ "glGetFloatv" , (void **)&pglGetFloatv },
  11175. -{ "glGetIntegerv" , (void **)&pglGetIntegerv },
  11176. -{ "glGetError" , (void **)&pglGetError },
  11177. -{ "glGetString" , (void **)&pglGetString },
  11178. -{ "glFinish" , (void **)&pglFinish },
  11179. -{ "glFlush" , (void **)&pglFlush },
  11180. -{ "glClearDepth" , (void **)&pglClearDepth },
  11181. -{ "glDepthFunc" , (void **)&pglDepthFunc },
  11182. -{ "glDepthMask" , (void **)&pglDepthMask },
  11183. -{ "glDepthRange" , (void **)&pglDepthRange },
  11184. -{ "glFrontFace" , (void **)&pglFrontFace },
  11185. -{ "glDrawElements" , (void **)&pglDrawElements },
  11186. -{ "glColorMask" , (void **)&pglColorMask },
  11187. -{ "glIndexPointer" , (void **)&pglIndexPointer },
  11188. -{ "glVertexPointer" , (void **)&pglVertexPointer },
  11189. -{ "glNormalPointer" , (void **)&pglNormalPointer },
  11190. -{ "glColorPointer" , (void **)&pglColorPointer },
  11191. -{ "glTexCoordPointer" , (void **)&pglTexCoordPointer },
  11192. -{ "glArrayElement" , (void **)&pglArrayElement },
  11193. -{ "glColor3f" , (void **)&pglColor3f },
  11194. -{ "glColor3fv" , (void **)&pglColor3fv },
  11195. -{ "glColor4f" , (void **)&pglColor4f },
  11196. -{ "glColor4fv" , (void **)&pglColor4fv },
  11197. -{ "glColor3ub" , (void **)&pglColor3ub },
  11198. -{ "glColor4ub" , (void **)&pglColor4ub },
  11199. -{ "glColor4ubv" , (void **)&pglColor4ubv },
  11200. -{ "glTexCoord1f" , (void **)&pglTexCoord1f },
  11201. -{ "glTexCoord2f" , (void **)&pglTexCoord2f },
  11202. -{ "glTexCoord3f" , (void **)&pglTexCoord3f },
  11203. -{ "glTexCoord4f" , (void **)&pglTexCoord4f },
  11204. -{ "glTexGenf" , (void **)&pglTexGenf },
  11205. -{ "glTexGenfv" , (void **)&pglTexGenfv },
  11206. -{ "glTexGeni" , (void **)&pglTexGeni },
  11207. -{ "glVertex2f" , (void **)&pglVertex2f },
  11208. -{ "glVertex3f" , (void **)&pglVertex3f },
  11209. -{ "glVertex3fv" , (void **)&pglVertex3fv },
  11210. -{ "glNormal3f" , (void **)&pglNormal3f },
  11211. -{ "glNormal3fv" , (void **)&pglNormal3fv },
  11212. -{ "glBegin" , (void **)&pglBegin },
  11213. -{ "glEnd" , (void **)&pglEnd },
  11214. -{ "glLineWidth" , (void**)&pglLineWidth },
  11215. -{ "glPointSize" , (void**)&pglPointSize },
  11216. -{ "glMatrixMode" , (void **)&pglMatrixMode },
  11217. -{ "glOrtho" , (void **)&pglOrtho },
  11218. -{ "glRasterPos2f" , (void **)&pglRasterPos2f },
  11219. -{ "glFrustum" , (void **)&pglFrustum },
  11220. -{ "glViewport" , (void **)&pglViewport },
  11221. -{ "glPushMatrix" , (void **)&pglPushMatrix },
  11222. -{ "glPopMatrix" , (void **)&pglPopMatrix },
  11223. -{ "glPushAttrib" , (void **)&pglPushAttrib },
  11224. -{ "glPopAttrib" , (void **)&pglPopAttrib },
  11225. -{ "glLoadIdentity" , (void **)&pglLoadIdentity },
  11226. -{ "glLoadMatrixd" , (void **)&pglLoadMatrixd },
  11227. -{ "glLoadMatrixf" , (void **)&pglLoadMatrixf },
  11228. -{ "glMultMatrixd" , (void **)&pglMultMatrixd },
  11229. -{ "glMultMatrixf" , (void **)&pglMultMatrixf },
  11230. -{ "glRotated" , (void **)&pglRotated },
  11231. -{ "glRotatef" , (void **)&pglRotatef },
  11232. -{ "glScaled" , (void **)&pglScaled },
  11233. -{ "glScalef" , (void **)&pglScalef },
  11234. -{ "glTranslated" , (void **)&pglTranslated },
  11235. -{ "glTranslatef" , (void **)&pglTranslatef },
  11236. -{ "glReadPixels" , (void **)&pglReadPixels },
  11237. -{ "glDrawPixels" , (void **)&pglDrawPixels },
  11238. -{ "glStencilFunc" , (void **)&pglStencilFunc },
  11239. -{ "glStencilMask" , (void **)&pglStencilMask },
  11240. -{ "glStencilOp" , (void **)&pglStencilOp },
  11241. -{ "glClearStencil" , (void **)&pglClearStencil },
  11242. -{ "glIsEnabled" , (void **)&pglIsEnabled },
  11243. -{ "glIsList" , (void **)&pglIsList },
  11244. -{ "glIsTexture" , (void **)&pglIsTexture },
  11245. -{ "glTexEnvf" , (void **)&pglTexEnvf },
  11246. -{ "glTexEnvfv" , (void **)&pglTexEnvfv },
  11247. -{ "glTexEnvi" , (void **)&pglTexEnvi },
  11248. -{ "glTexParameterf" , (void **)&pglTexParameterf },
  11249. -{ "glTexParameterfv" , (void **)&pglTexParameterfv },
  11250. -{ "glTexParameteri" , (void **)&pglTexParameteri },
  11251. -{ "glHint" , (void **)&pglHint },
  11252. -{ "glPixelStoref" , (void **)&pglPixelStoref },
  11253. -{ "glPixelStorei" , (void **)&pglPixelStorei },
  11254. -{ "glGenTextures" , (void **)&pglGenTextures },
  11255. -{ "glDeleteTextures" , (void **)&pglDeleteTextures },
  11256. -{ "glBindTexture" , (void **)&pglBindTexture },
  11257. -{ "glTexImage1D" , (void **)&pglTexImage1D },
  11258. -{ "glTexImage2D" , (void **)&pglTexImage2D },
  11259. -{ "glTexSubImage1D" , (void **)&pglTexSubImage1D },
  11260. -{ "glTexSubImage2D" , (void **)&pglTexSubImage2D },
  11261. -{ "glCopyTexImage1D" , (void **)&pglCopyTexImage1D },
  11262. -{ "glCopyTexImage2D" , (void **)&pglCopyTexImage2D },
  11263. -{ "glCopyTexSubImage1D" , (void **)&pglCopyTexSubImage1D },
  11264. -{ "glCopyTexSubImage2D" , (void **)&pglCopyTexSubImage2D },
  11265. -{ "glScissor" , (void **)&pglScissor },
  11266. -{ "glGetTexEnviv" , (void **)&pglGetTexEnviv },
  11267. -{ "glPolygonOffset" , (void **)&pglPolygonOffset },
  11268. -{ "glPolygonMode" , (void **)&pglPolygonMode },
  11269. -{ "glPolygonStipple" , (void **)&pglPolygonStipple },
  11270. -{ "glClipPlane" , (void **)&pglClipPlane },
  11271. -{ "glGetClipPlane" , (void **)&pglGetClipPlane },
  11272. -{ "glShadeModel" , (void **)&pglShadeModel },
  11273. -{ "glFogfv" , (void **)&pglFogfv },
  11274. -{ "glFogf" , (void **)&pglFogf },
  11275. -{ "glFogi" , (void **)&pglFogi },
  11276. -{ NULL, NULL }
  11277. -};
  11278. -
  11279. -static dllfunc_t pointparametersfunc[] =
  11280. -{
  11281. -{ "glPointParameterfEXT" , (void **)&pglPointParameterfEXT },
  11282. -{ "glPointParameterfvEXT" , (void **)&pglPointParameterfvEXT },
  11283. -{ NULL, NULL }
  11284. +{ "glClearColor" , (void **)&pglClearColor },
  11285. +{ "glClear" , (void **)&pglClear },
  11286. +{ "glAlphaFunc" , (void **)&pglAlphaFunc },
  11287. +{ "glBlendFunc" , (void **)&pglBlendFunc },
  11288. +{ "glCullFace" , (void **)&pglCullFace },
  11289. +{ "glDrawBuffer" , (void **)&pglDrawBuffer },
  11290. +{ "glReadBuffer" , (void **)&pglReadBuffer },
  11291. +{ "glAccum" , (void **)&pglAccum },
  11292. +{ "glEnable" , (void **)&pglEnable },
  11293. +{ "glDisable" , (void **)&pglDisable },
  11294. +{ "glEnableClientState" , (void **)&pglEnableClientState },
  11295. +{ "glDisableClientState" , (void **)&pglDisableClientState },
  11296. +{ "glGetBooleanv" , (void **)&pglGetBooleanv },
  11297. +{ "glGetDoublev" , (void **)&pglGetDoublev },
  11298. +{ "glGetFloatv" , (void **)&pglGetFloatv },
  11299. +{ "glGetIntegerv" , (void **)&pglGetIntegerv },
  11300. +{ "glGetError" , (void **)&pglGetError },
  11301. +{ "glGetString" , (void **)&pglGetString },
  11302. +{ "glFinish" , (void **)&pglFinish },
  11303. +{ "glFlush" , (void **)&pglFlush },
  11304. +{ "glClearDepth" , (void **)&pglClearDepth },
  11305. +{ "glDepthFunc" , (void **)&pglDepthFunc },
  11306. +{ "glDepthMask" , (void **)&pglDepthMask },
  11307. +{ "glDepthRange" , (void **)&pglDepthRange },
  11308. +{ "glFrontFace" , (void **)&pglFrontFace },
  11309. +{ "glDrawElements" , (void **)&pglDrawElements },
  11310. +{ "glDrawArrays" , (void **)&pglDrawArrays },
  11311. +{ "glColorMask" , (void **)&pglColorMask },
  11312. +{ "glIndexPointer" , (void **)&pglIndexPointer },
  11313. +{ "glVertexPointer" , (void **)&pglVertexPointer },
  11314. +{ "glNormalPointer" , (void **)&pglNormalPointer },
  11315. +{ "glColorPointer" , (void **)&pglColorPointer },
  11316. +{ "glTexCoordPointer" , (void **)&pglTexCoordPointer },
  11317. +{ "glArrayElement" , (void **)&pglArrayElement },
  11318. +{ "glColor3f" , (void **)&pglColor3f },
  11319. +{ "glColor3fv" , (void **)&pglColor3fv },
  11320. +{ "glColor4f" , (void **)&pglColor4f },
  11321. +{ "glColor4fv" , (void **)&pglColor4fv },
  11322. +{ "glColor3ub" , (void **)&pglColor3ub },
  11323. +{ "glColor4ub" , (void **)&pglColor4ub },
  11324. +{ "glColor4ubv" , (void **)&pglColor4ubv },
  11325. +{ "glTexCoord1f" , (void **)&pglTexCoord1f },
  11326. +{ "glTexCoord2f" , (void **)&pglTexCoord2f },
  11327. +{ "glTexCoord3f" , (void **)&pglTexCoord3f },
  11328. +{ "glTexCoord4f" , (void **)&pglTexCoord4f },
  11329. +{ "glTexCoord1fv" , (void **)&pglTexCoord1fv },
  11330. +{ "glTexCoord2fv" , (void **)&pglTexCoord2fv },
  11331. +{ "glTexCoord3fv" , (void **)&pglTexCoord3fv },
  11332. +{ "glTexCoord4fv" , (void **)&pglTexCoord4fv },
  11333. +{ "glTexGenf" , (void **)&pglTexGenf },
  11334. +{ "glTexGenfv" , (void **)&pglTexGenfv },
  11335. +{ "glTexGeni" , (void **)&pglTexGeni },
  11336. +{ "glVertex2f" , (void **)&pglVertex2f },
  11337. +{ "glVertex3f" , (void **)&pglVertex3f },
  11338. +{ "glVertex3fv" , (void **)&pglVertex3fv },
  11339. +{ "glNormal3f" , (void **)&pglNormal3f },
  11340. +{ "glNormal3fv" , (void **)&pglNormal3fv },
  11341. +{ "glBegin" , (void **)&pglBegin },
  11342. +{ "glEnd" , (void **)&pglEnd },
  11343. +{ "glLineWidth" , (void**)&pglLineWidth },
  11344. +{ "glPointSize" , (void**)&pglPointSize },
  11345. +{ "glMatrixMode" , (void **)&pglMatrixMode },
  11346. +{ "glOrtho" , (void **)&pglOrtho },
  11347. +{ "glRasterPos2f" , (void **) &pglRasterPos2f },
  11348. +{ "glFrustum" , (void **)&pglFrustum },
  11349. +{ "glViewport" , (void **)&pglViewport },
  11350. +{ "glPushMatrix" , (void **)&pglPushMatrix },
  11351. +{ "glPopMatrix" , (void **)&pglPopMatrix },
  11352. +{ "glPushAttrib" , (void **)&pglPushAttrib },
  11353. +{ "glPopAttrib" , (void **)&pglPopAttrib },
  11354. +{ "glLoadIdentity" , (void **)&pglLoadIdentity },
  11355. +{ "glLoadMatrixd" , (void **)&pglLoadMatrixd },
  11356. +{ "glLoadMatrixf" , (void **)&pglLoadMatrixf },
  11357. +{ "glMultMatrixd" , (void **)&pglMultMatrixd },
  11358. +{ "glMultMatrixf" , (void **)&pglMultMatrixf },
  11359. +{ "glRotated" , (void **)&pglRotated },
  11360. +{ "glRotatef" , (void **)&pglRotatef },
  11361. +{ "glScaled" , (void **)&pglScaled },
  11362. +{ "glScalef" , (void **)&pglScalef },
  11363. +{ "glTranslated" , (void **)&pglTranslated },
  11364. +{ "glTranslatef" , (void **)&pglTranslatef },
  11365. +{ "glReadPixels" , (void **)&pglReadPixels },
  11366. +{ "glDrawPixels" , (void **)&pglDrawPixels },
  11367. +{ "glStencilFunc" , (void **)&pglStencilFunc },
  11368. +{ "glStencilMask" , (void **)&pglStencilMask },
  11369. +{ "glStencilOp" , (void **)&pglStencilOp },
  11370. +{ "glClearStencil" , (void **)&pglClearStencil },
  11371. +{ "glIsEnabled" , (void **)&pglIsEnabled },
  11372. +{ "glIsList" , (void **)&pglIsList },
  11373. +{ "glIsTexture" , (void **)&pglIsTexture },
  11374. +{ "glTexEnvf" , (void **)&pglTexEnvf },
  11375. +{ "glTexEnvfv" , (void **)&pglTexEnvfv },
  11376. +{ "glTexEnvi" , (void **)&pglTexEnvi },
  11377. +{ "glTexParameterf" , (void **)&pglTexParameterf },
  11378. +{ "glTexParameterfv" , (void **)&pglTexParameterfv },
  11379. +{ "glTexParameteri" , (void **)&pglTexParameteri },
  11380. +{ "glHint" , (void **)&pglHint },
  11381. +{ "glPixelStoref" , (void **)&pglPixelStoref },
  11382. +{ "glPixelStorei" , (void **)&pglPixelStorei },
  11383. +{ "glGenTextures" , (void **)&pglGenTextures },
  11384. +{ "glDeleteTextures" , (void **)&pglDeleteTextures },
  11385. +{ "glBindTexture" , (void **)&pglBindTexture },
  11386. +{ "glTexImage1D" , (void **)&pglTexImage1D },
  11387. +{ "glTexImage2D" , (void **)&pglTexImage2D },
  11388. +{ "glTexSubImage1D" , (void **)&pglTexSubImage1D },
  11389. +{ "glTexSubImage2D" , (void **)&pglTexSubImage2D },
  11390. +{ "glCopyTexImage1D" , (void **)&pglCopyTexImage1D },
  11391. +{ "glCopyTexImage2D" , (void **)&pglCopyTexImage2D },
  11392. +{ "glCopyTexSubImage1D" , (void **)&pglCopyTexSubImage1D },
  11393. +{ "glCopyTexSubImage2D" , (void **)&pglCopyTexSubImage2D },
  11394. +{ "glScissor" , (void **)&pglScissor },
  11395. +{ "glGetTexImage" , (void **)&pglGetTexImage },
  11396. +{ "glGetTexEnviv" , (void **)&pglGetTexEnviv },
  11397. +{ "glPolygonOffset" , (void **)&pglPolygonOffset },
  11398. +{ "glPolygonMode" , (void **)&pglPolygonMode },
  11399. +{ "glPolygonStipple" , (void **)&pglPolygonStipple },
  11400. +{ "glClipPlane" , (void **)&pglClipPlane },
  11401. +{ "glGetClipPlane" , (void **)&pglGetClipPlane },
  11402. +{ "glShadeModel" , (void **)&pglShadeModel },
  11403. +{ "glGetTexLevelParameteriv" , (void **)&pglGetTexLevelParameteriv },
  11404. +{ "glGetTexLevelParameterfv" , (void **)&pglGetTexLevelParameterfv },
  11405. +{ "glFogfv" , (void **)&pglFogfv },
  11406. +{ "glFogf" , (void **)&pglFogf },
  11407. +{ "glFogi" , (void **)&pglFogi },
  11408. +{ NULL , NULL }
  11409. };
  11410.  
  11411. static dllfunc_t drawrangeelementsfuncs[] =
  11412. {
  11413. -{ "glDrawRangeElements" , (void **)&pglDrawRangeElements },
  11414. -{ NULL, NULL }
  11415. +{ "glDrawRangeElements" , (void **)&pglDrawRangeElements },
  11416. +{ NULL , NULL }
  11417. };
  11418.  
  11419. static dllfunc_t drawrangeelementsextfuncs[] =
  11420. {
  11421. -{ "glDrawRangeElementsEXT" , (void **)&pglDrawRangeElementsEXT },
  11422. -{ NULL, NULL }
  11423. +{ "glDrawRangeElementsEXT" , (void **)&pglDrawRangeElementsEXT },
  11424. +{ NULL , NULL }
  11425. };
  11426.  
  11427. -static dllfunc_t sgis_multitexturefuncs[] =
  11428. +static dllfunc_t debugoutputfuncs[] =
  11429. {
  11430. -{ "glSelectTextureSGIS" , (void **)&pglSelectTextureSGIS },
  11431. -{ "glMTexCoord2fSGIS" , (void **)&pglMTexCoord2fSGIS },
  11432. -{ NULL, NULL }
  11433. +{ "glDebugMessageControlARB" , (void **)&pglDebugMessageControlARB },
  11434. +{ "glDebugMessageInsertARB" , (void **)&pglDebugMessageInsertARB },
  11435. +{ "glDebugMessageCallbackARB" , (void **)&pglDebugMessageCallbackARB },
  11436. +{ "glGetDebugMessageLogARB" , (void **)&pglGetDebugMessageLogARB },
  11437. +{ NULL , NULL }
  11438. };
  11439.  
  11440. static dllfunc_t multitexturefuncs[] =
  11441. {
  11442. -{ "glMultiTexCoord1fARB" , (void **)&pglMultiTexCoord1f },
  11443. -{ "glMultiTexCoord2fARB" , (void **)&pglMultiTexCoord2f },
  11444. -{ "glMultiTexCoord3fARB" , (void **)&pglMultiTexCoord3f },
  11445. -{ "glMultiTexCoord4fARB" , (void **)&pglMultiTexCoord4f },
  11446. -{ "glActiveTextureARB" , (void **)&pglActiveTextureARB },
  11447. -{ "glClientActiveTextureARB" , (void **)&pglClientActiveTexture },
  11448. -{ "glClientActiveTextureARB" , (void **)&pglClientActiveTextureARB },
  11449. -{ NULL, NULL }
  11450. -};
  11451. -
  11452. -static dllfunc_t compiledvertexarrayfuncs[] =
  11453. -{
  11454. -{ "glLockArraysEXT" , (void **)&pglLockArraysEXT },
  11455. -{ "glUnlockArraysEXT" , (void **)&pglUnlockArraysEXT },
  11456. -{ "glDrawArrays" , (void **)&pglDrawArrays },
  11457. -{ NULL, NULL }
  11458. +{ "glMultiTexCoord1fARB" , (void **)&pglMultiTexCoord1f },
  11459. +{ "glMultiTexCoord2fARB" , (void **)&pglMultiTexCoord2f },
  11460. +{ "glMultiTexCoord3fARB" , (void **)&pglMultiTexCoord3f },
  11461. +{ "glMultiTexCoord4fARB" , (void **)&pglMultiTexCoord4f },
  11462. +{ "glActiveTextureARB" , (void **)&pglActiveTexture },
  11463. +{ "glActiveTextureARB" , (void **)&pglActiveTextureARB },
  11464. +{ "glClientActiveTextureARB" , (void **)&pglClientActiveTexture },
  11465. +{ "glClientActiveTextureARB" , (void **)&pglClientActiveTextureARB },
  11466. +{ NULL , NULL }
  11467. };
  11468.  
  11469. static dllfunc_t texture3dextfuncs[] =
  11470. {
  11471. -{ "glTexImage3DEXT" , (void **)&pglTexImage3D },
  11472. -{ "glTexSubImage3DEXT" , (void **)&pglTexSubImage3D },
  11473. -{ "glCopyTexSubImage3DEXT" , (void **)&pglCopyTexSubImage3D },
  11474. -{ NULL, NULL }
  11475. +{ "glTexImage3DEXT" , (void **)&pglTexImage3D },
  11476. +{ "glTexSubImage3DEXT" , (void **)&pglTexSubImage3D },
  11477. +{ "glCopyTexSubImage3DEXT" , (void **)&pglCopyTexSubImage3D },
  11478. +{ NULL , NULL }
  11479. };
  11480.  
  11481. -static dllfunc_t atiseparatestencilfuncs[] =
  11482. +static dllfunc_t shaderobjectsfuncs[] =
  11483. {
  11484. -{ "glStencilOpSeparateATI" , (void **)&pglStencilOpSeparate },
  11485. -{ "glStencilFuncSeparateATI" , (void **)&pglStencilFuncSeparate },
  11486. -{ NULL, NULL }
  11487. +{ "glDeleteObjectARB" , (void **)&pglDeleteObjectARB },
  11488. +{ "glGetHandleARB" , (void **)&pglGetHandleARB },
  11489. +{ "glDetachObjectARB" , (void **)&pglDetachObjectARB },
  11490. +{ "glCreateShaderObjectARB" , (void **)&pglCreateShaderObjectARB },
  11491. +{ "glShaderSourceARB" , (void **)&pglShaderSourceARB },
  11492. +{ "glCompileShaderARB" , (void **)&pglCompileShaderARB },
  11493. +{ "glCreateProgramObjectARB" , (void **)&pglCreateProgramObjectARB },
  11494. +{ "glAttachObjectARB" , (void **)&pglAttachObjectARB },
  11495. +{ "glLinkProgramARB" , (void **)&pglLinkProgramARB },
  11496. +{ "glUseProgramObjectARB" , (void **)&pglUseProgramObjectARB },
  11497. +{ "glValidateProgramARB" , (void **)&pglValidateProgramARB },
  11498. +{ "glUniform1fARB" , (void **)&pglUniform1fARB },
  11499. +{ "glUniform2fARB" , (void **)&pglUniform2fARB },
  11500. +{ "glUniform3fARB" , (void **)&pglUniform3fARB },
  11501. +{ "glUniform4fARB" , (void **)&pglUniform4fARB },
  11502. +{ "glUniform1iARB" , (void **)&pglUniform1iARB },
  11503. +{ "glUniform2iARB" , (void **)&pglUniform2iARB },
  11504. +{ "glUniform3iARB" , (void **)&pglUniform3iARB },
  11505. +{ "glUniform4iARB" , (void **)&pglUniform4iARB },
  11506. +{ "glUniform1fvARB" , (void **)&pglUniform1fvARB },
  11507. +{ "glUniform2fvARB" , (void **)&pglUniform2fvARB },
  11508. +{ "glUniform3fvARB" , (void **)&pglUniform3fvARB },
  11509. +{ "glUniform4fvARB" , (void **)&pglUniform4fvARB },
  11510. +{ "glUniform1ivARB" , (void **)&pglUniform1ivARB },
  11511. +{ "glUniform2ivARB" , (void **)&pglUniform2ivARB },
  11512. +{ "glUniform3ivARB" , (void **)&pglUniform3ivARB },
  11513. +{ "glUniform4ivARB" , (void **)&pglUniform4ivARB },
  11514. +{ "glUniformMatrix2fvARB" , (void **)&pglUniformMatrix2fvARB },
  11515. +{ "glUniformMatrix3fvARB" , (void **)&pglUniformMatrix3fvARB },
  11516. +{ "glUniformMatrix4fvARB" , (void **)&pglUniformMatrix4fvARB },
  11517. +{ "glGetObjectParameterfvARB" , (void **)&pglGetObjectParameterfvARB },
  11518. +{ "glGetObjectParameterivARB" , (void **)&pglGetObjectParameterivARB },
  11519. +{ "glGetInfoLogARB" , (void **)&pglGetInfoLogARB },
  11520. +{ "glGetAttachedObjectsARB" , (void **)&pglGetAttachedObjectsARB },
  11521. +{ "glGetUniformLocationARB" , (void **)&pglGetUniformLocationARB },
  11522. +{ "glGetActiveUniformARB" , (void **)&pglGetActiveUniformARB },
  11523. +{ "glGetUniformfvARB" , (void **)&pglGetUniformfvARB },
  11524. +{ "glGetUniformivARB" , (void **)&pglGetUniformivARB },
  11525. +{ "glGetShaderSourceARB" , (void **)&pglGetShaderSourceARB },
  11526. +{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
  11527. +{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
  11528. +{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
  11529. +{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
  11530. +{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
  11531. +{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
  11532. +{ "glVertexAttrib2f" , (void **)&pglVertexAttrib2fARB },
  11533. +{ "glVertexAttrib2fv" , (void **)&pglVertexAttrib2fvARB },
  11534. +{ "glVertexAttrib3fv" , (void **)&pglVertexAttrib3fvARB },
  11535. +{ NULL , NULL }
  11536. };
  11537.  
  11538. -static dllfunc_t gl2separatestencilfuncs[] =
  11539. +static dllfunc_t vbofuncs[] =
  11540. {
  11541. -{ "glStencilOpSeparate" , (void **)&pglStencilOpSeparate },
  11542. -{ "glStencilFuncSeparate" , (void **)&pglStencilFuncSeparate },
  11543. -{ NULL, NULL }
  11544. +{ "glBindBufferARB" , (void **)&pglBindBufferARB },
  11545. +{ "glDeleteBuffersARB" , (void **)&pglDeleteBuffersARB },
  11546. +{ "glGenBuffersARB" , (void **)&pglGenBuffersARB },
  11547. +{ "glIsBufferARB" , (void **)&pglIsBufferARB },
  11548. +{ "glMapBufferARB" , (void **)&pglMapBufferARB },
  11549. +{ "glUnmapBufferARB" , (void **)&pglUnmapBufferARB },
  11550. +{ "glBufferDataARB" , (void **)&pglBufferDataARB },
  11551. +{ "glBufferSubDataARB" , (void **)&pglBufferSubDataARB },
  11552. +{ NULL , NULL}
  11553. };
  11554.  
  11555. -static dllfunc_t stenciltwosidefuncs[] =
  11556. +static dllfunc_t vaofuncs[] =
  11557. {
  11558. -{ "glActiveStencilFaceEXT" , (void **)&pglActiveStencilFaceEXT },
  11559. -{ NULL, NULL }
  11560. +{ "glBindVertexArray" , (void **)&pglBindVertexArray },
  11561. +{ "glDeleteVertexArrays" , (void **)&pglDeleteVertexArrays },
  11562. +{ "glGenVertexArrays" , (void **)&pglGenVertexArrays },
  11563. +{ "glIsVertexArray" , (void **)&pglIsVertexArray },
  11564. +{ NULL , NULL }
  11565. };
  11566.  
  11567. -static dllfunc_t blendequationfuncs[] =
  11568. +static dllfunc_t arbfbofuncs[] =
  11569. {
  11570. -{ "glBlendEquationEXT" , (void **)&pglBlendEquationEXT },
  11571. -{ NULL, NULL }
  11572. +{ "glIsRenderbuffer" , (void **)&pglIsRenderbuffer },
  11573. +{ "glBindRenderbuffer" , (void **)&pglBindRenderbuffer },
  11574. +{ "glDeleteRenderbuffers" , (void **)&pglDeleteRenderbuffers },
  11575. +{ "glGenRenderbuffers" , (void **)&pglGenRenderbuffers },
  11576. +{ "glRenderbufferStorage" , (void **)&pglRenderbufferStorage },
  11577. +{ "glRenderbufferStorageMultisample" , (void **)&pglRenderbufferStorageMultisample }, // not in GL_EXT_framebuffer_object
  11578. +{ "glGetRenderbufferParameteriv" , (void **)&pglGetRenderbufferParameteriv },
  11579. +{ "glIsFramebuffer" , (void **)&pglIsFramebuffer },
  11580. +{ "glBindFramebuffer" , (void **)&pglBindFramebuffer },
  11581. +{ "glDeleteFramebuffers" , (void **)&pglDeleteFramebuffers },
  11582. +{ "glGenFramebuffers" , (void **)&pglGenFramebuffers },
  11583. +{ "glCheckFramebufferStatus" , (void **)&pglCheckFramebufferStatus },
  11584. +{ "glFramebufferTexture1D" , (void **)&pglFramebufferTexture1D },
  11585. +{ "glFramebufferTexture2D" , (void **)&pglFramebufferTexture2D },
  11586. +{ "glFramebufferTexture3D" , (void **)&pglFramebufferTexture3D },
  11587. +{ "glFramebufferTextureLayer" , (void **)&pglFramebufferTextureLayer }, // not in GL_EXT_framebuffer_object
  11588. +{ "glFramebufferRenderbuffer" , (void **)&pglFramebufferRenderbuffer },
  11589. +{ "glGetFramebufferAttachmentParameteriv" , (void **)&pglGetFramebufferAttachmentParameteriv },
  11590. +{ "glBlitFramebuffer" , (void **)&pglBlitFramebuffer }, // not in GL_EXT_framebuffer_object
  11591. +{ "glGenerateMipmap" , (void **)&pglGenerateMipmap },
  11592. +{ NULL , NULL}
  11593. };
  11594.  
  11595. -static dllfunc_t shaderobjectsfuncs[] =
  11596. +static dllfunc_t extfbofuncs[] =
  11597. {
  11598. -{ "glDeleteObjectARB" , (void **)&pglDeleteObjectARB },
  11599. -{ "glGetHandleARB" , (void **)&pglGetHandleARB },
  11600. -{ "glDetachObjectARB" , (void **)&pglDetachObjectARB },
  11601. -{ "glCreateShaderObjectARB" , (void **)&pglCreateShaderObjectARB },
  11602. -{ "glShaderSourceARB" , (void **)&pglShaderSourceARB },
  11603. -{ "glCompileShaderARB" , (void **)&pglCompileShaderARB },
  11604. -{ "glCreateProgramObjectARB" , (void **)&pglCreateProgramObjectARB },
  11605. -{ "glAttachObjectARB" , (void **)&pglAttachObjectARB },
  11606. -{ "glLinkProgramARB" , (void **)&pglLinkProgramARB },
  11607. -{ "glUseProgramObjectARB" , (void **)&pglUseProgramObjectARB },
  11608. -{ "glValidateProgramARB" , (void **)&pglValidateProgramARB },
  11609. -{ "glUniform1fARB" , (void **)&pglUniform1fARB },
  11610. -{ "glUniform2fARB" , (void **)&pglUniform2fARB },
  11611. -{ "glUniform3fARB" , (void **)&pglUniform3fARB },
  11612. -{ "glUniform4fARB" , (void **)&pglUniform4fARB },
  11613. -{ "glUniform1iARB" , (void **)&pglUniform1iARB },
  11614. -{ "glUniform2iARB" , (void **)&pglUniform2iARB },
  11615. -{ "glUniform3iARB" , (void **)&pglUniform3iARB },
  11616. -{ "glUniform4iARB" , (void **)&pglUniform4iARB },
  11617. -{ "glUniform1fvARB" , (void **)&pglUniform1fvARB },
  11618. -{ "glUniform2fvARB" , (void **)&pglUniform2fvARB },
  11619. -{ "glUniform3fvARB" , (void **)&pglUniform3fvARB },
  11620. -{ "glUniform4fvARB" , (void **)&pglUniform4fvARB },
  11621. -{ "glUniform1ivARB" , (void **)&pglUniform1ivARB },
  11622. -{ "glUniform2ivARB" , (void **)&pglUniform2ivARB },
  11623. -{ "glUniform3ivARB" , (void **)&pglUniform3ivARB },
  11624. -{ "glUniform4ivARB" , (void **)&pglUniform4ivARB },
  11625. -{ "glUniformMatrix2fvARB" , (void **)&pglUniformMatrix2fvARB },
  11626. -{ "glUniformMatrix3fvARB" , (void **)&pglUniformMatrix3fvARB },
  11627. -{ "glUniformMatrix4fvARB" , (void **)&pglUniformMatrix4fvARB },
  11628. -{ "glGetObjectParameterfvARB" , (void **)&pglGetObjectParameterfvARB },
  11629. -{ "glGetObjectParameterivARB" , (void **)&pglGetObjectParameterivARB },
  11630. -{ "glGetInfoLogARB" , (void **)&pglGetInfoLogARB },
  11631. -{ "glGetAttachedObjectsARB" , (void **)&pglGetAttachedObjectsARB },
  11632. -{ "glGetUniformLocationARB" , (void **)&pglGetUniformLocationARB },
  11633. -{ "glGetActiveUniformARB" , (void **)&pglGetActiveUniformARB },
  11634. -{ "glGetUniformfvARB" , (void **)&pglGetUniformfvARB },
  11635. -{ "glGetUniformivARB" , (void **)&pglGetUniformivARB },
  11636. -{ "glGetShaderSourceARB" , (void **)&pglGetShaderSourceARB },
  11637. -{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
  11638. -{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
  11639. -{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
  11640. -{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
  11641. -{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
  11642. -{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
  11643. -{ NULL, NULL }
  11644. +{ "glIsRenderbufferEXT" , (void **)&pglIsRenderbuffer },
  11645. +{ "glBindRenderbufferEXT" , (void **)&pglBindRenderbuffer },
  11646. +{ "glDeleteRenderbuffersEXT" , (void **)&pglDeleteRenderbuffers },
  11647. +{ "glGenRenderbuffersEXT" , (void **)&pglGenRenderbuffers },
  11648. +{ "glRenderbufferStorageEXT" , (void **)&pglRenderbufferStorage },
  11649. +{ "glGetRenderbufferParameterivEXT" , (void **)&pglGetRenderbufferParameteriv },
  11650. +{ "glIsFramebufferEXT" , (void **)&pglIsFramebuffer },
  11651. +{ "glBindFramebufferEXT" , (void **)&pglBindFramebuffer },
  11652. +{ "glDeleteFramebuffersEXT" , (void **)&pglDeleteFramebuffers },
  11653. +{ "glGenFramebuffersEXT" , (void **)&pglGenFramebuffers },
  11654. +{ "glCheckFramebufferStatusEXT" , (void **)&pglCheckFramebufferStatus },
  11655. +{ "glFramebufferTexture1DEXT" , (void **)&pglFramebufferTexture1D },
  11656. +{ "glFramebufferTexture2DEXT" , (void **)&pglFramebufferTexture2D },
  11657. +{ "glFramebufferTexture3DEXT" , (void **)&pglFramebufferTexture3D },
  11658. +{ "glFramebufferRenderbufferEXT" , (void **)&pglFramebufferRenderbuffer },
  11659. +{ "glGetFramebufferAttachmentParameterivEXT" , (void **)&pglGetFramebufferAttachmentParameteriv },
  11660. +{ "glGenerateMipmapEXT" , (void **)&pglGenerateMipmap },
  11661. +{ NULL, NULL}
  11662. };
  11663.  
  11664. -static dllfunc_t vertexshaderfuncs[] =
  11665. +static dllfunc_t occlusionfunc[] =
  11666. {
  11667. -{ "glVertexAttribPointerARB" , (void **)&pglVertexAttribPointerARB },
  11668. -{ "glEnableVertexAttribArrayARB" , (void **)&pglEnableVertexAttribArrayARB },
  11669. -{ "glDisableVertexAttribArrayARB" , (void **)&pglDisableVertexAttribArrayARB },
  11670. -{ "glBindAttribLocationARB" , (void **)&pglBindAttribLocationARB },
  11671. -{ "glGetActiveAttribARB" , (void **)&pglGetActiveAttribARB },
  11672. -{ "glGetAttribLocationARB" , (void **)&pglGetAttribLocationARB },
  11673. -{ NULL, NULL }
  11674. +{ "glGenQueriesARB" , (void **)&pglGenQueriesARB },
  11675. +{ "glDeleteQueriesARB" , (void **)&pglDeleteQueriesARB },
  11676. +{ "glIsQueryARB" , (void **)&pglIsQueryARB },
  11677. +{ "glBeginQueryARB" , (void **)&pglBeginQueryARB },
  11678. +{ "glEndQueryARB" , (void **)&pglEndQueryARB },
  11679. +{ "glGetQueryivARB" , (void **)&pglGetQueryivARB },
  11680. +{ "glGetQueryObjectivARB" , (void **)&pglGetQueryObjectivARB },
  11681. +{ "glGetQueryObjectuivARB" , (void **)&pglGetQueryObjectuivARB },
  11682. +{ NULL , NULL }
  11683. };
  11684.  
  11685. -static dllfunc_t vbofuncs[] =
  11686. +static dllfunc_t texturecompressionfuncs[] =
  11687. {
  11688. -{ "glBindBufferARB" , (void **)&pglBindBufferARB },
  11689. -{ "glDeleteBuffersARB" , (void **)&pglDeleteBuffersARB },
  11690. -{ "glGenBuffersARB" , (void **)&pglGenBuffersARB },
  11691. -{ "glIsBufferARB" , (void **)&pglIsBufferARB },
  11692. -{ "glMapBufferARB" , (void **)&pglMapBufferARB },
  11693. -{ "glUnmapBufferARB" , (void **)&pglUnmapBufferARB },
  11694. -{ "glBufferDataARB" , (void **)&pglBufferDataARB },
  11695. -{ "glBufferSubDataARB" , (void **)&pglBufferSubDataARB },
  11696. -{ NULL, NULL}
  11697. +{ "glCompressedTexImage3DARB" , (void **)&pglCompressedTexImage3DARB },
  11698. +{ "glCompressedTexImage2DARB" , (void **)&pglCompressedTexImage2DARB },
  11699. +{ "glCompressedTexImage1DARB" , (void **)&pglCompressedTexImage1DARB },
  11700. +{ "glCompressedTexSubImage3DARB" , (void **)&pglCompressedTexSubImage3DARB },
  11701. +{ "glCompressedTexSubImage2DARB" , (void **)&pglCompressedTexSubImage2DARB },
  11702. +{ "glCompressedTexSubImage1DARB" , (void **)&pglCompressedTexSubImage1DARB },
  11703. +{ "glGetCompressedTexImageARB" , (void **)&pglGetCompressedTexImage },
  11704. +{ NULL , NULL }
  11705. };
  11706.  
  11707. -static dllfunc_t occlusionfunc[] =
  11708. +static dllfunc_t drawbuffersfuncs[] =
  11709. {
  11710. -{ "glGenQueriesARB" , (void **)&pglGenQueriesARB },
  11711. -{ "glDeleteQueriesARB" , (void **)&pglDeleteQueriesARB },
  11712. -{ "glIsQueryARB" , (void **)&pglIsQueryARB },
  11713. -{ "glBeginQueryARB" , (void **)&pglBeginQueryARB },
  11714. -{ "glEndQueryARB" , (void **)&pglEndQueryARB },
  11715. -{ "glGetQueryivARB" , (void **)&pglGetQueryivARB },
  11716. -{ "glGetQueryObjectivARB" , (void **)&pglGetQueryObjectivARB },
  11717. -{ "glGetQueryObjectuivARB" , (void **)&pglGetQueryObjectuivARB },
  11718. -{ NULL, NULL }
  11719. +{ "glDrawBuffersARB" , (void **)&pglDrawBuffersARB },
  11720. +{ NULL , NULL }
  11721. };
  11722.  
  11723. -static dllfunc_t texturecompressionfuncs[] =
  11724. +static dllfunc_t wgl_funcs[] =
  11725. {
  11726. -{ "glCompressedTexImage3DARB" , (void **)&pglCompressedTexImage3DARB },
  11727. -{ "glCompressedTexImage2DARB" , (void **)&pglCompressedTexImage2DARB },
  11728. -{ "glCompressedTexImage1DARB" , (void **)&pglCompressedTexImage1DARB },
  11729. -{ "glCompressedTexSubImage3DARB" , (void **)&pglCompressedTexSubImage3DARB },
  11730. -{ "glCompressedTexSubImage2DARB" , (void **)&pglCompressedTexSubImage2DARB },
  11731. -{ "glCompressedTexSubImage1DARB" , (void **)&pglCompressedTexSubImage1DARB },
  11732. -{ "glGetCompressedTexImageARB" , (void **)&pglGetCompressedTexImage },
  11733. -{ NULL, NULL }
  11734. +{ "wglSwapBuffers" , (void **)&pwglSwapBuffers },
  11735. +{ "wglCreateContext" , (void **)&pwglCreateContext },
  11736. +{ "wglDeleteContext" , (void **)&pwglDeleteContext },
  11737. +{ "wglMakeCurrent" , (void **)&pwglMakeCurrent },
  11738. +{ "wglGetCurrentContext" , (void **)&pwglGetCurrentContext },
  11739. +{ NULL , NULL }
  11740. };
  11741.  
  11742. -static dllfunc_t wgl_funcs[] =
  11743. +static dllfunc_t wglproc_funcs[] =
  11744. {
  11745. -{ "wglSwapBuffers" , (void **)&pwglSwapBuffers },
  11746. -{ "wglCreateContext" , (void **)&pwglCreateContext },
  11747. -{ "wglDeleteContext" , (void **)&pwglDeleteContext },
  11748. -{ "wglMakeCurrent" , (void **)&pwglMakeCurrent },
  11749. -{ "wglGetCurrentContext" , (void **)&pwglGetCurrentContext },
  11750. +{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
  11751. { NULL, NULL }
  11752. };
  11753.  
  11754. -static dllfunc_t wglproc_funcs[] =
  11755. +static dllfunc_t wglswapintervalfuncs[] =
  11756. {
  11757. -{ "wglGetProcAddress" , (void **)&pwglGetProcAddress },
  11758. +{ "wglSwapIntervalEXT" , (void **)&pwglSwapIntervalEXT },
  11759. { NULL, NULL }
  11760. };
  11761.  
  11762. -static dllfunc_t wglswapintervalfuncs[] =
  11763. +static dllfunc_t wglgetextensionsstring[] =
  11764. {
  11765. -{ "wglSwapIntervalEXT" , (void **)&pwglSwapIntervalEXT },
  11766. +{ "wglGetExtensionsStringEXT" , (void **)&pwglGetExtensionsStringEXT },
  11767. { NULL, NULL }
  11768. };
  11769.  
  11770. dll_info_t opengl_dll = { "opengl32.dll", wgl_funcs, true };
  11771.  
  11772. /*
  11773. +========================
  11774. +DebugCallback
  11775. +
  11776. +For ARB_debug_output
  11777. +========================
  11778. +*/
  11779. +static void CALLBACK GL_DebugOutput( GLuint source, GLuint type, GLuint id, GLuint severity, GLint length, const GLcharARB *message, GLvoid *userParam )
  11780. +{
  11781. + switch( type )
  11782. + {
  11783. + case GL_DEBUG_TYPE_ERROR_ARB:
  11784. + if( host.developer < D_ERROR ) // "-dev 2"
  11785. + return;
  11786. + Con_Printf( "^1OpenGL Error:^7 %s\n", message );
  11787. + break;
  11788. + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
  11789. + if( host.developer < D_WARN ) // "-dev 3"
  11790. + return;
  11791. + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
  11792. + break;
  11793. + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
  11794. + if( host.developer < D_WARN ) // "-dev 3"
  11795. + return;
  11796. + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
  11797. + break;
  11798. + case GL_DEBUG_TYPE_PORTABILITY_ARB:
  11799. + if( host.developer < D_REPORT ) // "-dev 4"
  11800. + return;
  11801. + Con_Printf( "^3OpenGL Warning:^7 %s\n", message );
  11802. + break;
  11803. + case GL_DEBUG_TYPE_PERFORMANCE_ARB:
  11804. + if( host.developer < D_REPORT ) // "-dev 4"
  11805. + return;
  11806. + Con_Printf( "OpenGL Notify: %s\n", message );
  11807. + break;
  11808. + case GL_DEBUG_TYPE_OTHER_ARB:
  11809. + default: if( host.developer < D_NOTE ) // "-dev 5"
  11810. + return;
  11811. + Con_Printf( "OpenGL: %s\n", message );
  11812. + break;
  11813. + }
  11814. +}
  11815. +
  11816. +/*
  11817. =================
  11818. GL_SetExtension
  11819. =================
  11820. @@ -502,7 +569,7 @@ GL_MaxTextureUnits
  11821. int GL_MaxTextureUnits( void )
  11822. {
  11823. if( GL_Support( GL_SHADER_GLSL100_EXT ))
  11824. - return min( max( glConfig.max_texture_coords, glConfig.max_teximage_units ), MAX_TEXTURE_UNITS );
  11825. + return Q_min( Q_max( glConfig.max_texture_coords, glConfig.max_teximage_units ), MAX_TEXTURE_UNITS );
  11826. return glConfig.max_texture_units;
  11827. }
  11828.  
  11829. @@ -531,6 +598,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
  11830. {
  11831. const dllfunc_t *func;
  11832. convar_t *parm;
  11833. + const char *extensions_string;
  11834.  
  11835. MsgDev( D_NOTE, "GL_CheckExtension: %s ", name );
  11836.  
  11837. @@ -548,7 +616,12 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
  11838. GL_SetExtension( r_ext, 1 );
  11839. }
  11840.  
  11841. - if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name ))
  11842. + extensions_string = glConfig.extensions_string;
  11843. +
  11844. + if( name[0] == 'W' && name[1] == 'G' && name[2] == 'L' && glConfig.wgl_extensions_string != NULL )
  11845. + extensions_string = glConfig.wgl_extensions_string;
  11846. +
  11847. + if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( extensions_string, name ))
  11848. {
  11849. GL_SetExtension( r_ext, false ); // update render info
  11850. MsgDev( D_NOTE, "- ^1failed\n" );
  11851. @@ -579,8 +652,9 @@ GL_BuildGammaTable
  11852. */
  11853. void GL_BuildGammaTable( void )
  11854. {
  11855. + double invGamma;
  11856. + double div;
  11857. int i, v;
  11858. - double invGamma, div;
  11859.  
  11860. invGamma = 1.0 / bound( 0.5, vid_gamma->value, 2.3 );
  11861. div = (double) 1.0 / 255.5;
  11862. @@ -699,13 +773,15 @@ qboolean GL_CreateContext( void )
  11863. {
  11864. HGLRC hBaseRC;
  11865.  
  11866. + glw_state.extended = false;
  11867. +
  11868. if(!( glw_state.hGLRC = pwglCreateContext( glw_state.hDC )))
  11869. return GL_DeleteContext();
  11870.  
  11871. if(!( pwglMakeCurrent( glw_state.hDC, glw_state.hGLRC )))
  11872. return GL_DeleteContext();
  11873.  
  11874. - if( !Sys_CheckParm( "-gldebug" ) || host.developer < 1 ) // debug bit the kills perfomance
  11875. + if( !Sys_CheckParm( "-gldebug" ) || host.developer < D_INFO ) // debug bit the kills perfomance
  11876. return true;
  11877.  
  11878. pwglCreateContextAttribsARB = GL_GetProcAddress( "wglCreateContextAttribsARB" );
  11879. @@ -741,6 +817,7 @@ qboolean GL_CreateContext( void )
  11880.  
  11881. MsgDev( D_NOTE, "GL_CreateContext: using extended context\n" );
  11882. pwglDeleteContext( hBaseRC ); // release first context
  11883. + glw_state.extended = true;
  11884. }
  11885.  
  11886. return true;
  11887. @@ -762,6 +839,8 @@ qboolean GL_UpdateContext( void )
  11888. /*
  11889. =================
  11890. GL_DeleteContext
  11891. +
  11892. +always return false
  11893. =================
  11894. */
  11895. qboolean GL_DeleteContext( void )
  11896. @@ -842,6 +921,13 @@ static int VID_ChoosePFD( PIXELFORMATDESCRIPTOR *pfd, int colorBits, int alphaBi
  11897. return pixelFormat;
  11898. }
  11899.  
  11900. +/*
  11901. +=================
  11902. +pfnEnumWnd
  11903. +
  11904. +callback to enumerate active windows
  11905. +=================
  11906. +*/
  11907. BOOL CALLBACK pfnEnumWnd( HWND hwnd, LPARAM lParam )
  11908. {
  11909. string wndname;
  11910. @@ -854,6 +940,11 @@ BOOL CALLBACK pfnEnumWnd( HWND hwnd, LPARAM lParam )
  11911. return true;
  11912. }
  11913.  
  11914. +/*
  11915. +=================
  11916. +VID_EnumerateInstances
  11917. +=================
  11918. +*/
  11919. uint VID_EnumerateInstances( void )
  11920. {
  11921. num_instances = 0;
  11922. @@ -863,6 +954,11 @@ uint VID_EnumerateInstances( void )
  11923. return 1;
  11924. }
  11925.  
  11926. +/*
  11927. +=================
  11928. +VID_StartupGamma
  11929. +=================
  11930. +*/
  11931. void VID_StartupGamma( void )
  11932. {
  11933. size_t gamma_size;
  11934. @@ -882,14 +978,11 @@ void VID_StartupGamma( void )
  11935. if( gl_ignorehwgamma->integer )
  11936. {
  11937. glConfig.deviceSupportsGamma = false; // even if supported!
  11938. - BuildGammaTable( vid_gamma->value, vid_texgamma->value );
  11939. + BuildGammaTable( vid_gamma->value, GAMMA );
  11940. MsgDev( D_NOTE, "VID_StartupGamma: software gamma initialized\n" );
  11941. return;
  11942. }
  11943.  
  11944. - // share this extension so engine can grab them
  11945. - GL_SetExtension( GL_HARDWARE_GAMMA_CONTROL, glConfig.deviceSupportsGamma );
  11946. -
  11947. savedGamma = FS_LoadFile( "gamma.dat", &gamma_size, false );
  11948.  
  11949. if( !savedGamma || gamma_size != sizeof( glState.stateRamp ))
  11950. @@ -956,6 +1049,11 @@ void VID_StartupGamma( void )
  11951. vid_gamma->modified = true;
  11952. }
  11953.  
  11954. +/*
  11955. +=================
  11956. +VID_RestoreGamma
  11957. +=================
  11958. +*/
  11959. void VID_RestoreGamma( void )
  11960. {
  11961. if( !glw_state.hDC || !glConfig.deviceSupportsGamma )
  11962. @@ -1021,12 +1119,6 @@ qboolean GL_SetPixelformat( void )
  11963. if( PFD.dwFlags & PFD_GENERIC_ACCELERATED )
  11964. {
  11965. MsgDev( D_NOTE, "VID_ChoosePFD: using Generic MCD acceleration\n" );
  11966. - glw_state.software = false;
  11967. - }
  11968. - else if( gl_allow_software->integer )
  11969. - {
  11970. - MsgDev( D_NOTE, "VID_ChoosePFD: using software emulation\n" );
  11971. - glw_state.software = true;
  11972. }
  11973. else
  11974. {
  11975. @@ -1037,7 +1129,6 @@ qboolean GL_SetPixelformat( void )
  11976. else
  11977. {
  11978. MsgDev( D_NOTE, "VID_ChoosePFD: using hardware acceleration\n");
  11979. - glw_state.software = false;
  11980. }
  11981.  
  11982. glConfig.color_bits = PFD.cColorBits;
  11983. @@ -1055,6 +1146,11 @@ qboolean GL_SetPixelformat( void )
  11984. return true;
  11985. }
  11986.  
  11987. +/*
  11988. +=================
  11989. +R_SaveVideoMode
  11990. +=================
  11991. +*/
  11992. void R_SaveVideoMode( int vid_mode )
  11993. {
  11994. int mode = bound( 0, vid_mode, num_vidmodes ); // check range
  11995. @@ -1070,6 +1166,11 @@ void R_SaveVideoMode( int vid_mode )
  11996. MsgDev( D_NOTE, "Set: %s [%dx%d]\n", vidmode[mode].desc, vidmode[mode].width, vidmode[mode].height );
  11997. }
  11998.  
  11999. +/*
  12000. +=================
  12001. +R_DescribeVIDMode
  12002. +=================
  12003. +*/
  12004. qboolean R_DescribeVIDMode( int width, int height )
  12005. {
  12006. int i;
  12007. @@ -1087,16 +1188,21 @@ qboolean R_DescribeVIDMode( int width, int height )
  12008. return false;
  12009. }
  12010.  
  12011. +/*
  12012. +=================
  12013. +VID_CreateWindow
  12014. +=================
  12015. +*/
  12016. qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
  12017. {
  12018. - WNDCLASS wc;
  12019. - RECT rect;
  12020. int x = 0, y = 0, w, h;
  12021. int stylebits = WINDOW_STYLE;
  12022. int exstyle = WINDOW_EX_STYLE;
  12023. static string wndname;
  12024. HWND window;
  12025. -
  12026. + RECT rect;
  12027. + WNDCLASS wc;
  12028. +
  12029. Q_strncpy( wndname, GI->title, sizeof( wndname ));
  12030.  
  12031. // register the frame class
  12032. @@ -1109,22 +1215,22 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
  12033. wc.hbrBackground = (void *)COLOR_3DSHADOW;
  12034. wc.lpszClassName = WINDOW_NAME;
  12035. wc.lpszMenuName = 0;
  12036. + wc.hIcon = 0;
  12037.  
  12038. // find the icon file in the filesystem
  12039. if( FS_FileExists( GI->iconpath, true ))
  12040. {
  12041. - char localPath[MAX_PATH];
  12042. -
  12043. - Q_snprintf( localPath, sizeof( localPath ), "%s/%s", GI->gamedir, GI->iconpath );
  12044. - wc.hIcon = LoadImage( NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
  12045. -
  12046. - if( !wc.hIcon )
  12047. + if( FS_GetDiskPath( GI->iconpath, true ))
  12048. {
  12049. - MsgDev( D_INFO, "Extract %s from pak if you want to see it.\n", GI->iconpath );
  12050. - wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
  12051. + string localPath;
  12052. + Q_snprintf( localPath, sizeof( localPath ), "%s/%s", GI->gamedir, GI->iconpath );
  12053. + wc.hIcon = LoadImage( NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
  12054. }
  12055. + else MsgDev( D_INFO, "Extract %s from pak if you want to see it.\n", GI->iconpath );
  12056. }
  12057. - else wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
  12058. +
  12059. + // couldn't loaded for some reasons? use default
  12060. + if( !wc.hIcon ) wc.hIcon = LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ));
  12061.  
  12062. if( !RegisterClass( &wc ))
  12063. {
  12064. @@ -1172,13 +1278,13 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
  12065.  
  12066. if( host.hWnd != window )
  12067. {
  12068. - // probably never happens
  12069. + // make sure what CreateWindowEx call the IN_WndProc
  12070. MsgDev( D_WARN, "VID_CreateWindow: bad hWnd for '%s'\n", wndname );
  12071. }
  12072.  
  12073. - // host.hWnd must be filled in IN_WndProc
  12074. if( !host.hWnd )
  12075. {
  12076. + // host.hWnd must be filled in IN_WndProc
  12077. MsgDev( D_ERROR, "VID_CreateWindow: couldn't create '%s'\n", wndname );
  12078. return false;
  12079. }
  12080. @@ -1218,6 +1324,11 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
  12081. return true;
  12082. }
  12083.  
  12084. +/*
  12085. +=================
  12086. +VID_DestroyWindow
  12087. +=================
  12088. +*/
  12089. void VID_DestroyWindow( void )
  12090. {
  12091. if( pwglMakeCurrent )
  12092. @@ -1244,6 +1355,11 @@ void VID_DestroyWindow( void )
  12093. }
  12094. }
  12095.  
  12096. +/*
  12097. +=================
  12098. +R_ChangeDisplaySettings
  12099. +=================
  12100. +*/
  12101. rserr_t R_ChangeDisplaySettings( int vid_mode, qboolean fullscreen )
  12102. {
  12103. int width, height;
  12104. @@ -1346,7 +1462,7 @@ rserr_t R_ChangeDisplaySettings( int vid_mode, qboolean fullscreen )
  12105. return rserr_invalid_mode;
  12106.  
  12107. if( freq_specified )
  12108. - MsgDev( D_ERROR, "VID_SetMode: display frequency %i Hz not supported by your display\n", freq_specified );
  12109. + MsgDev( D_ERROR, "VID_SetMode: display frequency %i Hz is not supported\n", freq_specified );
  12110. glState.fullScreen = true;
  12111. return rserr_ok;
  12112. }
  12113. @@ -1375,8 +1491,6 @@ qboolean VID_SetMode( void )
  12114. qboolean fullscreen;
  12115. rserr_t err;
  12116.  
  12117. - gl_swapInterval->modified = true;
  12118. -
  12119. if( vid_mode->integer == -1 ) // trying to get resolution automatically by default
  12120. {
  12121. HDC hDCScreen = GetDC( NULL );
  12122. @@ -1398,6 +1512,7 @@ qboolean VID_SetMode( void )
  12123. }
  12124.  
  12125. fullscreen = vid_fullscreen->integer;
  12126. + gl_swapInterval->modified = true;
  12127.  
  12128. if(( err = R_ChangeDisplaySettings( vid_mode->integer, fullscreen )) == rserr_ok )
  12129. {
  12130. @@ -1447,10 +1562,10 @@ void VID_CheckChanges( void )
  12131.  
  12132. if( renderinfo->modified )
  12133. {
  12134. - if( !VID_SetMode())
  12135. + if( !VID_SetMode( ))
  12136. {
  12137. - // can't initialize video subsystem
  12138. - Host_NewInstance( va("#%s", GI->gamefolder ), "fallback to dedicated mode\n" );
  12139. + Msg( "Error: can't initialize video subsystem\n" );
  12140. + Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" );
  12141. }
  12142. else
  12143. {
  12144. @@ -1472,7 +1587,8 @@ qboolean R_Init_OpenGL( void )
  12145. if( !opengl_dll.link )
  12146. return false;
  12147.  
  12148. - GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
  12149. + if( Sys_CheckParm( "-gldebug" ) && host.developer >= 1 )
  12150. + GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
  12151.  
  12152. return VID_SetMode();
  12153. }
  12154. @@ -1493,7 +1609,7 @@ void R_Free_OpenGL( void )
  12155. Sys_FreeLibrary( &opengl_dll );
  12156.  
  12157. // now all extensions are disabled
  12158. - memset( glConfig.extension, 0, sizeof( glConfig.extension[0] ) * GL_EXTCOUNT );
  12159. + memset( glConfig.extension, 0, sizeof( glConfig.extension ));
  12160. glw_state.initialized = false;
  12161. }
  12162.  
  12163. @@ -1504,8 +1620,6 @@ GL_SetDefaults
  12164. */
  12165. static void GL_SetDefaults( void )
  12166. {
  12167. - int i;
  12168. -
  12169. pglFinish();
  12170.  
  12171. pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
  12172. @@ -1529,39 +1643,20 @@ static void GL_SetDefaults( void )
  12173. pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  12174. pglPolygonOffset( -1.0f, -2.0f );
  12175.  
  12176. - // properly disable multitexturing at startup
  12177. - for( i = (MAX_TEXTURE_UNITS - 1); i > 0; i-- )
  12178. - {
  12179. - if( i >= GL_MaxTextureUnits( ))
  12180. - continue;
  12181. + GL_CleanupAllTextureUnits();
  12182.  
  12183. - GL_SelectTexture( i );
  12184. - pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  12185. - pglDisable( GL_BLEND );
  12186. - pglDisable( GL_TEXTURE_2D );
  12187. - }
  12188. -
  12189. - GL_SelectTexture( 0 );
  12190. pglDisable( GL_BLEND );
  12191. pglDisable( GL_ALPHA_TEST );
  12192. pglDisable( GL_POLYGON_OFFSET_FILL );
  12193. - pglAlphaFunc( GL_GREATER, 0.0f );
  12194. + pglAlphaFunc( GL_GEQUAL, 0.5f );
  12195. pglEnable( GL_TEXTURE_2D );
  12196. - pglShadeModel( GL_FLAT );
  12197. + pglShadeModel( GL_SMOOTH );
  12198.  
  12199. pglPointSize( 1.2f );
  12200. pglLineWidth( 1.2f );
  12201.  
  12202. - GL_Cull( 0 );
  12203. + GL_Cull( GL_NONE );
  12204. GL_FrontFace( 0 );
  12205. -
  12206. - R_SetTextureParameters();
  12207. -
  12208. - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  12209. - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  12210. -
  12211. - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  12212. - pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  12213. }
  12214.  
  12215. /*
  12216. @@ -1577,19 +1672,26 @@ void R_RenderInfo_f( void )
  12217. Msg( "GL_VERSION: %s\n", glConfig.version_string );
  12218.  
  12219. // don't spam about extensions
  12220. - if( host.developer >= 4 )
  12221. + if( host.developer >= D_REPORT )
  12222. + {
  12223. Msg( "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
  12224.  
  12225. + if( glConfig.wgl_extensions_string != NULL )
  12226. + Msg( "\nWGL_EXTENSIONS: %s\n", glConfig.wgl_extensions_string );
  12227. + }
  12228. +
  12229. Msg( "GL_MAX_TEXTURE_SIZE: %i\n", glConfig.max_2d_texture_size );
  12230.  
  12231. if( GL_Support( GL_ARB_MULTITEXTURE ))
  12232. Msg( "GL_MAX_TEXTURE_UNITS_ARB: %i\n", glConfig.max_texture_units );
  12233. - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
  12234. + if( GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  12235. Msg( "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB: %i\n", glConfig.max_cubemap_size );
  12236. if( GL_Support( GL_ANISOTROPY_EXT ))
  12237. Msg( "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: %.1f\n", glConfig.max_texture_anisotropy );
  12238. - if( glConfig.texRectangle )
  12239. - Msg( "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV: %i\n", glConfig.max_2d_rectangle_size );
  12240. + if( GL_Support( GL_TEXTURE_2D_RECT_EXT ))
  12241. + Msg( "GL_MAX_RECTANGLE_TEXTURE_SIZE: %i\n", glConfig.max_2d_rectangle_size );
  12242. + if( GL_Support( GL_TEXTURE_ARRAY_EXT ))
  12243. + Msg( "GL_MAX_ARRAY_TEXTURE_LAYERS_EXT: %i\n", glConfig.max_2d_texture_layers );
  12244. if( GL_Support( GL_SHADER_GLSL100_EXT ))
  12245. {
  12246. Msg( "GL_MAX_TEXTURE_COORDS_ARB: %i\n", glConfig.max_texture_coords );
  12247. @@ -1599,12 +1701,11 @@ void R_RenderInfo_f( void )
  12248. }
  12249.  
  12250. Msg( "\n" );
  12251. - Msg( "MODE: %i, %i x %i %s\n", vid_mode->integer, r_width->integer, r_height->integer );
  12252. + Msg( "MODE: %i, %i x %i %s\n", vid_mode->integer, r_width->integer, r_height->integer, vidmode[vid_mode->integer].desc );
  12253. Msg( "GAMMA: %s\n", (glConfig.deviceSupportsGamma) ? "hardware" : "software" );
  12254. Msg( "\n" );
  12255. Msg( "PICMIP: %i\n", gl_picmip->integer );
  12256. Msg( "SKYMIP: %i\n", gl_skymip->integer );
  12257. - Msg( "TEXTUREMODE: %s\n", gl_texturemode->string );
  12258. Msg( "VERTICAL SYNC: %s\n", gl_swapInterval->integer ? "enabled" : "disabled" );
  12259. Msg( "Color %d bits, Alpha %d bits, Depth %d bits, Stencil %d bits\n", glConfig.color_bits,
  12260. glConfig.alpha_bits, glConfig.depth_bits, glConfig.stencil_bits );
  12261. @@ -1612,9 +1713,13 @@ void R_RenderInfo_f( void )
  12262.  
  12263. //=======================================================================
  12264.  
  12265. +/*
  12266. +=================
  12267. +GL_InitCommands
  12268. +=================
  12269. +*/
  12270. void GL_InitCommands( void )
  12271. {
  12272. - Cbuf_AddText( "vidlatch\n" );
  12273. Cbuf_Execute();
  12274.  
  12275. // system screen width and height (don't suppose for change from console at all)
  12276. @@ -1631,7 +1736,7 @@ void GL_InitCommands( void )
  12277. r_novis = Cvar_Get( "r_novis", "0", 0, "ignore vis information (perfomance test)" );
  12278. r_nocull = Cvar_Get( "r_nocull", "0", 0, "ignore frustrum culling (perfomance test)" );
  12279. r_faceplanecull = Cvar_Get( "r_faceplanecull", "1", 0, "ignore face plane culling (perfomance test)" );
  12280. - r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use \"2\" for auto-generate mapname_detail.txt" );
  12281. + r_detailtextures = Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE, "enable detail textures support, use '2' for autogenerate detail.txt" );
  12282. r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT, "lockpvs area at current point (pvs test)" );
  12283. r_lockcull = Cvar_Get( "r_lockcull", "0", CVAR_CHEAT, "lock frustrum area at current point (cull test)" );
  12284. r_dynamic = Cvar_Get( "r_dynamic", "1", CVAR_ARCHIVE, "allow dynamic lighting (dlights, lightstyles)" );
  12285. @@ -1647,9 +1752,8 @@ void GL_InitCommands( void )
  12286. gl_picmip = Cvar_Get( "gl_picmip", "0", CVAR_GLCONFIG, "reduces resolution of textures by powers of 2" );
  12287. gl_skymip = Cvar_Get( "gl_skymip", "0", CVAR_GLCONFIG, "reduces resolution of skybox textures by powers of 2" );
  12288. gl_ignorehwgamma = Cvar_Get( "gl_ignorehwgamma", "0", CVAR_GLCONFIG, "ignore hardware gamma" );
  12289. - gl_allow_software = Cvar_Get( "gl_allow_software", "0", CVAR_ARCHIVE, "allow OpenGL software emulation" );
  12290. gl_alphabits = Cvar_Get( "gl_alphabits", "8", CVAR_GLCONFIG, "pixelformat alpha bits (0 - auto)" );
  12291. - gl_texturemode = Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "texture filter" );
  12292. + gl_texture_nearest = Cvar_Get( "gl_texture_nearest", "0", CVAR_ARCHIVE, "disable texture filter" );
  12293. gl_round_down = Cvar_Get( "gl_round_down", "0", CVAR_GLCONFIG, "down size non-power of two textures" );
  12294. gl_max_size = Cvar_Get( "gl_max_size", "512", CVAR_ARCHIVE, "no effect in Xash3D just a legacy" );
  12295. gl_stencilbits = Cvar_Get( "gl_stencilbits", "8", CVAR_GLCONFIG, "pixelformat stencil bits (0 - auto)" );
  12296. @@ -1658,19 +1762,18 @@ void GL_InitCommands( void )
  12297. gl_extensions = Cvar_Get( "gl_extensions", "1", CVAR_GLCONFIG, "allow gl_extensions" );
  12298. gl_detailscale = Cvar_Get( "gl_detailscale", "4.0", CVAR_ARCHIVE, "default scale applies while auto-generate list of detail textures" );
  12299. gl_texture_anisotropy = Cvar_Get( "gl_anisotropy", "2.0", CVAR_ARCHIVE, "textures anisotropic filter" );
  12300. - gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures" );
  12301. + gl_texture_lodbias = Cvar_Get( "gl_texture_lodbias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures (prefomance|quality)" );
  12302. gl_compress_textures = Cvar_Get( "gl_compress_textures", "0", CVAR_GLCONFIG, "compress textures to safe video memory" );
  12303. - gl_luminance_textures = Cvar_Get( "gl_luminance_textures", "0", CVAR_GLCONFIG, "force all textures to luminance" );
  12304. - gl_compensate_gamma_screenshots = Cvar_Get( "gl_compensate_gamma_screenshots", "0", CVAR_ARCHIVE, "allow to apply gamma value for screenshots and snapshots" );
  12305. - gl_keeptjunctions = Cvar_Get( "gl_keeptjunctions", "1", CVAR_ARCHIVE, "disable to reduce vertexes count but removing tjuncs causes blinking pixels" );
  12306. + gl_compensate_gamma_screenshots = Cvar_Get( "gl_compensate_gamma_screenshots", "0", CVAR_ARCHIVE, "allow to apply gamma for screenshots" );
  12307. + gl_keeptjunctions = Cvar_Get( "gl_keeptjunctions", "1", CVAR_ARCHIVE, "but removing tjuncs causes blinking pixels" );
  12308. gl_allow_static = Cvar_Get( "gl_allow_static", "0", CVAR_ARCHIVE, "force to drawing non-moveable brushes as part of world (save FPS)" );
  12309. gl_allow_mirrors = Cvar_Get( "gl_allow_mirrors", "1", CVAR_ARCHIVE, "allow to draw mirror surfaces" );
  12310. - gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures (type values from 1 to 13)" );
  12311. + gl_showtextures = Cvar_Get( "r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures" );
  12312. gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE, "use glFinish instead of glFlush" );
  12313. gl_nosort = Cvar_Get( "gl_nosort", "0", CVAR_ARCHIVE, "disable sorting of translucent surfaces" );
  12314. gl_clear = Cvar_Get( "gl_clear", "0", CVAR_ARCHIVE, "clearing screen after each frame" );
  12315. gl_test = Cvar_Get( "gl_test", "0", 0, "engine developer cvar for quick testing new features" );
  12316. - gl_wireframe = Cvar_Get( "gl_wireframe", "0", 0, "show wireframe overlay" );
  12317. + gl_wireframe = Cvar_Get( "gl_wireframe", "0", CVAR_ARCHIVE, "show wireframe overlay" );
  12318. gl_overview = Cvar_Get( "dev_overview", "0", 0, "show level overview" );
  12319.  
  12320. // these cvar not used by engine but some mods requires this
  12321. @@ -1680,21 +1783,28 @@ void GL_InitCommands( void )
  12322. gl_swapInterval->modified = true;
  12323.  
  12324. vid_gamma = Cvar_Get( "gamma", "1.0", CVAR_ARCHIVE, "gamma amount" );
  12325. - vid_texgamma = Cvar_Get( "texgamma", "2.2", CVAR_GLCONFIG, "texgamma amount (default Half-Life artwork gamma)" );
  12326. vid_mode = Cvar_Get( "vid_mode", VID_AUTOMODE, CVAR_RENDERINFO, "display resolution mode" );
  12327. vid_fullscreen = Cvar_Get( "fullscreen", "0", CVAR_RENDERINFO, "set in 1 to enable fullscreen mode" );
  12328. vid_displayfrequency = Cvar_Get ( "vid_displayfrequency", "0", CVAR_RENDERINFO, "fullscreen refresh rate" );
  12329.  
  12330. Cmd_AddCommand( "r_info", R_RenderInfo_f, "display renderer info" );
  12331. - Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
  12332. }
  12333.  
  12334. +/*
  12335. +=================
  12336. +GL_RemoveCommands
  12337. +=================
  12338. +*/
  12339. void GL_RemoveCommands( void )
  12340. {
  12341. Cmd_RemoveCommand( "r_info");
  12342. - Cmd_RemoveCommand( "texturelist" );
  12343. }
  12344.  
  12345. +/*
  12346. +=================
  12347. +GL_InitExtensions
  12348. +=================
  12349. +*/
  12350. void GL_InitExtensions( void )
  12351. {
  12352. // initialize gl extensions
  12353. @@ -1707,6 +1817,35 @@ void GL_InitExtensions( void )
  12354. glConfig.extensions_string = pglGetString( GL_EXTENSIONS );
  12355. MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string );
  12356.  
  12357. + // intialize wrapper type
  12358. + glConfig.context = CONTEXT_TYPE_GL;
  12359. + glConfig.wrapper = GLES_WRAPPER_NONE;
  12360. +
  12361. + if( Q_stristr( glConfig.renderer_string, "geforce" ))
  12362. + glConfig.hardware_type = GLHW_NVIDIA;
  12363. + else if( Q_stristr( glConfig.renderer_string, "quadro fx" ))
  12364. + glConfig.hardware_type = GLHW_NVIDIA;
  12365. + else if( Q_stristr(glConfig.renderer_string, "rv770" ))
  12366. + glConfig.hardware_type = GLHW_RADEON;
  12367. + else if( Q_stristr(glConfig.renderer_string, "radeon hd" ))
  12368. + glConfig.hardware_type = GLHW_RADEON;
  12369. + else if( Q_stristr( glConfig.renderer_string, "eah4850" ) || Q_stristr( glConfig.renderer_string, "eah4870" ))
  12370. + glConfig.hardware_type = GLHW_RADEON;
  12371. + else if( Q_stristr( glConfig.renderer_string, "radeon" ))
  12372. + glConfig.hardware_type = GLHW_RADEON;
  12373. + else glConfig.hardware_type = GLHW_GENERIC;
  12374. +
  12375. + // initalize until base opengl functions loaded (old-context)
  12376. + if( !Sys_CheckParm( "-gldebug" ) || host.developer < D_INFO )
  12377. + GL_CheckExtension( "OpenGL Internal ProcAddress", wglproc_funcs, NULL, GL_WGL_PROCADDRESS );
  12378. +
  12379. + // windows-specific extensions
  12380. + GL_CheckExtension( "WGL Extensions String", wglgetextensionsstring, NULL, GL_WGL_EXTENSIONS );
  12381. +
  12382. + if( pwglGetExtensionsStringEXT != NULL )
  12383. + glConfig.wgl_extensions_string = pwglGetExtensionsStringEXT();
  12384. + else glConfig.wgl_extensions_string = NULL;
  12385. +
  12386. // initalize until base opengl functions loaded
  12387. GL_CheckExtension( "WGL_EXT_swap_control", wglswapintervalfuncs, NULL, GL_WGL_SWAPCONTROL );
  12388.  
  12389. @@ -1715,26 +1854,15 @@ void GL_InitExtensions( void )
  12390. if( !GL_Support( GL_DRAW_RANGEELEMENTS_EXT ))
  12391. GL_CheckExtension( "GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "gl_drawrangeelments", GL_DRAW_RANGEELEMENTS_EXT );
  12392.  
  12393. + // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
  12394. + if( pglDrawRangeElementsEXT == NULL ) pglDrawRangeElementsEXT = pglDrawRangeElements;
  12395. +
  12396. // multitexture
  12397. glConfig.max_texture_units = glConfig.max_texture_coords = glConfig.max_teximage_units = 1;
  12398. GL_CheckExtension( "GL_ARB_multitexture", multitexturefuncs, "gl_arb_multitexture", GL_ARB_MULTITEXTURE );
  12399.  
  12400. if( GL_Support( GL_ARB_MULTITEXTURE ))
  12401. - {
  12402. pglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glConfig.max_texture_units );
  12403. - GL_CheckExtension( "GL_ARB_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT );
  12404. -
  12405. - if( !GL_Support( GL_ENV_COMBINE_EXT ))
  12406. - GL_CheckExtension( "GL_EXT_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT );
  12407. -
  12408. - if( GL_Support( GL_ENV_COMBINE_EXT ))
  12409. - GL_CheckExtension( "GL_ARB_texture_env_dot3", NULL, "gl_texture_env_dot3", GL_DOT3_ARB_EXT );
  12410. - }
  12411. - else
  12412. - {
  12413. - GL_CheckExtension( "GL_SGIS_multitexture", sgis_multitexturefuncs, "gl_sgis_multitexture", GL_ARB_MULTITEXTURE );
  12414. - if( GL_Support( GL_ARB_MULTITEXTURE )) glConfig.max_texture_units = 2;
  12415. - }
  12416.  
  12417. if( glConfig.max_texture_units == 1 )
  12418. GL_SetExtension( GL_ARB_MULTITEXTURE, false );
  12419. @@ -1753,12 +1881,18 @@ void GL_InitExtensions( void )
  12420. }
  12421. }
  12422.  
  12423. - GL_CheckExtension( "GL_SGIS_generate_mipmap", NULL, "gl_sgis_generate_mipmaps", GL_SGIS_MIPMAPS_EXT );
  12424. + // 2d texture array support
  12425. + GL_CheckExtension( "GL_EXT_texture_array", texture3dextfuncs, "gl_texture_2d_array", GL_TEXTURE_ARRAY_EXT );
  12426. +
  12427. + if( GL_Support( GL_TEXTURE_ARRAY_EXT ))
  12428. + pglGetIntegerv( GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &glConfig.max_2d_texture_layers );
  12429.  
  12430. // hardware cubemaps
  12431. - GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURECUBEMAP_EXT );
  12432. + GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURE_CUBEMAP_EXT );
  12433.  
  12434. - if( GL_Support( GL_TEXTURECUBEMAP_EXT ))
  12435. + GL_CheckExtension( "GL_ARB_draw_buffers", drawbuffersfuncs, "gl_draw_buffers", GL_DRAW_BUFFERS_EXT );
  12436. +
  12437. + if( GL_Support( GL_TEXTURE_CUBEMAP_EXT ))
  12438. {
  12439. pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size );
  12440.  
  12441. @@ -1766,15 +1900,8 @@ void GL_InitExtensions( void )
  12442. GL_CheckExtension( "GL_ARB_seamless_cube_map", NULL, "gl_seamless_cubemap", GL_ARB_SEAMLESS_CUBEMAP );
  12443. }
  12444.  
  12445. - // point particles extension
  12446. - GL_CheckExtension( "GL_EXT_point_parameters", pointparametersfunc, NULL, GL_EXT_POINTPARAMETERS );
  12447. -
  12448. GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT );
  12449. GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_dds_hardware_support", GL_TEXTURE_COMPRESSION_EXT );
  12450. - GL_CheckExtension( "GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT );
  12451. -
  12452. - if( !GL_Support( GL_CUSTOM_VERTEX_ARRAY_EXT ))
  12453. - GL_CheckExtension( "GL_SGI_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT );
  12454.  
  12455. GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT );
  12456.  
  12457. @@ -1787,47 +1914,56 @@ void GL_InitExtensions( void )
  12458. if( GL_Support( GL_ANISOTROPY_EXT ))
  12459. pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy );
  12460.  
  12461. - GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_ext_texture_lodbias", GL_TEXTURE_LODBIAS );
  12462. - if( GL_Support( GL_TEXTURE_LODBIAS ))
  12463. - pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lodbias );
  12464. -
  12465. - GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT );
  12466. -
  12467. - GL_CheckExtension( "GL_EXT_blend_minmax", blendequationfuncs, "gl_ext_customblend", GL_BLEND_MINMAX_EXT );
  12468. - GL_CheckExtension( "GL_EXT_blend_subtract", blendequationfuncs, "gl_ext_customblend", GL_BLEND_SUBTRACT_EXT );
  12469. + GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_ext_texture_lod_bias", GL_TEXTURE_LOD_BIAS );
  12470.  
  12471. - GL_CheckExtension( "glStencilOpSeparate", gl2separatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT );
  12472. + if( GL_Support( GL_TEXTURE_LOD_BIAS ))
  12473. + pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lod_bias );
  12474.  
  12475. - if( !GL_Support( GL_SEPARATESTENCIL_EXT ))
  12476. - GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT );
  12477. + GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT );
  12478.  
  12479. - GL_CheckExtension( "GL_EXT_stencil_two_side", stenciltwosidefuncs, "gl_stenciltwoside", GL_STENCILTWOSIDE_EXT );
  12480. GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT );
  12481. -
  12482. - // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code
  12483. - if( pglDrawRangeElementsEXT == NULL ) pglDrawRangeElementsEXT = pglDrawRangeElements;
  12484. -
  12485. - GL_CheckExtension( "GL_ARB_texture_env_add", NULL, "gl_texture_env_add", GL_TEXTURE_ENV_ADD_EXT );
  12486. + GL_CheckExtension( "GL_ARB_vertex_array_object", vaofuncs, "gl_vertex_array_object", GL_ARB_VERTEX_ARRAY_OBJECT_EXT );
  12487. + GL_CheckExtension( "GL_ARB_half_float_pixel", NULL, "gl_half_float", GL_ARB_HALF_FLOAT_EXT );
  12488.  
  12489. // vp and fp shaders
  12490. GL_CheckExtension( "GL_ARB_shader_objects", shaderobjectsfuncs, "gl_shaderobjects", GL_SHADER_OBJECTS_EXT );
  12491. - GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT );
  12492. - GL_CheckExtension( "GL_ARB_vertex_shader", vertexshaderfuncs, "gl_vertexshader", GL_VERTEX_SHADER_EXT );
  12493. - GL_CheckExtension( "GL_ARB_fragment_shader", NULL, "gl_pixelshader", GL_FRAGMENT_SHADER_EXT );
  12494. + GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_shading_language", GL_SHADER_GLSL100_EXT );
  12495.  
  12496. GL_CheckExtension( "GL_ARB_depth_texture", NULL, "gl_depthtexture", GL_DEPTH_TEXTURE );
  12497. GL_CheckExtension( "GL_ARB_shadow", NULL, "gl_arb_shadow", GL_SHADOW_EXT );
  12498.  
  12499. GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_arb_texture_float", GL_ARB_TEXTURE_FLOAT_EXT );
  12500. GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT );
  12501. + GL_CheckExtension( "GL_ARB_texture_rg", NULL, "gl_arb_texture_rg", GL_ARB_TEXTURE_RG );
  12502. + GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, "gl_ext_gpu_shader4", GL_EXT_GPU_SHADER4 );
  12503. +
  12504. + // this won't work without extended context
  12505. + if( glw_state.extended )
  12506. + GL_CheckExtension( "GL_ARB_debug_output", debugoutputfuncs, "gl_debug_output", GL_DEBUG_OUTPUT );
  12507. +
  12508. + // FBO support
  12509. + GL_CheckExtension( "GL_ARB_framebuffer_object", arbfbofuncs, "gl_framebuffer_object", GL_FRAMEBUFFER_OBJECT );
  12510. +
  12511. + if( !GL_Support( GL_FRAMEBUFFER_OBJECT ))
  12512. + GL_CheckExtension( "GL_EXT_framebuffer_object", extfbofuncs, "gl_framebuffer_object", GL_FRAMEBUFFER_OBJECT );
  12513.  
  12514. // occlusion queries
  12515. GL_CheckExtension( "GL_ARB_occlusion_query", occlusionfunc, "gl_occlusion_queries", GL_OCCLUSION_QUERIES_EXT );
  12516.  
  12517. + // rectangle textures support
  12518. + GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT );
  12519. +
  12520. if( GL_Support( GL_SHADER_GLSL100_EXT ))
  12521. {
  12522. pglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &glConfig.max_texture_coords );
  12523. pglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &glConfig.max_teximage_units );
  12524. +
  12525. + // check for hardware skinning
  12526. + pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms );
  12527. + pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs );
  12528. +
  12529. + if( glConfig.hardware_type == GLHW_RADEON )
  12530. + glConfig.max_vertex_uniforms /= 4; // radeon returns not correct info
  12531. }
  12532. else
  12533. {
  12534. @@ -1835,42 +1971,41 @@ void GL_InitExtensions( void )
  12535. glConfig.max_texture_coords = glConfig.max_teximage_units = glConfig.max_texture_units;
  12536. }
  12537.  
  12538. - // rectangle textures support
  12539. - if( Q_strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ))
  12540. - {
  12541. - glConfig.texRectangle = GL_TEXTURE_RECTANGLE_NV;
  12542. - pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &glConfig.max_2d_rectangle_size );
  12543. - }
  12544. - else if( Q_strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ))
  12545. - {
  12546. - glConfig.texRectangle = GL_TEXTURE_RECTANGLE_EXT;
  12547. - pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &glConfig.max_2d_rectangle_size );
  12548. - }
  12549. - else glConfig.texRectangle = glConfig.max_2d_rectangle_size = 0; // no rectangle
  12550. -
  12551. - glConfig.max_2d_texture_size = 0;
  12552. pglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.max_2d_texture_size );
  12553. if( glConfig.max_2d_texture_size <= 0 ) glConfig.max_2d_texture_size = 256;
  12554.  
  12555. + pglGetIntegerv( GL_MAX_DRAW_BUFFERS_ARB, &glConfig.max_draw_buffers );
  12556. +
  12557. + if( GL_Support( GL_TEXTURE_2D_RECT_EXT ))
  12558. + pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &glConfig.max_2d_rectangle_size );
  12559. +
  12560. Cvar_Get( "gl_max_texture_size", "0", CVAR_INIT, "opengl texture max dims" );
  12561. Cvar_Set( "gl_max_texture_size", va( "%i", glConfig.max_2d_texture_size ));
  12562.  
  12563. - pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms );
  12564. - pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs );
  12565. -
  12566. // MCD has buffering issues
  12567. - if(Q_strstr( glConfig.renderer_string, "gdi" ))
  12568. + if( Q_stristr( glConfig.renderer_string, "gdi" ))
  12569. Cvar_SetFloat( "gl_finish", 1 );
  12570.  
  12571. Cvar_Set( "gl_anisotropy", va( "%f", bound( 0, gl_texture_anisotropy->value, glConfig.max_texture_anisotropy )));
  12572.  
  12573. - // software mipmap generator does wrong result with NPOT textures ...
  12574. - if( !GL_Support( GL_SGIS_MIPMAPS_EXT ))
  12575. - GL_SetExtension( GL_ARB_TEXTURE_NPOT_EXT, false );
  12576. -
  12577. if( GL_Support( GL_TEXTURE_COMPRESSION_EXT ))
  12578. Image_AddCmdFlags( IL_DDS_HARDWARE );
  12579.  
  12580. + // enable gldebug if allowed
  12581. + if( GL_Support( GL_DEBUG_OUTPUT ))
  12582. + {
  12583. + if( host.developer >= D_ERROR )
  12584. + pglDebugMessageCallbackARB( GL_DebugOutput, NULL );
  12585. +
  12586. + // force everything to happen in the main thread instead of in a separate driver thread
  12587. + if( host.developer >= D_WARN )
  12588. + pglEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
  12589. +
  12590. + // enable all the low priority messages
  12591. + if( host.developer >= D_REPORT )
  12592. + pglDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, true );
  12593. + }
  12594. +
  12595. glw_state.initialized = true;
  12596.  
  12597. tr.framecount = tr.visframecount = 1;
  12598. @@ -1898,8 +2033,8 @@ qboolean R_Init( void )
  12599. GL_RemoveCommands();
  12600. R_Free_OpenGL();
  12601.  
  12602. - // can't initialize video subsystem
  12603. - Host_NewInstance( va("#%s", GI->gamefolder ), "fallback to dedicated mode\n" );
  12604. + Msg( "^1Error:^7 can't initialize video subsystem\n" );
  12605. + Host_NewInstance( va( "#%s", GI->gamefolder ), "stopped" );
  12606. return false;
  12607. }
  12608.  
  12609. @@ -1990,5 +2125,5 @@ void GL_CheckForErrors_( const char *filename, const int fileline )
  12610. break;
  12611. }
  12612.  
  12613. - Host_Error( "GL_CheckForErrors: %s (called at %s:%i)\n", str, filename, fileline );
  12614. + MsgDev( D_ERROR, "OpenGL: %s (called at %s:%i)\n", str, filename, fileline );
  12615. }
  12616. \ No newline at end of file
  12617. diff --git b/engine/client/gl_warp.c a/engine/client/gl_warp.c
  12618. index 5023b70..06903ec 100644
  12619. --- b/engine/client/gl_warp.c
  12620. +++ a/engine/client/gl_warp.c
  12621. @@ -19,9 +19,9 @@ GNU General Public License for more details.
  12622. #include "com_model.h"
  12623. #include "wadfile.h"
  12624.  
  12625. -#define MAX_CLIP_VERTS 64 // skybox clip vertices
  12626. +#define SKYCLOUDS_QUALITY 12
  12627. +#define MAX_CLIP_VERTS 128 // skybox clip vertices
  12628. #define TURBSCALE ( 256.0f / ( M_PI2 ))
  12629. -static float speedscale;
  12630. static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
  12631. static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
  12632.  
  12633. @@ -127,6 +127,8 @@ void DrawSkyPolygon( int nump, vec3_t vecs )
  12634. j = vec_to_st[axis][2];
  12635. dv = (j > 0) ? vecs[j-1] : -vecs[-j-1];
  12636.  
  12637. + if( dv == 0.0f ) continue;
  12638. +
  12639. j = vec_to_st[axis][0];
  12640. s = (j < 0) ? -vecs[-j-1] / dv : vecs[j-1] / dv;
  12641.  
  12642. @@ -302,6 +304,7 @@ void R_AddSkyBoxSurface( msurface_t *fa )
  12643. {
  12644. vec3_t verts[MAX_CLIP_VERTS];
  12645. glpoly_t *p;
  12646. + float *v;
  12647. int i;
  12648.  
  12649. if( r_fastsky->integer )
  12650. @@ -317,6 +320,20 @@ void R_AddSkyBoxSurface( msurface_t *fa )
  12651. }
  12652. }
  12653.  
  12654. + if( world.sky_sphere && fa->polys && !world.custom_skybox )
  12655. + {
  12656. + glpoly_t *p = fa->polys;
  12657. +
  12658. + // draw the sky poly
  12659. + pglBegin( GL_POLYGON );
  12660. + for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
  12661. + {
  12662. + pglTexCoord2f( v[3], v[4] );
  12663. + pglVertex3fv( v );
  12664. + }
  12665. + pglEnd ();
  12666. + }
  12667. +
  12668. // calculate vertex values for sky box
  12669. for( p = fa->polys; p; p = p->next )
  12670. {
  12671. @@ -347,6 +364,7 @@ void R_UnloadSkybox( void )
  12672. tr.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes)
  12673.  
  12674. memset( tr.skyboxTextures, 0, sizeof( tr.skyboxTextures ));
  12675. + world.custom_skybox = false;
  12676. }
  12677.  
  12678. /*
  12679. @@ -445,11 +463,14 @@ void R_SetupSky( const char *skyboxname )
  12680. {
  12681. Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
  12682. tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
  12683. - GL_SetTextureType( tr.skyboxTextures[i], TEX_CUBEMAP );
  12684. if( !tr.skyboxTextures[i] ) break;
  12685. }
  12686.  
  12687. - if( i == 6 ) return; // loaded
  12688. + if( i == 6 )
  12689. + {
  12690. + world.custom_skybox = true;
  12691. + return; // loaded
  12692. + }
  12693.  
  12694. // clear previous and try again
  12695. R_UnloadSkybox();
  12696. @@ -458,16 +479,193 @@ void R_SetupSky( const char *skyboxname )
  12697. {
  12698. Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
  12699. tr.skyboxTextures[i] = GL_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY, NULL );
  12700. - GL_SetTextureType( tr.skyboxTextures[i], TEX_CUBEMAP );
  12701. if( !tr.skyboxTextures[i] ) break;
  12702. }
  12703. - if( i == 6 ) return; // loaded
  12704. +
  12705. + if( i == 6 )
  12706. + {
  12707. + world.custom_skybox = true;
  12708. + return; // loaded
  12709. + }
  12710.  
  12711. // completely couldn't load skybox (probably never happens)
  12712. MsgDev( D_ERROR, "R_SetupSky: couldn't load skybox '%s'\n", skyboxname );
  12713. R_UnloadSkybox();
  12714. }
  12715.  
  12716. +//==============================================================================
  12717. +//
  12718. +// RENDER CLOUDS
  12719. +//
  12720. +//==============================================================================
  12721. +/*
  12722. +==============
  12723. +R_CloudVertex
  12724. +==============
  12725. +*/
  12726. +void R_CloudVertex( float s, float t, int axis, vec3_t v )
  12727. +{
  12728. + int j, k, farclip;
  12729. + vec3_t b;
  12730. +
  12731. + farclip = RI.farClip;
  12732. +
  12733. + b[0] = s * (farclip >> 1);
  12734. + b[1] = t * (farclip >> 1);
  12735. + b[2] = (farclip >> 1);
  12736. +
  12737. + for( j = 0; j < 3; j++ )
  12738. + {
  12739. + k = st_to_vec[axis][j];
  12740. + v[j] = (k < 0) ? -b[-k-1] : b[k-1];
  12741. + v[j] += RI.cullorigin[j];
  12742. + }
  12743. +}
  12744. +
  12745. +/*
  12746. +=============
  12747. +R_CloudTexCoord
  12748. +=============
  12749. +*/
  12750. +void R_CloudTexCoord( vec3_t v, float speed, float *s, float *t )
  12751. +{
  12752. + float length, speedscale;
  12753. + vec3_t dir;
  12754. +
  12755. + speedscale = cl.time * speed;
  12756. + speedscale -= (int)speedscale & ~127;
  12757. +
  12758. + VectorSubtract( v, RI.vieworg, dir );
  12759. + dir[2] *= 3.0f; // flatten the sphere
  12760. +
  12761. + length = VectorLength( dir );
  12762. + length = 6.0f * 63.0f / length;
  12763. +
  12764. + *s = ( speedscale + dir[0] * length ) * (1.0f / 128.0f);
  12765. + *t = ( speedscale + dir[1] * length ) * (1.0f / 128.0f);
  12766. +}
  12767. +
  12768. +/*
  12769. +===============
  12770. +R_CloudDrawPoly
  12771. +===============
  12772. +*/
  12773. +void R_CloudDrawPoly( glpoly_t *p )
  12774. +{
  12775. + float s, t;
  12776. + float *v;
  12777. + int i;
  12778. +
  12779. + GL_SetRenderMode( kRenderNormal );
  12780. + GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
  12781. +
  12782. + pglBegin( GL_QUADS );
  12783. + for( i = 0, v = p->verts[0]; i < 4; i++, v += VERTEXSIZE )
  12784. + {
  12785. + R_CloudTexCoord( v, 8.0f, &s, &t );
  12786. + pglTexCoord2f( s, t );
  12787. + pglVertex3fv( v );
  12788. + }
  12789. + pglEnd();
  12790. +
  12791. + GL_SetRenderMode( kRenderTransTexture );
  12792. + GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
  12793. +
  12794. + pglBegin( GL_QUADS );
  12795. + for( i = 0, v = p->verts[0]; i < 4; i++, v += VERTEXSIZE )
  12796. + {
  12797. + R_CloudTexCoord( v, 16.0f, &s, &t );
  12798. + pglTexCoord2f( s, t );
  12799. + pglVertex3fv( v );
  12800. + }
  12801. + pglEnd();
  12802. +
  12803. + pglDisable( GL_BLEND );
  12804. +}
  12805. +
  12806. +/*
  12807. +==============
  12808. +R_CloudRenderSide
  12809. +==============
  12810. +*/
  12811. +void R_CloudRenderSide( int axis )
  12812. +{
  12813. + vec3_t verts[4];
  12814. + float di, qi, dj, qj;
  12815. + vec3_t vup, vright;
  12816. + vec3_t temp, temp2;
  12817. + glpoly_t p[1];
  12818. + int i, j;
  12819. +
  12820. + R_CloudVertex( -1.0f, -1.0f, axis, verts[0] );
  12821. + R_CloudVertex( -1.0f, 1.0f, axis, verts[1] );
  12822. + R_CloudVertex( 1.0f, 1.0f, axis, verts[2] );
  12823. + R_CloudVertex( 1.0f, -1.0f, axis, verts[3] );
  12824. +
  12825. + VectorSubtract( verts[2], verts[3], vup );
  12826. + VectorSubtract( verts[2], verts[1], vright );
  12827. +
  12828. + p->numverts = 4;
  12829. + di = SKYCLOUDS_QUALITY;
  12830. + qi = 1.0 / di;
  12831. + dj = (axis < 4) ? di * 2 : di; //subdivide vertically more than horizontally on skybox sides
  12832. + qj = 1.0 / dj;
  12833. +
  12834. + for( i = 0; i < di; i++ )
  12835. + {
  12836. + for( j = 0; j < dj; j++ )
  12837. + {
  12838. + if( i * qi < RI.skyMins[0][axis] / 2 + 0.5f - qi
  12839. + || i * qi > RI.skyMaxs[0][axis] / 2 + 0.5f
  12840. + || j * qj < RI.skyMins[1][axis] / 2 + 0.5f - qj
  12841. + || j * qj > RI.skyMaxs[1][axis] / 2 + 0.5f )
  12842. + continue;
  12843. +
  12844. + VectorScale( vright, qi * i, temp );
  12845. + VectorScale( vup, qj * j, temp2 );
  12846. + VectorAdd( temp, temp2, temp );
  12847. + VectorAdd( verts[0], temp, p->verts[0] );
  12848. +
  12849. + VectorScale( vup, qj, temp );
  12850. + VectorAdd( p->verts[0], temp, p->verts[1] );
  12851. +
  12852. + VectorScale( vright, qi, temp );
  12853. + VectorAdd( p->verts[1], temp, p->verts[2] );
  12854. +
  12855. + VectorAdd( p->verts[0], temp, p->verts[3] );
  12856. +
  12857. + R_CloudDrawPoly( p );
  12858. + }
  12859. + }
  12860. +}
  12861. +
  12862. +/*
  12863. +==============
  12864. +R_DrawClouds
  12865. +
  12866. +Quake-style clouds
  12867. +==============
  12868. +*/
  12869. +void R_DrawClouds( void )
  12870. +{
  12871. + int i;
  12872. +
  12873. + RI.isSkyVisible = true;
  12874. +
  12875. + pglDepthFunc( GL_GEQUAL );
  12876. + pglDepthMask( 0 );
  12877. +
  12878. + for( i = 0; i < 6; i++ )
  12879. + {
  12880. + if( RI.skyMins[0][i] >= RI.skyMaxs[0][i] || RI.skyMins[1][i] >= RI.skyMaxs[1][i] )
  12881. + continue;
  12882. + R_CloudRenderSide( i );
  12883. + }
  12884. +
  12885. + pglDepthMask( GL_TRUE );
  12886. + pglDepthFunc( GL_LEQUAL );
  12887. +}
  12888. +
  12889. /*
  12890. =============
  12891. R_InitSky
  12892. @@ -502,7 +700,7 @@ void R_InitSky( mip_t *mt, texture_t *tx )
  12893. }
  12894.  
  12895. // make sure what sky image is valid
  12896. - if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 )
  12897. + if( !r_sky || !r_sky->palette || r_sky->type != PF_INDEXED_32 || r_sky->height == 0 )
  12898. {
  12899. MsgDev( D_ERROR, "R_InitSky: unable to load sky texture %s\n", tx->name );
  12900. FS_FreeImage( r_sky );
  12901. @@ -567,9 +765,6 @@ void R_InitSky( mip_t *mt, texture_t *tx )
  12902. // load it in
  12903. tr.alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_UNCOMPRESSED|TF_NOMIPMAP, false );
  12904.  
  12905. - GL_SetTextureType( tr.solidskyTexture, TEX_BRUSH );
  12906. - GL_SetTextureType( tr.alphaskyTexture, TEX_BRUSH );
  12907. -
  12908. // clean up
  12909. FS_FreeImage( r_sky );
  12910. Mem_Free( trans );
  12911. @@ -582,17 +777,20 @@ EmitWaterPolys
  12912. Does a water warp on the pre-fragmented glpoly_t chain
  12913. =============
  12914. */
  12915. -void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
  12916. +void EmitWaterPolys( glpoly_t *polys, qboolean noCull, qboolean direction )
  12917. {
  12918. - glpoly_t *p;
  12919. + glpoly_t *p = polys;
  12920. float *v, nv, waveHeight;
  12921. float s, t, os, ot;
  12922. int i;
  12923.  
  12924. + if( !polys ) return;
  12925. if( noCull ) pglDisable( GL_CULL_FACE );
  12926.  
  12927. // set the current waveheight
  12928. - waveHeight = RI.currentWaveHeight;
  12929. + if( p->verts[0][2] >= RI.refdef.vieworg[2] )
  12930. + waveHeight = -RI.currententity->curstate.scale;
  12931. + else waveHeight = RI.currententity->curstate.scale;
  12932.  
  12933. // reset fog color for nonlightmapped water
  12934. GL_ResetFogColor();
  12935. @@ -601,29 +799,37 @@ void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
  12936. {
  12937. pglBegin( GL_POLYGON );
  12938.  
  12939. - for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
  12940. + if( direction )
  12941. + v = p->verts[0] + ( p->numverts - 1 ) * VERTEXSIZE;
  12942. + else v = p->verts[0];
  12943. +
  12944. + for( i = 0; i < p->numverts; i++ )
  12945. {
  12946. if( waveHeight )
  12947. {
  12948. - nv = v[2] + waveHeight + ( waveHeight * sin(v[0] * 0.02f + cl.time)
  12949. - * sin(v[1] * 0.02 + cl.time) * sin(v[2] * 0.02f + cl.time));
  12950. - nv -= waveHeight;
  12951. + nv = r_turbsin[(int)(cl.time * 160.0f + v[1] + v[0]) & 255] + 8.0f;
  12952. + nv = (r_turbsin[(int)(v[0] * 5.0f + cl.time * 171.0f - v[1]) & 255] + 8.0f ) * 0.8f + nv;
  12953. + nv = nv * waveHeight + v[2];
  12954. }
  12955. else nv = v[2];
  12956.  
  12957. os = v[3];
  12958. ot = v[4];
  12959.  
  12960. - s = os + r_turbsin[(int)((ot * 0.125f + cl.time ) * TURBSCALE) & 255];
  12961. + s = os + r_turbsin[(int)((ot * 0.125f + cl.time) * TURBSCALE) & 255];
  12962. s *= ( 1.0f / SUBDIVIDE_SIZE );
  12963.  
  12964. - t = ot + r_turbsin[(int)((os * 0.125f + cl.time ) * TURBSCALE) & 255];
  12965. + t = ot + r_turbsin[(int)((os * 0.125f + cl.time) * TURBSCALE) & 255];
  12966. t *= ( 1.0f / SUBDIVIDE_SIZE );
  12967.  
  12968. if( glState.activeTMU != 0 )
  12969. GL_MultiTexCoord2f( glState.activeTMU, s, t );
  12970. else pglTexCoord2f( s, t );
  12971. pglVertex3f( v[0], v[1], nv );
  12972. +
  12973. + if( direction )
  12974. + v -= VERTEXSIZE;
  12975. + else v += VERTEXSIZE;
  12976. }
  12977. pglEnd();
  12978. }
  12979. @@ -632,103 +838,4 @@ void EmitWaterPolys( glpoly_t *polys, qboolean noCull )
  12980. if( noCull ) pglEnable( GL_CULL_FACE );
  12981.  
  12982. GL_SetupFogColorForSurfaces();
  12983. -}
  12984. -
  12985. -/*
  12986. -=============
  12987. -EmitSkyPolys
  12988. -=============
  12989. -*/
  12990. -void EmitSkyPolys( msurface_t *fa )
  12991. -{
  12992. - glpoly_t *p;
  12993. - float *v;
  12994. - int i;
  12995. - float s, t;
  12996. - vec3_t dir;
  12997. - float length;
  12998. -
  12999. - for( p = fa->polys; p; p = p->next )
  13000. - {
  13001. - pglBegin( GL_POLYGON );
  13002. -
  13003. - for( i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE )
  13004. - {
  13005. - VectorSubtract( v, RI.vieworg, dir );
  13006. - dir[2] *= 3.0f; // flatten the sphere
  13007. -
  13008. - length = VectorLength( dir );
  13009. - length = 6.0f * 63.0f / length;
  13010. -
  13011. - dir[0] *= length;
  13012. - dir[1] *= length;
  13013. -
  13014. - s = ( speedscale + dir[0] ) * (1.0f / 128.0f);
  13015. - t = ( speedscale + dir[1] ) * (1.0f / 128.0f);
  13016. -
  13017. - pglTexCoord2f( s, t );
  13018. - pglVertex3fv( v );
  13019. - }
  13020. - pglEnd ();
  13021. - }
  13022. -}
  13023. -
  13024. -/*
  13025. -=================
  13026. -R_DrawSkyChain
  13027. -=================
  13028. -*/
  13029. -void R_DrawSkyChain( msurface_t *s )
  13030. -{
  13031. - msurface_t *fa;
  13032. -
  13033. - GL_SetRenderMode( kRenderNormal );
  13034. - GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
  13035. -
  13036. - speedscale = cl.time * 8.0f;
  13037. - speedscale -= (int)speedscale & ~127;
  13038. -
  13039. - for( fa = s; fa; fa = fa->texturechain )
  13040. - EmitSkyPolys( fa );
  13041. -
  13042. - GL_SetRenderMode( kRenderTransTexture );
  13043. - GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
  13044. -
  13045. - speedscale = cl.time * 16.0f;
  13046. - speedscale -= (int)speedscale & ~127;
  13047. -
  13048. - for( fa = s; fa; fa = fa->texturechain )
  13049. - EmitSkyPolys( fa );
  13050. -
  13051. - pglDisable( GL_BLEND );
  13052. -}
  13053. -
  13054. -/*
  13055. -===============
  13056. -EmitBothSkyLayers
  13057. -
  13058. -Does a sky warp on the pre-fragmented glpoly_t chain
  13059. -This will be called for brushmodels, the world
  13060. -will have them chained together.
  13061. -===============
  13062. -*/
  13063. -void EmitSkyLayers( msurface_t *fa )
  13064. -{
  13065. - GL_SetRenderMode( kRenderNormal );
  13066. - GL_Bind( GL_TEXTURE0, tr.solidskyTexture );
  13067. -
  13068. - speedscale = cl.time * 8.0f;
  13069. - speedscale -= (int)speedscale & ~127;
  13070. -
  13071. - EmitSkyPolys( fa );
  13072. -
  13073. - GL_SetRenderMode( kRenderTransTexture );
  13074. - GL_Bind( GL_TEXTURE0, tr.alphaskyTexture );
  13075. -
  13076. - speedscale = cl.time * 16.0f;
  13077. - speedscale -= (int)speedscale & ~127;
  13078. -
  13079. - EmitSkyPolys( fa );
  13080. -
  13081. - pglDisable( GL_BLEND );
  13082. }
  13083. \ No newline at end of file
  13084. diff --git b/engine/client/s_backend.c a/engine/client/s_backend.c
  13085. index 071d55d..2221c5f 100644
  13086. --- b/engine/client/s_backend.c
  13087. +++ a/engine/client/s_backend.c
  13088. @@ -361,7 +361,7 @@ int SNDDMA_Init( void *hInst )
  13089. else
  13090. {
  13091. if( snd_firsttime )
  13092. - MsgDev( D_ERROR, "SNDDMA_Init: can't initialize sound device\n" );
  13093. + MsgDev( D_ERROR, "Audio: can't initialize sound device\n" );
  13094. return false;
  13095. }
  13096.  
  13097. diff --git b/engine/client/s_dsp.c a/engine/client/s_dsp.c
  13098. index cc7e01d..efed07c 100644
  13099. --- b/engine/client/s_dsp.c
  13100. +++ a/engine/client/s_dsp.c
  13101. @@ -14,5445 +14,917 @@ GNU General Public License for more details.
  13102. */
  13103.  
  13104. #include "common.h"
  13105. +#include "client.h"
  13106. #include "sound.h"
  13107.  
  13108. -#define SIGN( d ) (( d ) < 0 ? -1 : 1 )
  13109. -#define ABS( a ) abs( a )
  13110. -#define MSEC_TO_SAMPS( a ) ((( a ) * SOUND_DMA_SPEED) / 1000 ) // convert milliseconds to # samples in equivalent time
  13111. -#define SEC_TO_SAMPS( a ) (( a ) * SOUND_DMA_SPEED) // conver seconds to # samples in equivalent time
  13112. -#define CLIP_DSP( x ) ( x )
  13113. -#define SOUND_MS_PER_FT 1 // sound travels approx 1 foot per millisecond
  13114. -#define ROOM_MAX_SIZE 1000 // max size in feet of room simulation for dsp
  13115. +#define MAX_DELAY 0.4f
  13116. +#define MAX_ROOM_TYPES ARRAYSIZE( rgsxpre )
  13117.  
  13118. -// Performance notes:
  13119. +#define MONODLY 0
  13120. +#define MAX_MONO_DELAY 0.4f
  13121.  
  13122. -// DSP processing should take no more than 3ms total time per frame to remain on par with hl1
  13123. -// Assume a min frame rate of 24fps = 42ms per frame
  13124. -// at 24fps, to maintain 44.1khz output rate, we must process about 1840 mono samples per frame.
  13125. -// So we must process 1840 samples in 3ms.
  13126. +#define REVERBPOS 1
  13127. +#define MAX_REVERB_DELAY 0.1f
  13128.  
  13129. -// on a 1Ghz CPU (mid-low end CPU) 3ms provides roughly 3,000,000 cycles.
  13130. -// Thus we have 3e6 / 1840 = 1630 cycles per sample.
  13131. +#define STEREODLY 3
  13132. +#define MAX_STEREO_DELAY 0.1f
  13133.  
  13134. -#define PBITS 12 // parameter bits
  13135. -#define PMAX ((1 << PBITS)-1) // parameter max size
  13136. +#define REVERB_XFADE 32
  13137.  
  13138. -// crossfade from y2 to y1 at point r (0 < r < PMAX )
  13139. -#define XFADE( y1, y2, r ) (((y1) * (r)) >> PBITS) + (((y2) * (PMAX - (r))) >> PBITS);
  13140. -#define XFADEF( y1, y2, r ) (((y1) * (r)) / (float)(PMAX)) + (((y2) * (PMAX - (r))) / (float)(PMAX));
  13141. +#define MAXDLY (STEREODLY + 1)
  13142. +#define MAXLP 10
  13143. +#define MAXPRESETS ARRAYSIZE( rgsxpre )
  13144.  
  13145. -/////////////////////
  13146. -// dsp helpers
  13147. -/////////////////////
  13148. -
  13149. -// dot two integer vectors of length M+1
  13150. -// M is filter order, h is filter vector, w is filter state vector
  13151. -_inline int dot ( int M, int *h, int *w )
  13152. -{
  13153. - int i, y;
  13154. -
  13155. - for( y = 0, i = 0; i <= M; i++ )
  13156. - y += ( h[i] * w[i] ) >> PBITS;
  13157. - return y;
  13158. -}
  13159. -
  13160. -// delay array w[] by D samples
  13161. -// w[0] = input, w[D] = output
  13162. -// practical for filters, but not for large values of D
  13163. -_inline void delay( int D, int *w )
  13164. -{
  13165. - int i;
  13166. -
  13167. - for( i = D; i >= 1; i-- ) // reverse order updating
  13168. - w[i] = w[i-1];
  13169. -}
  13170. -
  13171. -// circular wrap of pointer p, relative to array w
  13172. -// D delay line size in samples w[0...D]
  13173. -// w delay line buffer pointer, dimension D+1
  13174. -// p circular pointer
  13175. -_inline void wrap( int D, int *w, int **p )
  13176. -{
  13177. - if( *p > w + D ) *p -= D + 1; // when *p = w + D + 1, it wraps around to *p = w
  13178. - if( *p < w ) *p += D + 1; // when *p = w - 1, it wraps around to *p = w + D
  13179. -}
  13180. -
  13181. -// simple averaging filter for performance - a[] is 0, b[] is 1, L is # of samples to average
  13182. -_inline int avg_filter( int M, int *a, int L, int *b, int *w, int x )
  13183. -{
  13184. - int i, y = 0;
  13185. -
  13186. - w[0] = x;
  13187. -
  13188. - // output adder
  13189. - switch( L )
  13190. - {
  13191. - default:
  13192. - case 12: y += w[12];
  13193. - case 11: y += w[11];
  13194. - case 10: y += w[10];
  13195. - case 9: y += w[9];
  13196. - case 8: y += w[8];
  13197. - case 7: y += w[7];
  13198. - case 6: y += w[6];
  13199. - case 5: y += w[5];
  13200. - case 4: y += w[4];
  13201. - case 3: y += w[3];
  13202. - case 2: y += w[2];
  13203. - case 1: y += w[1];
  13204. - case 0: y += w[0];
  13205. - }
  13206. -
  13207. - for( i = L; i >= 1; i-- ) // reverse update internal state
  13208. - w[i] = w[i-1];
  13209. -
  13210. - switch( L )
  13211. - {
  13212. - default:
  13213. - case 12: return y / 13;
  13214. - case 11: return y / 12;
  13215. - case 10: return y / 11;
  13216. - case 9: return y / 10;
  13217. - case 8: return y / 9;
  13218. - case 7: return y >> 3;
  13219. - case 6: return y / 7;
  13220. - case 5: return y / 6;
  13221. - case 4: return y / 5;
  13222. - case 3: return y >> 2;
  13223. - case 2: return y / 3;
  13224. - case 1: return y >> 1;
  13225. - case 0: return y;
  13226. - }
  13227. -}
  13228. -
  13229. -// IIR filter, cannonical form
  13230. -// returns single sample y for current input value x
  13231. -// x is input sample
  13232. -// w = internal state vector, dimension max(M,L) + 1
  13233. -// L, M numerator and denominator filter orders
  13234. -// a,b are M+1 dimensional arrays of filter params
  13235. -//
  13236. -// for M = 4:
  13237. -//
  13238. -// 1 w0(n) b0
  13239. -// x(n)--->(+)--(*)-----.------(*)->(+)---> y(n)
  13240. -// ^ | ^
  13241. -// | [Delay d] |
  13242. -// | | |
  13243. -// | -a1 |W1 b1 |
  13244. -// ----(*)---.------(*)----
  13245. -// ^ | ^
  13246. -// | [Delay d] |
  13247. -// | | |
  13248. -// | -a2 |W2 b2 |
  13249. -// ----(*)---.------(*)----
  13250. -// ^ | ^
  13251. -// | [Delay d] |
  13252. -// | | |
  13253. -// | -a3 |W3 b3 |
  13254. -// ----(*)---.------(*)----
  13255. -// ^ | ^
  13256. -// | [Delay d] |
  13257. -// | | |
  13258. -// | -a4 |W4 b4 |
  13259. -// ----(*)---.------(*)----
  13260. -//
  13261. -// for each input sample x, do:
  13262. -// w0 = x - a1*w1 - a2*w2 - ... aMwM
  13263. -// y = b0*w0 + b1*w1 + ...bL*wL
  13264. -// wi = wi-1, i = K, K-1, ..., 1
  13265. -
  13266. -_inline int iir_filter( int M, int *a, int L, int *b, int *w, int x )
  13267. -{
  13268. - int K, i, y, x0;
  13269. -
  13270. - if( M == 0 )
  13271. - return avg_filter( M, a, L, b, w, x );
  13272. -
  13273. - y = 0;
  13274. - x0 = x;
  13275. -
  13276. - K = max ( M, L );
  13277. -
  13278. - // for (i = 1; i <= M; i++) // input adder
  13279. - // w[0] -= ( a[i] * w[i] ) >> PBITS;
  13280. -
  13281. - // M is clamped between 1 and FLT_M
  13282. - // change this switch statement if FLT_M changes!
  13283. -
  13284. - switch( M )
  13285. - {
  13286. - case 12: x0 -= ( a[12] * w[12] ) >> PBITS;
  13287. - case 11: x0 -= ( a[11] * w[11] ) >> PBITS;
  13288. - case 10: x0 -= ( a[10] * w[10] ) >> PBITS;
  13289. - case 9: x0 -= ( a[9] * w[9] ) >> PBITS;
  13290. - case 8: x0 -= ( a[8] * w[8] ) >> PBITS;
  13291. - case 7: x0 -= ( a[7] * w[7] ) >> PBITS;
  13292. - case 6: x0 -= ( a[6] * w[6] ) >> PBITS;
  13293. - case 5: x0 -= ( a[5] * w[5] ) >> PBITS;
  13294. - case 4: x0 -= ( a[4] * w[4] ) >> PBITS;
  13295. - case 3: x0 -= ( a[3] * w[3] ) >> PBITS;
  13296. - case 2: x0 -= ( a[2] * w[2] ) >> PBITS;
  13297. - default:
  13298. - case 1: x0 -= ( a[1] * w[1] ) >> PBITS;
  13299. - }
  13300. -
  13301. - w[0] = x0;
  13302. -
  13303. - // for( i = 0; i <= L; i++ ) // output adder
  13304. - // y += ( b[i] * w[i] ) >> PBITS;
  13305. -
  13306. - switch( L )
  13307. - {
  13308. - case 12: y += ( b[12] * w[12] ) >> PBITS;
  13309. - case 11: y += ( b[11] * w[11] ) >> PBITS;
  13310. - case 10: y += ( b[10] * w[10] ) >> PBITS;
  13311. - case 9: y += ( b[9] * w[9] ) >> PBITS;
  13312. - case 8: y += ( b[8] * w[8] ) >> PBITS;
  13313. - case 7: y += ( b[7] * w[7] ) >> PBITS;
  13314. - case 6: y += ( b[6] * w[6] ) >> PBITS;
  13315. - case 5: y += ( b[5] * w[5] ) >> PBITS;
  13316. - case 4: y += ( b[4] * w[4] ) >> PBITS;
  13317. - case 3: y += ( b[3] * w[3] ) >> PBITS;
  13318. - case 2: y += ( b[2] * w[2] ) >> PBITS;
  13319. - default:
  13320. - case 1: y += ( b[1] * w[1] ) >> PBITS;
  13321. - case 0: y += ( b[0] * w[0] ) >> PBITS;
  13322. - }
  13323. -
  13324. - for( i = K; i >= 1; i-- ) // reverse update internal state
  13325. - w[i] = w[i-1];
  13326. -
  13327. - return y; // current output sample
  13328. -}
  13329. -
  13330. -// IIR filter, cannonical form, using dot product and delay implementation
  13331. -// (may be easier to optimize this routine.)
  13332. -_inline int iir_filter2( int M, int *a, int L, int *b, int *w, int x )
  13333. -{
  13334. - int K, y;
  13335. -
  13336. - K = max( M, L ); // K = max (M, L)
  13337. - w[0] = 0; // needed for dot (M, a, w)
  13338. -
  13339. - w[0] = x - dot( M, a, w ); // input adder
  13340. - y = dot( L, b, w ); // output adder
  13341. -
  13342. - delay( K, w ); // update delay line
  13343. -
  13344. - return y; // current output sample
  13345. -}
  13346. -
  13347. -
  13348. -// fir filter - no feedback = high stability but also may be more expensive computationally
  13349. -_inline int fir_filter( int M, int *h, int *w, int x )
  13350. -{
  13351. - int i, y;
  13352. -
  13353. - w[0] = x;
  13354. -
  13355. - for( y = 0, i = 0; i <= M; i++ )
  13356. - y += h[i] * w[i];
  13357. -
  13358. - for( i = M; i >= -1; i-- )
  13359. - w[i] = w[i-1];
  13360. -
  13361. - return y;
  13362. -}
  13363. -
  13364. -// fir filter, using dot product and delay implementation
  13365. -_inline int fir_filter2( int M, int *h, int *w, int x )
  13366. -{
  13367. - int y;
  13368. -
  13369. - w[0] = x;
  13370. - y = dot( M, h, w );
  13371. - delay( M, w );
  13372. -
  13373. - return y;
  13374. -}
  13375. -
  13376. -
  13377. -// tap - i-th tap of circular delay line buffer
  13378. -// D delay line size in samples
  13379. -// w delay line buffer pointer, of dimension D+1
  13380. -// p circular pointer
  13381. -// t = 0...D
  13382. -int tap( int D, int *w, int *p, int t )
  13383. -{
  13384. - return w[(p - w + t) % (D + 1)];
  13385. -}
  13386. -
  13387. -// tapi - interpolated tap output of a delay line
  13388. -// interpolates sample between adjacent samples in delay line for 'frac' part of delay
  13389. -// D delay line size in samples
  13390. -// w delay line buffer pointer, of dimension D+1
  13391. -// p circular pointer
  13392. -// t - delay tap integer value 0...D. (complete delay is t.frac )
  13393. -// frac - varying 16 bit fractional delay value 0...32767 (normalized to 0.0 - 1.0)
  13394. -_inline int tapi( int D, int *w, int *p, int t, int frac )
  13395. -{
  13396. - int i, j;
  13397. - int si, sj;
  13398. -
  13399. - i = t; // tap value, interpolate between adjacent samples si and sj
  13400. - j = (i + 1) % (D+1); // if i = D, then j = 0; otherwise, j = i + 1
  13401. -
  13402. - si = tap( D, w, p, i ); // si(n) = x(n - i)
  13403. - sj = tap( D, w, p, j ); // sj(n) = x(n - j)
  13404. -
  13405. - return si + (((frac) * (sj - si) ) >> 16);
  13406. -}
  13407. -
  13408. -// circular delay line, D-fold delay
  13409. -// D delay line size in samples w[0..D]
  13410. -// w delay line buffer pointer, dimension D+1
  13411. -// p circular pointer
  13412. -_inline void cdelay( int D, int *w, int **p )
  13413. -{
  13414. - (*p)--; // decrement pointer and wrap modulo (D+1)
  13415. - wrap ( D, w, p ); // when *p = w-1, it wraps around to *p = w+D
  13416. -}
  13417. -
  13418. -// plain reverberator with circular delay line
  13419. -// D delay line size in samples
  13420. -// t tap from this location - <= D
  13421. -// w delay line buffer pointer of dimension D+1
  13422. -// p circular pointer, must be init to &w[0] before first call
  13423. -// a feedback value, 0-PMAX (normalized to 0.0-1.0)
  13424. -// b gain
  13425. -// x input sample
  13426. -
  13427. -// w0(n) b
  13428. -// x(n)--->(+)--------.-----(*)-> y(n)
  13429. -// ^ |
  13430. -// | [Delay d]
  13431. -// | |
  13432. -// | a |Wd(n)
  13433. -// ----(*)---.
  13434. -
  13435. -_inline int dly_plain( int D, int t, int *w, int **p, int a, int b, int x )
  13436. -{
  13437. - int y, sD;
  13438. -
  13439. - sD = tap( D, w, *p, t ); // Tth tap delay output
  13440. - y = x + (( a * sD ) >> PBITS); // filter output
  13441. - **p = y; // delay input
  13442. - cdelay( D, w, p ); // update delay line
  13443. -
  13444. - return (( y * b ) >> PBITS );
  13445. -}
  13446. -
  13447. -// straight delay line
  13448. -//
  13449. -// D delay line size in samples
  13450. -// t tap from this location - <= D
  13451. -// w delay line buffer pointer of dimension D+1
  13452. -// p circular pointer, must be init to &w[0] before first call
  13453. -// x input sample
  13454. -//
  13455. -// x(n)--->[Delay d]---> y(n)
  13456. -//
  13457. -_inline int dly_linear ( int D, int t, int *w, int **p, int x )
  13458. -{
  13459. - int y;
  13460. -
  13461. - y = tap( D, w, *p, t ); // Tth tap delay output
  13462. - **p = x; // delay input
  13463. - cdelay( D, w, p ); // update delay line
  13464. -
  13465. - return y;
  13466. -}
  13467. -
  13468. -// lowpass reverberator, replace feedback multiplier 'a' in
  13469. -// plain reverberator with a low pass filter
  13470. -// D delay line size in samples
  13471. -// t tap from this location - <= D
  13472. -// w delay line buffer pointer of dimension D+1
  13473. -// p circular pointer, must be init to &w[0] before first call
  13474. -// a feedback gain
  13475. -// b output gain
  13476. -// M filter order
  13477. -// bf filter numerator, 0-PMAX (normalized to 0.0-1.0), M+1 dimensional
  13478. -// af filter denominator, 0-PMAX (normalized to 0.0-1.0), M+1 dimensional
  13479. -// vf filter state, M+1 dimensional
  13480. -// x input sample
  13481. -// w0(n) b
  13482. -// x(n)--->(+)--------------.----(*)--> y(n)
  13483. -// ^ |
  13484. -// | [Delay d]
  13485. -// | |
  13486. -// | a |Wd(n)
  13487. -// --(*)--[Filter])-
  13488. -
  13489. -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 )
  13490. -{
  13491. - int y, sD;
  13492. -
  13493. - sD = tap( D, w, *p, t ); // delay output is filter input
  13494. - y = x + ((iir_filter ( M, af, L, bf, vf, sD ) * a) >> PBITS); // filter output with gain
  13495. - **p = y; // delay input
  13496. - cdelay( D, w, p ); // update delay line
  13497. -
  13498. - return (( y * b ) >> PBITS ); // output with gain
  13499. -}
  13500. -
  13501. -// allpass reverberator with circular delay line
  13502. -// D delay line size in samples
  13503. -// t tap from this location - <= D
  13504. -// w delay line buffer pointer of dimension D+1
  13505. -// p circular pointer, must be init to &w[0] before first call
  13506. -// a feedback value, 0-PMAX (normalized to 0.0-1.0)
  13507. -// b gain
  13508. -
  13509. -// w0(n) -a b
  13510. -// x(n)--->(+)--------.-----(*)-->(+)--(*)-> y(n)
  13511. -// ^ | ^
  13512. -// | [Delay d] |
  13513. -// | | |
  13514. -// | a |Wd(n) |
  13515. -// ----(*)---.-------------
  13516. -//
  13517. -// for each input sample x, do:
  13518. -// w0 = x + a*Wd
  13519. -// y = -a*w0 + Wd
  13520. -// delay (d, W) - w is the delay buffer array
  13521. -//
  13522. -// or, using circular delay, for each input sample x do:
  13523. -//
  13524. -// Sd = tap (D,w,p,D)
  13525. -// S0 = x + a*Sd
  13526. -// y = -a*S0 + Sd
  13527. -// *p = S0
  13528. -// cdelay(D, w, &p)
  13529. -
  13530. -_inline int dly_allpass( int D, int t, int *w, int **p, int a, int b, int x )
  13531. -{
  13532. - int y, s0, sD;
  13533. -
  13534. - sD = tap( D, w, *p, t ); // Dth tap delay output
  13535. - s0 = x + (( a * sD ) >> PBITS);
  13536. -
  13537. - y = (( -a * s0 ) >> PBITS ) + sD; // filter output
  13538. - **p = s0; // delay input
  13539. - cdelay( D, w, p ); // update delay line
  13540. -
  13541. - return (( y * b ) >> PBITS );
  13542. -}
  13543. -
  13544. -
  13545. -///////////////////////////////////////////////////////////////////////////////////
  13546. -// fixed point math for real-time wave table traversing, pitch shifting, resampling
  13547. -///////////////////////////////////////////////////////////////////////////////////
  13548. -#define FIX20_BITS 20 // 20 bits of fractional part
  13549. -#define FIX20_SCALE (1 << FIX20_BITS)
  13550. -#define FIX20_INTMAX ((1 << (32 - FIX20_BITS))-1) // maximum step integer
  13551. -#define FLOAT_TO_FIX20(a) ((int)((a) * (float)FIX20_SCALE)) // convert float to fixed point
  13552. -#define INT_TO_FIX20(a) (((int)(a)) << FIX20_BITS) // convert int to fixed point
  13553. -#define FIX20_TO_FLOAT(a) ((float)(a) / (float)FIX20_SCALE) // convert fix20 to float
  13554. -#define FIX20_INTPART(a) (((int)(a)) >> FIX20_BITS) // get integer part of fixed point
  13555. -#define FIX20_FRACPART(a) ((a) - (((a) >> FIX20_BITS) << FIX20_BITS)) // get fractional part of fixed point
  13556. -#define FIX20_FRACTION(a,b) (FIX(a)/(b)) // convert int a to fixed point, divide by b
  13557. -
  13558. -typedef int fix20int;
  13559. -
  13560. -/////////////////////////////////
  13561. -// DSP processor parameter block
  13562. -/////////////////////////////////
  13563. -
  13564. -// NOTE: these prototypes must match the XXX_Params ( prc_t *pprc ) and XXX_GetNext ( XXX_t *p, int x ) functions
  13565. -
  13566. -typedef void * (*prc_Param_t)( void *pprc ); // individual processor allocation functions
  13567. -typedef int (*prc_GetNext_t)( void *pdata, int x ); // get next function for processor
  13568. -typedef int (*prc_GetNextN_t)( void *pdata, portable_samplepair_t *pbuffer, int SampleCount, int op); // batch version of getnext
  13569. -typedef void (*prc_Free_t)( void *pdata ); // free function for processor
  13570. -typedef void (*prc_Mod_t)(void *pdata, float v); // modulation function for processor
  13571. -
  13572. -#define OP_LEFT 0 // batch process left channel in place
  13573. -#define OP_RIGHT 1 // batch process right channel in place
  13574. -#define OP_LEFT_DUPLICATE 2 // batch process left channel in place, duplicate to right channel
  13575. -
  13576. -#define PRC_NULL 0 // pass through - must be 0
  13577. -#define PRC_DLY 1 // simple feedback reverb
  13578. -#define PRC_RVA 2 // parallel reverbs
  13579. -#define PRC_FLT 3 // lowpass or highpass filter
  13580. -#define PRC_CRS 4 // chorus
  13581. -#define PRC_PTC 5 // pitch shifter
  13582. -#define PRC_ENV 6 // adsr envelope
  13583. -#define PRC_LFO 7 // lfo
  13584. -#define PRC_EFO 8 // envelope follower
  13585. -#define PRC_MDY 9 // mod delay
  13586. -#define PRC_DFR 10 // diffusor - n series allpass delays
  13587. -#define PRC_AMP 11 // amplifier with distortion
  13588. -
  13589. -#define QUA_LO 0 // quality of filter or reverb. Must be 0,1,2,3.
  13590. -#define QUA_MED 1
  13591. -#define QUA_HI 2
  13592. -#define QUA_VHI 3
  13593. -#define QUA_MAX QUA_VHI
  13594. -
  13595. -#define CPRCPARAMS 16 // up to 16 floating point params for each processor type
  13596. -
  13597. -// processor definition - one for each running instance of a dsp processor
  13598. -typedef struct
  13599. -{
  13600. - int type; // PRC type
  13601. -
  13602. - float prm[CPRCPARAMS]; // dsp processor parameters - array of floats
  13603. -
  13604. - prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  13605. - prc_GetNext_t pfnGetNext; // get next function
  13606. - prc_GetNextN_t pfnGetNextN; // batch version of get next
  13607. - prc_Free_t pfnFree; // free function
  13608. - prc_Mod_t pfnMod; // modulation function
  13609. -
  13610. - void *pdata; // processor state data - ie: pdly, pflt etc.
  13611. -} prc_t;
  13612. -
  13613. -// processor parameter ranges - for validating parameters during allocation of new processor
  13614. -typedef struct prm_rng_s
  13615. -{
  13616. - int iprm; // parameter index
  13617. - float lo; // min value of parameter
  13618. - float hi; // max value of parameter
  13619. -} prm_rng_t;
  13620. -
  13621. -void PRC_CheckParams( prc_t *pprc, prm_rng_t *prng );
  13622. -
  13623. -///////////
  13624. -// Filters
  13625. -///////////
  13626. -
  13627. -#define CFLTS 64 // max number of filters simultaneously active
  13628. -#define FLT_M 12 // max order of any filter
  13629. -
  13630. -#define FLT_LP 0 // lowpass filter
  13631. -#define FLT_HP 1 // highpass filter
  13632. -#define FTR_MAX FLT_HP
  13633. -
  13634. -// flt parameters
  13635. -
  13636. -typedef struct
  13637. -{
  13638. - qboolean fused; // true if slot in use
  13639. -
  13640. - int b[FLT_M+1]; // filter numerator parameters (convert 0.0-1.0 to 0-PMAX representation)
  13641. - int a[FLT_M+1]; // filter denominator parameters (convert 0.0-1.0 to 0-PMAX representation)
  13642. - int w[FLT_M+1]; // filter state - samples (dimension of max (M, L))
  13643. - int L; // filter order numerator (dimension of a[M+1])
  13644. - int M; // filter order denominator (dimension of b[L+1])
  13645. -} flt_t;
  13646. -
  13647. -// flt flts
  13648. -flt_t flts[CFLTS];
  13649. -
  13650. -void FLT_Init( flt_t *pf ) { if( pf ) memset( pf, 0, sizeof( flt_t )); }
  13651. -void FLT_InitAll( void ) { int i; for( i = 0; i < CFLTS; i++ ) FLT_Init( &flts[i] ); }
  13652. -void FLT_Free( flt_t *pf ) { if( pf ) memset( pf, 0, sizeof( flt_t )); }
  13653. -void FLT_FreeAll( void ) { int i; for( i = 0; i < CFLTS; i++ ) FLT_Free( &flts[i] ); }
  13654. -
  13655. -
  13656. -// find a free filter from the filter pool
  13657. -// initialize filter numerator, denominator b[0..M], a[0..L]
  13658. -flt_t * FLT_Alloc( int M, int L, int *a, int *b )
  13659. -{
  13660. - int i, j;
  13661. - flt_t *pf = NULL;
  13662. -
  13663. - for( i = 0; i < CFLTS; i++ )
  13664. - {
  13665. - if( !flts[i].fused )
  13666. - {
  13667. - pf = &flts[i];
  13668. -
  13669. - // transfer filter params into filter struct
  13670. - pf->M = M;
  13671. - pf->L = L;
  13672. - for( j = 0; j <= M; j++ )
  13673. - pf->a[j] = a[j];
  13674. -
  13675. - for( j = 0; j <= L; j++ )
  13676. - pf->b[j] = b[j];
  13677. -
  13678. - pf->fused = true;
  13679. - break;
  13680. - }
  13681. - }
  13682. -
  13683. - ASSERT( pf ); // make sure we're not trying to alloc more than CFLTS flts
  13684. -
  13685. - return pf;
  13686. -}
  13687. -
  13688. -// convert filter params cutoff and type into
  13689. -// iir transfer function params M, L, a[], b[]
  13690. -// iir filter, 1st order, transfer function is H(z) = b0 + b1 Z^-1 / a0 + a1 Z^-1
  13691. -// or H(z) = b0 - b1 Z^-1 / a0 + a1 Z^-1 for lowpass
  13692. -// design cutoff filter at 3db (.5 gain) p579
  13693. -void FLT_Design_3db_IIR( float cutoff, float ftype, int *pM, int *pL, int *a, int *b )
  13694. -{
  13695. - // ftype: FLT_LP, FLT_HP, FLT_BP
  13696. -
  13697. - double Wc = M_PI2 * cutoff / SOUND_DMA_SPEED; // radians per sample
  13698. - double Oc;
  13699. - double fa;
  13700. - double fb;
  13701. -
  13702. - // calculations:
  13703. - // Wc = 2pi * fc/44100 convert to radians
  13704. - // Oc = tan (Wc/2) * Gc / sqt ( 1 - Gc^2) get analog version, low pass
  13705. - // Oc = tan (Wc/2) * (sqt (1 - Gc^2)) / Gc analog version, high pass
  13706. - // Gc = 10 ^ (-Ac/20) gain at cutoff. Ac = 3db, so Gc^2 = 0.5
  13707. - // a = ( 1 - Oc ) / ( 1 + Oc )
  13708. - // b = ( 1 - a ) / 2
  13709. -
  13710. - Oc = tan( Wc / 2.0 );
  13711. -
  13712. - fa = ( 1.0 - Oc ) / ( 1.0 + Oc );
  13713. -
  13714. - fb = ( 1.0 - fa ) / 2.0;
  13715. -
  13716. - if( ftype == FLT_HP )
  13717. - fb = ( 1.0 + fa ) / 2.0;
  13718. -
  13719. - a[0] = 0; // a0 always ignored
  13720. - a[1] = (int)( -fa * PMAX ); // quantize params down to 0-PMAX >> PBITS
  13721. - b[0] = (int)( fb * PMAX );
  13722. - b[1] = b[0];
  13723. -
  13724. - if( ftype == FLT_HP )
  13725. - b[1] = -b[1];
  13726. -
  13727. - *pM = *pL = 1;
  13728. -}
  13729. -
  13730. -
  13731. -// convolution of x[n] with h[n], resulting in y[n]
  13732. -// h, x, y filter, input and output arrays (double precision)
  13733. -// M = filter order, L = input length
  13734. -// h is M+1 dimensional
  13735. -// x is L dimensional
  13736. -// y is L+M dimensional
  13737. -void conv( int M, double *h, int L, double *x, double *y )
  13738. -{
  13739. - int n, m;
  13740. -
  13741. - for( n = 0; n < L+M; n++ )
  13742. - {
  13743. - for( y[n] = 0, m = max(0, n-L+1); m <= min(n, M); m++ )
  13744. - {
  13745. - y[n] += h[m] * x[n-m];
  13746. - }
  13747. - }
  13748. -}
  13749. -
  13750. -// cas2can - convert cascaded, second order section parameter arrays to
  13751. -// canonical numerator/denominator arrays. Canonical implementations
  13752. -// have half as many multiplies as cascaded implementations.
  13753. -
  13754. -// K is number of cascaded sections
  13755. -// A is Kx3 matrix of sos params A[K] = A[0]..A[K-1]
  13756. -// a is (2K + 1) -dimensional output of canonical params
  13757. -
  13758. -#define KMAX 32 // max # of sos sections - 8 is the most we should ever see at runtime
  13759. -
  13760. -void cas2can( int K, double A[KMAX+1][3], int *aout )
  13761. -{
  13762. - int i, j;
  13763. - double d[2*KMAX + 1];
  13764. - double a[2*KMAX + 1];
  13765. -
  13766. - ASSERT( K <= KMAX );
  13767. -
  13768. - memset( d, 0, sizeof( double ) * ( 2 * KMAX + 1 ));
  13769. - memset( a, 0, sizeof( double ) * ( 2 * KMAX + 1 ));
  13770. -
  13771. - a[0] = 1;
  13772. -
  13773. - for( i = 0; i < K; i++ )
  13774. - {
  13775. - conv( 2, A[i], 2 * i + 1, a, d );
  13776. -
  13777. - for( j = 0; j < 2 * i + 3; j++ )
  13778. - a[j] = d[j];
  13779. - }
  13780. -
  13781. - for( i = 0; i < (2*K + 1); i++ )
  13782. - aout[i] = a[i] * PMAX;
  13783. -}
  13784. -
  13785. -
  13786. -// chebyshev IIR design, type 2, Lowpass or Highpass
  13787. -
  13788. -#define lnf( e ) ( 2.303 * log10( e ))
  13789. -#define acosh( e ) ( lnf( (e) + sqrt(( e ) * ( e ) - 1) ))
  13790. -#define asinh( e ) ( lnf( (e) + sqrt(( e ) * ( e ) + 1) ))
  13791. -
  13792. -
  13793. -// returns a[], b[] which are Kx3 matrices of cascaded second-order sections
  13794. -// these matrices may be passed directly to the iir_cas() routine for evaluation
  13795. -// Nmax - maximum order of filter
  13796. -// cutoff, ftype, qwidth - filter cutoff in hz, filter type FLT_LOWPASS/HIGHPASS, qwidth in hz
  13797. -// pM - denominator order
  13798. -// pL - numerator order
  13799. -// a - array of canonical filter params
  13800. -// b - array of canonical filter params
  13801. -void FLT_Design_Cheb( int Nmax, float cutoff, float ftype, float qwidth, int *pM, int *pL, int *a, int *b )
  13802. -{
  13803. -// p769 - converted from MATLAB
  13804. -
  13805. - double s = (ftype == FLT_LP ? 1 : -1 ); // 1 for LP, -1 for HP
  13806. - double fs = SOUND_DMA_SPEED; // sampling frequency
  13807. - double fpass = cutoff; // cutoff frequency
  13808. - double fstop = fpass + max (2000, qwidth); // stop frequency
  13809. - double Apass = 0.5; // max attenuation of pass band UNDONE: use Quality to select this
  13810. - double Astop = 10; // max amplitude of stop band UNDONE: use Quality to select this
  13811. -
  13812. - double Wpass, Wstop, epass, estop, Nex, aa;
  13813. - double W3, f3, W0, G, Wi2, W02, a1, a2, th, Wi, D, b1;
  13814. - int i, K, r, N;
  13815. - double A[KMAX+1][3]; // denominator output matrices, second order sections
  13816. - double B[KMAX+1][3]; // numerator output matrices, second order sections
  13817. -
  13818. - Wpass = tan( M_PI * fpass / fs );
  13819. - Wpass = pow( Wpass, s );
  13820. - Wstop = tan( M_PI * fstop / fs );
  13821. - Wstop = pow( Wstop, s );
  13822. -
  13823. - epass = sqrt( pow( (float)10.0f, (float)Apass/10.0f ) - 1 );
  13824. - estop = sqrt( pow( (float)10.0f, (float)Astop/10.0f ) - 1 );
  13825. -
  13826. - // calculate filter order N
  13827. -
  13828. - Nex = acosh( estop/epass ) / acosh ( Wstop/Wpass );
  13829. - N = min ( ceil(Nex), Nmax ); // don't exceed Nmax for filter order
  13830. - r = ( (int)N & 1); // r == 1 if N is odd
  13831. - K = (N - r ) / 2;
  13832. -
  13833. - aa = asinh ( estop ) / N;
  13834. - W3 = Wstop / cosh( acosh( estop ) / N );
  13835. - f3 = (fs / M_PI) * atan( pow( W3, s ));
  13836. -
  13837. - W0 = sinh( aa ) / Wstop;
  13838. - W02 = W0 * W0;
  13839. -
  13840. - // 1st order section for N odd
  13841. - if( r == 1 )
  13842. - {
  13843. - G = 1 / (1 + W0);
  13844. - A[0][0] = 1; A[0][1] = s * (2*G-1); A[0][2] = 0;
  13845. - B[0][0] = G; B[0][1] = G * s; B[0][2] = 0;
  13846. - }
  13847. - else
  13848. - {
  13849. - A[0][0] = 1; A[0][1] = 0; A[0][2] = 0;
  13850. - B[0][0] = 1; B[0][1] = 0; B[0][2] = 0;
  13851. - }
  13852. -
  13853. - for( i = 1; i <= K ; i++ )
  13854. - {
  13855. - th = M_PI * (N - 1 + 2 * i) / (2 * N);
  13856. - Wi = sin( th ) / Wstop;
  13857. - Wi2 = Wi * Wi;
  13858. -
  13859. - D = 1 - 2 * W0 * cos( th ) + W02 + Wi2;
  13860. - G = ( 1 + Wi2 ) / D;
  13861. -
  13862. - b1 = 2 * ( 1 - Wi2 ) / ( 1 + Wi2 );
  13863. - a1 = 2 * ( 1 - W02 - Wi2) / D;
  13864. - a2 = ( 1 + 2 * W0 * cos( th ) + W02 + Wi2) / D;
  13865. -
  13866. - A[i][0] = 1;
  13867. - A[i][1] = s * a1;
  13868. - A[i][2] = a2;
  13869. -
  13870. - B[i][0] = G;
  13871. - B[i][1] = G* s* b1;
  13872. - B[i][2] = G;
  13873. - }
  13874. -
  13875. - // convert cascade parameters to canonical parameters
  13876. -
  13877. - cas2can( K, A, a );
  13878. - *pM = 2*K + 1;
  13879. -
  13880. - cas2can( K, B, b );
  13881. - *pL = 2*K + 1;
  13882. -}
  13883. -
  13884. -// filter parameter order
  13885. -
  13886. -typedef enum
  13887. -{
  13888. - flt_iftype,
  13889. - flt_icutoff,
  13890. - flt_iqwidth,
  13891. - flt_iquality,
  13892. -
  13893. - flt_cparam // # of params
  13894. -} flt_e;
  13895. -
  13896. -// filter parameter ranges
  13897. -
  13898. -prm_rng_t flt_rng[] =
  13899. -{
  13900. -{ flt_cparam, 0, 0 }, // first entry is # of parameters
  13901. -{ flt_iftype, 0, FTR_MAX }, // filter type FLT_LP, FLT_HP, FLT_BP (UNDONE: FLT_BP currently ignored)
  13902. -{ flt_icutoff, 10, 22050 }, // cutoff frequency in hz at -3db gain
  13903. -{ flt_iqwidth, 100, 11025 }, // width of BP, or steepness of LP/HP (ie: fcutoff + qwidth = -60db gain point)
  13904. -{ flt_iquality, 0, QUA_MAX }, // QUA_LO, _MED, _HI 0,1,2,3
  13905. -};
  13906. -
  13907. -
  13908. -// convert prc float params to iir filter params, alloc filter and return ptr to it
  13909. -// filter quality set by prc quality - 0,1,2
  13910. -flt_t * FLT_Params ( prc_t *pprc )
  13911. -{
  13912. - float qual = pprc->prm[flt_iquality];
  13913. - float cutoff = pprc->prm[flt_icutoff];
  13914. - float ftype = pprc->prm[flt_iftype];
  13915. - float qwidth = pprc->prm[flt_iqwidth];
  13916. -
  13917. - int L = 0; // numerator order
  13918. - int M = 0; // denominator order
  13919. - int b[FLT_M+1]; // numerator params 0..PMAX
  13920. - int a[FLT_M+1]; // denominator params 0..PMAX
  13921. -
  13922. - // low pass and highpass filter design
  13923. -
  13924. - if( (int)qual == QUA_LO )
  13925. - qual = QUA_MED; // disable lowest quality filter - check perf on lowend KDB
  13926. -
  13927. - switch ( (int)qual )
  13928. - {
  13929. - case QUA_LO:
  13930. - // lowpass averaging filter: perf KDB
  13931. - ASSERT( ftype == FLT_LP );
  13932. - ASSERT( cutoff <= SOUND_DMA_SPEED );
  13933. - M = 0;
  13934. -
  13935. - // L is # of samples to average
  13936. -
  13937. - L = 0;
  13938. - if( cutoff <= SOUND_DMA_SPEED / 4 ) L = 1; // 11k
  13939. - if( cutoff <= SOUND_DMA_SPEED / 8 ) L = 2; // 5.5k
  13940. - if( cutoff <= SOUND_DMA_SPEED / 16 ) L = 4; // 2.75k
  13941. - if( cutoff <= SOUND_DMA_SPEED / 32 ) L = 8; // 1.35k
  13942. - if( cutoff <= SOUND_DMA_SPEED / 64 ) L = 12; // 750hz
  13943. -
  13944. - break;
  13945. - case QUA_MED:
  13946. - // 1st order IIR filter, 3db cutoff at fc
  13947. - FLT_Design_3db_IIR( cutoff, ftype, &M, &L, a, b );
  13948. -
  13949. - M = bound( 1, M, FLT_M );
  13950. - L = bound( 1, L, FLT_M );
  13951. - break;
  13952. - case QUA_HI:
  13953. - // type 2 chebyshev N = 4 IIR
  13954. - FLT_Design_Cheb( 4, cutoff, ftype, qwidth, &M, &L, a, b );
  13955. -
  13956. - M = bound( 1, M, FLT_M );
  13957. - L = bound( 1, L, FLT_M );
  13958. - break;
  13959. - case QUA_VHI:
  13960. - // type 2 chebyshev N = 7 IIR
  13961. - FLT_Design_Cheb( 8, cutoff, ftype, qwidth, &M, &L, a, b );
  13962. -
  13963. - M = bound( 1, M, FLT_M );
  13964. - L = bound( 1, L, FLT_M );
  13965. - break;
  13966. - }
  13967. -
  13968. - return FLT_Alloc( M, L, a, b );
  13969. -}
  13970. -
  13971. -_inline void * FLT_VParams( void *p )
  13972. -{
  13973. - PRC_CheckParams(( prc_t *)p, flt_rng );
  13974. - return (void *)FLT_Params ((prc_t *)p);
  13975. -}
  13976. -
  13977. -_inline void FLT_Mod( void *p, float v )
  13978. -{
  13979. -}
  13980. -
  13981. -// get next filter value for filter pf and input x
  13982. -_inline int FLT_GetNext( flt_t *pf, int x )
  13983. -{
  13984. - return iir_filter( pf->M, pf->a, pf->L, pf->b, pf->w, x );
  13985. -}
  13986. -
  13987. -// batch version for performance
  13988. -_inline void FLT_GetNextN( flt_t *pflt, portable_samplepair_t *pbuffer, int SampleCount, int op )
  13989. -{
  13990. - int count = SampleCount;
  13991. - portable_samplepair_t *pb = pbuffer;
  13992. -
  13993. - switch( op )
  13994. - {
  13995. - default:
  13996. - case OP_LEFT:
  13997. - while( count-- )
  13998. - {
  13999. - pb->left = FLT_GetNext( pflt, pb->left );
  14000. - pb++;
  14001. - }
  14002. - break;
  14003. - case OP_RIGHT:
  14004. - while( count-- )
  14005. - {
  14006. - pb->right = FLT_GetNext( pflt, pb->right );
  14007. - pb++;
  14008. - }
  14009. - break;
  14010. - case OP_LEFT_DUPLICATE:
  14011. - while( count-- )
  14012. - {
  14013. - pb->left = pb->right = FLT_GetNext( pflt, pb->left );
  14014. - pb++;
  14015. - }
  14016. - break;
  14017. - }
  14018. -}
  14019. -
  14020. -///////////////////////////////////////////////////////////////////////////
  14021. -// Positional updaters for pitch shift etc
  14022. -///////////////////////////////////////////////////////////////////////////
  14023. -
  14024. -// looping position within a wav, with integer and fractional parts
  14025. -// used for pitch shifting, upsampling/downsampling
  14026. -// 20 bits of fraction, 8+ bits of integer
  14027. -typedef struct
  14028. -{
  14029. -
  14030. - fix20int step; // wave table whole and fractional step value
  14031. - fix20int cstep; // current cummulative step value
  14032. - int pos; // current position within wav table
  14033. -
  14034. - int D; // max dimension of array w[0...D] ie: # of samples = D+1
  14035. -} pos_t;
  14036. -
  14037. -// circular wrap of pointer p, relative to array w
  14038. -// D max buffer index w[0...D] (count of samples in buffer is D+1)
  14039. -// i circular index
  14040. -_inline void POS_Wrap( int D, int *i )
  14041. -{
  14042. - if( *i > D ) *i -= D + 1; // when *pi = D + 1, it wraps around to *pi = 0
  14043. - if( *i < 0 ) *i += D + 1; // when *pi = - 1, it wraps around to *pi = D
  14044. -}
  14045. -
  14046. -// set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  14047. -// D is array max dimension w[0...D] (ie: size D+1)
  14048. -// w is ptr to array
  14049. -// p is ptr to pos_t to initialize
  14050. -_inline void POS_Init( pos_t *p, int D, float fstep )
  14051. -{
  14052. - float step = fstep;
  14053. -
  14054. - // make sure int part of step is capped at fix20_intmax
  14055. -
  14056. - if( (int)step > FIX20_INTMAX )
  14057. - step = (step - (int)step) + FIX20_INTMAX;
  14058. -
  14059. - p->step = FLOAT_TO_FIX20( step ); // convert fstep to fixed point
  14060. - p->cstep = 0;
  14061. - p->pos = 0; // current update value
  14062. - p->D = D; // always init to end value, in case we're stepping backwards
  14063. -}
  14064. -
  14065. -// change step value - this is an instantaneous change, not smoothed.
  14066. -_inline void POS_ChangeVal( pos_t *p, float fstepnew )
  14067. -{
  14068. - p->step = FLOAT_TO_FIX20( fstepnew ); // convert fstep to fixed point
  14069. -}
  14070. -
  14071. -// return current integer position, then update internal position value
  14072. -_inline int POS_GetNext ( pos_t *p )
  14073. -{
  14074. - // float f = FIX20_TO_FLOAT( p->cstep );
  14075. - // int i1 = FIX20_INTPART( p->cstep );
  14076. - // float f1 = FIX20_TO_FLOAT( FIX20_FRACPART( p->cstep ));
  14077. - // float f2 = FIX20_TO_FLOAT( p->step );
  14078. -
  14079. - p->cstep += p->step; // update accumulated fraction step value (fixed point)
  14080. - p->pos += FIX20_INTPART( p->cstep ); // update pos with integer part of accumulated step
  14081. - p->cstep = FIX20_FRACPART( p->cstep ); // throw away the integer part of accumulated step
  14082. -
  14083. - // wrap pos around either end of buffer if needed
  14084. - POS_Wrap( p->D, &( p->pos ));
  14085. -
  14086. - // make sure returned position is within array bounds
  14087. - ASSERT( p->pos <= p->D );
  14088. -
  14089. - return p->pos;
  14090. -}
  14091. -
  14092. -// oneshot position within wav
  14093. -typedef struct
  14094. -{
  14095. - pos_t p; // pos_t
  14096. - qboolean fhitend; // flag indicating we hit end of oneshot wav
  14097. -} pos_one_t;
  14098. -
  14099. -// set initial update value - fstep can have no more than 8 bits of integer and 20 bits of fract
  14100. -// one shot position - play only once, don't wrap, when hit end of buffer, return last position
  14101. -_inline void POS_ONE_Init( pos_one_t *p1, int D, float fstep )
  14102. -{
  14103. - POS_Init( &p1->p, D, fstep ) ;
  14104. -
  14105. - p1->fhitend = false;
  14106. -}
  14107. -
  14108. -// return current integer position, then update internal position value
  14109. -_inline int POS_ONE_GetNext( pos_one_t *p1 )
  14110. -{
  14111. - int pos;
  14112. - pos_t *p0;
  14113. -
  14114. - pos = p1->p.pos; // return current position
  14115. -
  14116. - if( p1->fhitend )
  14117. - return pos;
  14118. -
  14119. - p0 = &(p1->p);
  14120. - p0->cstep += p0->step; // update accumulated fraction step value (fixed point)
  14121. - p0->pos += FIX20_INTPART( p0->cstep ); // update pos with integer part of accumulated step
  14122. - //p0->cstep = SIGN(p0->cstep) * FIX20_FRACPART( p0->cstep );
  14123. - p0->cstep = FIX20_FRACPART( p0->cstep ); // throw away the integer part of accumulated step
  14124. -
  14125. - // if we wrapped, stop updating, always return last position
  14126. - // if step value is 0, return hit end
  14127. -
  14128. - if( !p0->step || p0->pos < 0 || p0->pos >= p0->D )
  14129. - p1->fhitend = true;
  14130. - else pos = p0->pos;
  14131. -
  14132. - // make sure returned value is within array bounds
  14133. - ASSERT( pos <= p0->D );
  14134. -
  14135. - return pos;
  14136. -}
  14137. -
  14138. -/////////////////////
  14139. -// Reverbs and delays
  14140. -/////////////////////
  14141. -#define CDLYS 128 // max delay lines active. Also used for lfos.
  14142. -
  14143. -#define DLY_PLAIN 0 // single feedback loop
  14144. -#define DLY_ALLPASS 1 // feedback and feedforward loop - flat frequency response (diffusor)
  14145. -#define DLY_LOWPASS 2 // lowpass filter in feedback loop
  14146. -#define DLY_LINEAR 3 // linear delay, no feedback, unity gain
  14147. -#define DLY_MAX DLY_LINEAR
  14148. -
  14149. -// delay line
  14150. -typedef struct
  14151. -{
  14152. - qboolean fused; // true if dly is in use
  14153. - int type; // delay type
  14154. - int D; // delay size, in samples
  14155. - int t; // current tap, <= D
  14156. - int D0; // original delay size (only relevant if calling DLY_ChangeVal)
  14157. - int *p; // circular buffer pointer
  14158. - int *w; // array of samples
  14159. - int a; // feedback value 0..PMAX,normalized to 0-1.0
  14160. - int b; // gain value 0..PMAX, normalized to 0-1.0
  14161. - flt_t *pflt; // pointer to filter, if type DLY_LOWPASS
  14162. - HANDLE h; // memory handle for sample array
  14163. -} dly_t;
  14164. -
  14165. -dly_t dlys[CDLYS]; // delay lines
  14166. -
  14167. -void DLY_Init( dly_t *pdly ) { if( pdly ) memset( pdly, 0, sizeof( dly_t )); }
  14168. -void DLY_InitAll( void ) { int i; for( i = 0; i < CDLYS; i++ ) DLY_Init( &dlys[i] ); }
  14169. -void DLY_Free( dly_t *pdly )
  14170. -{
  14171. - // free memory buffer
  14172. - if( pdly )
  14173. - {
  14174. - FLT_Free( pdly->pflt );
  14175. -
  14176. - if( pdly->w )
  14177. - {
  14178. - GlobalUnlock( pdly->h );
  14179. - GlobalFree( pdly->h );
  14180. - }
  14181. -
  14182. - // free dly slot
  14183. - memset( pdly, 0, sizeof( dly_t ));
  14184. - }
  14185. -}
  14186. -
  14187. -
  14188. -void DLY_FreeAll( void ) { int i; for( i = 0; i < CDLYS; i++ ) DLY_Free( &dlys[i] ); }
  14189. -
  14190. -// set up 'b' gain parameter of feedback delay to
  14191. -// compensate for gain caused by feedback.
  14192. -void DLY_SetNormalizingGain( dly_t *pdly )
  14193. -{
  14194. - // compute normalized gain, set as output gain
  14195. -
  14196. - // calculate gain of delay line with feedback, and use it to
  14197. - // reduce output. ie: force delay line with feedback to unity gain
  14198. -
  14199. - // for constant input x with feedback fb:
  14200. -
  14201. - // out = x + x*fb + x * fb^2 + x * fb^3...
  14202. - // gain = out/x
  14203. - // so gain = 1 + fb + fb^2 + fb^3...
  14204. - // which, by the miracle of geometric series, equates to 1/1-fb
  14205. - // thus, gain = 1/(1-fb)
  14206. -
  14207. - float fgain = 0;
  14208. - float gain;
  14209. - int b;
  14210. -
  14211. - // if b is 0, set b to PMAX (1)
  14212. - b = pdly->b ? pdly->b : PMAX;
  14213. -
  14214. - // fgain = b * (1.0 / (1.0 - (float)pdly->a / (float)PMAX)) / (float)PMAX;
  14215. - fgain = (1.0 / (1.0 - (float)pdly->a / (float)PMAX ));
  14216. -
  14217. - // compensating gain - multiply rva output by gain then >> PBITS
  14218. - gain = (int)((1.0 / fgain) * PMAX);
  14219. -
  14220. - gain = gain * 4; // compensate for fact that gain calculation is for +/- 32767 amplitude wavs
  14221. - // ie: ok to allow a bit more gain because most wavs are not at theoretical peak amplitude at all times
  14222. -
  14223. - gain = min( gain, PMAX ); // cap at PMAX
  14224. - gain = ((float)b/(float)PMAX) * gain; // scale final gain by pdly->b.
  14225. -
  14226. - pdly->b = (int)gain;
  14227. -}
  14228. -
  14229. -// allocate a new delay line
  14230. -// D number of samples to delay
  14231. -// a feedback value (0-PMAX normalized to 0.0-1.0)
  14232. -// b gain value (0-PMAX normalized to 0.0-1.0)
  14233. -// if DLY_LOWPASS:
  14234. -// L - numerator order of filter
  14235. -// M - denominator order of filter
  14236. -// fb - numerator params, M+1
  14237. -// fa - denominator params, L+1
  14238. -
  14239. -dly_t * DLY_AllocLP( int D, int a, int b, int type, int M, int L, int *fa, int *fb )
  14240. -{
  14241. - HANDLE h;
  14242. - int cb;
  14243. - int *w;
  14244. - int i;
  14245. - dly_t *pdly = NULL;
  14246. -
  14247. - // find open slot
  14248. - for( i = 0; i < CDLYS; i++ )
  14249. - {
  14250. - if( !dlys[i].fused )
  14251. - {
  14252. - pdly = &dlys[i];
  14253. - DLY_Init( pdly );
  14254. - break;
  14255. - }
  14256. - }
  14257. -
  14258. - if( i == CDLYS )
  14259. - {
  14260. - MsgDev( D_WARN, "DSP: failed to allocate delay line.\n" );
  14261. - return NULL; // all delay lines in use
  14262. - }
  14263. -
  14264. - cb = (D + 1) * sizeof( int ); // assume all samples are signed integers
  14265. -
  14266. - if( type == DLY_LOWPASS )
  14267. - {
  14268. - // alloc lowpass fir_filter
  14269. - pdly->pflt = FLT_Alloc( M, L, fa, fb );
  14270. - if( !pdly->pflt )
  14271. - {
  14272. - MsgDev( D_WARN, "DSP: failed to allocate filter for delay line.\n" );
  14273. - return NULL;
  14274. - }
  14275. - }
  14276. -
  14277. - // alloc delay memory
  14278. - h = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, cb );
  14279. - if( !h )
  14280. - {
  14281. - MsgDev( D_ERROR, "Sound DSP: Out of memory.\n" );
  14282. - FLT_Free( pdly->pflt );
  14283. - return NULL;
  14284. - }
  14285. -
  14286. - // lock delay memory
  14287. - w = (int *)GlobalLock( h );
  14288. -
  14289. - if( !w )
  14290. - {
  14291. - MsgDev( D_ERROR, "Sound DSP: Failed to lock.\n" );
  14292. - GlobalFree( h );
  14293. - FLT_Free( pdly->pflt );
  14294. - return NULL;
  14295. - }
  14296. -
  14297. - // clear delay array
  14298. - memset( w, 0, cb );
  14299. -
  14300. - // init values
  14301. - pdly->type = type;
  14302. - pdly->D = D;
  14303. - pdly->t = D; // set delay tap to full delay
  14304. - pdly->D0 = D;
  14305. - pdly->p = w; // init circular pointer to head of buffer
  14306. - pdly->w = w;
  14307. - pdly->h = h;
  14308. - pdly->a = min( a, PMAX ); // do not allow 100% feedback
  14309. - pdly->b = b;
  14310. - pdly->fused = true;
  14311. -
  14312. - if( type == DLY_LINEAR )
  14313. - {
  14314. - // linear delay has no feedback and unity gain
  14315. - pdly->a = 0;
  14316. - pdly->b = PMAX;
  14317. - }
  14318. - else
  14319. - {
  14320. - // adjust b to compensate for feedback gain
  14321. - DLY_SetNormalizingGain( pdly );
  14322. - }
  14323. -
  14324. - return pdly;
  14325. -}
  14326. -
  14327. -// allocate lowpass or allpass delay
  14328. -dly_t * DLY_Alloc( int D, int a, int b, int type )
  14329. -{
  14330. - return DLY_AllocLP( D, a, b, type, 0, 0, 0, 0 );
  14331. -}
  14332. -
  14333. -
  14334. -// Allocate new delay, convert from float params in prc preset to internal parameters
  14335. -// Uses filter params in prc if delay is type lowpass
  14336. -
  14337. -// delay parameter order
  14338. -typedef enum
  14339. -{
  14340. - dly_idtype, // NOTE: first 8 params must match those in mdy_e
  14341. - dly_idelay,
  14342. - dly_ifeedback,
  14343. - dly_igain,
  14344. - dly_iftype,
  14345. - dly_icutoff,
  14346. - dly_iqwidth,
  14347. - dly_iquality,
  14348. - dly_cparam
  14349. -} dly_e;
  14350. -
  14351. -
  14352. -// delay parameter ranges
  14353. -prm_rng_t dly_rng[] =
  14354. -{
  14355. -{ dly_cparam, 0, 0 }, // first entry is # of parameters
  14356. -
  14357. -// delay params
  14358. -{ dly_idtype, 0, DLY_MAX }, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  14359. -{ dly_idelay, 0.0, 1000.0 }, // delay in milliseconds
  14360. -{ dly_ifeedback, 0.0, 0.99 }, // feedback 0-1.0
  14361. -{ dly_igain, 0.0, 1.0 }, // final gain of output stage, 0-1.0
  14362. -
  14363. -// filter params if dly type DLY_LOWPASS
  14364. -{ dly_iftype, 0, FTR_MAX },
  14365. -{ dly_icutoff, 10.0, 22050.0 },
  14366. -{ dly_iqwidth, 100.0, 11025.0 },
  14367. -{ dly_iquality, 0, QUA_MAX },
  14368. -};
  14369. -
  14370. -dly_t * DLY_Params( prc_t *pprc )
  14371. -{
  14372. - dly_t *pdly = NULL;
  14373. - int D, a, b;
  14374. -
  14375. - float delay = pprc->prm[dly_idelay];
  14376. - float feedback = pprc->prm[dly_ifeedback];
  14377. - float gain = pprc->prm[dly_igain];
  14378. - int type = pprc->prm[dly_idtype];
  14379. -
  14380. - float ftype = pprc->prm[dly_iftype];
  14381. - float cutoff = pprc->prm[dly_icutoff];
  14382. - float qwidth = pprc->prm[dly_iqwidth];
  14383. - float qual = pprc->prm[dly_iquality];
  14384. -
  14385. - D = MSEC_TO_SAMPS( delay ); // delay samples
  14386. - a = feedback * PMAX; // feedback
  14387. - b = gain * PMAX; // gain
  14388. -
  14389. - switch( type )
  14390. - {
  14391. - case DLY_PLAIN:
  14392. - case DLY_ALLPASS:
  14393. - case DLY_LINEAR:
  14394. - pdly = DLY_Alloc( D, a, b, type );
  14395. - break;
  14396. - case DLY_LOWPASS:
  14397. - {
  14398. - // set up dummy lowpass filter to convert params
  14399. - prc_t prcf;
  14400. - flt_t *pflt;
  14401. -
  14402. - // 0,1,2 - high, medium, low (low quality implies faster execution time)
  14403. - prcf.prm[flt_iquality] = qual;
  14404. - prcf.prm[flt_icutoff] = cutoff;
  14405. - prcf.prm[flt_iftype] = ftype;
  14406. - prcf.prm[flt_iqwidth] = qwidth;
  14407. -
  14408. - pflt = (flt_t *)FLT_Params( &prcf );
  14409. -
  14410. - if( !pflt )
  14411. - {
  14412. - MsgDev( D_WARN, "DSP: failed to allocate filter.\n" );
  14413. - return NULL;
  14414. - }
  14415. -
  14416. - pdly = DLY_AllocLP( D, a, b, type, pflt->M, pflt->L, pflt->a, pflt->b );
  14417. -
  14418. - FLT_Free( pflt );
  14419. - break;
  14420. - }
  14421. - }
  14422. - return pdly;
  14423. -}
  14424. -
  14425. -_inline void *DLY_VParams( void *p )
  14426. -{
  14427. - PRC_CheckParams(( prc_t *)p, dly_rng );
  14428. - return (void *) DLY_Params((prc_t *)p);
  14429. -}
  14430. -
  14431. -// get next value from delay line, move x into delay line
  14432. -int DLY_GetNext( dly_t *pdly, int x )
  14433. -{
  14434. - switch( pdly->type )
  14435. - {
  14436. - default:
  14437. - case DLY_PLAIN:
  14438. - return dly_plain( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  14439. - case DLY_ALLPASS:
  14440. - return dly_allpass( pdly->D, pdly->t, pdly->w, &pdly->p, pdly->a, pdly->b, x );
  14441. - case DLY_LOWPASS:
  14442. - 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 );
  14443. - case DLY_LINEAR:
  14444. - return dly_linear( pdly->D, pdly->t, pdly->w, &pdly->p, x );
  14445. - }
  14446. -}
  14447. -
  14448. -// batch version for performance
  14449. -void DLY_GetNextN( dly_t *pdly, portable_samplepair_t *pbuffer, int SampleCount, int op )
  14450. -{
  14451. - int count = SampleCount;
  14452. - portable_samplepair_t *pb = pbuffer;
  14453. -
  14454. - switch( op )
  14455. - {
  14456. - default:
  14457. - case OP_LEFT:
  14458. - while( count-- )
  14459. - {
  14460. - pb->left = DLY_GetNext( pdly, pb->left );
  14461. - pb++;
  14462. - }
  14463. - break;
  14464. - case OP_RIGHT:
  14465. - while( count-- )
  14466. - {
  14467. - pb->right = DLY_GetNext( pdly, pb->right );
  14468. - pb++;
  14469. - }
  14470. - break;
  14471. - case OP_LEFT_DUPLICATE:
  14472. - while( count-- )
  14473. - {
  14474. - pb->left = pb->right = DLY_GetNext( pdly, pb->left );
  14475. - pb++;
  14476. - }
  14477. - break;
  14478. - }
  14479. -}
  14480. -
  14481. -// get tap on t'th sample in delay - don't update buffer pointers, this is done via DLY_GetNext
  14482. -_inline int DLY_GetTap( dly_t *pdly, int t )
  14483. -{
  14484. - return tap( pdly->D, pdly->w, pdly->p, t );
  14485. -}
  14486. -
  14487. -
  14488. -// make instantaneous change to new delay value D.
  14489. -// t tap value must be <= original D (ie: we don't do any reallocation here)
  14490. -void DLY_ChangeVal( dly_t *pdly, int t )
  14491. -{
  14492. - // never set delay > original delay
  14493. - pdly->t = min( t, pdly->D0 );
  14494. -}
  14495. -
  14496. -// ignored - use MDY_ for modulatable delay
  14497. -_inline void DLY_Mod( void *p, float v )
  14498. -{
  14499. -}
  14500. -
  14501. -///////////////////
  14502. -// Parallel reverbs
  14503. -///////////////////
  14504. -
  14505. -// Reverb A
  14506. -// M parallel reverbs, mixed to mono output
  14507. -
  14508. -#define CRVAS 64 // max number of parallel series reverbs active
  14509. -#define CRVA_DLYS 12 // max number of delays making up reverb_a
  14510. -
  14511. -typedef struct
  14512. -{
  14513. - qboolean fused;
  14514. - int m; // number of parallel plain or lowpass delays
  14515. - int fparallel; // true if filters in parallel with delays, otherwise single output filter
  14516. - flt_t *pflt;
  14517. -
  14518. - dly_t *pdlys[CRVA_DLYS]; // array of pointers to delays
  14519. -} rva_t;
  14520. -
  14521. -rva_t rvas[CRVAS];
  14522. -
  14523. -void RVA_Init( rva_t *prva ) { if( prva ) memset( prva, 0, sizeof( rva_t )); }
  14524. -void RVA_InitAll( void ) { int i; for( i = 0; i < CRVAS; i++ ) RVA_Init( &rvas[i] ); }
  14525. -
  14526. -// free parallel series reverb
  14527. -void RVA_Free( rva_t *prva )
  14528. -{
  14529. - if( prva )
  14530. - {
  14531. - int i;
  14532. -
  14533. - // free all delays
  14534. - for( i = 0; i < CRVA_DLYS; i++)
  14535. - DLY_Free ( prva->pdlys[i] );
  14536. -
  14537. - FLT_Free( prva->pflt );
  14538. - memset( prva, 0, sizeof (rva_t) );
  14539. - }
  14540. -}
  14541. -
  14542. -
  14543. -void RVA_FreeAll( void ) { int i; for( i = 0; i < CRVAS; i++ ) RVA_Free( &rvas[i] ); }
  14544. -
  14545. -// create parallel reverb - m parallel reverbs summed
  14546. -// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  14547. -// a array of reverb feedback parms for parallel reverbs (CRVB_P_DLYS)
  14548. -// b array of CRVB_P_DLYS - mix params for parallel reverbs
  14549. -// m - number of parallel delays
  14550. -// pflt - filter template, to be used by all parallel delays
  14551. -// fparallel - true if filter operates in parallel with delays, otherwise filter output only
  14552. -rva_t *RVA_Alloc( int *D, int *a, int *b, int m, flt_t *pflt, int fparallel )
  14553. -{
  14554. - int i;
  14555. - rva_t *prva;
  14556. - flt_t *pflt2 = NULL;
  14557. -
  14558. - // find open slot
  14559. - for( i = 0; i < CRVAS; i++ )
  14560. - {
  14561. - if( !rvas[i].fused )
  14562. - break;
  14563. - }
  14564. -
  14565. - // return null if no free slots
  14566. - if( i == CRVAS )
  14567. - {
  14568. - MsgDev( D_WARN, "DSP: failed to allocate reverb.\n" );
  14569. - return NULL;
  14570. - }
  14571. -
  14572. - prva = &rvas[i];
  14573. -
  14574. - // if series filter specified, alloc
  14575. - if( pflt && !fparallel )
  14576. - {
  14577. - // use filter data as template for a filter on output
  14578. - pflt2 = FLT_Alloc( pflt->M, pflt->L, pflt->a, pflt->b );
  14579. -
  14580. - if( !pflt2 )
  14581. - {
  14582. - MsgDev( D_WARN, "DSP: failed to allocate flt for reverb.\n" );
  14583. - return NULL;
  14584. - }
  14585. - }
  14586. -
  14587. - // alloc parallel reverbs
  14588. - if( pflt && fparallel )
  14589. - {
  14590. -
  14591. - // use this filter data as a template to alloc a filter for each parallel delay
  14592. - for( i = 0; i < m; i++ )
  14593. - prva->pdlys[i] = DLY_AllocLP( D[i], a[i], b[i], DLY_LOWPASS, pflt->M, pflt->L, pflt->a, pflt->b );
  14594. - }
  14595. - else
  14596. - {
  14597. - // no filter specified, use plain delays in parallel sections
  14598. - for( i = 0; i < m; i++ )
  14599. - prva->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_PLAIN );
  14600. - }
  14601. -
  14602. -
  14603. - // if we failed to alloc any reverb, free all, return NULL
  14604. - for( i = 0; i < m; i++ )
  14605. - {
  14606. - if( !prva->pdlys[i] )
  14607. - {
  14608. - FLT_Free( pflt2 );
  14609. - RVA_Free( prva );
  14610. - MsgDev( D_WARN, "DSP: failed to allocate delay for reverb.\n" );
  14611. - return NULL;
  14612. - }
  14613. - }
  14614. -
  14615. - prva->fused = true;
  14616. - prva->m = m;
  14617. - prva->fparallel = fparallel;
  14618. - prva->pflt = pflt2;
  14619. -
  14620. - return prva;
  14621. -}
  14622. -
  14623. -
  14624. -// parallel reverberator
  14625. -//
  14626. -// for each input sample x do:
  14627. -// x0 = plain(D0,w0,&p0,a0,x)
  14628. -// x1 = plain(D1,w1,&p1,a1,x)
  14629. -// x2 = plain(D2,w2,&p2,a2,x)
  14630. -// x3 = plain(D3,w3,&p3,a3,x)
  14631. -// y = b0*x0 + b1*x1 + b2*x2 + b3*x3
  14632. -//
  14633. -// rgdly - array of 6 delays:
  14634. -// D - Delay values (typical - 29, 37, 44, 50, 27, 31)
  14635. -// w - array of delayed values
  14636. -// p - array of pointers to circular delay line pointers
  14637. -// a - array of 6 feedback values (typical - all equal, like 0.75 * PMAX)
  14638. -// b - array of 6 gain values for plain reverb outputs (1, .9, .8, .7)
  14639. -// xin - input value
  14640. -// if fparallel, filters are built into delays,
  14641. -// otherwise, filter output
  14642. -
  14643. -_inline int RVA_GetNext( rva_t *prva, int x )
  14644. -{
  14645. - int m = prva->m;
  14646. - int i, y, sum;
  14647. -
  14648. - sum = 0;
  14649. -
  14650. - for( i = 0; i < m; i++ )
  14651. - sum += DLY_GetNext( prva->pdlys[i], x );
  14652. -
  14653. - // m is clamped between RVA_BASEM & CRVA_DLYS
  14654. -
  14655. - if( m ) y = sum/m;
  14656. - else y = x;
  14657. -#if 0
  14658. - // PERFORMANCE:
  14659. - // UNDONE: build as array
  14660. - int mm;
  14661. -
  14662. - switch( m )
  14663. - {
  14664. - case 12: mm = (PMAX/12); break;
  14665. - case 11: mm = (PMAX/11); break;
  14666. - case 10: mm = (PMAX/10); break;
  14667. - case 9: mm = (PMAX/9); break;
  14668. - case 8: mm = (PMAX/8); break;
  14669. - case 7: mm = (PMAX/7); break;
  14670. - case 6: mm = (PMAX/6); break;
  14671. - case 5: mm = (PMAX/5); break;
  14672. - case 4: mm = (PMAX/4); break;
  14673. - case 3: mm = (PMAX/3); break;
  14674. - case 2: mm = (PMAX/2); break;
  14675. - default:
  14676. - case 1: mm = (PMAX/1); break;
  14677. - }
  14678. -
  14679. - y = (sum * mm) >> PBITS;
  14680. -
  14681. -#endif // 0
  14682. -
  14683. - // run series filter if present
  14684. - if( prva->pflt && !prva->fparallel )
  14685. - y = FLT_GetNext( prva->pflt, y );
  14686. -
  14687. - return y;
  14688. -}
  14689. -
  14690. -// batch version for performance
  14691. -_inline void RVA_GetNextN( rva_t *prva, portable_samplepair_t *pbuffer, int SampleCount, int op )
  14692. -{
  14693. - int count = SampleCount;
  14694. - portable_samplepair_t *pb = pbuffer;
  14695. -
  14696. - switch( op )
  14697. - {
  14698. - default:
  14699. - case OP_LEFT:
  14700. - while( count-- )
  14701. - {
  14702. - pb->left = RVA_GetNext( prva, pb->left );
  14703. - pb++;
  14704. - }
  14705. - break;
  14706. - case OP_RIGHT:
  14707. - while( count-- )
  14708. - {
  14709. - pb->right = RVA_GetNext( prva, pb->right );
  14710. - pb++;
  14711. - }
  14712. - break;
  14713. - case OP_LEFT_DUPLICATE:
  14714. - while( count-- )
  14715. - {
  14716. - pb->left = pb->right = RVA_GetNext( prva, pb->left );
  14717. - pb++;
  14718. - }
  14719. - break;
  14720. - }
  14721. -}
  14722. -
  14723. -#define RVA_BASEM 3 // base number of parallel delays
  14724. -
  14725. -// nominal delay and feedback values
  14726. -
  14727. -//float rvadlys[] = { 29, 37, 44, 50, 62, 75, 96, 118, 127, 143, 164, 175 };
  14728. -float rvadlys[] = { 18, 23, 28, 36, 47, 21, 26, 33, 40, 49, 45, 38 };
  14729. -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 };
  14730. -
  14731. -// reverb parameter order
  14732. -typedef enum
  14733. -{
  14734. - // parameter order
  14735. - rva_isize,
  14736. - rva_idensity,
  14737. - rva_idecay,
  14738. - rva_iftype,
  14739. - rva_icutoff,
  14740. - rva_iqwidth,
  14741. - rva_ifparallel,
  14742. - rva_cparam // # of params
  14743. -} rva_e;
  14744. -
  14745. -// filter parameter ranges
  14746. -prm_rng_t rva_rng[] =
  14747. -{
  14748. -{ rva_cparam, 0, 0 }, // first entry is # of parameters
  14749. -
  14750. -// reverb params
  14751. -{ rva_isize, 0.0, 2.0 }, // 0-2.0 scales nominal delay parameters (starting at approx 20ms)
  14752. -{ rva_idensity, 0.0, 2.0 }, // 0-2.0 density of reverbs (room shape) - controls # of parallel or series delays
  14753. -{ rva_idecay, 0.0, 2.0 }, // 0-2.0 scales feedback parameters (starting at approx 0.15)
  14754. -
  14755. -// filter params for each parallel reverb (quality set to 0 for max execution speed)
  14756. -{ rva_iftype, 0, FTR_MAX },
  14757. -{ rva_icutoff, 10, 22050 },
  14758. -{ rva_iqwidth, 100, 11025 },
  14759. -{ rva_ifparallel, 0, 1 } // if 1, then all filters operate in parallel with delays. otherwise filter output only
  14760. -};
  14761. -
  14762. -rva_t * RVA_Params( prc_t *pprc )
  14763. -{
  14764. - flt_t *pflt;
  14765. - rva_t *prva;
  14766. - float size = pprc->prm[rva_isize]; // 0-2.0 controls scale of delay parameters
  14767. - float density = pprc->prm[rva_idensity]; // 0-2.0 density of reverbs (room shape) - controls # of parallel delays
  14768. - float decay = pprc->prm[rva_idecay]; // 0-1.0 controls feedback parameters
  14769. -
  14770. - float ftype = pprc->prm[rva_iftype];
  14771. - float cutoff = pprc->prm[rva_icutoff];
  14772. - float qwidth = pprc->prm[rva_iqwidth];
  14773. -
  14774. - float fparallel = pprc->prm[rva_ifparallel];
  14775. -
  14776. - // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  14777. - // a array of reverb feedback parms for parallel delays
  14778. - // b array of CRVB_P_DLYS - mix params for parallel reverbs
  14779. - // m - number of parallel delays
  14780. -
  14781. - int D[CRVA_DLYS];
  14782. - int a[CRVA_DLYS];
  14783. - int b[CRVA_DLYS];
  14784. - int m = RVA_BASEM;
  14785. - int i;
  14786. -
  14787. - m = density * CRVA_DLYS / 2;
  14788. -
  14789. - // limit # delays 3-12
  14790. - m = bound( RVA_BASEM, m, CRVA_DLYS );
  14791. -
  14792. - // average time sound takes to travel from most distant wall
  14793. - // (cap at 1000 ft room)
  14794. - for( i = 0; i < m; i++ )
  14795. - {
  14796. - // delays of parallel reverb
  14797. - D[i] = MSEC_TO_SAMPS( rvadlys[i] * size );
  14798. -
  14799. - // feedback and gain of parallel reverb
  14800. - a[i] = (int)min( 0.9 * PMAX, rvafbs[i] * (float)PMAX * decay );
  14801. - b[i] = PMAX;
  14802. - }
  14803. -
  14804. - // add filter
  14805. - pflt = NULL;
  14806. -
  14807. - if( cutoff )
  14808. - {
  14809. - // set up dummy lowpass filter to convert params
  14810. - prc_t prcf;
  14811. -
  14812. - prcf.prm[flt_iquality] = QUA_LO; // force filter to low quality for faster execution time
  14813. - prcf.prm[flt_icutoff] = cutoff;
  14814. - prcf.prm[flt_iftype] = ftype;
  14815. - prcf.prm[flt_iqwidth] = qwidth;
  14816. -
  14817. - pflt = (flt_t *)FLT_Params( &prcf );
  14818. - }
  14819. -
  14820. - prva = RVA_Alloc( D, a, b, m, pflt, fparallel );
  14821. - FLT_Free( pflt );
  14822. -
  14823. - return prva;
  14824. -}
  14825. -
  14826. -_inline void *RVA_VParams( void *p )
  14827. -{
  14828. - PRC_CheckParams((prc_t *)p, rva_rng );
  14829. - return (void *)RVA_Params((prc_t *)p );
  14830. -}
  14831. -
  14832. -_inline void RVA_Mod( void *p, float v )
  14833. -{
  14834. -}
  14835. -
  14836. -
  14837. -////////////
  14838. -// Diffusor
  14839. -///////////
  14840. -
  14841. -// (N series allpass reverbs)
  14842. -#define CDFRS 64 // max number of series reverbs active
  14843. -#define CDFR_DLYS 16 // max number of delays making up diffusor
  14844. -
  14845. -typedef struct
  14846. -{
  14847. - qboolean fused;
  14848. - int n; // series allpass delays
  14849. - int w[CDFR_DLYS]; // internal state array for series allpass filters
  14850. - dly_t *pdlys[CDFR_DLYS]; // array of pointers to delays
  14851. -} dfr_t;
  14852. -
  14853. -dfr_t dfrs[CDFRS];
  14854. -
  14855. -void DFR_Init( dfr_t *pdfr ) { if( pdfr ) memset( pdfr, 0, sizeof( dfr_t )); }
  14856. -void DFR_InitAll( void ) { int i; for( i = 0; i < CDFRS; i++ ) DFR_Init ( &dfrs[i] ); }
  14857. -
  14858. -// free parallel series reverb
  14859. -void DFR_Free( dfr_t *pdfr )
  14860. -{
  14861. - if( pdfr )
  14862. - {
  14863. - int i;
  14864. -
  14865. - // free all delays
  14866. - for( i = 0; i < CDFR_DLYS; i++ )
  14867. - DLY_Free( pdfr->pdlys[i] );
  14868. -
  14869. - memset( pdfr, 0, sizeof( dfr_t ));
  14870. - }
  14871. -}
  14872. -
  14873. -
  14874. -void DFR_FreeAll( void ) { int i; for( i = 0; i < CDFRS; i++ ) DFR_Free( &dfrs[i] ); }
  14875. -
  14876. -// create n series allpass reverbs
  14877. -// D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  14878. -// a array of reverb feedback parms for series delays
  14879. -// b array of gain params for parallel reverbs
  14880. -// n - number of series delays
  14881. -
  14882. -dfr_t *DFR_Alloc( int *D, int *a, int *b, int n )
  14883. -{
  14884. - int i;
  14885. - dfr_t *pdfr;
  14886. -
  14887. - // find open slot
  14888. - for( i = 0; i < CDFRS; i++ )
  14889. - {
  14890. - if( !dfrs[i].fused )
  14891. - break;
  14892. - }
  14893. -
  14894. - // return null if no free slots
  14895. - if( i == CDFRS )
  14896. - {
  14897. - MsgDev( D_WARN, "DSP: failed to allocate diffusor.\n" );
  14898. - return NULL;
  14899. - }
  14900. -
  14901. - pdfr = &dfrs[i];
  14902. -
  14903. - DFR_Init( pdfr );
  14904. -
  14905. - // alloc reverbs
  14906. - for( i = 0; i < n; i++ )
  14907. - pdfr->pdlys[i] = DLY_Alloc( D[i], a[i], b[i], DLY_ALLPASS );
  14908. -
  14909. - // if we failed to alloc any reverb, free all, return NULL
  14910. - for( i = 0; i < n; i++ )
  14911. - {
  14912. - if( !pdfr->pdlys[i] )
  14913. - {
  14914. - DFR_Free( pdfr );
  14915. - MsgDev( D_WARN, "DSP: failed to allocate delay for diffusor.\n" );
  14916. - return NULL;
  14917. - }
  14918. - }
  14919. -
  14920. - pdfr->fused = true;
  14921. - pdfr->n = n;
  14922. -
  14923. - return pdfr;
  14924. -}
  14925. -
  14926. -// series reverberator
  14927. -_inline int DFR_GetNext( dfr_t *pdfr, int x )
  14928. -{
  14929. - int i, y;
  14930. - int n = pdfr->n;
  14931. -
  14932. - y = x;
  14933. - for( i = 0; i < n; i++ )
  14934. - y = DLY_GetNext( pdfr->pdlys[i], y );
  14935. - return y;
  14936. -
  14937. -#if 0
  14938. - // alternate method, using internal state - causes PREDELAY = sum of delay times
  14939. -
  14940. - int *v = pdfr->w; // intermediate results
  14941. -
  14942. - v[0] = x;
  14943. -
  14944. - // reverse evaluate series delays
  14945. - // w[0] w[1] w[2] w[n-1] w[n]
  14946. - // x---->D[0]--->D[1]--->D[2]...-->D[n-1]--->out
  14947. - //
  14948. -
  14949. - for( i = n; i > 0; i-- )
  14950. - v[i] = DLY_GetNext( pdfr->pdlys[i-1], v[i-1] );
  14951. -
  14952. - return v[n];
  14953. -#endif
  14954. -}
  14955. -
  14956. -// batch version for performance
  14957. -_inline void DFR_GetNextN( dfr_t *pdfr, portable_samplepair_t *pbuffer, int SampleCount, int op )
  14958. -{
  14959. - int count = SampleCount;
  14960. - portable_samplepair_t *pb = pbuffer;
  14961. -
  14962. - switch( op )
  14963. - {
  14964. - default:
  14965. - case OP_LEFT:
  14966. - while( count-- )
  14967. - {
  14968. - pb->left = DFR_GetNext( pdfr, pb->left );
  14969. - pb++;
  14970. - }
  14971. - break;
  14972. - case OP_RIGHT:
  14973. - while( count-- )
  14974. - {
  14975. - pb->right = DFR_GetNext( pdfr, pb->right );
  14976. - pb++;
  14977. - }
  14978. - break;
  14979. - case OP_LEFT_DUPLICATE:
  14980. - while( count-- )
  14981. - {
  14982. - pb->left = pb->right = DFR_GetNext( pdfr, pb->left );
  14983. - pb++;
  14984. - }
  14985. - break;
  14986. - }
  14987. -}
  14988. -
  14989. -#define DFR_BASEN 2 // base number of series allpass delays
  14990. -
  14991. -// nominal diffusor delay and feedback values
  14992. -//float dfrdlys[] = { 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95 };
  14993. -float dfrdlys[] = { 13, 19, 26, 21, 32, 36, 38, 16, 24, 28, 41, 35, 10, 46, 50, 27 };
  14994. -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 };
  14995. -
  14996. -
  14997. -// diffusor parameter order
  14998. -
  14999. -typedef enum
  15000. -{
  15001. - // parameter order
  15002. - dfr_isize,
  15003. - dfr_idensity,
  15004. - dfr_idecay,
  15005. - dfr_cparam // # of params
  15006. -
  15007. -} dfr_e;
  15008. -
  15009. -// diffusor parameter ranges
  15010. -
  15011. -prm_rng_t dfr_rng[] =
  15012. -{
  15013. -{ dfr_cparam, 0, 0 }, // first entry is # of parameters
  15014. -{ dfr_isize, 0.0, 1.0 }, // 0-1.0 scales all delays
  15015. -{ dfr_idensity, 0.0, 1.0 }, // 0-1.0 controls # of series delays
  15016. -{ dfr_idecay, 0.0, 1.0 }, // 0-1.0 scales all feedback parameters
  15017. -};
  15018. -
  15019. -dfr_t *DFR_Params( prc_t *pprc )
  15020. -{
  15021. - dfr_t *pdfr;
  15022. - int i, s;
  15023. - float size = pprc->prm[dfr_isize]; // 0-1.0 scales all delays
  15024. - float density = pprc->prm[dfr_idensity]; // 0-1.0 controls # of series delays
  15025. - float diffusion = pprc->prm[dfr_idecay]; // 0-1.0 scales all feedback parameters
  15026. -
  15027. - // D array of CRVB_DLYS reverb delay sizes max sample index w[0...D] (ie: D+1 samples)
  15028. - // a array of reverb feedback parms for series delays (CRVB_S_DLYS)
  15029. - // b gain of each reverb section
  15030. - // n - number of series delays
  15031. -
  15032. - int D[CDFR_DLYS];
  15033. - int a[CDFR_DLYS];
  15034. - int b[CDFR_DLYS];
  15035. - int n = DFR_BASEN;
  15036. -
  15037. - // increase # of series diffusors with increased density
  15038. - n += density * 2;
  15039. -
  15040. - // limit m, n to half max number of delays
  15041. - n = min( CDFR_DLYS / 2, n );
  15042. -
  15043. - // compute delays for diffusors
  15044. - for( i = 0; i < n; i++ )
  15045. - {
  15046. - s = (int)( dfrdlys[i] * size );
  15047. -
  15048. - // delay of diffusor
  15049. - D[i] = MSEC_TO_SAMPS( s );
  15050. -
  15051. - // feedback and gain of diffusor
  15052. - a[i] = min( 0.9 * PMAX, dfrfbs[i] * PMAX * diffusion );
  15053. - b[i] = PMAX;
  15054. - }
  15055. -
  15056. - pdfr = DFR_Alloc( D, a, b, n );
  15057. -
  15058. - return pdfr;
  15059. -}
  15060. -
  15061. -_inline void *DFR_VParams( void *p )
  15062. -{
  15063. - PRC_CheckParams((prc_t *)p, dfr_rng );
  15064. - return (void *)DFR_Params((prc_t *)p );
  15065. -}
  15066. -
  15067. -_inline void DFR_Mod( void *p, float v )
  15068. -{
  15069. -}
  15070. -
  15071. -//////////////////////
  15072. -// LFO wav definitions
  15073. -//////////////////////
  15074. -
  15075. -#define CLFOSAMPS 512 // samples per wav table - single cycle only
  15076. -#define LFOBITS 14 // bits of peak amplitude of lfo wav
  15077. -#define LFOAMP ((1<<LFOBITS)-1) // peak amplitude of lfo wav
  15078. -
  15079. -//types of lfo wavs
  15080. -
  15081. -#define LFO_SIN 0 // sine wav
  15082. -#define LFO_TRI 1 // triangle wav
  15083. -#define LFO_SQR 2 // square wave, 50% duty cycle
  15084. -#define LFO_SAW 3 // forward saw wav
  15085. -#define LFO_RND 4 // random wav
  15086. -#define LFO_LOG_IN 5 // logarithmic fade in
  15087. -#define LFO_LOG_OUT 6 // logarithmic fade out
  15088. -#define LFO_LIN_IN 7 // linear fade in
  15089. -#define LFO_LIN_OUT 8 // linear fade out
  15090. -#define LFO_MAX LFO_LIN_OUT
  15091. -
  15092. -#define CLFOWAV 9 // number of LFO wav tables
  15093. -
  15094. -typedef struct // lfo or envelope wave table
  15095. -{
  15096. - int type; // lfo type
  15097. - dly_t *pdly; // delay holds wav values and step pointers
  15098. -} lfowav_t;
  15099. -
  15100. -lfowav_t lfowavs[CLFOWAV];
  15101. -
  15102. -// deallocate lfo wave table. Called only when sound engine exits.
  15103. -void LFOWAV_Free( lfowav_t *plw )
  15104. -{
  15105. - // free delay
  15106. - if( plw ) DLY_Free( plw->pdly );
  15107. -
  15108. - memset( plw, 0, sizeof( lfowav_t ));
  15109. -}
  15110. -
  15111. -// deallocate all lfo wave tables. Called only when sound engine exits.
  15112. -void LFOWAV_FreeAll( void )
  15113. -{
  15114. - int i;
  15115. -
  15116. - for( i = 0; i < CLFOWAV; i++ )
  15117. - LFOWAV_Free( &lfowavs[i] );
  15118. -}
  15119. -
  15120. -// fill lfo array w with count samples of lfo type 'type'
  15121. -// all lfo wavs except fade out, rnd, and log_out should start with 0 output
  15122. -void LFOWAV_Fill( int *w, int count, int type )
  15123. -{
  15124. - int i,x;
  15125. -
  15126. - switch( type )
  15127. - {
  15128. - default:
  15129. - case LFO_SIN: // sine wav, all values 0 <= x <= LFOAMP, initial value = 0
  15130. - for( i = 0; i < count; i++ )
  15131. - {
  15132. - x = ( int )(( float)(LFOAMP) * sin( (M_PI2 * (float)i / (float)count ) + ( M_PI_F * 1.5 )));
  15133. - w[i] = (x + LFOAMP)/2;
  15134. - }
  15135. - break;
  15136. - case LFO_TRI: // triangle wav, all values 0 <= x <= LFOAMP, initial value = 0
  15137. - for( i = 0; i < count; i++ )
  15138. - {
  15139. - w[i] = ( int ) ( (float)(2 * LFOAMP * i ) / (float)(count) );
  15140. -
  15141. - if( i > count / 2 )
  15142. - w[i] = ( int )( (float) (2 * LFOAMP) - (float)( 2 * LFOAMP * i ) / (float)( count ));
  15143. - }
  15144. - break;
  15145. - case LFO_SQR: // square wave, 50% duty cycle, all values 0 <= x <= LFOAMP, initial value = 0
  15146. - for( i = 0; i < count; i++ )
  15147. - w[i] = i > count / 2 ? 0 : LFOAMP;
  15148. - break;
  15149. - case LFO_SAW: // forward saw wav, aall values 0 <= x <= LFOAMP, initial value = 0
  15150. - for( i = 0; i < count; i++ )
  15151. - w[i] = ( int )( (float)(LFOAMP) * (float)i / (float)( count ));
  15152. - break;
  15153. - case LFO_RND: // random wav, all values 0 <= x <= LFOAMP
  15154. - for( i = 0; i < count; i++ )
  15155. - w[i] = ( int )( Com_RandomLong( 0, LFOAMP ));
  15156. - break;
  15157. - case LFO_LOG_IN: // logarithmic fade in, all values 0 <= x <= LFOAMP, initial value = 0
  15158. - for( i = 0; i < count; i++ )
  15159. - w[i] = ( int ) ( (float)(LFOAMP) * pow( (float)i / (float)count, 2 ));
  15160. - break;
  15161. - case LFO_LOG_OUT: // logarithmic fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  15162. - for( i = 0; i < count; i++ )
  15163. - w[i] = ( int ) ( (float)(LFOAMP) * pow( 1.0 - ((float)i / (float)count), 2 ));
  15164. - break;
  15165. - case LFO_LIN_IN: // linear fade in, all values 0 <= x <= LFOAMP, initial value = 0
  15166. - for( i = 0; i < count; i++ )
  15167. - w[i] = ( int )( (float)(LFOAMP) * (float)i / (float)(count) );
  15168. - break;
  15169. - case LFO_LIN_OUT: // linear fade out, all values 0 <= x <= LFOAMP, initial value = LFOAMP
  15170. - for( i = 0; i < count; i++ )
  15171. - w[i] = LFOAMP - ( int )( (float)(LFOAMP) * (float)i / (float)(count) );
  15172. - break;
  15173. - }
  15174. -}
  15175. -
  15176. -// allocate all lfo wave tables. Called only when sound engine loads.
  15177. -void LFOWAV_InitAll( void )
  15178. -{
  15179. - int i;
  15180. - dly_t *pdly;
  15181. -
  15182. - memset( lfowavs, 0, sizeof( lfowavs ));
  15183. -
  15184. - // alloc space for each lfo wav type
  15185. - for( i = 0; i < CLFOWAV; i++ )
  15186. - {
  15187. - pdly = DLY_Alloc( CLFOSAMPS, 0, 0 , DLY_PLAIN );
  15188. -
  15189. - lfowavs[i].pdly = pdly;
  15190. - lfowavs[i].type = i;
  15191. -
  15192. - LFOWAV_Fill( pdly->w, CLFOSAMPS, i );
  15193. - }
  15194. -
  15195. - // if any dlys fail to alloc, free all
  15196. - for( i = 0; i < CLFOWAV; i++ )
  15197. - {
  15198. - if( !lfowavs[i].pdly )
  15199. - LFOWAV_FreeAll();
  15200. - }
  15201. -}
  15202. -
  15203. -
  15204. -////////////////////////////////////////
  15205. -// LFO iterators - one shot and looping
  15206. -////////////////////////////////////////
  15207. -
  15208. -#define CLFO 16 // max active lfos (this steals from active delays)
  15209. -
  15210. -typedef struct
  15211. -{
  15212. - qboolean fused; // true if slot take
  15213. - dly_t *pdly; // delay points to lfo wav within lfowav_t (don't free this)
  15214. - float f; // playback frequency in hz
  15215. - pos_t pos; // current position within wav table, looping
  15216. - pos_one_t pos1; // current position within wav table, one shot
  15217. - int foneshot; // true - one shot only, don't repeat
  15218. -} lfo_t;
  15219. -
  15220. -lfo_t lfos[CLFO];
  15221. -
  15222. -void LFO_Init( lfo_t *plfo ) { if( plfo ) memset( plfo, 0, sizeof( lfo_t )); }
  15223. -void LFO_InitAll( void ) { int i; for( i = 0; i < CLFO; i++ ) LFO_Init( &lfos[i] ); }
  15224. -void LFO_Free( lfo_t *plfo ) { if( plfo ) memset( plfo, 0, sizeof( lfo_t )); }
  15225. -void LFO_FreeAll( void ) { int i; for( i = 0; i < CLFO; i++ ) LFO_Free( &lfos[i] ); }
  15226. -
  15227. -
  15228. -// get step value given desired playback frequency
  15229. -_inline float LFO_HzToStep( float freqHz )
  15230. -{
  15231. - float lfoHz;
  15232. -
  15233. - // calculate integer and fractional step values,
  15234. - // assume an update rate of SOUND_DMA_SPEED samples/sec
  15235. -
  15236. - // 1 cycle/CLFOSAMPS * SOUND_DMA_SPEED samps/sec = cycles/sec = current lfo rate
  15237. - //
  15238. - // lforate * X = freqHz so X = freqHz/lforate = update rate
  15239. - lfoHz = (float)(SOUND_DMA_SPEED) / (float)(CLFOSAMPS);
  15240. -
  15241. - return freqHz / lfoHz;
  15242. -}
  15243. -
  15244. -// return pointer to new lfo
  15245. -
  15246. -lfo_t *LFO_Alloc( int wtype, float freqHz, qboolean foneshot )
  15247. -{
  15248. - int i, type = min( CLFOWAV - 1, wtype );
  15249. - float lfostep;
  15250. -
  15251. - for( i = 0; i < CLFO; i++ )
  15252. - {
  15253. - if( !lfos[i].fused )
  15254. - {
  15255. - lfo_t *plfo = &lfos[i];
  15256. -
  15257. - LFO_Init( plfo );
  15258. -
  15259. - plfo->fused = true;
  15260. - plfo->pdly = lfowavs[type].pdly; // pdly in lfo points to wav table data in lfowavs
  15261. - plfo->f = freqHz;
  15262. - plfo->foneshot = foneshot;
  15263. -
  15264. - lfostep = LFO_HzToStep( freqHz );
  15265. -
  15266. - // init positional pointer (ie: fixed point updater for controlling pitch of lfo)
  15267. - if( !foneshot ) POS_Init(&(plfo->pos), plfo->pdly->D, lfostep );
  15268. - else POS_ONE_Init(&(plfo->pos1), plfo->pdly->D,lfostep );
  15269. -
  15270. - return plfo;
  15271. - }
  15272. - }
  15273. -
  15274. - MsgDev( D_WARN, "DSP: failed to allocate LFO.\n" );
  15275. - return NULL;
  15276. -}
  15277. -
  15278. -// get next lfo value
  15279. -// Value returned is 0..LFOAMP. can be normalized by shifting right by LFOBITS
  15280. -// To play back at correct passed in frequency, routien should be
  15281. -// called once for every output sample (ie: at SOUND_DMA_SPEED)
  15282. -// x is dummy param
  15283. -_inline int LFO_GetNext( lfo_t *plfo, int x )
  15284. -{
  15285. - int i;
  15286. -
  15287. - // get current position
  15288. - if( !plfo->foneshot ) i = POS_GetNext( &plfo->pos );
  15289. - else i = POS_ONE_GetNext( &plfo->pos1 );
  15290. -
  15291. - // return current sample
  15292. - return plfo->pdly->w[i];
  15293. -}
  15294. -
  15295. -// batch version for performance
  15296. -_inline void LFO_GetNextN( lfo_t *plfo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  15297. -{
  15298. - int count = SampleCount;
  15299. - portable_samplepair_t *pb = pbuffer;
  15300. -
  15301. - switch( op )
  15302. - {
  15303. - default:
  15304. - case OP_LEFT:
  15305. - while( count-- )
  15306. - {
  15307. - pb->left = LFO_GetNext( plfo, pb->left );
  15308. - pb++;
  15309. - }
  15310. - break;
  15311. - case OP_RIGHT:
  15312. - while( count-- )
  15313. - {
  15314. - pb->right = LFO_GetNext( plfo, pb->right );
  15315. - pb++;
  15316. - }
  15317. - break;
  15318. - case OP_LEFT_DUPLICATE:
  15319. - while( count-- )
  15320. - {
  15321. - pb->left = pb->right = LFO_GetNext( plfo, pb->left );
  15322. - pb++;
  15323. - }
  15324. - break;
  15325. - }
  15326. -}
  15327. -
  15328. -// uses lfowav, rate, foneshot
  15329. -typedef enum
  15330. -{
  15331. - // parameter order
  15332. - lfo_iwav,
  15333. - lfo_irate,
  15334. - lfo_ifoneshot,
  15335. - lfo_cparam // # of params
  15336. -
  15337. -} lfo_e;
  15338. -
  15339. -// parameter ranges
  15340. -
  15341. -prm_rng_t lfo_rng[] =
  15342. -{
  15343. -{ lfo_cparam, 0, 0 }, // first entry is # of parameters
  15344. -{ lfo_iwav, 0.0, LFO_MAX }, // lfo type to use (LFO_SIN, LFO_RND...)
  15345. -{ lfo_irate, 0.0, 16000.0 }, // modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
  15346. -{ lfo_ifoneshot, 0.0, 1.0 }, // 1.0 if lfo is oneshot
  15347. -};
  15348. -
  15349. -lfo_t * LFO_Params( prc_t *pprc )
  15350. -{
  15351. - lfo_t *plfo;
  15352. - qboolean foneshot = pprc->prm[lfo_ifoneshot] > 0 ? true : false;
  15353. -
  15354. - plfo = LFO_Alloc( pprc->prm[lfo_iwav], pprc->prm[lfo_irate], foneshot );
  15355. -
  15356. - return plfo;
  15357. -}
  15358. -
  15359. -void LFO_ChangeVal( lfo_t *plfo, float fhz )
  15360. -{
  15361. - float fstep = LFO_HzToStep( fhz );
  15362. -
  15363. - // change lfo playback rate to new frequency fhz
  15364. - if( plfo->foneshot ) POS_ChangeVal( &plfo->pos, fstep );
  15365. - else POS_ChangeVal( &plfo->pos1.p, fstep );
  15366. -}
  15367. -
  15368. -_inline void *LFO_VParams( void *p )
  15369. -{
  15370. - PRC_CheckParams((prc_t *)p, lfo_rng );
  15371. - return (void *)LFO_Params((prc_t *)p);
  15372. -}
  15373. -
  15374. -// v is +/- 0-1.0
  15375. -// v changes current lfo frequency up/down by +/- v%
  15376. -_inline void LFO_Mod( lfo_t *plfo, float v )
  15377. -{
  15378. - float fhz;
  15379. - float fhznew;
  15380. -
  15381. - fhz = plfo->f;
  15382. - fhznew = fhz * (1.0 + v);
  15383. -
  15384. - LFO_ChangeVal( plfo, fhznew );
  15385. -
  15386. - return;
  15387. -}
  15388. -
  15389. -
  15390. -/////////////////////////////////////////////////////////////////////////////
  15391. -// Ramp - used for varying smoothly between int parameters ie: modulation delays
  15392. -/////////////////////////////////////////////////////////////////////////////
  15393. -typedef struct
  15394. -{
  15395. - int initval; // initial ramp value
  15396. - int target; // final ramp value
  15397. - int sign; // increasing (1) or decreasing (-1) ramp
  15398. - int yprev; // previous output value
  15399. - qboolean fhitend; // true if hit end of ramp
  15400. - pos_one_t ps; // current ramp output
  15401. -} rmp_t;
  15402. -
  15403. -// ramp smoothly between initial value and target value in approx 'ramptime' seconds.
  15404. -// (initial value may be greater or less than target value)
  15405. -// never changes output by more than +1 or -1 (which can cause the ramp to take longer to complete than ramptime)
  15406. -// called once per sample while ramping
  15407. -// ramptime - duration of ramp in seconds
  15408. -// initval - initial ramp value
  15409. -// targetval - target ramp value
  15410. -void RMP_Init( rmp_t *prmp, float ramptime, int initval, int targetval )
  15411. -{
  15412. - int rise;
  15413. - int run;
  15414. -
  15415. - if( prmp ) memset( prmp, 0, sizeof( rmp_t ));
  15416. -
  15417. - run = (int)( ramptime * SOUND_DMA_SPEED ); // 'samples' in ramp
  15418. - rise = (targetval - initval); // height of ramp
  15419. -
  15420. - // init fixed point iterator to iterate along the height of the ramp 'rise'
  15421. - // always iterates from 0..'rise', increasing in value
  15422. -
  15423. - POS_ONE_Init( &prmp->ps, ABS( rise ), ABS((float) rise) / ((float) run));
  15424. -
  15425. - prmp->yprev = initval;
  15426. - prmp->initval = initval;
  15427. - prmp->target = targetval;
  15428. - prmp->sign = SIGN( rise );
  15429. -
  15430. -}
  15431. -
  15432. -// continues from current position to new target position
  15433. -void RMP_SetNext( rmp_t *prmp, float ramptime, int targetval )
  15434. -{
  15435. - RMP_Init( prmp, ramptime, prmp->yprev, targetval );
  15436. -}
  15437. -
  15438. -_inline qboolean RMP_HitEnd( rmp_t *prmp )
  15439. -{
  15440. - return prmp->fhitend;
  15441. -}
  15442. -
  15443. -_inline void RMP_SetEnd( rmp_t *prmp )
  15444. -{
  15445. - prmp->fhitend = true;
  15446. -}
  15447. -
  15448. -// get next ramp value & update ramp, never varies by more than +1 or -1 between calls
  15449. -// when ramp hits target value, it thereafter always returns last value
  15450. -
  15451. -_inline int RMP_GetNext( rmp_t *prmp )
  15452. -{
  15453. - int y, d;
  15454. -
  15455. - // if we hit ramp end, return last value
  15456. - if( prmp->fhitend )
  15457. - return prmp->yprev;
  15458. -
  15459. - // get next integer position in ramp height.
  15460. - d = POS_ONE_GetNext( &prmp->ps );
  15461. -
  15462. - if( prmp->ps.fhitend )
  15463. - prmp->fhitend = true;
  15464. -
  15465. - // increase or decrease from initval, depending on ramp sign
  15466. - if( prmp->sign > 0 )
  15467. - y = prmp->initval + d;
  15468. - else y = prmp->initval - d;
  15469. -
  15470. - // only update current height by a max of +1 or -1
  15471. - // this means that for short ramp times, we may not hit target
  15472. - if( ABS( y - prmp->yprev ) >= 1 )
  15473. - prmp->yprev += prmp->sign;
  15474. -
  15475. - return prmp->yprev;
  15476. -}
  15477. -
  15478. -// get current ramp value, don't update ramp
  15479. -_inline int RMP_GetCurrent( rmp_t *prmp )
  15480. -{
  15481. - return prmp->yprev;
  15482. -}
  15483. -
  15484. -////////////////////////////////////////
  15485. -// Time Compress/expand with pitch shift
  15486. -////////////////////////////////////////
  15487. -
  15488. -// realtime pitch shift - ie: pitch shift without change to playback rate
  15489. -
  15490. -#define CPTCS 64
  15491. -
  15492. -typedef struct
  15493. -{
  15494. - qboolean fused;
  15495. - dly_t *pdly_in; // input buffer space
  15496. - dly_t *pdly_out; // output buffer space
  15497. - int *pin; // input buffer (pdly_in->w)
  15498. - int *pout; // output buffer (pdly_out->w)
  15499. - int cin; // # samples in input buffer
  15500. - int cout; // # samples in output buffer
  15501. - int cxfade; // # samples in crossfade segment
  15502. - int ccut; // # samples to cut
  15503. - int cduplicate; // # samples to duplicate (redundant - same as ccut)
  15504. - int iin; // current index into input buffer (reading)
  15505. - pos_one_t psn; // stepping index through output buffer
  15506. - qboolean fdup; // true if duplicating, false if cutting
  15507. - float fstep; // pitch shift & time compress/expand
  15508. -} ptc_t;
  15509. -
  15510. -ptc_t ptcs[CPTCS];
  15511. -
  15512. -void PTC_Init( ptc_t *pptc ) { if( pptc ) memset( pptc, 0, sizeof( ptc_t )); };
  15513. -void PTC_Free( ptc_t *pptc )
  15514. -{
  15515. - if( pptc )
  15516. - {
  15517. - DLY_Free( pptc->pdly_in );
  15518. - DLY_Free( pptc->pdly_out );
  15519. -
  15520. - memset( pptc, 0, sizeof( ptc_t ));
  15521. - }
  15522. -};
  15523. -
  15524. -void PTC_InitAll() { int i; for( i = 0; i < CPTCS; i++ ) PTC_Init( &ptcs[i] ); };
  15525. -void PTC_FreeAll() { int i; for( i = 0; i < CPTCS; i++ ) PTC_Free( &ptcs[i] ); };
  15526. -
  15527. -// Time compressor/expander with pitch shift (ie: pitch changes, playback rate does not)
  15528. -//
  15529. -// Algorithm:
  15530. -// 1) Duplicate or discard chunks of sound to provide tslice * fstep seconds of sound.
  15531. -// (The user-selectable size of the buffer to process is tslice milliseconds in length)
  15532. -// 2) Resample this compressed/expanded buffer at fstep to produce a pitch shifted
  15533. -// output with the same duration as the input (ie: #samples out = # samples in, an
  15534. -// obvious requirement for realtime _inline processing).
  15535. -
  15536. -// timeslice is size in milliseconds of full buffer to process.
  15537. -// timeslice * fstep is the size of the expanded/compressed buffer
  15538. -// timexfade is length in milliseconds of crossfade region between duplicated or cut sections
  15539. -// fstep is % expanded/compressed sound normalized to 0.01-2.0 (1% - 200%)
  15540. -
  15541. -// input buffer:
  15542. -
  15543. -// iin-->
  15544. -
  15545. -// [0... tslice ...D] input samples 0...D (D is NEWEST sample)
  15546. -// [0... ...n][m... tseg ...D] region to be cut or duplicated m...D
  15547. -
  15548. -// [0... [p..txf1..n][m... tseg ...D] fade in region 1 txf1 p...n
  15549. -// [0... ...n][m..[q..txf2..D] fade out region 2 txf2 q...D
  15550. -
  15551. -
  15552. -// pitch up: duplicate into output buffer: tdup = tseg
  15553. -
  15554. -// [0... ...n][m... tdup ...D][m... tdup ...D] output buffer size with duplicate region
  15555. -// [0... ...n][m..[p...xf1..n][m... tdup ...D] fade in p...n while fading out q...D
  15556. -// [0... ...n][m..[q...xf2..D][m... tdup ...D]
  15557. -// [0... ...n][m..[.XFADE...n][m... tdup ...D] final duplicated output buffer - resample at fstep
  15558. -
  15559. -// pitch down: cut into output buffer: tcut = tseg
  15560. -
  15561. -// [0... ...n][m... tcut ...D] input samples with cut region delineated m...D
  15562. -// [0... ...n] output buffer size after cut
  15563. -// [0... [q..txf2...D] fade in txf1 q...D while fade out txf2 p...n
  15564. -// [0... [.XFADE ...D] final cut output buffer - resample at fstep
  15565. -
  15566. -
  15567. -ptc_t * PTC_Alloc( float timeslice, float timexfade, float fstep )
  15568. -{
  15569. - int i;
  15570. - ptc_t *pptc;
  15571. - float tout;
  15572. - int cin, cout;
  15573. - float tslice = timeslice;
  15574. - float txfade = timexfade;
  15575. - float tcutdup;
  15576. -
  15577. - // find time compressor slot
  15578. - for( i = 0; i < CPTCS; i++ )
  15579. - {
  15580. - if( !ptcs[i].fused )
  15581. - break;
  15582. - }
  15583. -
  15584. - if( i == CPTCS )
  15585. - {
  15586. - MsgDev( D_WARN, "DSP: failed to allocate pitch shifter.\n" );
  15587. - return NULL;
  15588. - }
  15589. -
  15590. - pptc = &ptcs[i];
  15591. - PTC_Init( pptc );
  15592. -
  15593. - // get size of region to cut or duplicate
  15594. - tcutdup = abs(( fstep - 1.0 ) * timeslice );
  15595. -
  15596. - // to prevent buffer overruns:
  15597. -
  15598. - // make sure timeslice is greater than cut/dup time
  15599. - tslice = max ( tslice, 1.1 * tcutdup);
  15600. -
  15601. - // make sure xfade time smaller than cut/dup time, and smaller than (timeslice-cutdup) time
  15602. - txfade = min( txfade, 0.9 * tcutdup );
  15603. - txfade = min( txfade, 0.9 * ( tslice - tcutdup ));
  15604. -
  15605. - pptc->cxfade = MSEC_TO_SAMPS( txfade );
  15606. - pptc->ccut = MSEC_TO_SAMPS( tcutdup );
  15607. - pptc->cduplicate = MSEC_TO_SAMPS( tcutdup );
  15608. -
  15609. - // alloc delay lines (buffers)
  15610. - tout = tslice * fstep;
  15611. -
  15612. - cin = MSEC_TO_SAMPS( tslice );
  15613. - cout = MSEC_TO_SAMPS( tout );
  15614. -
  15615. - pptc->pdly_in = DLY_Alloc( cin, 0, 1, DLY_LINEAR ); // alloc input buffer
  15616. - pptc->pdly_out = DLY_Alloc( cout, 0, 1, DLY_LINEAR ); // alloc output buffer
  15617. -
  15618. - if( !pptc->pdly_in || !pptc->pdly_out )
  15619. - {
  15620. - PTC_Free( pptc );
  15621. - MsgDev( D_WARN, "DSP: failed to allocate delay for pitch shifter.\n" );
  15622. - return NULL;
  15623. - }
  15624. -
  15625. - // buffer pointers
  15626. - pptc->pin = pptc->pdly_in->w;
  15627. - pptc->pout = pptc->pdly_out->w;
  15628. -
  15629. - // input buffer index
  15630. - pptc->iin = 0;
  15631. -
  15632. - // output buffer index
  15633. - POS_ONE_Init( &pptc->psn, cout, fstep );
  15634. -
  15635. - // if fstep > 1.0 we're pitching shifting up, so fdup = true
  15636. - pptc->fdup = fstep > 1.0 ? true : false;
  15637. -
  15638. - pptc->cin = cin;
  15639. - pptc->cout = cout;
  15640. -
  15641. - pptc->fstep = fstep;
  15642. - pptc->fused = true;
  15643. -
  15644. - return pptc;
  15645. -}
  15646. -
  15647. -// linear crossfader
  15648. -// yfadein - instantaneous value fading in
  15649. -// ydafeout -instantaneous value fading out
  15650. -// nsamples - duration in #samples of fade
  15651. -// isample - index in to fade 0...nsamples-1
  15652. -_inline int xfade( int yfadein, int yfadeout, int nsamples, int isample )
  15653. -{
  15654. - int yout;
  15655. - int m = (isample << PBITS ) / nsamples;
  15656. -
  15657. - yout = ((yfadein * m) >> PBITS) + ((yfadeout * (PMAX - m)) >> PBITS);
  15658. -
  15659. - return yout;
  15660. -}
  15661. -
  15662. -// w - pointer to start of input buffer samples
  15663. -// v - pointer to start of output buffer samples
  15664. -// cin - # of input buffer samples
  15665. -// cout = # of output buffer samples
  15666. -// cxfade = # of crossfade samples
  15667. -// cduplicate = # of samples in duplicate/cut segment
  15668. -void TimeExpand( int *w, int *v, int cin, int cout, int cxfade, int cduplicate )
  15669. -{
  15670. - int i, j;
  15671. - int m;
  15672. - int p;
  15673. - int q;
  15674. - int D;
  15675. -
  15676. - // input buffer
  15677. - // xfade source duplicate
  15678. - // [0...........][p.......n][m...........D]
  15679. -
  15680. - // output buffer
  15681. - // xfade region duplicate
  15682. - // [0.....................n][m..[q.......D][m...........D]
  15683. -
  15684. - // D - index of last sample in input buffer
  15685. - // m - index of 1st sample in duplication region
  15686. - // p - index of 1st sample of crossfade source
  15687. - // q - index of 1st sample in crossfade region
  15688. -
  15689. - D = cin - 1;
  15690. - m = cin - cduplicate;
  15691. - p = m - cxfade;
  15692. - q = cin - cxfade;
  15693. -
  15694. - // copy up to crossfade region
  15695. - for( i = 0; i < q; i++ )
  15696. - v[i] = w[i];
  15697. -
  15698. - // crossfade region
  15699. - j = p;
  15700. -
  15701. - for( i = q; i <= D; i++ )
  15702. - v[i] = xfade( w[j++], w[i], cxfade, i-q ); // fade out p..n, fade in q..D
  15703. -
  15704. - // duplicate region
  15705. - j = D+1;
  15706. -
  15707. - for( i = m; i <= D; i++ )
  15708. - v[j++] = w[i];
  15709. -
  15710. -}
  15711. -
  15712. -// cut ccut samples from end of input buffer, crossfade end of cut section
  15713. -// with end of remaining section
  15714. -
  15715. -// w - pointer to start of input buffer samples
  15716. -// v - pointer to start of output buffer samples
  15717. -// cin - # of input buffer samples
  15718. -// cout = # of output buffer samples
  15719. -// cxfade = # of crossfade samples
  15720. -// ccut = # of samples in cut segment
  15721. -void TimeCompress( int *w, int *v, int cin, int cout, int cxfade, int ccut )
  15722. -{
  15723. - int i, j;
  15724. - int m;
  15725. - int p;
  15726. - int q;
  15727. - int D;
  15728. -
  15729. - // input buffer
  15730. - // xfade source
  15731. - // [0.....................n][m..[p.......D]
  15732. -
  15733. - // xfade region cut
  15734. - // [0...........][q.......n][m...........D]
  15735. -
  15736. - // output buffer
  15737. - // xfade to source
  15738. - // [0...........][p.......D]
  15739. -
  15740. - // D - index of last sample in input buffer
  15741. - // m - index of 1st sample in cut region
  15742. - // p - index of 1st sample of crossfade source
  15743. - // q - index of 1st sample in crossfade region
  15744. -
  15745. - D = cin - 1;
  15746. - m = cin - ccut;
  15747. - p = cin - cxfade;
  15748. - q = m - cxfade;
  15749. -
  15750. - // copy up to crossfade region
  15751. -
  15752. - for( i = 0; i < q; i++ )
  15753. - v[i] = w[i];
  15754. -
  15755. - // crossfade region
  15756. - j = p;
  15757. -
  15758. - for( i = q; i < m; i++ )
  15759. - v[i] = xfade( w[j++], w[i], cxfade, i-q ); // fade out p..n, fade in q..D
  15760. -
  15761. - // skip rest of input buffer
  15762. -}
  15763. -
  15764. -// get next sample
  15765. -
  15766. -// put input sample into input (delay) buffer
  15767. -// get output sample from output buffer, step by fstep %
  15768. -// output buffer is time expanded or compressed version of previous input buffer
  15769. -_inline int PTC_GetNext( ptc_t *pptc, int x )
  15770. -{
  15771. - int iout, xout;
  15772. - qboolean fhitend = false;
  15773. -
  15774. - // write x into input buffer
  15775. - ASSERT( pptc->iin < pptc->cin );
  15776. -
  15777. - pptc->pin[pptc->iin] = x;
  15778. -
  15779. - pptc->iin++;
  15780. -
  15781. - // check for end of input buffer
  15782. - if( pptc->iin >= pptc->cin )
  15783. - fhitend = true;
  15784. -
  15785. - // read sample from output buffer, resampling at fstep
  15786. - iout = POS_ONE_GetNext( &pptc->psn );
  15787. - ASSERT( iout < pptc->cout );
  15788. - xout = pptc->pout[iout];
  15789. -
  15790. - if( fhitend )
  15791. - {
  15792. - // if hit end of input buffer (ie: input buffer is full)
  15793. - // reset input buffer pointer
  15794. - // reset output buffer pointer
  15795. - // rebuild entire output buffer (TimeCompress/TimeExpand)
  15796. -
  15797. - pptc->iin = 0;
  15798. -
  15799. - POS_ONE_Init( &pptc->psn, pptc->cout, pptc->fstep );
  15800. -
  15801. - if( pptc->fdup ) TimeExpand ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->cduplicate );
  15802. - else TimeCompress ( pptc->pin, pptc->pout, pptc->cin, pptc->cout, pptc->cxfade, pptc->ccut );
  15803. - }
  15804. -
  15805. - return xout;
  15806. -}
  15807. -
  15808. -// batch version for performance
  15809. -_inline void PTC_GetNextN( ptc_t *pptc, portable_samplepair_t *pbuffer, int SampleCount, int op )
  15810. -{
  15811. - int count = SampleCount;
  15812. - portable_samplepair_t *pb = pbuffer;
  15813. -
  15814. - switch( op )
  15815. - {
  15816. - default:
  15817. - case OP_LEFT:
  15818. - while( count-- )
  15819. - {
  15820. - pb->left = PTC_GetNext( pptc, pb->left );
  15821. - pb++;
  15822. - }
  15823. - break;
  15824. - case OP_RIGHT:
  15825. - while( count-- )
  15826. - {
  15827. - pb->right = PTC_GetNext( pptc, pb->right );
  15828. - pb++;
  15829. - }
  15830. - break;
  15831. - case OP_LEFT_DUPLICATE:
  15832. - while( count-- )
  15833. - {
  15834. - pb->left = pb->right = PTC_GetNext( pptc, pb->left );
  15835. - pb++;
  15836. - }
  15837. - break;
  15838. - }
  15839. -}
  15840. -
  15841. -// change time compression to new value
  15842. -// fstep is new value
  15843. -// ramptime is how long change takes in seconds (ramps smoothly), 0 for no ramp
  15844. -
  15845. -void PTC_ChangeVal( ptc_t *pptc, float fstep, float ramptime )
  15846. -{
  15847. -// UNDONE: ignored
  15848. -// UNDONE: just realloc time compressor with new fstep
  15849. -}
  15850. -
  15851. -// uses pitch:
  15852. -// 1.0 = playback normal rate
  15853. -// 0.5 = cut 50% of sound (2x playback)
  15854. -// 1.5 = add 50% sound (0.5x playback)
  15855. -
  15856. -typedef enum
  15857. -{
  15858. - // parameter order
  15859. - ptc_ipitch,
  15860. - ptc_itimeslice,
  15861. - ptc_ixfade,
  15862. - ptc_cparam // # of params
  15863. -} ptc_e;
  15864. -
  15865. -// diffusor parameter ranges
  15866. -prm_rng_t ptc_rng[] =
  15867. -{
  15868. -{ ptc_cparam, 0, 0 }, // first entry is # of parameters
  15869. -{ ptc_ipitch, 0.1, 4.0 }, // 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
  15870. -{ ptc_itimeslice, 20.0, 300.0 }, // in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
  15871. -{ ptc_ixfade, 1.0, 200.0 }, // in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
  15872. -};
  15873. -
  15874. -ptc_t *PTC_Params( prc_t *pprc )
  15875. -{
  15876. - ptc_t *pptc;
  15877. -
  15878. - float pitch = pprc->prm[ptc_ipitch];
  15879. - float timeslice = pprc->prm[ptc_itimeslice];
  15880. - float txfade = pprc->prm[ptc_ixfade];
  15881. -
  15882. - pptc = PTC_Alloc( timeslice, txfade, pitch );
  15883. -
  15884. - return pptc;
  15885. -}
  15886. -
  15887. -_inline void *PTC_VParams( void *p )
  15888. -{
  15889. - PRC_CheckParams((prc_t *)p, ptc_rng );
  15890. - return (void *)PTC_Params((prc_t *)p);
  15891. -}
  15892. -
  15893. -// change to new pitch value
  15894. -// v is +/- 0-1.0
  15895. -// v changes current pitch up/down by +/- v%
  15896. -void PTC_Mod( ptc_t *pptc, float v )
  15897. -{
  15898. - float fstep;
  15899. - float fstepnew;
  15900. -
  15901. - fstep = pptc->fstep;
  15902. - fstepnew = fstep * (1.0 + v);
  15903. -
  15904. - PTC_ChangeVal( pptc, fstepnew, 0.01 );
  15905. -}
  15906. -
  15907. -
  15908. -////////////////////
  15909. -// ADSR envelope
  15910. -////////////////////
  15911. -
  15912. -#define CENVS 64 // max # of envelopes active
  15913. -#define CENVRMPS 4 // A, D, S, R
  15914. -
  15915. -#define ENV_LIN 0 // linear a,d,s,r
  15916. -#define ENV_EXP 1 // exponential a,d,s,r
  15917. -#define ENV_MAX ENV_EXP
  15918. -
  15919. -#define ENV_BITS 14 // bits of resolution of ramp
  15920. -
  15921. -typedef struct
  15922. -{
  15923. - qboolean fused;
  15924. - qboolean fhitend; // true if done
  15925. - int ienv; // current ramp
  15926. - rmp_t rmps[CENVRMPS]; // ramps
  15927. -} env_t;
  15928. -
  15929. -env_t envs[CENVS];
  15930. -
  15931. -void ENV_Init( env_t *penv ) { if( penv ) memset( penv, 0, sizeof( env_t )); };
  15932. -void ENV_Free( env_t *penv ) { if( penv ) memset( penv, 0, sizeof( env_t )); };
  15933. -void ENV_InitAll() { int i; for( i = 0; i < CENVS; i++ ) ENV_Init( &envs[i] ); };
  15934. -void ENV_FreeAll() { int i; for( i = 0; i < CENVS; i++ ) ENV_Free( &envs[i] ); };
  15935. -
  15936. -
  15937. -// allocate ADSR envelope
  15938. -// all times are in seconds
  15939. -// amp1 - attack amplitude multiplier 0-1.0
  15940. -// amp2 - sustain amplitude multiplier 0-1.0
  15941. -// amp3 - end of sustain amplitude multiplier 0-1.0
  15942. -env_t *ENV_Alloc( int type, float famp1, float famp2, float famp3, float attack, float decay, float sustain, float release )
  15943. -{
  15944. - int i;
  15945. - env_t *penv;
  15946. -
  15947. - for( i = 0; i < CENVS; i++ )
  15948. - {
  15949. - if( !envs[i].fused )
  15950. - {
  15951. - int amp1 = famp1 * (1 << ENV_BITS); // ramp resolution
  15952. - int amp2 = famp2 * (1 << ENV_BITS);
  15953. - int amp3 = famp3 * (1 << ENV_BITS);
  15954. -
  15955. - penv = &envs[i];
  15956. -
  15957. - ENV_Init( penv );
  15958. -
  15959. - // UNDONE: ignoring type = ENV_EXP - use oneshot LFOS instead with sawtooth/exponential
  15960. -
  15961. - // set up ramps
  15962. - RMP_Init( &penv->rmps[0], attack, 0, amp1 );
  15963. - RMP_Init( &penv->rmps[1], decay, amp1, amp2 );
  15964. - RMP_Init( &penv->rmps[2], sustain, amp2, amp3 );
  15965. - RMP_Init( &penv->rmps[3], release, amp3, 0 );
  15966. -
  15967. - penv->ienv = 0;
  15968. - penv->fused = true;
  15969. - penv->fhitend = false;
  15970. -
  15971. - return penv;
  15972. - }
  15973. - }
  15974. -
  15975. - MsgDev( D_WARN, "DSP: failed to allocate envelope.\n" );
  15976. - return NULL;
  15977. -}
  15978. -
  15979. -_inline int ENV_GetNext( env_t *penv, int x )
  15980. -{
  15981. - if( !penv->fhitend )
  15982. - {
  15983. - int i, y;
  15984. -
  15985. - i = penv->ienv;
  15986. - y = RMP_GetNext( &penv->rmps[i] );
  15987. -
  15988. - // check for next ramp
  15989. - if( penv->rmps[i].fhitend )
  15990. - i++;
  15991. -
  15992. - penv->ienv = i;
  15993. -
  15994. - // check for end of all ramps
  15995. - if( i > 3 ) penv->fhitend = true;
  15996. -
  15997. - // multiply input signal by ramp
  15998. - return (x * y) >> ENV_BITS;
  15999. - }
  16000. - return 0;
  16001. -}
  16002. -
  16003. -// batch version for performance
  16004. -
  16005. -_inline void ENV_GetNextN( env_t *penv, portable_samplepair_t *pbuffer, int SampleCount, int op )
  16006. -{
  16007. - int count = SampleCount;
  16008. - portable_samplepair_t *pb = pbuffer;
  16009. -
  16010. - switch( op )
  16011. - {
  16012. - default:
  16013. - case OP_LEFT:
  16014. - while( count-- )
  16015. - {
  16016. - pb->left = ENV_GetNext( penv, pb->left );
  16017. - pb++;
  16018. - }
  16019. - break;
  16020. - case OP_RIGHT:
  16021. - while( count-- )
  16022. - {
  16023. - pb->right = ENV_GetNext( penv, pb->right );
  16024. - pb++;
  16025. - }
  16026. - break;
  16027. - case OP_LEFT_DUPLICATE:
  16028. - while( count-- )
  16029. - {
  16030. - pb->left = pb->right = ENV_GetNext( penv, pb->left );
  16031. - pb++;
  16032. - }
  16033. - break;
  16034. - }
  16035. -}
  16036. -
  16037. -// uses lfowav, amp1, amp2, amp3, attack, decay, sustain, release
  16038. -// lfowav is type, currently ignored - ie: LFO_LIN_IN, LFO_LOG_IN
  16039. -
  16040. -// parameter order
  16041. -typedef enum
  16042. -{
  16043. - env_itype,
  16044. - env_iamp1,
  16045. - env_iamp2,
  16046. - env_iamp3,
  16047. - env_iattack,
  16048. - env_idecay,
  16049. - env_isustain,
  16050. - env_irelease,
  16051. - env_cparam // # of params
  16052. -
  16053. -} env_e;
  16054. -
  16055. -// parameter ranges
  16056. -prm_rng_t env_rng[] =
  16057. -{
  16058. -{ env_cparam, 0, 0 }, // first entry is # of parameters
  16059. -{ env_itype, 0.0, ENV_MAX }, // ENV_LINEAR, ENV_LOG - currently ignored
  16060. -{ env_iamp1, 0.0, 1.0 }, // attack peak amplitude 0-1.0
  16061. -{ env_iamp2, 0.0, 1.0 }, // decay target amplitued 0-1.0
  16062. -{ env_iamp3, 0.0, 1.0 }, // sustain target amplitude 0-1.0
  16063. -{ env_iattack, 0.0, 20000.0 }, // attack time in milliseconds
  16064. -{ env_idecay, 0.0, 20000.0 }, // envelope decay time in milliseconds
  16065. -{ env_isustain, 0.0, 20000.0 }, // sustain time in milliseconds
  16066. -{ env_irelease, 0.0, 20000.0 }, // release time in milliseconds
  16067. -};
  16068. -
  16069. -env_t *ENV_Params( prc_t *pprc )
  16070. -{
  16071. - env_t *penv;
  16072. -
  16073. - float type = pprc->prm[env_itype];
  16074. - float amp1 = pprc->prm[env_iamp1];
  16075. - float amp2 = pprc->prm[env_iamp2];
  16076. - float amp3 = pprc->prm[env_iamp3];
  16077. - float attack = pprc->prm[env_iattack] / 1000.0f;
  16078. - float decay = pprc->prm[env_idecay] / 1000.0f;
  16079. - float sustain = pprc->prm[env_isustain] / 1000.0f;
  16080. - float release = pprc->prm[env_irelease] / 1000.0f;
  16081. -
  16082. - penv = ENV_Alloc( type, amp1, amp2, amp3, attack, decay, sustain, release );
  16083. - return penv;
  16084. -}
  16085. -
  16086. -_inline void *ENV_VParams( void *p )
  16087. -{
  16088. - PRC_CheckParams((prc_t *)p, env_rng );
  16089. - return (void *)ENV_Params((prc_t *)p);
  16090. -}
  16091. -
  16092. -_inline void ENV_Mod ( void *p, float v )
  16093. -{
  16094. -}
  16095. -
  16096. -////////////////////
  16097. -// envelope follower
  16098. -////////////////////
  16099. -#define CEFOS 64 // max # of envelope followers active
  16100. -
  16101. -#define CEFOBITS 6 // size 2^6 = 64
  16102. -#define CEFOWINDOW (1 << (CEFOBITS)) // size of sample window
  16103. -
  16104. -typedef struct
  16105. -{
  16106. - qboolean fused;
  16107. - int avg; // accumulating average over sample window
  16108. - int cavg; // count down
  16109. - int xout; // current output value
  16110. -
  16111. -} efo_t;
  16112. -
  16113. -efo_t efos[CEFOS];
  16114. -
  16115. -void EFO_Init( efo_t *pefo ) { if( pefo ) memset( pefo, 0, sizeof( efo_t )); };
  16116. -void EFO_Free( efo_t *pefo ) { if( pefo ) memset( pefo, 0, sizeof( efo_t )); };
  16117. -void EFO_InitAll() { int i; for( i = 0; i < CEFOS; i++ ) EFO_Init( &efos[i] ); };
  16118. -void EFO_FreeAll() { int i; for( i = 0; i < CEFOS; i++ ) EFO_Free( &efos[i] ); };
  16119. -
  16120. -// allocate enveloper follower
  16121. -efo_t *EFO_Alloc( void )
  16122. -{
  16123. - int i;
  16124. - efo_t *pefo;
  16125. -
  16126. - for( i = 0; i < CEFOS; i++ )
  16127. - {
  16128. - if( !efos[i].fused )
  16129. - {
  16130. - pefo = &efos[i];
  16131. -
  16132. - EFO_Init( pefo );
  16133. -
  16134. - pefo->xout = 0;
  16135. - pefo->cavg = CEFOWINDOW;
  16136. - pefo->fused = true;
  16137. -
  16138. - return pefo;
  16139. - }
  16140. - }
  16141. -
  16142. - MsgDev( D_WARN, "DSP: failed to allocate envelope follower.\n" );
  16143. - return NULL;
  16144. -}
  16145. -
  16146. -
  16147. -_inline int EFO_GetNext( efo_t *pefo, int x )
  16148. -{
  16149. - int xa = ABS( x ); // rectify input wav
  16150. -
  16151. - // get running sum / 2
  16152. - pefo->avg += xa >> 1; // divide by 2 to prevent overflow
  16153. -
  16154. - pefo->cavg--;
  16155. -
  16156. - if( !pefo->cavg )
  16157. - {
  16158. - // new output value - end of window
  16159. -
  16160. - // get average over window
  16161. - pefo->xout = pefo->avg >> (CEFOBITS - 1); // divide by window size / 2
  16162. - pefo->cavg = CEFOWINDOW;
  16163. - pefo->avg = 0;
  16164. - }
  16165. -
  16166. - return pefo->xout;
  16167. -}
  16168. -
  16169. -// batch version for performance
  16170. -_inline void EFO_GetNextN( efo_t *pefo, portable_samplepair_t *pbuffer, int SampleCount, int op )
  16171. -{
  16172. - int count = SampleCount;
  16173. - portable_samplepair_t *pb = pbuffer;
  16174. -
  16175. - switch( op )
  16176. - {
  16177. - default:
  16178. - case OP_LEFT:
  16179. - while( count-- )
  16180. - {
  16181. - pb->left = EFO_GetNext( pefo, pb->left );
  16182. - pb++;
  16183. - }
  16184. - break;
  16185. - case OP_RIGHT:
  16186. - while( count-- )
  16187. - {
  16188. - pb->right = EFO_GetNext( pefo, pb->right );
  16189. - pb++;
  16190. - }
  16191. - break;
  16192. - case OP_LEFT_DUPLICATE:
  16193. - while( count-- )
  16194. - {
  16195. - pb->left = pb->right = EFO_GetNext( pefo, pb->left );
  16196. - pb++;
  16197. - }
  16198. - break;
  16199. - }
  16200. -}
  16201. -
  16202. -
  16203. -efo_t * EFO_Params( prc_t *pprc )
  16204. -{
  16205. - return EFO_Alloc();
  16206. -}
  16207. -
  16208. -_inline void *EFO_VParams( void *p )
  16209. -{
  16210. - // PRC_CheckParams(( prc_t *)p, efo_rng ); - efo has no params
  16211. - return (void *)EFO_Params((prc_t *)p );
  16212. -}
  16213. -
  16214. -_inline void EFO_Mod( void *p, float v )
  16215. -{
  16216. -}
  16217. -
  16218. -//////////////
  16219. -// mod delay
  16220. -//////////////
  16221. -
  16222. -// modulate delay time anywhere from 0..D using MDY_ChangeVal. no output glitches (uses RMP)
  16223. -
  16224. -#define CMDYS 64 // max # of mod delays active (steals from delays)
  16225. -
  16226. -typedef struct
  16227. -{
  16228. - qboolean fused;
  16229. - qboolean fchanging; // true if modulating to new delay value
  16230. - dly_t *pdly; // delay
  16231. - int Dcur; // current delay value
  16232. - float ramptime; // ramp 'glide' time - time in seconds to change between values
  16233. - int mtime; // time in samples between delay changes. 0 implies no self-modulating
  16234. - int mtimecur; // current time in samples until next delay change
  16235. - float depth; // modulate delay from D to D - (D*depth) depth 0-1.0
  16236. - int xprev; // previous delay output, used to smooth transitions between delays
  16237. - rmp_t rmp; // ramp
  16238. -} mdy_t;
  16239. -
  16240. -mdy_t mdys[CMDYS];
  16241. -
  16242. -void MDY_Init( mdy_t *pmdy ) { if( pmdy ) memset( pmdy, 0, sizeof( mdy_t )); };
  16243. -void MDY_Free( mdy_t *pmdy ) { if( pmdy ) { DLY_Free( pmdy->pdly ); memset( pmdy, 0, sizeof( mdy_t )); } };
  16244. -void MDY_InitAll() { int i; for( i = 0; i < CMDYS; i++ ) MDY_Init( &mdys[i] ); };
  16245. -void MDY_FreeAll() { int i; for( i = 0; i < CMDYS; i++ ) MDY_Free( &mdys[i] ); };
  16246. -
  16247. -
  16248. -// allocate mod delay, given previously allocated dly
  16249. -// ramptime is time in seconds for delay to change from dcur to dnew
  16250. -// modtime is time in seconds between modulations. 0 if no self-modulation
  16251. -// depth is 0-1.0 multiplier, new delay values when modulating are Dnew = randomlong (D - D*depth, D)
  16252. -mdy_t *MDY_Alloc( dly_t *pdly, float ramptime, float modtime, float depth )
  16253. -{
  16254. - int i;
  16255. - mdy_t *pmdy;
  16256. -
  16257. - if( !pdly )
  16258. - return NULL;
  16259. -
  16260. - for( i = 0; i < CMDYS; i++ )
  16261. - {
  16262. - if( !mdys[i].fused )
  16263. - {
  16264. - pmdy = &mdys[i];
  16265. -
  16266. - MDY_Init( pmdy );
  16267. -
  16268. - pmdy->pdly = pdly;
  16269. -
  16270. - if( !pmdy->pdly )
  16271. - {
  16272. - MsgDev( D_WARN, "DSP: failed to allocate delay for mod delay.\n" );
  16273. - return NULL;
  16274. - }
  16275. -
  16276. - pmdy->Dcur = pdly->D0;
  16277. - pmdy->fused = true;
  16278. - pmdy->ramptime = ramptime;
  16279. - pmdy->mtime = SEC_TO_SAMPS( modtime );
  16280. - pmdy->mtimecur = pmdy->mtime;
  16281. - pmdy->depth = depth;
  16282. -
  16283. - return pmdy;
  16284. - }
  16285. - }
  16286. -
  16287. - MsgDev( D_WARN, "DSP: failed to allocate mod delay.\n" );
  16288. - return NULL;
  16289. -}
  16290. -
  16291. -// change to new delay tap value t samples, ramp linearly over ramptime seconds
  16292. -void MDY_ChangeVal( mdy_t *pmdy, int t )
  16293. -{
  16294. - // if D > original delay value, cap at original value
  16295. -
  16296. - t = min( pmdy->pdly->D0, t );
  16297. - pmdy->fchanging = true;
  16298. -
  16299. - RMP_Init( &pmdy->rmp, pmdy->ramptime, pmdy->Dcur, t );
  16300. -}
  16301. -
  16302. -// get next value from modulating delay
  16303. -int MDY_GetNext( mdy_t *pmdy, int x )
  16304. -{
  16305. - int xout;
  16306. - int xcur;
  16307. -
  16308. - // get current delay output
  16309. - xcur = DLY_GetNext( pmdy->pdly, x );
  16310. -
  16311. - // return right away if not modulating (not changing and not self modulating)
  16312. - if( !pmdy->fchanging && !pmdy->mtime )
  16313. - {
  16314. - pmdy->xprev = xcur;
  16315. - return xcur;
  16316. - }
  16317. -
  16318. - xout = xcur;
  16319. -
  16320. - // if currently changing to new delay target, get next delay value
  16321. - if( pmdy->fchanging )
  16322. - {
  16323. - // get next ramp value, test for done
  16324. - int r = RMP_GetNext( &pmdy->rmp );
  16325. -
  16326. - if( RMP_HitEnd( &pmdy->rmp ))
  16327. - pmdy->fchanging = false;
  16328. -
  16329. - // if new delay different from current delay, change delay
  16330. - if( r != pmdy->Dcur )
  16331. - {
  16332. - // ramp never changes by more than + or - 1
  16333. -
  16334. - // change delay tap value to r
  16335. - DLY_ChangeVal( pmdy->pdly, r );
  16336. -
  16337. - pmdy->Dcur = r;
  16338. -
  16339. - // filter delay output within transitions.
  16340. - // note: xprev = xcur = 0 if changing delay on 1st sample
  16341. - xout = ( xcur + pmdy->xprev ) >> 1;
  16342. - }
  16343. - }
  16344. -
  16345. - // if self-modulating and timer has expired, get next change
  16346. - if( pmdy->mtime && !pmdy->mtimecur-- )
  16347. - {
  16348. - int D0 = pmdy->pdly->D0;
  16349. - int Dnew;
  16350. - float D1;
  16351. -
  16352. - pmdy->mtimecur = pmdy->mtime;
  16353. -
  16354. - // modulate between 0 and 100% of d0
  16355. - D1 = (float)D0 * (1.0 - pmdy->depth);
  16356. - Dnew = Com_RandomLong( (int)D1, D0 );
  16357. -
  16358. - MDY_ChangeVal( pmdy, Dnew );
  16359. - }
  16360. -
  16361. - pmdy->xprev = xcur;
  16362. -
  16363. - return xout;
  16364. -}
  16365. -
  16366. -// batch version for performance
  16367. -_inline void MDY_GetNextN( mdy_t *pmdy, portable_samplepair_t *pbuffer, int SampleCount, int op )
  16368. -{
  16369. - int count = SampleCount;
  16370. - portable_samplepair_t *pb = pbuffer;
  16371. -
  16372. - switch( op )
  16373. - {
  16374. - default:
  16375. - case OP_LEFT:
  16376. - while( count-- )
  16377. - {
  16378. - pb->left = MDY_GetNext( pmdy, pb->left );
  16379. - pb++;
  16380. - }
  16381. - return;
  16382. - case OP_RIGHT:
  16383. - while( count-- )
  16384. - {
  16385. - pb->right = MDY_GetNext( pmdy, pb->right );
  16386. - pb++;
  16387. - }
  16388. - return;
  16389. - case OP_LEFT_DUPLICATE:
  16390. - while( count-- )
  16391. - {
  16392. - pb->left = pb->right = MDY_GetNext( pmdy, pb->left );
  16393. - pb++;
  16394. - }
  16395. - return;
  16396. - }
  16397. -}
  16398. -
  16399. -// parameter order
  16400. -typedef enum
  16401. -{
  16402. - mdy_idtype, // NOTE: first 8 params must match params in dly_e
  16403. - mdy_idelay,
  16404. - mdy_ifeedback,
  16405. - mdy_igain,
  16406. - mdy_iftype,
  16407. - mdy_icutoff,
  16408. - mdy_iqwidth,
  16409. - mdy_iquality,
  16410. - mdy_imodrate,
  16411. - mdy_imoddepth,
  16412. - mdy_imodglide,
  16413. - mdy_cparam
  16414. -} mdy_e;
  16415. -
  16416. -
  16417. -// parameter ranges
  16418. -prm_rng_t mdy_rng[] =
  16419. -{
  16420. -{ mdy_cparam, 0, 0 }, // first entry is # of parameters
  16421. -
  16422. -// delay params
  16423. -{ mdy_idtype, 0, DLY_MAX }, // delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  16424. -{ mdy_idelay, 0.0, 1000.0 }, // delay in milliseconds
  16425. -{ mdy_ifeedback, 0.0, 0.99 }, // feedback 0-1.0
  16426. -{ mdy_igain, 0.0, 1.0 }, // final gain of output stage, 0-1.0
  16427. -
  16428. -// filter params if mdy type DLY_LOWPASS
  16429. -{ mdy_iftype, 0, FTR_MAX },
  16430. -{ mdy_icutoff, 10.0, 22050.0 },
  16431. -{ mdy_iqwidth, 100.0, 11025.0 },
  16432. -{ mdy_iquality, 0, QUA_MAX },
  16433. -{ mdy_imodrate, 0.01, 200.0 }, // frequency at which delay values change to new random value. 0 is no self-modulation
  16434. -{ mdy_imoddepth, 0.0, 1.0 }, // how much delay changes (decreases) from current value (0-1.0)
  16435. -{ mdy_imodglide, 0.01, 100.0 }, // glide time between dcur and dnew in milliseconds
  16436. -};
  16437. -
  16438. -// convert user parameters to internal parameters, allocate and return
  16439. -mdy_t *MDY_Params( prc_t *pprc )
  16440. -{
  16441. - mdy_t *pmdy;
  16442. - dly_t *pdly;
  16443. -
  16444. - float ramptime = pprc->prm[mdy_imodglide] / 1000.0; // get ramp time in seconds
  16445. - float modtime = 1.0 / pprc->prm[mdy_imodrate]; // time between modulations in seconds
  16446. - float depth = pprc->prm[mdy_imoddepth]; // depth of modulations 0-1.0
  16447. -
  16448. - // alloc plain, allpass or lowpass delay
  16449. - pdly = DLY_Params( pprc );
  16450. - if( !pdly ) return NULL;
  16451. -
  16452. - pmdy = MDY_Alloc( pdly, ramptime, modtime, depth );
  16453. -
  16454. - return pmdy;
  16455. -}
  16456. -
  16457. -_inline void * MDY_VParams( void *p )
  16458. -{
  16459. - PRC_CheckParams(( prc_t *)p, mdy_rng );
  16460. - return (void *)MDY_Params ((prc_t *)p );
  16461. -}
  16462. -
  16463. -// v is +/- 0-1.0
  16464. -// change current delay value 0..D
  16465. -void MDY_Mod( mdy_t *pmdy, float v )
  16466. -{
  16467. - int D = pmdy->Dcur;
  16468. - float v2 = -(v + 1.0)/2.0; // v2 varies -1.0-0.0
  16469. -
  16470. - // D varies 0..D
  16471. - D = D + (int)((float)D * v2);
  16472. -
  16473. - // change delay
  16474. - MDY_ChangeVal( pmdy, D );
  16475. -}
  16476. -
  16477. -
  16478. -///////////////////////////////////////////
  16479. -// Chorus - lfo modulated delay
  16480. -///////////////////////////////////////////
  16481. -
  16482. -
  16483. -#define CCRSS 64 // max number chorus' active
  16484. -
  16485. -typedef struct
  16486. -{
  16487. - qboolean fused;
  16488. - mdy_t *pmdy; // modulatable delay
  16489. - lfo_t *plfo; // modulating lfo
  16490. - int lfoprev; // previous modulator value from lfo
  16491. - int mix; // mix of clean & chorus signal - 0..PMAX
  16492. -} crs_t;
  16493. -
  16494. -crs_t crss[CCRSS];
  16495. -
  16496. -void CRS_Init( crs_t *pcrs ) { if( pcrs ) memset( pcrs, 0, sizeof( crs_t )); };
  16497. -void CRS_Free( crs_t *pcrs )
  16498. -{
  16499. - if( pcrs )
  16500. - {
  16501. - MDY_Free( pcrs->pmdy );
  16502. - LFO_Free( pcrs->plfo );
  16503. - memset( pcrs, 0, sizeof( crs_t ));
  16504. - }
  16505. -}
  16506. -
  16507. -void CRS_InitAll() { int i; for( i = 0; i < CCRSS; i++ ) CRS_Init( &crss[i] ); }
  16508. -void CRS_FreeAll() { int i; for( i = 0; i < CCRSS; i++ ) CRS_Free( &crss[i] ); }
  16509. -
  16510. -// fstep is base pitch shift, ie: floating point step value, where 1.0 = +1 octave, 0.5 = -1 octave
  16511. -// lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  16512. -// fHz is modulation frequency in Hz
  16513. -// depth is modulation depth, 0-1.0
  16514. -// mix is mix of chorus and clean signal
  16515. -
  16516. -#define CRS_DELAYMAX 100 // max milliseconds of sweepable delay
  16517. -#define CRS_RAMPTIME 5 // milliseconds to ramp between new delay values
  16518. -
  16519. -crs_t * CRS_Alloc( int lfotype, float fHz, float fdepth, float mix )
  16520. -{
  16521. - int i, D;
  16522. - crs_t *pcrs;
  16523. - dly_t *pdly;
  16524. - mdy_t *pmdy;
  16525. - lfo_t *plfo;
  16526. - float ramptime;
  16527. -
  16528. - // find free chorus slot
  16529. - for( i = 0; i < CCRSS; i++ )
  16530. - {
  16531. - if( !crss[i].fused )
  16532. - break;
  16533. - }
  16534. -
  16535. - if( i == CCRSS )
  16536. - {
  16537. - MsgDev( D_WARN, "DSP: failed to allocate chorus.\n" );
  16538. - return NULL;
  16539. - }
  16540. -
  16541. - pcrs = &crss[i];
  16542. - CRS_Init( pcrs );
  16543. -
  16544. - D = fdepth * MSEC_TO_SAMPS( CRS_DELAYMAX ); // sweep from 0 - n milliseconds
  16545. -
  16546. - ramptime = (float)CRS_RAMPTIME / 1000.0f; // # milliseconds to ramp between new values
  16547. -
  16548. - pdly = DLY_Alloc( D, 0, 1, DLY_LINEAR );
  16549. - pmdy = MDY_Alloc( pdly, ramptime, 0.0, 0.0 );
  16550. - plfo = LFO_Alloc( lfotype, fHz, false );
  16551. -
  16552. - if( !plfo || !pmdy )
  16553. - {
  16554. - LFO_Free( plfo );
  16555. - MDY_Free( pmdy );
  16556. - MsgDev( D_WARN, "DSP: failed to allocate lfo or mdy for chorus.\n" );
  16557. - return NULL;
  16558. - }
  16559. -
  16560. - pcrs->pmdy = pmdy;
  16561. - pcrs->plfo = plfo;
  16562. - pcrs->mix = (int)( PMAX * mix );
  16563. - pcrs->fused = true;
  16564. -
  16565. - return pcrs;
  16566. -}
  16567. -
  16568. -// return next chorused sample (modulated delay) mixed with input sample
  16569. -_inline int CRS_GetNext( crs_t *pcrs, int x )
  16570. -{
  16571. - int l, y;
  16572. -
  16573. - // get current mod delay value
  16574. - y = MDY_GetNext( pcrs->pmdy, x );
  16575. -
  16576. - // get next lfo value for modulation
  16577. - // note: lfo must return 0 as first value
  16578. - l = LFO_GetNext( pcrs->plfo, x );
  16579. -
  16580. - // if modulator has changed, change mdy
  16581. - if( l != pcrs->lfoprev )
  16582. - {
  16583. - // calculate new tap (starts at D)
  16584. - int D = pcrs->pmdy->pdly->D0;
  16585. - int tap;
  16586. -
  16587. - // lfo should always output values 0 <= l <= LFOMAX
  16588. -
  16589. - if( l < 0 ) l = 0;
  16590. -
  16591. - tap = D - ((l * D) >> LFOBITS);
  16592. - MDY_ChangeVal ( pcrs->pmdy, tap );
  16593. - pcrs->lfoprev = l;
  16594. - }
  16595. -
  16596. - return ((y * pcrs->mix) >> PBITS) + x;
  16597. -}
  16598. -
  16599. -// batch version for performance
  16600. -_inline void CRS_GetNextN( crs_t *pcrs, portable_samplepair_t *pbuffer, int SampleCount, int op )
  16601. -{
  16602. - int count = SampleCount;
  16603. - portable_samplepair_t *pb = pbuffer;
  16604. -
  16605. - switch( op )
  16606. - {
  16607. - default:
  16608. - case OP_LEFT:
  16609. - while( count-- )
  16610. - {
  16611. - pb->left = CRS_GetNext( pcrs, pb->left );
  16612. - pb++;
  16613. - }
  16614. - break;
  16615. - case OP_RIGHT:
  16616. - while( count-- )
  16617. - {
  16618. - pb->right = CRS_GetNext( pcrs, pb->right );
  16619. - pb++;
  16620. - }
  16621. - break;
  16622. - case OP_LEFT_DUPLICATE:
  16623. - while( count-- )
  16624. - {
  16625. - pb->left = pb->right = CRS_GetNext( pcrs, pb->left );
  16626. - pb++;
  16627. - }
  16628. - break;
  16629. - }
  16630. -}
  16631. -
  16632. -// parameter order
  16633. -typedef enum
  16634. -{
  16635. - crs_ilfotype,
  16636. - crs_irate,
  16637. - crs_idepth,
  16638. - crs_imix,
  16639. - crs_cparam
  16640. -} crs_e;
  16641. -
  16642. -
  16643. -// parameter ranges
  16644. -prm_rng_t crs_rng[] =
  16645. -{
  16646. -{ crs_cparam, 0, 0 }, // first entry is # of parameters
  16647. -{ crs_ilfotype, 0, LFO_MAX }, // lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  16648. -{ crs_irate, 0.0, 1000.0 }, // rate is modulation frequency in Hz
  16649. -{ crs_idepth, 0.0, 1.0 }, // depth is modulation depth, 0-1.0
  16650. -{ crs_imix, 0.0, 1.0 }, // mix is mix of chorus and clean signal
  16651. -};
  16652. -
  16653. -// uses pitch, lfowav, rate, depth
  16654. -crs_t *CRS_Params( prc_t *pprc )
  16655. -{
  16656. - crs_t *pcrs;
  16657. -
  16658. - pcrs = CRS_Alloc( pprc->prm[crs_ilfotype], pprc->prm[crs_irate], pprc->prm[crs_idepth], pprc->prm[crs_imix] );
  16659. -
  16660. - return pcrs;
  16661. -}
  16662. -
  16663. -_inline void *CRS_VParams( void *p )
  16664. -{
  16665. - PRC_CheckParams((prc_t *)p, crs_rng );
  16666. - return (void *)CRS_Params((prc_t *)p );
  16667. -}
  16668. -
  16669. -_inline void CRS_Mod( void *p, float v )
  16670. -{
  16671. -}
  16672. -
  16673. -////////////////////////////////////////////////////
  16674. -// amplifier - modulatable gain, distortion
  16675. -////////////////////////////////////////////////////
  16676. -
  16677. -#define CAMPS 64 // max number amps active
  16678. -#define AMPSLEW 10 // milliseconds of slew time between gain changes
  16679. -
  16680. -typedef struct
  16681. -{
  16682. - qboolean fused;
  16683. - float gain; // amplification 0-6.0
  16684. - float vthresh; // clip distortion threshold 0-1.0
  16685. - float distmix; // 0-1.0 mix of distortion with clean
  16686. - float vfeed; // 0-1.0 feedback with distortion;
  16687. - float gaintarget; // new gain
  16688. - float gaindif; // incrementer
  16689. -} amp_t;
  16690. -
  16691. -amp_t amps[CAMPS];
  16692. -
  16693. -void AMP_Init( amp_t *pamp ) { if( pamp ) memset( pamp, 0, sizeof( amp_t )); }
  16694. -void AMP_Free( amp_t *pamp ) { if( pamp ) memset( pamp, 0, sizeof( amp_t )); }
  16695. -void AMP_InitAll() { int i; for( i = 0; i < CAMPS; i++ ) AMP_Init( &amps[i] ); }
  16696. -void AMP_FreeAll() { int i; for( i = 0; i < CAMPS; i++ ) AMP_Free( &amps[i] ); }
  16697. -
  16698. -amp_t *AMP_Alloc( float gain, float vthresh, float distmix, float vfeed )
  16699. -{
  16700. - int i;
  16701. - amp_t *pamp;
  16702. -
  16703. - // find free amp slot
  16704. - for( i = 0; i < CAMPS; i++ )
  16705. - {
  16706. - if ( !amps[i].fused )
  16707. - break;
  16708. - }
  16709. -
  16710. - if( i == CAMPS )
  16711. - {
  16712. - MsgDev( D_WARN, "DSP: failed to allocate amp.\n" );
  16713. - return NULL;
  16714. - }
  16715. -
  16716. - pamp = &amps[i];
  16717. -
  16718. - AMP_Init ( pamp );
  16719. -
  16720. - pamp->gain = gain;
  16721. - pamp->vthresh = vthresh;
  16722. - pamp->distmix = distmix;
  16723. - pamp->vfeed = vfeed;
  16724. -
  16725. - return pamp;
  16726. -}
  16727. -
  16728. -// return next amplified sample
  16729. -_inline int AMP_GetNext( amp_t *pamp, int x )
  16730. -{
  16731. - float y = (float)x;
  16732. - float yin;
  16733. - float gain = pamp->gain;
  16734. -
  16735. - yin = y;
  16736. -
  16737. - // slew between gains
  16738. - if( gain != pamp->gaintarget )
  16739. - {
  16740. - float gaintarget = pamp->gaintarget;
  16741. - float gaindif = pamp->gaindif;
  16742. -
  16743. - if( gain > gaintarget )
  16744. - {
  16745. - gain -= gaindif;
  16746. - if( gain <= gaintarget )
  16747. - pamp->gaintarget = gain;
  16748. - }
  16749. - else
  16750. - {
  16751. - gain += gaindif;
  16752. - if( gain >= gaintarget )
  16753. - pamp->gaintarget = gain;
  16754. - }
  16755. -
  16756. - pamp->gain = gain;
  16757. - }
  16758. -
  16759. - // if distortion is on, add distortion, feedback
  16760. - if( pamp->vthresh < 1.0 )
  16761. - {
  16762. - float fclip = pamp->vthresh * 32767.0;
  16763. -
  16764. - if( pamp->vfeed > 0.0 )
  16765. - {
  16766. - // UNDONE: feedback
  16767. - }
  16768. -
  16769. - // clip distort
  16770. - y = ( y > fclip ? fclip : ( y < -fclip ? -fclip : y));
  16771. -
  16772. - // mix distorted with clean (1.0 = full distortion)
  16773. - if( pamp->distmix > 0.0 )
  16774. - y = y * pamp->distmix + yin * (1.0 - pamp->distmix);
  16775. - }
  16776. -
  16777. - // amplify
  16778. - y *= gain;
  16779. -
  16780. - return (int)y;
  16781. -}
  16782. -
  16783. -// batch version for performance
  16784. -_inline void AMP_GetNextN( amp_t *pamp, portable_samplepair_t *pbuffer, int SampleCount, int op )
  16785. -{
  16786. - int count = SampleCount;
  16787. - portable_samplepair_t *pb = pbuffer;
  16788. -
  16789. - switch( op )
  16790. - {
  16791. - default:
  16792. - case OP_LEFT:
  16793. - while( count-- )
  16794. - {
  16795. - pb->left = AMP_GetNext( pamp, pb->left );
  16796. - pb++;
  16797. - }
  16798. - break;
  16799. - case OP_RIGHT:
  16800. - while( count-- )
  16801. - {
  16802. - pb->right = AMP_GetNext( pamp, pb->right );
  16803. - pb++;
  16804. - }
  16805. - break;
  16806. - case OP_LEFT_DUPLICATE:
  16807. - while( count-- )
  16808. - {
  16809. - pb->left = pb->right = AMP_GetNext( pamp, pb->left );
  16810. - pb++;
  16811. - }
  16812. - break;
  16813. - }
  16814. -}
  16815. -
  16816. -_inline void AMP_Mod( amp_t *pamp, float v )
  16817. -{
  16818. - float vmod = bound( v, 0.0, 1.0 );
  16819. - float samps = MSEC_TO_SAMPS( AMPSLEW ); // # samples to slew between amp values
  16820. -
  16821. - // ramp to new amplification value
  16822. - pamp->gaintarget = pamp->gain * vmod;
  16823. -
  16824. - pamp->gaindif = fabs( pamp->gain - pamp->gaintarget ) / samps;
  16825. -
  16826. - if( pamp->gaindif == 0.0f )
  16827. - pamp->gaindif = fabs( pamp->gain - pamp->gaintarget ) / 100;
  16828. -}
  16829. -
  16830. -
  16831. -// parameter order
  16832. -typedef enum
  16833. -{
  16834. - amp_gain,
  16835. - amp_vthresh,
  16836. - amp_distmix,
  16837. - amp_vfeed,
  16838. - amp_cparam
  16839. -} amp_e;
  16840. -
  16841. -
  16842. -// parameter ranges
  16843. -prm_rng_t amp_rng[] =
  16844. -{
  16845. -{ amp_cparam, 0, 0 }, // first entry is # of parameters
  16846. -{ amp_gain, 0.0, 10.0 }, // amplification
  16847. -{ amp_vthresh, 0.0, 1.0 }, // threshold for distortion (1.0 = no distortion)
  16848. -{ amp_distmix, 0.0, 1.0 }, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
  16849. -{ amp_vfeed, 0.0, 1.0 }, // distortion feedback
  16850. -};
  16851. -
  16852. -amp_t * AMP_Params( prc_t *pprc )
  16853. -{
  16854. - amp_t *pamp;
  16855. -
  16856. - pamp = AMP_Alloc( pprc->prm[amp_gain], pprc->prm[amp_vthresh], pprc->prm[amp_distmix], pprc->prm[amp_vfeed] );
  16857. -
  16858. - return pamp;
  16859. -}
  16860. -
  16861. -_inline void *AMP_VParams( void *p )
  16862. -{
  16863. - PRC_CheckParams((prc_t *)p, amp_rng );
  16864. - return (void *)AMP_Params((prc_t *)p );
  16865. -}
  16866. -
  16867. -
  16868. -/////////////////
  16869. -// NULL processor
  16870. -/////////////////
  16871. -typedef struct
  16872. -{
  16873. - int type;
  16874. -} nul_t;
  16875. -
  16876. -nul_t nuls[] = { 0 };
  16877. -
  16878. -void NULL_Init( nul_t *pnul ) { }
  16879. -void NULL_InitAll( ) { }
  16880. -void NULL_Free( nul_t *pnul ) { }
  16881. -void NULL_FreeAll( ) { }
  16882. -nul_t *NULL_Alloc( ) { return &nuls[0]; }
  16883. -
  16884. -_inline int NULL_GetNext( void *p, int x ) { return x; }
  16885. -_inline void NULL_GetNextN( nul_t *pnul, portable_samplepair_t *pbuffer, int SampleCount, int op ) { return; }
  16886. -_inline void NULL_Mod( void *p, float v ) { return; }
  16887. -_inline void * NULL_VParams( void *p ) { return (void *)(&nuls[0]); }
  16888. -
  16889. -//////////////////////////
  16890. -// DSP processors presets
  16891. -//////////////////////////
  16892. -
  16893. -// A dsp processor (prc) performs a single-sample function, such as pitch shift, delay, reverb, filter
  16894. -
  16895. -// note, this array must have CPRCPARMS entries
  16896. -#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
  16897. -#define PFNZERO NULL,NULL,NULL,NULL,NULL // zero pointers for pfnparam...pdata within prc_t
  16898. -
  16899. -//////////////////
  16900. -// NULL processor
  16901. -/////////////////
  16902. -
  16903. -#define PRC_NULL1 { PRC_NULL, PRMZERO, PFNZERO }
  16904. -
  16905. -#define PRC0 PRC_NULL1
  16906. -
  16907. -//////////////
  16908. -// Amplifiers
  16909. -//////////////
  16910. -
  16911. -// {amp_gain, 0.0, 10.0 }, // amplification
  16912. -// {amp_vthresh, 0.0, 1.0 }, // threshold for distortion (1.0 = no distortion)
  16913. -// {amp_distmix, 0.0, 1.0 }, // mix of clean and distortion (1.0 = full distortion, 0.0 = full clean)
  16914. -// {amp_vfeed, 0.0, 1.0 }, // distortion feedback
  16915. -
  16916. -// prctype gain vthresh distmix vfeed
  16917. -#define PRC_AMP1 {PRC_AMP, { 1.0, 1.0, 0.0, 0.0, }, PFNZERO } // modulatable unity gain amp
  16918. -#define PRC_AMP2 {PRC_AMP, { 1.5, 0.75, 1.0, 0.0, }, PFNZERO } // amp with light distortion
  16919. -#define PRC_AMP3 {PRC_AMP, { 2.0, 0.5, 1.0, 0.0, }, PFNZERO } // amp with medium distortion
  16920. -#define PRC_AMP4 {PRC_AMP, { 4.0, 0.25, 1.0, 0.0, }, PFNZERO } // amp with heavy distortion
  16921. -#define PRC_AMP5 {PRC_AMP, { 10.0, 0.10, 1.0, 0.0, }, PFNZERO } // mega distortion
  16922. -
  16923. -#define PRC_AMP6 {PRC_AMP, { 0.1, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
  16924. -#define PRC_AMP7 {PRC_AMP, { 0.2, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
  16925. -#define PRC_AMP8 {PRC_AMP, { 0.3, 1.0, 0.0, 0.0, }, PFNZERO } // fade out
  16926. -
  16927. -#define PRC_AMP9 {PRC_AMP, { 0.75, 1.0, 0.0, 0.0, }, PFNZERO } // duck out
  16928. -
  16929. -
  16930. -///////////
  16931. -// Filters
  16932. -///////////
  16933. -
  16934. -// ftype: filter type FLT_LP, FLT_HP, FLT_BP (UNDONE: FLT_BP currently ignored)
  16935. -// cutoff: cutoff frequency in hz at -3db gain
  16936. -// qwidth: width of BP, or steepness of LP/HP (ie: fcutoff + qwidth = -60db gain point)
  16937. -// quality: QUA_LO, _MED, _HI 0,1,2
  16938. -
  16939. -// prctype ftype cutoff qwidth quality
  16940. -#define PRC_FLT1 {PRC_FLT, { FLT_LP, 3000, 1000, QUA_MED, }, PFNZERO }
  16941. -#define PRC_FLT2 {PRC_FLT, { FLT_LP, 2000, 2000, QUA_MED, }, PFNZERO } // lowpass for facing away
  16942. -#define PRC_FLT3 {PRC_FLT, { FLT_LP, 1000, 1000, QUA_MED, }, PFNZERO }
  16943. -#define PRC_FLT4 {PRC_FLT, { FLT_LP, 700, 700, QUA_LO, }, PFNZERO } // muffle filter
  16944. -
  16945. -#define PRC_FLT5 {PRC_FLT, { FLT_HP, 700, 200, QUA_MED, }, PFNZERO } // highpass (bandpass pair)
  16946. -#define PRC_FLT6 {PRC_FLT, { FLT_HP, 2000, 1000, QUA_MED, }, PFNZERO } // lowpass (bandpass pair)
  16947. -
  16948. -//////////
  16949. -// Delays
  16950. -//////////
  16951. -
  16952. -// dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  16953. -// delay: delay in milliseconds
  16954. -// feedback: feedback 0-1.0
  16955. -// gain: final gain of output stage, 0-1.0
  16956. -
  16957. -// prctype dtype delay feedbk gain ftype cutoff qwidth quality
  16958. -#define PRC_DLY1 {PRC_DLY, { DLY_PLAIN, 500.0, 0.5, 0.6, 0.0, 0.0, 0.0, 0.0, }, PFNZERO }
  16959. -#define PRC_DLY2 {PRC_DLY, { DLY_LOWPASS, 45.0, 0.8, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO }
  16960. -#define PRC_DLY3 {PRC_DLY, { DLY_LOWPASS, 300.0, 0.5, 0.6, FLT_LP, 2000, 2000, QUA_LO, }, PFNZERO } // outside S
  16961. -#define PRC_DLY4 {PRC_DLY, { DLY_LOWPASS, 400.0, 0.5, 0.6, FLT_LP, 1500, 1500, QUA_LO, }, PFNZERO } // outside M
  16962. -#define PRC_DLY5 {PRC_DLY, { DLY_LOWPASS, 750.0, 0.5, 0.6, FLT_LP, 1000, 1000, QUA_LO, }, PFNZERO } // outside L
  16963. -#define PRC_DLY6 {PRC_DLY, { DLY_LOWPASS, 1000.0, 0.5, 0.6, FLT_LP, 800, 400, QUA_LO, }, PFNZERO } // outside VL
  16964. -#define PRC_DLY7 {PRC_DLY, { DLY_LOWPASS, 45.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel S
  16965. -#define PRC_DLY8 {PRC_DLY, { DLY_LOWPASS, 55.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel M
  16966. -#define PRC_DLY9 {PRC_DLY, { DLY_LOWPASS, 65.0, 0.4, 0.5, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // tunnel L
  16967. -#define PRC_DLY10 {PRC_DLY, { DLY_LOWPASS, 150.0, 0.5, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern S
  16968. -#define PRC_DLY11 {PRC_DLY, { DLY_LOWPASS, 200.0, 0.7, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern M
  16969. -#define PRC_DLY12 {PRC_DLY, { DLY_LOWPASS, 300.0, 0.7, 0.6, FLT_LP, 3000, 3000, QUA_LO, }, PFNZERO } // cavern L
  16970. -#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
  16971. -#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
  16972. -
  16973. -///////////
  16974. -// Reverbs
  16975. -///////////
  16976. -
  16977. -// size: 0-2.0 scales nominal delay parameters (starting at approx 20ms)
  16978. -// density: 0-2.0 density of reverbs (room shape) - controls # of parallel or series delays
  16979. -// decay: 0-2.0 scales feedback parameters (starting at approx 0.15)
  16980. -
  16981. -// prctype size density decay ftype cutoff qwidth fparallel
  16982. -#define PRC_RVA1 {PRC_RVA, {2.0, 0.5, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO }
  16983. -#define PRC_RVA2 {PRC_RVA, {1.0, 0.2, 1.5, 0, 0, 0, 0}, PFNZERO }
  16984. -
  16985. -#define PRC_RVA3 {PRC_RVA, {0.8, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic S
  16986. -#define PRC_RVA4 {PRC_RVA, {1.0, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic M
  16987. -#define PRC_RVA5 {PRC_RVA, {1.2, 0.5, 1.5, FLT_LP, 2500, 2000, 0}, PFNZERO } // metallic L
  16988. -
  16989. -#define PRC_RVA6 {PRC_RVA, {0.8, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel S
  16990. -#define PRC_RVA7 {PRC_RVA, {0.9, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel M
  16991. -#define PRC_RVA8 {PRC_RVA, {1.0, 0.3, 1.5, FLT_LP, 4000, 2000, 0}, PFNZERO } // tunnel L
  16992. -
  16993. -#define PRC_RVA9 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern S
  16994. -#define PRC_RVA10 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern M
  16995. -#define PRC_RVA11 {PRC_RVA, {2.0, 1.5, 2.0, FLT_LP, 1500, 1500, 1}, PFNZERO } // cavern L
  16996. -
  16997. -#define PRC_RVA12 {PRC_RVA, {2.0, 0.5, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber S
  16998. -#define PRC_RVA13 {PRC_RVA, {2.0, 1.0, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber M
  16999. -#define PRC_RVA14 {PRC_RVA, {2.0, 2.0, 1.5, FLT_LP, 6000, 2000, 1}, PFNZERO } // chamber L
  17000. -
  17001. -#define PRC_RVA15 {PRC_RVA, {1.7, 1.0, 1.2, FLT_LP, 5000, 4000, 1}, PFNZERO } // brite S
  17002. -#define PRC_RVA16 {PRC_RVA, {1.75, 1.0, 1.5, FLT_LP, 5000, 4000, 1}, PFNZERO } // brite M
  17003. -#define PRC_RVA17 {PRC_RVA, {1.85, 1.0, 2.0, FLT_LP, 6000, 4000, 1}, PFNZERO } // brite L
  17004. -
  17005. -#define PRC_RVA18 {PRC_RVA, {1.0, 1.5, 1.0, FLT_LP, 1000, 1000, 0}, PFNZERO } // generic
  17006. -
  17007. -#define PRC_RVA19 {PRC_RVA, {1.9, 1.8, 1.25, FLT_LP, 4000, 2000, 1}, PFNZERO } // concrete S
  17008. -#define PRC_RVA20 {PRC_RVA, {2.0, 1.8, 1.5, FLT_LP, 3500, 2000, 1}, PFNZERO } // concrete M
  17009. -#define PRC_RVA21 {PRC_RVA, {2.0, 1.8, 1.75, FLT_LP, 3000, 2000, 1}, PFNZERO } // concrete L
  17010. -
  17011. -#define PRC_RVA22 {PRC_RVA, {1.8, 1.5, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water S
  17012. -#define PRC_RVA23 {PRC_RVA, {1.9, 1.75, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water M
  17013. -#define PRC_RVA24 {PRC_RVA, {2.0, 2.0, 1.5, FLT_LP, 1000, 1000, 0}, PFNZERO } // water L
  17014. -
  17015. -
  17016. -/////////////
  17017. -// Diffusors
  17018. -/////////////
  17019. -
  17020. -// size: 0-1.0 scales all delays
  17021. -// density: 0-1.0 controls # of series delays
  17022. -// decay: 0-1.0 scales all feedback parameters
  17023. -
  17024. -// prctype size density decay
  17025. -#define PRC_DFR1 {PRC_DFR, { 1.0, 0.5, 1.0 }, PFNZERO }
  17026. -#define PRC_DFR2 {PRC_DFR, { 0.5, 0.3, 0.5 }, PFNZERO } // S
  17027. -#define PRC_DFR3 {PRC_DFR, { 0.75, 0.5, 0.75 }, PFNZERO } // M
  17028. -#define PRC_DFR4 {PRC_DFR, { 1.0, 0.5, 1.0 }, PFNZERO } // L
  17029. -#define PRC_DFR5 {PRC_DFR, { 1.0, 1.0, 1.0 }, PFNZERO } // VL
  17030. -
  17031. -////////
  17032. -// LFOs
  17033. -////////
  17034. -
  17035. -// wavtype: lfo type to use (LFO_SIN, LFO_RND...)
  17036. -// rate: modulation rate in hz. for MDY, 1/rate = 'glide' time in seconds
  17037. -// foneshot: 1.0 if lfo is oneshot
  17038. -
  17039. -// prctype wavtype rate foneshot
  17040. -#define PRC_LFO1 {PRC_LFO, { LFO_SIN, 440.0, 0.0, }, PFNZERO}
  17041. -#define PRC_LFO2 {PRC_LFO, { LFO_SIN, 3000.0, 0.0, }, PFNZERO} // ear noise ring
  17042. -#define PRC_LFO3 {PRC_LFO, { LFO_SIN, 4500.0, 0.0, }, PFNZERO} // ear noise ring
  17043. -#define PRC_LFO4 {PRC_LFO, { LFO_SIN, 6000.0, 0.0, }, PFNZERO} // ear noise ring
  17044. -#define PRC_LFO5 {PRC_LFO, { LFO_SAW, 100.0, 0.0, }, PFNZERO} // sub bass
  17045. -
  17046. -/////////
  17047. -// Pitch
  17048. -/////////
  17049. -
  17050. -// pitch: 0-n.0 where 1.0 = 1 octave up and 0.5 is one octave down
  17051. -// timeslice: in milliseconds - size of sound chunk to analyze and cut/duplicate - 100ms nominal
  17052. -// xfade: in milliseconds - size of crossfade region between spliced chunks - 20ms nominal
  17053. -
  17054. -// prctype pitch timeslice xfade
  17055. -#define PRC_PTC1 {PRC_PTC, { 1.1, 100.0, 20.0 }, PFNZERO} // pitch up 10%
  17056. -#define PRC_PTC2 {PRC_PTC, { 0.9, 100.0, 20.0 }, PFNZERO} // pitch down 10%
  17057. -#define PRC_PTC3 {PRC_PTC, { 0.95, 100.0, 20.0 }, PFNZERO} // pitch down 5%
  17058. -#define PRC_PTC4 {PRC_PTC, { 1.01, 100.0, 20.0 }, PFNZERO} // pitch up 1%
  17059. -#define PRC_PTC5 {PRC_PTC, { 0.5, 100.0, 20.0 }, PFNZERO} // pitch down 50%
  17060. -
  17061. -/////////////
  17062. -// Envelopes
  17063. -/////////////
  17064. -
  17065. -// etype: ENV_LINEAR, ENV_LOG - currently ignored
  17066. -// amp1: attack peak amplitude 0-1.0
  17067. -// amp2: decay target amplitued 0-1.0
  17068. -// amp3: sustain target amplitude 0-1.0
  17069. -// attack time in milliseconds
  17070. -// envelope decay time in milliseconds
  17071. -// sustain time in milliseconds
  17072. -// release time in milliseconds
  17073. -
  17074. -// prctype etype amp1 amp2 amp3 attack decay sustain release
  17075. -#define PRC_ENV1 {PRC_ENV, {ENV_LIN, 1.0, 0.5, 0.4, 500, 500, 3000, 6000 }, PFNZERO}
  17076. -
  17077. -
  17078. -//////////////
  17079. -// Mod delays
  17080. -//////////////
  17081. -
  17082. -// dtype: delay type DLY_PLAIN, DLY_LOWPASS, DLY_ALLPASS
  17083. -// delay: delay in milliseconds
  17084. -// feedback: feedback 0-1.0
  17085. -// gain: final gain of output stage, 0-1.0
  17086. -
  17087. -// modrate: frequency at which delay values change to new random value. 0 is no self-modulation
  17088. -// moddepth: how much delay changes (decreases) from current value (0-1.0)
  17089. -// modglide: glide time between dcur and dnew in milliseconds
  17090. -
  17091. -// prctype dtype delay feedback gain ftype cutoff qwidth qual modrate moddepth modglide
  17092. -#define PRC_MDY1 {PRC_MDY, {DLY_PLAIN, 500.0, 0.5, 1.0, 0, 0, 0, 0, 10, 0.8, 5,}, PFNZERO}
  17093. -#define PRC_MDY2 {PRC_MDY, {DLY_PLAIN, 50.0, 0.8, 1.0, 0, 0, 0, 0, 5, 0.8, 5,}, PFNZERO}
  17094. -
  17095. -#define PRC_MDY3 {PRC_MDY, {DLY_PLAIN, 300.0, 0.2, 1.0, 0, 0, 0, 0, 30, 0.01, 15,}, PFNZERO } // weird 1
  17096. -#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
  17097. -#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
  17098. -
  17099. -//////////
  17100. -// Chorus
  17101. -//////////
  17102. -
  17103. -// lfowav: lfotype is LFO_SIN, LFO_RND, LFO_TRI etc (LFO_RND for chorus, LFO_SIN for flange)
  17104. -// rate: rate is modulation frequency in Hz
  17105. -// depth: depth is modulation depth, 0-1.0
  17106. -// mix: mix is mix of chorus and clean signal
  17107. -
  17108. -// prctype lfowav rate depth mix
  17109. -#define PRC_CRS1 {PRC_CRS, { LFO_SIN, 10, 1.0, 0.5, }, PFNZERO }
  17110. -
  17111. -/////////////////////
  17112. -// Envelope follower
  17113. -/////////////////////
  17114. -
  17115. -// takes no parameters
  17116. -#define PRC_EFO1 {PRC_EFO, { PRMZERO }, PFNZERO }
  17117. -
  17118. -// init array of processors - first store pfnParam, pfnGetNext and pfnFree functions for type,
  17119. -// then call the pfnParam function to initialize each processor
  17120. -
  17121. -// prcs - an array of prc structures, all with initialized params
  17122. -// count - number of elements in the array
  17123. -// returns false if failed to init one or more processors
  17124. -
  17125. -qboolean PRC_InitAll( prc_t *prcs, int count )
  17126. -{
  17127. - int i;
  17128. - prc_Param_t pfnParam; // allocation function - takes ptr to prc, returns ptr to specialized data struct for proc type
  17129. - prc_GetNext_t pfnGetNext; // get next function
  17130. - prc_GetNextN_t pfnGetNextN; // get next function, batch version
  17131. - prc_Free_t pfnFree;
  17132. - prc_Mod_t pfnMod;
  17133. - qboolean fok = true;
  17134. -
  17135. - // set up pointers to XXX_Free, XXX_GetNext and XXX_Params functions
  17136. -
  17137. - for( i = 0; i < count; i++ )
  17138. - {
  17139. - switch (prcs[i].type)
  17140. - {
  17141. - case PRC_DLY:
  17142. - pfnFree = &(prc_Free_t)DLY_Free;
  17143. - pfnGetNext = &(prc_GetNext_t)DLY_GetNext;
  17144. - pfnGetNextN = &(prc_GetNextN_t)DLY_GetNextN;
  17145. - pfnParam = &DLY_VParams;
  17146. - pfnMod = &(prc_Mod_t)DLY_Mod;
  17147. - break;
  17148. - case PRC_RVA:
  17149. - pfnFree = &(prc_Free_t)RVA_Free;
  17150. - pfnGetNext = &(prc_GetNext_t)RVA_GetNext;
  17151. - pfnGetNextN = &(prc_GetNextN_t)RVA_GetNextN;
  17152. - pfnParam = &RVA_VParams;
  17153. - pfnMod = &(prc_Mod_t)RVA_Mod;
  17154. - break;
  17155. - case PRC_FLT:
  17156. - pfnFree = &(prc_Free_t)FLT_Free;
  17157. - pfnGetNext = &(prc_GetNext_t)FLT_GetNext;
  17158. - pfnGetNextN = &(prc_GetNextN_t)FLT_GetNextN;
  17159. - pfnParam = &FLT_VParams;
  17160. - pfnMod = &(prc_Mod_t)FLT_Mod;
  17161. - break;
  17162. - case PRC_CRS:
  17163. - pfnFree = &(prc_Free_t)CRS_Free;
  17164. - pfnGetNext = &(prc_GetNext_t)CRS_GetNext;
  17165. - pfnGetNextN = &(prc_GetNextN_t)CRS_GetNextN;
  17166. - pfnParam = &CRS_VParams;
  17167. - pfnMod = &(prc_Mod_t)CRS_Mod;
  17168. - break;
  17169. - case PRC_PTC:
  17170. - pfnFree = &(prc_Free_t)PTC_Free;
  17171. - pfnGetNext = &(prc_GetNext_t)PTC_GetNext;
  17172. - pfnGetNextN = &(prc_GetNextN_t)PTC_GetNextN;
  17173. - pfnParam = &PTC_VParams;
  17174. - pfnMod = &(prc_Mod_t)PTC_Mod;
  17175. - break;
  17176. - case PRC_ENV:
  17177. - pfnFree = &(prc_Free_t)ENV_Free;
  17178. - pfnGetNext = &(prc_GetNext_t)ENV_GetNext;
  17179. - pfnGetNextN = &(prc_GetNextN_t)ENV_GetNextN;
  17180. - pfnParam = &ENV_VParams;
  17181. - pfnMod = &(prc_Mod_t)ENV_Mod;
  17182. - break;
  17183. - case PRC_LFO:
  17184. - pfnFree = &(prc_Free_t)LFO_Free;
  17185. - pfnGetNext = &(prc_GetNext_t)LFO_GetNext;
  17186. - pfnGetNextN = &(prc_GetNextN_t)LFO_GetNextN;
  17187. - pfnParam = &LFO_VParams;
  17188. - pfnMod = &(prc_Mod_t)LFO_Mod;
  17189. - break;
  17190. - case PRC_EFO:
  17191. - pfnFree = &(prc_Free_t)EFO_Free;
  17192. - pfnGetNext = &(prc_GetNext_t)EFO_GetNext;
  17193. - pfnGetNextN = &(prc_GetNextN_t)EFO_GetNextN;
  17194. - pfnParam = &EFO_VParams;
  17195. - pfnMod = &(prc_Mod_t)EFO_Mod;
  17196. - break;
  17197. - case PRC_MDY:
  17198. - pfnFree = &(prc_Free_t)MDY_Free;
  17199. - pfnGetNext = &(prc_GetNext_t)MDY_GetNext;
  17200. - pfnGetNextN = &(prc_GetNextN_t)MDY_GetNextN;
  17201. - pfnParam = &MDY_VParams;
  17202. - pfnMod = &(prc_Mod_t)MDY_Mod;
  17203. - break;
  17204. - case PRC_DFR:
  17205. - pfnFree = &(prc_Free_t)DFR_Free;
  17206. - pfnGetNext = &(prc_GetNext_t)DFR_GetNext;
  17207. - pfnGetNextN = &(prc_GetNextN_t)DFR_GetNextN;
  17208. - pfnParam = &DFR_VParams;
  17209. - pfnMod = &(prc_Mod_t)DFR_Mod;
  17210. - break;
  17211. - case PRC_AMP:
  17212. - pfnFree = &(prc_Free_t)AMP_Free;
  17213. - pfnGetNext = &(prc_GetNext_t)AMP_GetNext;
  17214. - pfnGetNextN = &(prc_GetNextN_t)AMP_GetNextN;
  17215. - pfnParam = &AMP_VParams;
  17216. - pfnMod = &(prc_Mod_t)AMP_Mod;
  17217. - break;
  17218. - case PRC_NULL:
  17219. - default:
  17220. - pfnFree = &(prc_Free_t)NULL_Free;
  17221. - pfnGetNext = &(prc_GetNext_t)NULL_GetNext;
  17222. - pfnGetNextN = &(prc_GetNextN_t)NULL_GetNextN;
  17223. - pfnParam = &NULL_VParams;
  17224. - pfnMod = &(prc_Mod_t)NULL_Mod;
  17225. - break;
  17226. - }
  17227. -
  17228. - // set up function pointers
  17229. - prcs[i].pfnParam = pfnParam;
  17230. - prcs[i].pfnGetNext = pfnGetNext;
  17231. - prcs[i].pfnGetNextN = pfnGetNextN;
  17232. - prcs[i].pfnFree = pfnFree;
  17233. -
  17234. - // call param function, store pdata for the processor type
  17235. - prcs[i].pdata = pfnParam((void *)( &prcs[i] ));
  17236. -
  17237. - if( !prcs[i].pdata )
  17238. - fok = false;
  17239. - }
  17240. - return fok;
  17241. -}
  17242. -
  17243. -// free individual processor's data
  17244. -void PRC_Free( prc_t *pprc )
  17245. -{
  17246. - if( pprc->pfnFree && pprc->pdata )
  17247. - pprc->pfnFree( pprc->pdata );
  17248. -}
  17249. -
  17250. -// free all processors for supplied array
  17251. -// prcs - array of processors
  17252. -// count - elements in array
  17253. -void PRC_FreeAll( prc_t *prcs, int count )
  17254. -{
  17255. - int i;
  17256. -
  17257. - for( i = 0; i < count; i++ )
  17258. - PRC_Free( &prcs[i] );
  17259. -}
  17260. -
  17261. -// get next value for processor - (usually called directly by PSET_GetNext)
  17262. -_inline int PRC_GetNext( prc_t *pprc, int x )
  17263. -{
  17264. - return pprc->pfnGetNext( pprc->pdata, x );
  17265. -}
  17266. -
  17267. -// automatic parameter range limiting
  17268. -// force parameters between specified min/max in param_rng
  17269. -void PRC_CheckParams( prc_t *pprc, prm_rng_t *prng )
  17270. -{
  17271. - // first entry in param_rng is # of parameters
  17272. - int cprm = prng[0].iprm;
  17273. - int i;
  17274. -
  17275. - for( i = 0; i < cprm; i++)
  17276. - {
  17277. - // if parameter is 0.0f, always allow it (this is 'off' for most params)
  17278. - if( pprc->prm[i] != 0.0f && ( pprc->prm[i] > prng[i+1].hi || pprc->prm[i] < prng[i+1].lo ))
  17279. - {
  17280. - MsgDev( D_WARN, "DSP: clamping out of range parameter.\n" );
  17281. - pprc->prm[i] = bound( prng[i+1].lo, pprc->prm[i], prng[i+1].hi );
  17282. - }
  17283. - }
  17284. -}
  17285. -
  17286. -// DSP presets
  17287. -// A dsp preset comprises one or more dsp processors in linear, parallel or feedback configuration
  17288. -// preset configurations
  17289. -//
  17290. -#define PSET_SIMPLE 0
  17291. -
  17292. -// x(n)--->P(0)--->y(n)
  17293. -#define PSET_LINEAR 1
  17294. -
  17295. -// x(n)--->P(0)-->P(1)-->...P(m)--->y(n)
  17296. -#define PSET_PARALLEL6 4
  17297. -
  17298. -// x(n)-P(0)-->P(1)-->P(2)-->(+)-P(5)->y(n)
  17299. -// | ^
  17300. -// | |
  17301. -// -->P(3)-->P(4)---->
  17302. -
  17303. -
  17304. -#define PSET_PARALLEL2 5
  17305. -
  17306. -// x(n)--->P(0)-->(+)-->y(n)
  17307. -// ^
  17308. -// |
  17309. -// x(n)--->P(1)-----
  17310. -
  17311. -#define PSET_PARALLEL4 6
  17312. -
  17313. -// x(n)--->P(0)-->P(1)-->(+)-->y(n)
  17314. -// ^
  17315. -// |
  17316. -// x(n)--->P(2)-->P(3)-----
  17317. -
  17318. -#define PSET_PARALLEL5 7
  17319. -
  17320. -// x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
  17321. -// ^
  17322. -// |
  17323. -// x(n)--->P(2)-->P(3)-----
  17324. -
  17325. -#define PSET_FEEDBACK 8
  17326. -
  17327. -// x(n)-P(0)--(+)-->P(1)-->P(2)-->P(5)->y(n)
  17328. -// ^ |
  17329. -// | v
  17330. -// -----P(4)<--P(3)--
  17331. -
  17332. -#define PSET_FEEDBACK3 9
  17333. -
  17334. -// x(n)---(+)-->P(0)--------->y(n)
  17335. -// ^ |
  17336. -// | v
  17337. -// -----P(2)<--P(1)--
  17338. -
  17339. -#define PSET_FEEDBACK4 10
  17340. -
  17341. -// x(n)---(+)-->P(0)-------->P(3)--->y(n)
  17342. -// ^ |
  17343. -// | v
  17344. -// ---P(2)<--P(1)--
  17345. -
  17346. -#define PSET_MOD 11
  17347. -
  17348. -//
  17349. -// x(n)------>P(1)--P(2)--P(3)--->y(n)
  17350. -// ^
  17351. -// x(n)------>P(0)....:
  17352. -
  17353. -#define PSET_MOD2 12
  17354. -
  17355. -//
  17356. -// x(n)-------P(1)-->y(n)
  17357. -// ^
  17358. -// x(n)-->P(0)..:
  17359. -
  17360. -
  17361. -#define PSET_MOD3 13
  17362. -
  17363. -//
  17364. -// x(n)-------P(1)-->P(2)-->y(n)
  17365. -// ^
  17366. -// x(n)-->P(0)..:
  17367. -
  17368. -
  17369. -#define CPSETS 64 // max number of presets simultaneously active
  17370. -
  17371. -#define CPSET_PRCS 6 // max # of processors per dsp preset
  17372. -#define CPSET_STATES (CPSET_PRCS+3) // # of internal states
  17373. -
  17374. -// NOTE: do not reorder members of pset_t - psettemplates relies on it!!!
  17375. -typedef struct
  17376. -{
  17377. - int type; // preset configuration type
  17378. - int cprcs; // number of processors for this preset
  17379. - prc_t prcs[CPSET_PRCS]; // processor preset data
  17380. - float gain; // preset gain 0.1->2.0
  17381. - int w[CPSET_STATES]; // internal states
  17382. - int fused;
  17383. -} pset_t;
  17384. -
  17385. -pset_t psets[CPSETS];
  17386. -
  17387. -// array of dsp presets, each with up to 6 processors per preset
  17388. -
  17389. -#define WZERO {0,0,0,0,0,0,0,0,0}, 0
  17390. -
  17391. -pset_t psettemplates[] =
  17392. -{
  17393. -// presets 0-29 map to legacy room_type 0-29
  17394. -
  17395. -// type # proc P0 P1 P2 P3 P4 P5 GAIN
  17396. -{PSET_SIMPLE, 1, { PRC_NULL1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // OFF 0
  17397. -{PSET_SIMPLE, 1, { PRC_RVA18, PRC0, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // GENERIC 1 // general, low reflective, diffuse room
  17398. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA3, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_S 2 // highly reflective, parallel surfaces
  17399. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA4, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_M 3
  17400. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA5, PRC0, PRC0, PRC0, PRC0 },1.4, WZERO }, // METALIC_L 4
  17401. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA6, PRC0, PRC0, PRC0, PRC0 },2.0, WZERO }, // TUNNEL_S 5 // resonant reflective, long surfaces
  17402. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA7, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // TUNNEL_M 6
  17403. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA8, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // TUNNEL_L 7
  17404. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA12,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CHAMBER_S 8 // diffuse, moderately reflective surfaces
  17405. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA13,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CHAMBER_M 9
  17406. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA14,PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // CHAMBER_L 10
  17407. -{PSET_SIMPLE, 1, { PRC_RVA15, PRC0, PRC0, PRC0, PRC0, PRC0 },1.5, WZERO }, // BRITE_S 11 // diffuse, highly reflective
  17408. -{PSET_SIMPLE, 1, { PRC_RVA16, PRC0, PRC0, PRC0, PRC0, PRC0 },1.6, WZERO }, // BRITE_M 12
  17409. -{PSET_SIMPLE, 1, { PRC_RVA17, PRC0, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // BRITE_L 13
  17410. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA22,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER1 14 // underwater fx
  17411. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA23,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER2 15
  17412. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_RVA24,PRC_MDY5, PRC0, PRC0, PRC0 },1.8, WZERO }, // WATER3 16
  17413. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA19,PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // CONCRTE_S 17 // bare, reflective, parallel surfaces
  17414. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA20,PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // CONCRTE_M 18
  17415. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA21,PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // CONCRTE_L 19
  17416. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_DLY3, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // OUTSIDE1 20 // echoing, moderately reflective
  17417. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_DLY4, PRC0, PRC0, PRC0, PRC0 },1.7, WZERO }, // OUTSIDE2 21 // echoing, dull
  17418. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_DLY5, PRC0, PRC0, PRC0 },1.6, WZERO }, // OUTSIDE3 22 // echoing, very dull
  17419. -{PSET_LINEAR, 2, { PRC_DLY10, PRC_RVA10,PRC0, PRC0, PRC0, PRC0 },2.8, WZERO }, // CAVERN_S 23 // large, echoing area
  17420. -{PSET_LINEAR, 2, { PRC_DLY11, PRC_RVA10,PRC0, PRC0, PRC0, PRC0 },2.6, WZERO }, // CAVERN_M 24
  17421. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DLY12,PRC_RVA11,PRC0, PRC0, PRC0 },2.6, WZERO }, // CAVERN_L 25
  17422. -{PSET_LINEAR, 2, { PRC_DLY7, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },2.0, WZERO }, // WEIRDO1 26
  17423. -{PSET_LINEAR, 2, { PRC_DLY8, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.9, WZERO }, // WEIRDO2 27
  17424. -{PSET_LINEAR, 2, { PRC_DLY9, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WEIRDO3 28
  17425. -{PSET_LINEAR, 2, { PRC_DLY9, PRC_DFR1, PRC0, PRC0, PRC0, PRC0 },1.8, WZERO }, // WEIRDO4 29
  17426. -
  17427. -// presets 30-40 are new presets
  17428. -{PSET_SIMPLE, 1, { PRC_FLT2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 30 lowpass - facing away
  17429. -{PSET_LINEAR, 2, { PRC_FLT3, PRC_DLY14,PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 31 lowpass - facing away+80ms delay
  17430. -//{PSET_PARALLEL2,2, { PRC_AMP6, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 32 explosion ring 1
  17431. -//{PSET_PARALLEL2,2, { PRC_AMP7, PRC_LFO3, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 33 explosion ring 2
  17432. -//{PSET_PARALLEL2,2, { PRC_AMP8, PRC_LFO4, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 34 explosion ring 3
  17433. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 32 explosion ring
  17434. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 33 explosion ring 2
  17435. -{PSET_LINEAR, 3, { PRC_DFR1, PRC_DFR1, PRC_FLT3, PRC0, PRC0, PRC0 },0.25, WZERO }, // 34 explosion ring 3
  17436. -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 35 shock muffle 1
  17437. -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 36 shock muffle 2
  17438. -{PSET_PARALLEL2,2, { PRC_DFR1, PRC_LFO2, PRC0, PRC0, PRC0, PRC0 },0.25, WZERO }, // 37 shock muffle 3
  17439. -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 35 shock muffle 1
  17440. -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 36 shock muffle 2
  17441. -//{PSET_LINEAR, 3, { PRC_DFR1, PRC_LFO4, PRC_FLT3, PRC0, PRC0, PRC0 },1.0, WZERO }, // 37 shock muffle 3
  17442. -{PSET_FEEDBACK3,3, { PRC_DLY13, PRC_PTC4, PRC_FLT2, PRC0, PRC0, PRC0 },0.25, WZERO }, // 38 fade pitchdown 1
  17443. -{PSET_LINEAR, 3, { PRC_AMP3, PRC_FLT5, PRC_FLT6, PRC0, PRC0, PRC0 },2.0, WZERO }, // 39 distorted speaker 1
  17444. -
  17445. -// fade out fade in
  17446. -
  17447. -// presets 40+ are test presets
  17448. -{PSET_SIMPLE, 1, { PRC_NULL1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 39 null
  17449. -{PSET_SIMPLE, 1, { PRC_DLY1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 40 delay
  17450. -{PSET_SIMPLE, 1, { PRC_RVA1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 41 parallel reverb
  17451. -{PSET_SIMPLE, 1, { PRC_DFR1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 42 series diffusor
  17452. -{PSET_LINEAR, 2, { PRC_DFR1, PRC_RVA1, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 43 diff & reverb
  17453. -{PSET_SIMPLE, 1, { PRC_DLY2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 44 lowpass delay
  17454. -{PSET_SIMPLE, 1, { PRC_MDY2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 45 modulating delay
  17455. -{PSET_SIMPLE, 1, { PRC_PTC1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 46 pitch shift
  17456. -{PSET_SIMPLE, 1, { PRC_PTC2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 47 pitch shift
  17457. -{PSET_SIMPLE, 1, { PRC_FLT1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 48 filter
  17458. -{PSET_SIMPLE, 1, { PRC_CRS1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 49 chorus
  17459. -{PSET_SIMPLE, 1, { PRC_ENV1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 50
  17460. -{PSET_SIMPLE, 1, { PRC_LFO1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 51 lfo
  17461. -{PSET_SIMPLE, 1, { PRC_EFO1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 52
  17462. -{PSET_SIMPLE, 1, { PRC_MDY1, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 53 modulating delay
  17463. -{PSET_SIMPLE, 1, { PRC_FLT2, PRC0, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 54 lowpass - facing away
  17464. -{PSET_PARALLEL2, 2, { PRC_PTC2, PRC_PTC1, PRC0, PRC0, PRC0, PRC0 },1.0, WZERO }, // 55 ptc1/ptc2
  17465. -{PSET_FEEDBACK, 6, { PRC_DLY1, PRC0, PRC0, PRC_PTC1, PRC_FLT1, PRC0 },1.0, WZERO }, // 56 dly/ptc1
  17466. -{PSET_MOD, 4, { PRC_EFO1, PRC0, PRC_PTC1, PRC0, PRC0, PRC0 },1.0, WZERO }, // 57 efo mod ptc
  17467. -{PSET_LINEAR, 3, { PRC_DLY1, PRC_RVA1, PRC_CRS1, PRC0, PRC0, PRC0 },1.0, WZERO } // 58 dly/rvb/crs
  17468. -};
  17469. -
  17470. -
  17471. -// number of presets currently defined above
  17472. -
  17473. -#define CPSETTEMPLATES 60 //(sizeof( psets ) / sizeof( pset_t ))
  17474. -
  17475. -// init a preset - just clear state array
  17476. -void PSET_Init( pset_t *ppset )
  17477. -{
  17478. - // clear state array
  17479. - if( ppset ) memset( ppset->w, 0, sizeof( int ) * ( CPSET_STATES ));
  17480. -}
  17481. -
  17482. -// clear runtime slots
  17483. -void PSET_InitAll( void )
  17484. -{
  17485. - int i;
  17486. -
  17487. - for( i = 0; i < CPSETS; i++ )
  17488. - memset( &psets[i], 0, sizeof( pset_t ));
  17489. -}
  17490. -
  17491. -// free the preset - free all processors
  17492. -
  17493. -void PSET_Free( pset_t *ppset )
  17494. -{
  17495. - if( ppset )
  17496. - {
  17497. - // free processors
  17498. - PRC_FreeAll( ppset->prcs, ppset->cprcs );
  17499. -
  17500. - // clear
  17501. - memset( ppset, 0, sizeof( pset_t ));
  17502. - }
  17503. -}
  17504. -
  17505. -void PSET_FreeAll() { int i; for( i = 0; i < CPSETS; i++ ) PSET_Free( &psets[i] ); };
  17506. -
  17507. -// return preset struct, given index into preset template array
  17508. -// NOTE: should not ever be more than 2 or 3 of these active simultaneously
  17509. -pset_t *PSET_Alloc( int ipsettemplate )
  17510. -{
  17511. - pset_t *ppset;
  17512. - qboolean fok;
  17513. - int i;
  17514. -
  17515. - // don't excede array bounds
  17516. - if( ipsettemplate >= CPSETTEMPLATES )
  17517. - ipsettemplate = 0;
  17518. -
  17519. - // find free slot
  17520. - for( i = 0; i < CPSETS; i++)
  17521. - {
  17522. - if( !psets[i].fused )
  17523. - break;
  17524. - }
  17525. -
  17526. - if( i == CPSETS )
  17527. - return NULL;
  17528. -
  17529. - ppset = &psets[i];
  17530. -
  17531. - // copy template into preset
  17532. - *ppset = psettemplates[ipsettemplate];
  17533. -
  17534. - ppset->fused = true;
  17535. -
  17536. - // clear state array
  17537. - PSET_Init( ppset );
  17538. -
  17539. - // init all processors, set up processor function pointers
  17540. - fok = PRC_InitAll( ppset->prcs, ppset->cprcs );
  17541. -
  17542. - if( !fok )
  17543. - {
  17544. - // failed to init one or more processors
  17545. - MsgDev( D_ERROR, "Sound DSP: preset failed to init.\n");
  17546. - PRC_FreeAll( ppset->prcs, ppset->cprcs );
  17547. - return NULL;
  17548. - }
  17549. - return ppset;
  17550. -}
  17551. -
  17552. -// batch version of PSET_GetNext for linear array of processors. For performance.
  17553. -
  17554. -// ppset - preset array
  17555. -// pbuffer - input sample data
  17556. -// SampleCount - size of input buffer
  17557. -// OP: OP_LEFT - process left channel in place
  17558. -// OP_RIGHT - process right channel in place
  17559. -// OP_LEFT_DUPLICATe - process left channel, duplicate into right
  17560. -
  17561. -_inline void PSET_GetNextN( pset_t *ppset, portable_samplepair_t *pbf, int SampleCount, int op )
  17562. -{
  17563. - prc_t *pprc;
  17564. - int i, count = ppset->cprcs;
  17565. -
  17566. - switch( ppset->type )
  17567. - {
  17568. - default:
  17569. - case PSET_SIMPLE:
  17570. - {
  17571. - // x(n)--->P(0)--->y(n)
  17572. - ppset->prcs[0].pfnGetNextN( ppset->prcs[0].pdata, pbf, SampleCount, op );
  17573. - break;
  17574. - }
  17575. - case PSET_LINEAR:
  17576. - {
  17577. -
  17578. - // w0 w1 w2
  17579. - // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  17580. -
  17581. - // w0 w1 w2 w3 w4 w5
  17582. - // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  17583. -
  17584. - // call batch processors in sequence - no internal state for batch processing
  17585. - // point to first processor
  17586. -
  17587. - pprc = &ppset->prcs[0];
  17588. -
  17589. - for( i = 0; i < count; i++ )
  17590. - {
  17591. - pprc->pfnGetNextN( pprc->pdata, pbf, SampleCount, op );
  17592. - pprc++;
  17593. - }
  17594. - break;
  17595. - }
  17596. - }
  17597. -}
  17598. -
  17599. -
  17600. -// Get next sample from this preset. called once for every sample in buffer
  17601. -// ppset is pointer to preset
  17602. -// x is input sample
  17603. -_inline int PSET_GetNext( pset_t *ppset, int x )
  17604. -{
  17605. - int *w = ppset->w;
  17606. - prc_t *pprc;
  17607. - int count = ppset->cprcs;
  17608. -
  17609. - // initialized 0'th element of state array
  17610. -
  17611. - w[0] = x;
  17612. -
  17613. - switch( ppset->type )
  17614. - {
  17615. - default:
  17616. - case PSET_SIMPLE:
  17617. - {
  17618. - // x(n)--->P(0)--->y(n)
  17619. - return ppset->prcs[0].pfnGetNext (ppset->prcs[0].pdata, x);
  17620. - }
  17621. - case PSET_LINEAR:
  17622. - {
  17623. - // w0 w1 w2
  17624. - // x(n)--->P(0)-->P(1)-->...P(count-1)--->y(n)
  17625. -
  17626. - // w0 w1 w2 w3 w4 w5
  17627. - // x(n)--->P(0)-->P(1)-->P(2)-->P(3)-->P(4)-->y(n)
  17628. -
  17629. - // call processors in reverse order, from count to 1
  17630. -
  17631. - // point to last processor
  17632. -
  17633. - pprc = &ppset->prcs[count-1];
  17634. -
  17635. - switch( count )
  17636. - {
  17637. - default:
  17638. - case 5:
  17639. - w[5] = pprc->pfnGetNext (pprc->pdata, w[4]);
  17640. - pprc--;
  17641. - case 4:
  17642. - w[4] = pprc->pfnGetNext (pprc->pdata, w[3]);
  17643. - pprc--;
  17644. - case 3:
  17645. - w[3] = pprc->pfnGetNext (pprc->pdata, w[2]);
  17646. - pprc--;
  17647. - case 2:
  17648. - w[2] = pprc->pfnGetNext (pprc->pdata, w[1]);
  17649. - pprc--;
  17650. - case 1:
  17651. - w[1] = pprc->pfnGetNext (pprc->pdata, w[0]);
  17652. - }
  17653. - return w[count];
  17654. - }
  17655. -
  17656. - case PSET_PARALLEL6:
  17657. - {
  17658. - // w0 w1 w2 w3 w6 w7
  17659. - // x(n)-P(0)-->P(1)-->P(2)-->(+)---P(5)--->y(n)
  17660. - // | ^
  17661. - // | w4 w5 |
  17662. - // -->P(3)-->P(4)---->
  17663. -
  17664. - pprc = &ppset->prcs[0];
  17665. -
  17666. - // start with all adders
  17667. -
  17668. - w[6] = w[3] + w[5];
  17669. -
  17670. - // top branch - evaluate in reverse order
  17671. -
  17672. - w[7] = pprc[5].pfnGetNext( pprc[5].pdata, w[6] );
  17673. - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
  17674. - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  17675. -
  17676. - // bottom branch - evaluate in reverse order
  17677. -
  17678. - w[5] = pprc[4].pfnGetNext( pprc[4].pdata, w[4] );
  17679. - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[1] );
  17680. -
  17681. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17682. -
  17683. - return w[7];
  17684. - }
  17685. - case PSET_PARALLEL2:
  17686. - { // w0 w1 w3
  17687. - // x(n)--->P(0)-->(+)-->y(n)
  17688. - // ^
  17689. - // w0 w2 |
  17690. - // x(n)--->P(1)-----
  17691. -
  17692. - pprc = &ppset->prcs[0];
  17693. -
  17694. - w[3] = w[1] + w[2];
  17695. -
  17696. - w[1] = pprc->pfnGetNext( pprc->pdata, w[0] );
  17697. - pprc++;
  17698. - w[2] = pprc->pfnGetNext( pprc->pdata, w[0] );
  17699. -
  17700. - return w[3];
  17701. - }
  17702. -
  17703. - case PSET_PARALLEL4:
  17704. - {
  17705. - // w0 w1 w2 w5
  17706. - // x(n)--->P(0)-->P(1)-->(+)-->y(n)
  17707. - // ^
  17708. - // w0 w3 w4 |
  17709. - // x(n)--->P(2)-->P(3)-----
  17710. +typedef struct sx_preset_s
  17711. +{
  17712. + float room_lp; // lowpass
  17713. + float room_mod; // modulation
  17714.  
  17715. - pprc = &ppset->prcs[0];
  17716. + // reverb
  17717. + float room_size;
  17718. + float room_refl;
  17719. + float room_rvblp;
  17720.  
  17721. - w[5] = w[2] + w[4];
  17722. + // delay
  17723. + float room_delay;
  17724. + float room_feedback;
  17725. + float room_dlylp;
  17726. + float room_left;
  17727. +} sx_preset_t;
  17728.  
  17729. - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  17730. - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  17731. +typedef struct dly_s
  17732. +{
  17733. + size_t cdelaysamplesmax; // delay line array size
  17734.  
  17735. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17736. - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  17737. + // delay line pointers
  17738. + size_t idelayinput;
  17739. + size_t idelayoutput;
  17740.  
  17741. - return w[5];
  17742. - }
  17743. + // crossfade
  17744. + size_t idelayoutputxf; // output pointer
  17745. + int xfade; // value
  17746.  
  17747. - case PSET_PARALLEL5:
  17748. - {
  17749. - // w0 w1 w2 w5 w6
  17750. - // x(n)--->P(0)-->P(1)-->(+)-->P(4)-->y(n)
  17751. - // ^
  17752. - // w0 w3 w4 |
  17753. - // x(n)--->P(2)-->P(3)-----
  17754. + int delaysamples; // delay setting
  17755. + int delayfeedback; // feedback setting
  17756.  
  17757. - pprc = &ppset->prcs[0];
  17758. + // lowpass
  17759. + int lp; // is lowpass enabled
  17760. + int lp0, lp1, lp2; // lowpass buffer
  17761.  
  17762. - w[5] = w[2] + w[4];
  17763. + // modulation
  17764. + int mod;
  17765. + int modcur;
  17766.  
  17767. - w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  17768. + // delay line
  17769. + int *lpdelayline;
  17770. +} dly_t;
  17771.  
  17772. - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[1] );
  17773. - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  17774. +const sx_preset_t rgsxpre[] =
  17775. +{
  17776. +// -------reverb-------- -------delay--------
  17777. +// lp mod size refl rvblp delay feedback dlylp left
  17778. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0 }, // 0 off
  17779. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.065, 0.1, 0.0, 0.01 }, // 1 generic
  17780. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.02, 0.75, 0.0, 0.01 }, // 2 metalic
  17781. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.03, 0.78, 0.0, 0.02 }, // 3
  17782. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.77, 0.0, 0.03 }, // 4
  17783. +{ 0.0, 0.0, 0.05, 0.85, 1.0, 0.008, 0.96, 2.0, 0.01 }, // 5 tunnel
  17784. +{ 0.0, 0.0, 0.05, 0.88, 1.0, 0.01, 0.98, 2.0, 0.02 }, // 6
  17785. +{ 0.0, 0.0, 0.05, 0.92, 1.0, 0.015, 0.995, 2.0, 0.04 }, // 7
  17786. +{ 0.0, 0.0, 0.05, 0.84, 1.0, 0.0, 0.0, 2.0, 0.012 }, // 8 chamber
  17787. +{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.0, 0.0, 2.0, 0.008 }, // 9
  17788. +{ 0.0, 0.0, 0.05, 0.95, 1.0, 0.0, 0.0, 2.0, 0.004 }, // 10
  17789. +{ 0.0, 0.0, 0.05, 0.7, 0.0, 0.0, 0.0, 2.0, 0.012 }, // 11 brite
  17790. +{ 0.0, 0.0, 0.055, 0.78, 0.0, 0.0, 0.0, 2.0, 0.008 }, // 12
  17791. +{ 0.0, 0.0, 0.05, 0.86, 0.0, 0.0, 0.0, 2.0, 0.002 }, // 13
  17792. +{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.01 }, // 14 water
  17793. +{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.06, 0.85, 2.0, 0.02 }, // 15
  17794. +{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.2, 0.6, 2.0, 0.05 }, // 16
  17795. +{ 0.0, 0.0, 0.05, 0.8, 1.0, 0.0, 0.48, 2.0, 0.016 }, // 17 concrete
  17796. +{ 0.0, 0.0, 0.06, 0.9, 1.0, 0.0, 0.52, 2.0, 0.01 }, // 18
  17797. +{ 0.0, 0.0, 0.07, 0.94, 1.0, 0.3, 0.6, 2.0, 0.008 }, // 19
  17798. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.3, 0.42, 2.0, 0.0 }, // 20 outside
  17799. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.35, 0.48, 2.0, 0.0 }, // 21
  17800. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.38, 0.6, 2.0, 0.0 }, // 22
  17801. +{ 0.0, 0.0, 0.05, 0.9, 1.0, 0.2, 0.28, 0.0, 0.0 }, // 23 cavern
  17802. +{ 0.0, 0.0, 0.07, 0.9, 1.0, 0.3, 0.4, 0.0, 0.0 }, // 24
  17803. +{ 0.0, 0.0, 0.09, 0.9, 1.0, 0.35, 0.5, 0.0, 0.0 }, // 25
  17804. +{ 0.0, 1.0, 0.01, 0.9, 0.0, 0.0, 0.0, 2.0, 0.05 }, // 26 weirdo
  17805. +{ 0.0, 0.0, 0.0, 0.0, 1.0, 0.009, 0.999, 2.0, 0.04 }, // 27
  17806. +{ 0.0, 0.0, 0.001, 0.999, 0.0, 0.2, 0.8, 2.0, 0.05 } // 28
  17807. +};
  17808.  
  17809. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17810. - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[0] );
  17811. +// cvars
  17812. +convar_t *dsp_off; // disable dsp
  17813. +convar_t *roomwater_type; // water room_type
  17814. +convar_t *room_type; // current room type
  17815. +convar_t *hisound; // DSP quality
  17816.  
  17817. - return w[6];
  17818. - }
  17819. +// underwater/special fx modulations
  17820. +convar_t *sxmod_mod;
  17821. +convar_t *sxmod_lowpass;
  17822.  
  17823. - case PSET_FEEDBACK:
  17824. - {
  17825. - // w0 w1 w2 w3 w4 w7
  17826. - // x(n)-P(0)--(+)-->P(1)-->P(2)-->P(5)->y(n)
  17827. - // ^ |
  17828. - // | w6 w5 v
  17829. - // -----P(4)<--P(3)--
  17830. -
  17831. - pprc = &ppset->prcs[0];
  17832. -
  17833. - // start with adders
  17834. -
  17835. - w[2] = w[1] + w[6];
  17836. -
  17837. - // evaluate in reverse order
  17838. -
  17839. - w[7] = pprc[5].pfnGetNext( pprc[5].pdata, w[4] );
  17840. - w[6] = pprc[4].pfnGetNext( pprc[4].pdata, w[5] );
  17841. - w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[4] );
  17842. - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  17843. - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  17844. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17845. -
  17846. - return w[7];
  17847. - }
  17848. - case PSET_FEEDBACK3:
  17849. - {
  17850. - // w0 w1 w2
  17851. - // x(n)---(+)-->P(0)--------->y(n)
  17852. - // ^ |
  17853. - // | w4 w3 v
  17854. - // -----P(2)<--P(1)--
  17855. -
  17856. - pprc = &ppset->prcs[0];
  17857. -
  17858. - // start with adders
  17859. -
  17860. - w[1] = w[0] + w[4];
  17861. -
  17862. - // evaluate in reverse order
  17863. -
  17864. - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  17865. - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  17866. - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  17867. -
  17868. - return w[2];
  17869. - }
  17870. - case PSET_FEEDBACK4:
  17871. - {
  17872. - // w0 w1 w2 w5
  17873. - // x(n)---(+)-->P(0)-------->P(3)--->y(n)
  17874. - // ^ |
  17875. - // | w4 w3 v
  17876. - // ---P(2)<--P(1)--
  17877. -
  17878. - pprc = &ppset->prcs[0];
  17879. -
  17880. - // start with adders
  17881. -
  17882. - w[1] = w[0] + w[4];
  17883. -
  17884. - // evaluate in reverse order
  17885. -
  17886. - w[5] = pprc[3].pfnGetNext( pprc[3].pdata, w[2] );
  17887. - w[4] = pprc[2].pfnGetNext( pprc[2].pdata, w[3] );
  17888. - w[3] = pprc[1].pfnGetNext( pprc[1].pdata, w[2] );
  17889. - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[1] );
  17890. -
  17891. - return w[2];
  17892. - }
  17893. - case PSET_MOD:
  17894. - {
  17895. - // w0 w1 w3 w4
  17896. - // x(n)------>P(1)--P(2)--P(3)--->y(n)
  17897. - // w0 w2 ^
  17898. - // x(n)------>P(0)....:
  17899. +// stereo delay(no feedback)
  17900. +convar_t *sxste_delay; // straight left delay
  17901.  
  17902. - pprc = &ppset->prcs[0];
  17903. +// mono reverb
  17904. +convar_t *sxrvb_lp; // lowpass
  17905. +convar_t *sxrvb_feedback; // reverb decay. Higher -- longer
  17906. +convar_t *sxrvb_size; // room size. Higher -- larger
  17907.  
  17908. - w[4] = pprc[3].pfnGetNext( pprc[3].pdata, w[3] );
  17909. +// mono delay
  17910. +convar_t *sxdly_lp; // lowpass
  17911. +convar_t *sxdly_feedback; // cycles
  17912. +convar_t *sxdly_delay; // current delay in seconds
  17913.  
  17914. - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[1] );
  17915. +convar_t *dsp_room; // for compability
  17916. +int idsp_dma_speed;
  17917. +int idsp_room;
  17918. +int room_typeprev;
  17919.  
  17920. - // modulate processor 2
  17921. +// routines
  17922. +int sxamodl, sxamodr; // amplitude modulation values
  17923. +int sxamodlt, sxamodrt; // modulation targets
  17924. +int sxmod1cur, sxmod2cur;
  17925. +int sxmod1, sxmod2;
  17926. +int sxhires;
  17927.  
  17928. - pprc[2].pfnMod( pprc[2].pdata, ((float)w[2] / (float)PMAX));
  17929. +portable_samplepair_t *paintto = NULL;
  17930.  
  17931. - // get modulator output
  17932. +dly_t rgsxdly[MAXDLY]; // stereo is last
  17933. +int rgsxlp[MAXLP];
  17934.  
  17935. - w[2] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17936. +void SX_Profiling_f( void );
  17937.  
  17938. - w[1] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  17939. +/*
  17940. +============
  17941. +SX_ReloadRoomFX
  17942.  
  17943. - return w[4];
  17944. - }
  17945. - case PSET_MOD2:
  17946. - {
  17947. - // w0 w2
  17948. - // x(n)---------P(1)-->y(n)
  17949. - // w0 w1 ^
  17950. - // x(n)-->P(0)....:
  17951. +============
  17952. +*/
  17953. +void SX_ReloadRoomFX( void )
  17954. +{
  17955. + if( !dsp_room ) return; // not initialized
  17956.  
  17957. - pprc = &ppset->prcs[0];
  17958. + sxste_delay->modified = true;
  17959. + sxrvb_feedback->modified = true;
  17960. + sxdly_delay->modified = true;
  17961. + room_type->modified = true;
  17962. +}
  17963.  
  17964. - // modulate processor 1
  17965. +/*
  17966. +============
  17967. +SX_Init()
  17968.  
  17969. - pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  17970. +Starts sound crackling system
  17971. +============
  17972. +*/
  17973. +void SX_Init( void )
  17974. +{
  17975. + memset( rgsxdly, 0, sizeof( rgsxdly ));
  17976. + memset( rgsxlp, 0, sizeof( rgsxlp ));
  17977.  
  17978. - // get modulator output
  17979. + sxamodr = sxamodl = sxamodrt = sxamodlt = 255;
  17980. + idsp_dma_speed = SOUND_11k;
  17981.  
  17982. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  17983. + hisound = Cvar_Get( "room_hires", "2", CVAR_ARCHIVE, "dsp quality. 1 for 22k, 2 for 44k(recommended) and 3 for 96k" );
  17984. + sxhires = 2;
  17985.  
  17986. - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  17987. + sxmod1cur = sxmod1 = 350 * ( idsp_dma_speed / SOUND_11k );
  17988. + sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
  17989.  
  17990. - return w[2];
  17991. + dsp_off = Cvar_Get( "dsp_off", "0", 0, "disable DSP processing" );
  17992. + roomwater_type = Cvar_Get( "waterroom_type", "14", 0, "water room type" );
  17993. + room_type = Cvar_Get( "room_type", "0", 0, "current room type preset" );
  17994.  
  17995. - }
  17996. - case PSET_MOD3:
  17997. - {
  17998. - // w0 w2 w3
  17999. - // x(n)----------P(1)-->P(2)-->y(n)
  18000. - // w0 w1 ^
  18001. - // x(n)-->P(0).....:
  18002. + sxmod_lowpass = Cvar_Get( "room_lp", "0", 0, "for water fx, lowpass for entire room" );
  18003. + sxmod_mod = Cvar_Get( "room_mod", "0", 0, "stereo amptitude modulation for room" );
  18004.  
  18005. - pprc = &ppset->prcs[0];
  18006. + sxrvb_size = Cvar_Get( "room_size", "0", 0, "reverb: initial reflection size" );
  18007. + sxrvb_feedback = Cvar_Get( "room_refl", "0", 0, "reverb: decay time" );
  18008. + sxrvb_lp = Cvar_Get( "room_rvblp", "1", 0, "reverb: low pass filtering level" );
  18009.  
  18010. - w[3] = pprc[2].pfnGetNext( pprc[2].pdata, w[2] );
  18011. + sxdly_delay = Cvar_Get( "room_delay", "0.8", 0, "mono delay: delay time" );
  18012. + sxdly_feedback = Cvar_Get( "room_feedback", "0.2", 0, "mono delay: decay time" );
  18013. + sxdly_lp = Cvar_Get( "room_dlylp", "1", 0, "mono delay: low pass filtering level" );
  18014.  
  18015. - // modulate processor 1
  18016. + sxste_delay = Cvar_Get( "room_left", "0", 0, "left channel delay time" );
  18017.  
  18018. - pprc[1].pfnMod( pprc[1].pdata, ((float)w[1] / (float)PMAX));
  18019. + Cmd_AddCommand( "dsp_profile", SX_Profiling_f, "dsp stress-test, first argument is room_type" );
  18020.  
  18021. - // get modulator output
  18022. + // for compability
  18023. + dsp_room = room_type;
  18024. + SX_ReloadRoomFX();
  18025. +}
  18026.  
  18027. - w[1] = pprc[0].pfnGetNext( pprc[0].pdata, w[0] );
  18028. +/*
  18029. +===========
  18030. +DLY_Free
  18031.  
  18032. - w[2] = pprc[1].pfnGetNext( pprc[1].pdata, w[0] );
  18033. +Free memory allocated for DSP
  18034. +===========
  18035. +*/
  18036. +void DLY_Free( int idelay )
  18037. +{
  18038. + Assert( idelay >= 0 && idelay < MAXDLY );
  18039.  
  18040. - return w[2];
  18041. - }
  18042. + if( rgsxdly[idelay].lpdelayline )
  18043. + {
  18044. + Z_Free( rgsxdly[idelay].lpdelayline );
  18045. + rgsxdly[idelay].lpdelayline = NULL;
  18046. }
  18047. }
  18048.  
  18049. +/*
  18050. +==========
  18051. +SX_Shutdown
  18052.  
  18053. -/////////////
  18054. -// DSP system
  18055. -/////////////
  18056. -
  18057. -// Main interface
  18058. -
  18059. -// Whenever the preset # changes on any of these processors, the old processor is faded out, new is faded in.
  18060. -// dsp_chan is optionally set when a sound is played - a preset is sent with the start_static/dynamic sound.
  18061. -//
  18062. -// sound1---->dsp_chan--> -------------(+)---->dsp_water--->dsp_player--->out
  18063. -// sound2---->dsp_chan--> | |
  18064. -// sound3---------------> ----dsp_room---
  18065. -// | |
  18066. -// --dsp_indirect-
  18067. -
  18068. -// dsp_room - set this cvar to a preset # to change the room dsp. room fx are more prevalent farther from player.
  18069. -// use: when player moves into a new room, all sounds played in room take on its reverberant character
  18070. -// dsp_water - set this cvar (once) to a preset # for serial underwater sound.
  18071. -// use: when player goes under water, all sounds pass through this dsp (such as low pass filter)
  18072. -// dsp_player - set this cvar to a preset # to cause all sounds to run through the effect (serial, in-line).
  18073. -// use: player is deafened, player fires special weapon, player is hit by special weapon.
  18074. -// dsp_facingaway- set this cvar to a preset # appropriate for sounds which are played facing away from player (weapon,voice)
  18075. -
  18076. -// Dsp presets
  18077. +Stop DSP processor
  18078. +==========
  18079. +*/
  18080. +void SX_Free( void )
  18081. +{
  18082. + int i;
  18083.  
  18084. -convar_t *dsp_room; // room dsp preset - sounds more distant from player (1ch)
  18085. + for( i = 0; i <= 3; i++ )
  18086. + DLY_Free( i );
  18087.  
  18088. -int ipset_room_prev;
  18089. + Cmd_RemoveCommand( "dsp_profile" );
  18090. +}
  18091.  
  18092. -// legacy room_type support
  18093. -convar_t *dsp_room_type;
  18094. -int ipset_room_typeprev;
  18095.  
  18096. +/*
  18097. +===========
  18098. +DLY_Init
  18099.  
  18100. -// DSP processors
  18101. +Initialize dly
  18102. +===========
  18103. +*/
  18104. +int DLY_Init( int idelay, float delay )
  18105. +{
  18106. + dly_t *cur;
  18107.  
  18108. -int idsp_room;
  18109. -convar_t *dsp_stereo; // set to 1 for true stereo processing. 2x perf hit.
  18110. + // DLY_Init called anytime with constants. So valid it in debug builds only.
  18111. + Assert( idelay >= 0 && idelay < MAXDLY );
  18112. + Assert( delay > 0.0f && delay <= MAX_DELAY );
  18113.  
  18114. -// DSP preset executor
  18115. -#define CDSPS 32 // max number dsp executors active
  18116. -#define DSPCHANMAX 4 // max number of channels dsp can process (allocs a separte processor for each chan)
  18117. + DLY_Free( idelay ); // free dly if it's allocated
  18118.  
  18119. -typedef struct
  18120. -{
  18121. - qboolean fused;
  18122. - int cchan; // 1-4 channels, ie: mono, FrontLeft, FrontRight, RearLeft, RearRight
  18123. - pset_t *ppset[DSPCHANMAX]; // current preset (1-4 channels)
  18124. - int ipset; // current ipreset
  18125. - pset_t *ppsetprev[DSPCHANMAX]; // previous preset (1-4 channels)
  18126. - int ipsetprev; // previous ipreset
  18127. - float xfade; // crossfade time between previous preset and new
  18128. - rmp_t xramp; // crossfade ramp
  18129. -} dsp_t;
  18130. -
  18131. -dsp_t dsps[CDSPS];
  18132. -
  18133. -void DSP_Init( int idsp )
  18134. -{
  18135. - dsp_t *pdsp;
  18136. -
  18137. - if( idsp < 0 || idsp > CDSPS )
  18138. - return;
  18139. -
  18140. - pdsp = &dsps[idsp];
  18141. - memset( pdsp, 0, sizeof( dsp_t ));
  18142. -}
  18143. + cur = &rgsxdly[idelay];
  18144. + cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
  18145. + cur->lpdelayline = (int *)Z_Malloc( cur->cdelaysamplesmax * sizeof( int ));
  18146. + cur->xfade = 0;
  18147.  
  18148. -void DSP_Free( int idsp )
  18149. -{
  18150. - dsp_t *pdsp;
  18151. - int i;
  18152. + // init modulation
  18153. + cur->mod = cur->modcur = 0;
  18154.  
  18155. - if( idsp < 0 || idsp > CDSPS )
  18156. - return;
  18157. -
  18158. - pdsp = &dsps[idsp];
  18159. + // init lowpass
  18160. + cur->lp = 1;
  18161. + cur->lp0 = cur->lp1 = cur->lp2 = 0;
  18162.  
  18163. - for( i = 0; i < pdsp->cchan; i++ )
  18164. - {
  18165. - if( pdsp->ppset[i] )
  18166. - PSET_Free( pdsp->ppset[i] );
  18167. -
  18168. - if( pdsp->ppsetprev[i] )
  18169. - PSET_Free( pdsp->ppsetprev[i] );
  18170. - }
  18171. + cur->idelayinput = 0;
  18172. + cur->idelayoutput = cur->cdelaysamplesmax - cur->delaysamples; // NOTE: delaysamples must be set!!!
  18173.  
  18174. - memset( pdsp, 0, sizeof( dsp_t ));
  18175. -}
  18176.  
  18177. -// Init all dsp processors - called once, during engine startup
  18178. -void DSP_InitAll( void )
  18179. -{
  18180. - int idsp;
  18181. -
  18182. - // order is important, don't rearange.
  18183. - FLT_InitAll();
  18184. - DLY_InitAll();
  18185. - RVA_InitAll();
  18186. - LFOWAV_InitAll();
  18187. - LFO_InitAll();
  18188. -
  18189. - CRS_InitAll();
  18190. - PTC_InitAll();
  18191. - ENV_InitAll();
  18192. - EFO_InitAll();
  18193. - MDY_InitAll();
  18194. - AMP_InitAll();
  18195. -
  18196. - PSET_InitAll();
  18197. -
  18198. - for( idsp = 0; idsp < CDSPS; idsp++ )
  18199. - DSP_Init( idsp );
  18200. + return 1;
  18201. }
  18202.  
  18203. -// free all resources associated with dsp - called once, during engine shutdown
  18204. +/*
  18205. +============
  18206. +DLY_MovePointer
  18207.  
  18208. -void DSP_FreeAll( void )
  18209. +Checks overflow and moves pointer
  18210. +============
  18211. +*/
  18212. +_inline void DLY_MovePointer( dly_t *dly )
  18213. {
  18214. - int idsp;
  18215. -
  18216. - // order is important, don't rearange.
  18217. - for( idsp = 0; idsp < CDSPS; idsp++ )
  18218. - DSP_Free( idsp );
  18219. -
  18220. - AMP_FreeAll();
  18221. - MDY_FreeAll();
  18222. - EFO_FreeAll();
  18223. - ENV_FreeAll();
  18224. - PTC_FreeAll();
  18225. - CRS_FreeAll();
  18226. -
  18227. - LFO_FreeAll();
  18228. - LFOWAV_FreeAll();
  18229. - RVA_FreeAll();
  18230. - DLY_FreeAll();
  18231. - FLT_FreeAll();
  18232. + if( ++dly->idelayinput >= dly->cdelaysamplesmax )
  18233. + dly->idelayinput = 0;
  18234. +
  18235. + if( ++dly->idelayoutput >= dly->cdelaysamplesmax )
  18236. + dly->idelayoutput = 0;
  18237. }
  18238.  
  18239. +/*
  18240. +=============
  18241. +DLY_CheckNewStereoDelayVal
  18242.  
  18243. -// allocate a new dsp processor chain, kill the old processor. Called by DSP_CheckNewPreset()
  18244. -// ipset is new preset
  18245. -// xfade is crossfade time when switching between presets (milliseconds)
  18246. -// cchan is how many simultaneous preset channels to allocate (1-4)
  18247. -// return index to new dsp
  18248. -int DSP_Alloc( int ipset, float xfade, int cchan )
  18249. +Update stereo processor settings if we are in new room
  18250. +=============
  18251. +*/
  18252. +void DLY_CheckNewStereoDelayVal( void )
  18253. {
  18254. - dsp_t *pdsp;
  18255. - int i, idsp;
  18256. - int cchans = bound( 1, cchan, DSPCHANMAX);
  18257. + dly_t *const dly = &rgsxdly[STEREODLY];
  18258. + float delay = sxste_delay->value;
  18259. +
  18260. + if( !sxste_delay->modified )
  18261. + return;
  18262.  
  18263. - // find free slot
  18264. - for( idsp = 0; idsp < CDSPS; idsp++ )
  18265. + if( delay == 0 )
  18266. {
  18267. - if( !dsps[idsp].fused )
  18268. - break;
  18269. + DLY_Free( STEREODLY );
  18270. }
  18271. + else
  18272. + {
  18273. + int samples;
  18274.  
  18275. - if( idsp == CDSPS )
  18276. - return -1;
  18277. + delay = Q_min( delay, MAX_STEREO_DELAY );
  18278. + samples = (int)(delay * idsp_dma_speed) << sxhires;
  18279.  
  18280. - pdsp = &dsps[idsp];
  18281. + // re-init dly
  18282. + if( !dly->lpdelayline )
  18283. + {
  18284. + dly->delaysamples = samples;
  18285. + DLY_Init( STEREODLY, MAX_STEREO_DELAY );
  18286. + }
  18287.  
  18288. - DSP_Init( idsp );
  18289. + if( dly->delaysamples != samples )
  18290. + {
  18291. + dly->xfade = 128;
  18292. + dly->idelayoutputxf = dly->idelayinput - samples;
  18293. + if( dly->idelayoutputxf < 0 )
  18294. + dly->idelayoutputxf += dly->cdelaysamplesmax;
  18295. + }
  18296.  
  18297. - pdsp->fused = true;
  18298. - pdsp->cchan = cchans;
  18299. + dly->modcur = dly->mod = 0;
  18300.  
  18301. - // allocate a preset processor for each channel
  18302. - pdsp->ipset = ipset;
  18303. - pdsp->ipsetprev = 0;
  18304. -
  18305. - for( i = 0; i < pdsp->cchan; i++ )
  18306. - {
  18307. - pdsp->ppset[i] = PSET_Alloc( ipset );
  18308. - pdsp->ppsetprev[i] = NULL;
  18309. + if( dly->delaysamples == 0 )
  18310. + DLY_Free( STEREODLY );
  18311. }
  18312.  
  18313. - // set up crossfade time in seconds
  18314. - pdsp->xfade = xfade / 1000.0f;
  18315. -
  18316. - RMP_SetEnd( &pdsp->xramp );
  18317. -
  18318. - return idsp;
  18319. + sxste_delay->modified = false;
  18320. }
  18321.  
  18322. -// return gain for current preset associated with dsp
  18323. -// get crossfade to new gain if switching from previous preset (from preset crossfader value)
  18324. -// Returns 1.0 gain if no preset (preset 0)
  18325. -float DSP_GetGain( int idsp )
  18326. +/*
  18327. +=============
  18328. +DLY_DoStereoDelay
  18329. +
  18330. +Do stereo processing
  18331. +=============
  18332. +*/
  18333. +void DLY_DoStereoDelay( int count )
  18334. {
  18335. - float gain_target = 0.0;
  18336. - float gain_prev = 0.0;
  18337. - float gain;
  18338. - dsp_t *pdsp;
  18339. - int r;
  18340. -
  18341. - if( idsp < 0 || idsp > CDSPS )
  18342. - return 1.0f;
  18343. -
  18344. - pdsp = &dsps[idsp];
  18345. -
  18346. - // get current preset's gain
  18347. - if( pdsp->ppset[0] )
  18348. - gain_target = pdsp->ppset[0]->gain;
  18349. - else gain_target = 1.0f;
  18350. -
  18351. - // if not crossfading, return current preset gain
  18352. - if( RMP_HitEnd( &pdsp->xramp ))
  18353. - {
  18354. - // return current preset's gain
  18355. - return gain_target;
  18356. - }
  18357. -
  18358. - // get previous preset gain
  18359. + int delay, samplexf;
  18360. + dly_t *const dly = &rgsxdly[STEREODLY];
  18361. + portable_samplepair_t *paint = paintto;
  18362.  
  18363. - if( pdsp->ppsetprev[0] )
  18364. - gain_prev = pdsp->ppsetprev[0]->gain;
  18365. - else gain_prev = 1.0;
  18366. + if( !dly->lpdelayline )
  18367. + return; // inactive
  18368.  
  18369. - // if current gain = target preset gain, return
  18370. - if( gain_target == gain_prev )
  18371. + for( ; count; count--, paint++ )
  18372. {
  18373. - if( gain_target == 0.0f )
  18374. - return 1.0f;
  18375. - return gain_target;
  18376. - }
  18377. + if( dly->mod && --dly->modcur < 0 )
  18378. + dly->modcur = dly->mod;
  18379.  
  18380. - // get crossfade ramp value (updated elsewhere, when actually crossfading preset data)
  18381. - r = RMP_GetCurrent( &pdsp->xramp );
  18382. + delay = dly->lpdelayline[dly->idelayoutput];
  18383.  
  18384. - // crossfade from previous to current preset gain
  18385. - if( gain_target > gain_prev )
  18386. - {
  18387. - // ramping gain up - ramp up gain to target in last 10% of ramp
  18388. - float rf = (float)r;
  18389. - float pmax = (float)PMAX;
  18390. + // process only if crossfading, active left value or delayline
  18391. + if( delay || paint->left || dly->xfade )
  18392. + {
  18393. + // set up new crossfade, if not crossfading, not modulating, but going to
  18394. + if( !dly->xfade && !dly->modcur && dly->mod )
  18395. + {
  18396. + dly->idelayoutputxf = dly->idelayoutput + ((Com_RandomLong( 0, 255 ) * dly->delaysamples ) >> 9 );
  18397.  
  18398. - rf = rf / pmax; // rf 0->1.0
  18399. + dly->xfade = 128;
  18400. + }
  18401.  
  18402. - if( rf < 0.9 ) rf = 0.0;
  18403. - else rf = (rf - 0.9) / (1.0 - 0.9); // 0->1.0 after rf > 0.9
  18404. + dly->idelayoutputxf %= dly->cdelaysamplesmax;
  18405.  
  18406. - // crossfade gain from prev to target over rf
  18407. - gain = gain_prev + (gain_target - gain_prev) * rf;
  18408. + // modify delay, if crossfading
  18409. + if( dly->xfade )
  18410. + {
  18411. + samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7;
  18412. + delay = samplexf + ((delay * dly->xfade) >> 7);
  18413.  
  18414. - return gain;
  18415. - }
  18416. - else
  18417. - {
  18418. - // ramping gain down - drop gain to target in first 10% of ramp
  18419. - float rf = (float) r;
  18420. - float pmax = (float)PMAX;
  18421. + if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
  18422. + dly->idelayoutputxf = 0;
  18423.  
  18424. - rf = rf / pmax; // rf 0.0->1.0
  18425. + if( --dly->xfade == 0 )
  18426. + dly->idelayoutput = dly->idelayoutputxf;
  18427. + }
  18428.  
  18429. - if( rf < 0.1 ) rf = (rf - 0.1) / (0.0 - 0.1); // 1.0->0.0 if rf < 0.1
  18430. - else rf = 0.0;
  18431. + // save left value to delay line
  18432. + dly->lpdelayline[dly->idelayinput] = CLIP( paint->left );
  18433.  
  18434. - // crossfade gain from prev to target over rf
  18435. - gain = gain_prev + (gain_target - gain_prev) * (1.0 - rf);
  18436. + // paint new delay value
  18437. + paint->left = delay;
  18438. + }
  18439. + else
  18440. + {
  18441. + // clear delay line
  18442. + dly->lpdelayline[dly->idelayinput] = 0;
  18443. + }
  18444.  
  18445. - return gain;
  18446. + DLY_MovePointer( dly );
  18447. }
  18448. }
  18449.  
  18450. -// free previous preset if not 0
  18451. -_inline void DSP_FreePrevPreset( dsp_t *pdsp )
  18452. +/*
  18453. +=============
  18454. +DLY_CheckNewDelayVal
  18455. +
  18456. +Update delay processor settings if we are in new room
  18457. +=============
  18458. +*/
  18459. +void DLY_CheckNewDelayVal( void )
  18460. {
  18461. - // free previous presets if non-null - ie: rapid change of preset just kills old without xfade
  18462. - if( pdsp->ipsetprev )
  18463. - {
  18464. - int i;
  18465. + float delay = sxdly_delay->value;
  18466. + dly_t *const dly = &rgsxdly[MONODLY];
  18467.  
  18468. - for( i = 0; i < pdsp->cchan; i++ )
  18469. + if( sxdly_delay->modified )
  18470. + {
  18471. + if( delay == 0 )
  18472. {
  18473. - if( pdsp->ppsetprev[i] )
  18474. + DLY_Free( MONODLY );
  18475. + }
  18476. + else
  18477. + {
  18478. + delay = min( delay, MAX_MONO_DELAY );
  18479. + dly->delaysamples = (int)(delay * idsp_dma_speed) << sxhires;
  18480. +
  18481. + // init dly
  18482. + if( !dly->lpdelayline )
  18483. + DLY_Init( MONODLY, MAX_MONO_DELAY );
  18484. +
  18485. + if( dly->lpdelayline )
  18486. {
  18487. - PSET_Free( pdsp->ppsetprev[i] );
  18488. - pdsp->ppsetprev[i] = NULL;
  18489. + memset( dly->lpdelayline, 0, dly->cdelaysamplesmax * sizeof( int ) );
  18490. + dly->lp0 = dly->lp1 = dly->lp2 = 0;
  18491. }
  18492. +
  18493. + dly->idelayinput = 0;
  18494. + dly->idelayoutput = dly->cdelaysamplesmax - dly->delaysamples;
  18495. +
  18496. + if( !dly->delaysamples )
  18497. + DLY_Free( MONODLY );
  18498. +
  18499. }
  18500. - pdsp->ipsetprev = 0;
  18501. }
  18502.  
  18503. + sxdly_delay->modified = false;
  18504. + dly->lp = sxdly_lp->integer;
  18505. + dly->delayfeedback = 255 * sxdly_feedback->value;
  18506. }
  18507.  
  18508. -// alloc new preset if different from current
  18509. -// xfade from prev to new preset
  18510. -// free previous preset, copy current into previous, set up xfade from previous to new
  18511. -void DSP_SetPreset( int idsp, int ipsetnew )
  18512. +/*
  18513. +=============
  18514. +DLY_DoDelay
  18515. +
  18516. +Do delay processing
  18517. +=============
  18518. +*/
  18519. +void DLY_DoDelay( int count )
  18520. {
  18521. - dsp_t *pdsp;
  18522. - pset_t *ppsetnew[DSPCHANMAX];
  18523. - int i;
  18524. + dly_t *const dly = &rgsxdly[MONODLY];
  18525. + portable_samplepair_t *paint = paintto;
  18526. + int delay;
  18527.  
  18528. - ASSERT( idsp >= 0 && idsp < CDSPS );
  18529. + if( !dly->lpdelayline || !count )
  18530. + return; // inactive
  18531.  
  18532. - pdsp = &dsps[idsp];
  18533. + for( ; count; count--, paint++ )
  18534. + {
  18535. + delay = dly->lpdelayline[dly->idelayoutput];
  18536.  
  18537. - // validate new preset range
  18538. - if( ipsetnew >= CPSETTEMPLATES || ipsetnew < 0 )
  18539. - return;
  18540. + // don't process if delay line and left/right samples are zero
  18541. + if( delay || paint->left || paint->right )
  18542. + {
  18543. + // calculate delayed value from average
  18544. + int val = (( paint->left + paint->right ) >> 1 ) + (( dly->delayfeedback * delay ) >> 8);
  18545. + val = CLIP( val );
  18546.  
  18547. - // ignore if new preset is same as current preset
  18548. - if( ipsetnew == pdsp->ipset )
  18549. - return;
  18550. + if( dly->lp ) // lowpass
  18551. + {
  18552. + dly->lp0 = dly->lp1;
  18553. + dly->lp1 = val;
  18554. + val = ( dly->lp0 + dly->lp1 + (val << 1) ) >> 2;
  18555. + }
  18556.  
  18557. - // alloc new presets (each channel is a duplicate preset)
  18558. - ASSERT( pdsp->cchan <= DSPCHANMAX );
  18559. + dly->lpdelayline[dly->idelayinput] = val;
  18560.  
  18561. - for( i = 0; i < pdsp->cchan; i++ )
  18562. - {
  18563. - ppsetnew[i] = PSET_Alloc( ipsetnew );
  18564. + val >>= 2;
  18565.  
  18566. - if( !ppsetnew[i] )
  18567. + paint->left = CLIP( paint->left + val );
  18568. + paint->right = CLIP( paint->right + val );
  18569. + }
  18570. + else
  18571. {
  18572. - MsgDev( D_NOTE, "DSP preset failed to allocate.\n" );
  18573. - return;
  18574. + dly->lpdelayline[dly->idelayinput] = 0;
  18575. + dly->lp0 = dly->lp1 = 0;
  18576. }
  18577. +
  18578. + DLY_MovePointer( dly );
  18579. }
  18580. +}
  18581. +
  18582. +/*
  18583. +===========
  18584. +RVB_SetUpDly
  18585.  
  18586. - ASSERT( pdsp );
  18587. +Set up dly for reverb
  18588. +===========
  18589. +*/
  18590. +void RVB_SetUpDly( int pos, float delay, int kmod )
  18591. +{
  18592. + int samples;
  18593.  
  18594. - // free PREVIOUS previous preset if not 0
  18595. - DSP_FreePrevPreset( pdsp );
  18596. + delay = Q_min( delay, MAX_REVERB_DELAY );
  18597. + samples = (int)(delay * idsp_dma_speed) << sxhires;
  18598.  
  18599. - for( i = 0; i < pdsp->cchan; i++ )
  18600. + if( !rgsxdly[pos].lpdelayline )
  18601. {
  18602. - // current becomes previous
  18603. - pdsp->ppsetprev[i] = pdsp->ppset[i];
  18604. -
  18605. - // new becomes current
  18606. - pdsp->ppset[i] = ppsetnew[i];
  18607. + rgsxdly[pos].delaysamples = samples;
  18608. + DLY_Init( pos, MAX_REVERB_DELAY );
  18609. }
  18610. -
  18611. - pdsp->ipsetprev = pdsp->ipset;
  18612. - pdsp->ipset = ipsetnew;
  18613.  
  18614. - // clear ramp
  18615. - RMP_SetEnd( &pdsp->xramp );
  18616. -
  18617. - // make sure previous dsp preset has data
  18618. - ASSERT( pdsp->ppsetprev[0] );
  18619. + rgsxdly[pos].modcur = rgsxdly[pos].mod = (int)(kmod * idsp_dma_speed / SOUND_11k) << sxhires;
  18620. +
  18621. + // set up crossfade, if delay has changed
  18622. + if( rgsxdly[pos].delaysamples != samples )
  18623. + {
  18624. + rgsxdly[pos].idelayoutputxf = rgsxdly[pos].idelayinput - samples;
  18625. + if( rgsxdly[pos].idelayoutputxf < 0 )
  18626. + rgsxdly[pos].idelayoutputxf += rgsxdly[pos].cdelaysamplesmax;
  18627. + rgsxdly[pos].xfade = 32;
  18628. + }
  18629.  
  18630. - // shouldn't be crossfading if current dsp preset == previous dsp preset
  18631. - ASSERT( pdsp->ipset != pdsp->ipsetprev );
  18632. + if( !rgsxdly[pos].delaysamples )
  18633. + DLY_Free( pos );
  18634.  
  18635. - RMP_Init( &pdsp->xramp, pdsp->xfade, 0, PMAX );
  18636. }
  18637.  
  18638. -///////////////////////////////////////
  18639. -// Helpers: called only from DSP_Process
  18640. -///////////////////////////////////////
  18641. +/*
  18642. +===========
  18643. +RVB_CheckNewReverbVal
  18644.  
  18645. -// return true if batch processing version of preset exists
  18646. -_inline qboolean FBatchPreset( pset_t *ppset )
  18647. +Update reverb settings if we are in new room
  18648. +===========
  18649. +*/
  18650. +void RVB_CheckNewReverbVal( void )
  18651. {
  18652. - switch( ppset->type )
  18653. + dly_t *const dly1 = &rgsxdly[REVERBPOS];
  18654. + dly_t *const dly2 = &rgsxdly[REVERBPOS + 1];
  18655. + float delay = sxrvb_size->value;
  18656. +
  18657. + if( sxrvb_size->modified )
  18658. {
  18659. - case PSET_LINEAR:
  18660. - return true;
  18661. - case PSET_SIMPLE:
  18662. - return true;
  18663. - default:
  18664. - return false;
  18665. + if( delay == 0.0f )
  18666. + {
  18667. + DLY_Free( REVERBPOS );
  18668. + DLY_Free( REVERBPOS + 1 );
  18669. + }
  18670. + else
  18671. + {
  18672. + RVB_SetUpDly( REVERBPOS, sxrvb_size->value, 500 );
  18673. + RVB_SetUpDly( REVERBPOS+1, sxrvb_size->value * 0.71f, 700 );
  18674. + }
  18675. }
  18676. +
  18677. + sxrvb_size->modified = false;
  18678. + dly1->lp = dly2->lp = sxrvb_lp->integer;
  18679. + dly1->delayfeedback = dly2->delayfeedback = (int)(255 * sxrvb_feedback->value);
  18680. }
  18681.  
  18682. -// Helper: called only from DSP_Process
  18683. -// mix front stereo buffer to mono buffer, apply dsp fx
  18684. -_inline void DSP_ProcessStereoToMono( dsp_t *pdsp, portable_samplepair_t *pbfront, int sampleCount, qboolean bcrossfading )
  18685. +/*
  18686. +===========
  18687. +RVB_DoReverbForOneDly
  18688. +
  18689. +Do reverberation for one dly
  18690. +===========
  18691. +*/
  18692. +int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair )
  18693. {
  18694. - portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  18695. - int count = sampleCount;
  18696. - int av, x;
  18697. + int delay;
  18698. + int samplexf;
  18699. + int val, valt;
  18700. + int voutm = 0;
  18701. +
  18702. + if( --dly->modcur < 0 )
  18703. + dly->modcur = dly->mod;
  18704. +
  18705. + delay = dly->lpdelayline[dly->idelayoutput];
  18706.  
  18707. - if( !bcrossfading )
  18708. + if( dly->xfade || delay || samplepair->left || samplepair->right )
  18709. {
  18710. - if( FBatchPreset( pdsp->ppset[0] ))
  18711. + // modulate delay rate
  18712. + if( !dly->mod )
  18713. {
  18714. - // convert Stereo to Mono in place, then batch process fx: perf KDB
  18715. + dly->idelayoutputxf = dly->idelayoutput + ((Com_RandomLong( 0, 255 ) * delay) >> 9 );
  18716.  
  18717. - // front->left + front->right / 2 into front->left, front->right duplicated.
  18718. - while( count-- )
  18719. - {
  18720. - pbf->left = (pbf->left + pbf->right) >> 1;
  18721. - pbf++;
  18722. - }
  18723. -
  18724. - // process left (mono), duplicate output into right
  18725. - PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT_DUPLICATE);
  18726. + if( dly->idelayoutputxf >= dly->cdelaysamplesmax )
  18727. + dly->idelayoutputxf -= dly->cdelaysamplesmax;
  18728. +
  18729. + dly->xfade = REVERB_XFADE;
  18730. }
  18731. - else
  18732. +
  18733. + if( dly->xfade )
  18734. {
  18735. - // avg left and right -> mono fx -> duplcate out left and right
  18736. - while( count-- )
  18737. - {
  18738. - av = ( ( pbf->left + pbf->right ) >> 1 );
  18739. - x = PSET_GetNext( pdsp->ppset[0], av );
  18740. - x = CLIP_DSP( x );
  18741. - pbf->left = pbf->right = x;
  18742. - pbf++;
  18743. - }
  18744. + samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE;
  18745. + delay = ((delay * dly->xfade) / REVERB_XFADE) + samplexf;
  18746. +
  18747. + if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
  18748. + dly->idelayoutputxf = 0;
  18749. +
  18750. + if( --dly->xfade == 0 )
  18751. + dly->idelayoutput = dly->idelayoutputxf;
  18752. }
  18753. - return;
  18754. - }
  18755.  
  18756. - // crossfading to current preset from previous preset
  18757. - if( bcrossfading )
  18758. - {
  18759. - int r = -1;
  18760. - int fl, flp;
  18761. - int xf_fl;
  18762. -
  18763. - while( count-- )
  18764. +
  18765. + if( delay )
  18766. {
  18767. - av = ( ( pbf->left + pbf->right ) >> 1 );
  18768. -
  18769. - // get current preset values
  18770. - fl = PSET_GetNext( pdsp->ppset[0], av );
  18771. -
  18772. - // get previous preset values
  18773. - flp = PSET_GetNext( pdsp->ppsetprev[0], av );
  18774. -
  18775. - fl = CLIP_DSP(fl);
  18776. - flp = CLIP_DSP(flp);
  18777. -
  18778. - // get current ramp value
  18779. - r = RMP_GetNext( &pdsp->xramp );
  18780. -
  18781. - // crossfade from previous to current preset
  18782. - xf_fl = XFADE( fl, flp, r ); // crossfade front left previous to front left
  18783. -
  18784. - pbf->left = xf_fl; // crossfaded front left, duplicate in right channel
  18785. - pbf->right = xf_fl;
  18786. -
  18787. - pbf++;
  18788. + val = vlr + ( ( dly->delayfeedback * delay ) >> 8 );
  18789. + val = CLIP( val );
  18790. + }
  18791. + else
  18792. + val = vlr;
  18793.  
  18794. + if( dly->lp )
  18795. + {
  18796. + valt = (dly->lp0 + val) >> 1;
  18797. + dly->lp0 = val;
  18798. }
  18799. + else
  18800. + valt = val;
  18801.  
  18802. + voutm = dly->lpdelayline[dly->idelayinput] = valt;
  18803. + }
  18804. + else
  18805. + {
  18806. + voutm = dly->lpdelayline[dly->idelayinput] = 0;
  18807. + dly->lp0 = 0;
  18808. }
  18809. +
  18810. + DLY_MovePointer( dly );
  18811. +
  18812. + return voutm;
  18813. +
  18814. }
  18815.  
  18816. -// Helper: called only from DSP_Process
  18817. -// DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  18818. -_inline void DSP_ProcessStereoToStereo( dsp_t *pdsp, portable_samplepair_t *pbfront, int sampleCount, qboolean bcrossfading )
  18819. +/*
  18820. +===========
  18821. +RVB_DoReverb
  18822. +
  18823. +Do reverberation processing
  18824. +===========
  18825. +*/
  18826. +void RVB_DoReverb( int count )
  18827. {
  18828. - portable_samplepair_t *pbf = pbfront; // pointer to buffer of front stereo samples to process
  18829. - int count = sampleCount;
  18830. - int fl, fr;
  18831. + dly_t *const dly1 = &rgsxdly[REVERBPOS];
  18832. + dly_t *const dly2 = &rgsxdly[REVERBPOS+1];
  18833. + portable_samplepair_t *paint = paintto;
  18834. + int vlr, voutm;
  18835. +
  18836. + if( !dly1->lpdelayline )
  18837. + return;
  18838.  
  18839. - if( !bcrossfading )
  18840. + for( ; count; count--, paint++ )
  18841. {
  18842. + vlr = ( paint->left + paint->right ) >> 1;
  18843.  
  18844. - if( FBatchPreset( pdsp->ppset[0] ) && FBatchPreset( pdsp->ppset[1] ))
  18845. - {
  18846. - // process left & right
  18847. - PSET_GetNextN( pdsp->ppset[0], pbfront, sampleCount, OP_LEFT );
  18848. - PSET_GetNextN( pdsp->ppset[1], pbfront, sampleCount, OP_RIGHT );
  18849. - }
  18850. - else
  18851. - {
  18852. - // left -> left fx, right -> right fx
  18853. - while( count-- )
  18854. - {
  18855. - fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  18856. - fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  18857. + voutm = RVB_DoReverbForOneDly( dly1, vlr, paint );
  18858. + voutm += RVB_DoReverbForOneDly( dly2, vlr, paint );
  18859.  
  18860. - fl = CLIP_DSP( fl );
  18861. - fr = CLIP_DSP( fr );
  18862. + voutm = (11 * voutm) >> 6;
  18863.  
  18864. - pbf->left = fl;
  18865. - pbf->right = fr;
  18866. - pbf++;
  18867. - }
  18868. - }
  18869. - return;
  18870. + paint->left = CLIP( paint->left + voutm );
  18871. + paint->right = CLIP( paint->right + voutm );
  18872. }
  18873. +}
  18874. +
  18875. +/*
  18876. +===========
  18877. +RVB_DoAMod
  18878. +
  18879. +Do amplification modulation processing
  18880. +===========
  18881. +*/
  18882. +void RVB_DoAMod( int count )
  18883. +{
  18884. + portable_samplepair_t *paint = paintto;
  18885. +
  18886. + if( !sxmod_lowpass->integer && !sxmod_mod->integer )
  18887. + return;
  18888.  
  18889. - // crossfading to current preset from previous preset
  18890. - if( bcrossfading )
  18891. + for( ; count; count--, paint++ )
  18892. {
  18893. - int r, flp, frp;
  18894. - int xf_fl, xf_fr;
  18895. + portable_samplepair_t res = *paint;
  18896.  
  18897. - while( count-- )
  18898. + if( sxmod_lowpass->value )
  18899. {
  18900. - // get current preset values
  18901. - fl = PSET_GetNext( pdsp->ppset[0], pbf->left );
  18902. - fr = PSET_GetNext( pdsp->ppset[1], pbf->right );
  18903. -
  18904. - // get previous preset values
  18905. - flp = PSET_GetNext( pdsp->ppsetprev[0], pbf->left );
  18906. - frp = PSET_GetNext( pdsp->ppsetprev[1], pbf->right );
  18907. -
  18908. - // get current ramp value
  18909. - r = RMP_GetNext( &pdsp->xramp );
  18910. -
  18911. - fl = CLIP_DSP( fl );
  18912. - fr = CLIP_DSP( fr );
  18913. - flp = CLIP_DSP( flp );
  18914. - frp = CLIP_DSP( frp );
  18915. -
  18916. - // crossfade from previous to current preset
  18917. - xf_fl = XFADE( fl, flp, r ); // crossfade front left previous to front left
  18918. - xf_fr = XFADE( fr, frp, r );
  18919. -
  18920. - pbf->left = xf_fl; // crossfaded front left
  18921. - pbf->right = xf_fr;
  18922. -
  18923. - pbf++;
  18924. - }
  18925. - }
  18926. -}
  18927. + res.left = rgsxlp[0] + rgsxlp[1] + rgsxlp[2] + rgsxlp[3] + rgsxlp[4] + res.left;
  18928. + res.right = rgsxlp[5] + rgsxlp[6] + rgsxlp[7] + rgsxlp[8] + rgsxlp[9] + res.right;
  18929.  
  18930. -void DSP_ClearState( void )
  18931. -{
  18932. - if( !dsp_room ) return; // not init
  18933. + res.left >>= 2;
  18934. + res.right >>= 2;
  18935.  
  18936. - Cvar_SetFloat( "dsp_room", 0.0f );
  18937. - Cvar_SetFloat( "room_type", 0.0f );
  18938. + rgsxlp[0] = rgsxlp[1];
  18939. + rgsxlp[1] = rgsxlp[2];
  18940. + rgsxlp[2] = rgsxlp[3];
  18941. + rgsxlp[3] = rgsxlp[4];
  18942. + rgsxlp[4] = paint->left;
  18943.  
  18944. - CheckNewDspPresets();
  18945. + rgsxlp[5] = rgsxlp[6];
  18946. + rgsxlp[6] = rgsxlp[7];
  18947. + rgsxlp[7] = rgsxlp[8];
  18948. + rgsxlp[8] = rgsxlp[9];
  18949. + rgsxlp[9] = paint->right;
  18950. + }
  18951.  
  18952. - // don't crossfade
  18953. - dsps[0].xramp.fhitend = true;
  18954. -}
  18955. + if( sxmod_mod->integer )
  18956. + {
  18957. + if( --sxmod1cur < 0 )
  18958. + sxmod1cur = sxmod1;
  18959.  
  18960. -// Main DSP processing routine:
  18961. -// process samples in buffers using pdsp processor
  18962. -// continue crossfade between 2 dsp processors if crossfading on switch
  18963. -// pfront - front stereo buffer to process
  18964. -// prear - rear stereo buffer to process (may be NULL)
  18965. -// sampleCount - number of samples in pbuf to process
  18966. -// This routine also maps the # processing channels in the pdsp to the number of channels
  18967. -// supplied. ie: if the pdsp has 4 channels and pbfront and pbrear are both non-null, the channels
  18968. -// map 1:1 through the processors.
  18969. + if( !sxmod1 )
  18970. + sxamodlt = Com_RandomLong( 32, 255 );
  18971.  
  18972. -void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
  18973. -{
  18974. - qboolean bcrossfading;
  18975. - int cprocs; // output cannels (1, 2 or 4)
  18976. - dsp_t *pdsp;
  18977. + if( --sxmod2cur < 0 )
  18978. + sxmod2cur = sxmod2;
  18979.  
  18980. - if( idsp < 0 || idsp >= CDSPS )
  18981. - return;
  18982. + if( !sxmod2 )
  18983. + sxamodrt = Com_RandomLong( 32, 255 );
  18984.  
  18985. - ASSERT ( idsp < CDSPS ); // make sure idsp is valid
  18986. + res.left = (sxamodl * res.left) >> 8;
  18987. + res.right = (sxamodr * res.right) >> 8;
  18988.  
  18989. - pdsp = &dsps[idsp];
  18990. + if( sxamodl < sxamodlt )
  18991. + sxamodl++;
  18992. + else if( sxamodl > sxamodlt )
  18993. + sxamodl--;
  18994.  
  18995. - // if current and previous preset 0, return - preset 0 is 'off'
  18996. - if( !pdsp->ipset && !pdsp->ipsetprev )
  18997. - return;
  18998. + if( sxamodr < sxamodrt )
  18999. + sxamodr++;
  19000. + else if( sxamodr > sxamodrt )
  19001. + sxamodr--;
  19002. + }
  19003. +
  19004. + paint->left = CLIP(res.left);
  19005. + paint->right = CLIP(res.right);
  19006. + }
  19007. +}
  19008.  
  19009. - ASSERT( pbfront );
  19010. +/*
  19011. +===========
  19012. +DSP_Process
  19013.  
  19014. - // return right away if fx processing is turned off
  19015. +(xash dsp interface)
  19016. +===========
  19017. +*/
  19018. +void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
  19019. +{
  19020. if( dsp_off->integer )
  19021. return;
  19022.  
  19023. - if( sampleCount < 0 )
  19024. + // HACKHACK: don't process while in menu
  19025. + if( cls.key_dest == key_menu || !sampleCount )
  19026. return;
  19027. -
  19028. - bcrossfading = !RMP_HitEnd( &pdsp->xramp );
  19029.  
  19030. - // if not crossfading, and previous channel is not null, free previous
  19031. - if( !bcrossfading ) DSP_FreePrevPreset( pdsp );
  19032. + // preset is already installed by CheckNewDspPresets
  19033. + paintto = pbfront;
  19034.  
  19035. - cprocs = pdsp->cchan;
  19036. -
  19037. - // NOTE: when mixing between different channel sizes,
  19038. - // always AVERAGE down to fewer channels and DUPLICATE up more channels.
  19039. - // The following routines always process cchan_in channels.
  19040. - // ie: QuadToMono still updates 4 values in buffer
  19041. + RVB_DoAMod( sampleCount );
  19042. + RVB_DoReverb( sampleCount );
  19043. + DLY_DoDelay( sampleCount );
  19044. + DLY_DoStereoDelay( sampleCount );
  19045. +}
  19046.  
  19047. - // DSP_Process stereo in to mono out (ie: left and right are averaged)
  19048. - if( cprocs == 1 )
  19049. - {
  19050. - DSP_ProcessStereoToMono( pdsp, pbfront, sampleCount, bcrossfading );
  19051. - return;
  19052. - }
  19053. +/*
  19054. +===========
  19055. +DSP_ClearState
  19056.  
  19057. - // DSP_Process stereo in to stereo out (if more than 2 procs, ignore them)
  19058. - if( cprocs >= 2 )
  19059. - {
  19060. - DSP_ProcessStereoToStereo( pdsp, pbfront, sampleCount, bcrossfading );
  19061. - return;
  19062. - }
  19063. +(xash dsp interface)
  19064. +===========
  19065. +*/
  19066. +void DSP_ClearState( void )
  19067. +{
  19068. + Cvar_SetFloat( "room_type", 0.0f );
  19069. + SX_ReloadRoomFX();
  19070. }
  19071.  
  19072. -// DSP helpers
  19073. +/*
  19074. +===========
  19075. +AllocDsps
  19076.  
  19077. -// free all dsp processors
  19078. -void FreeDsps( void )
  19079. +(xash dsp interface)
  19080. +===========
  19081. +*/
  19082. +qboolean AllocDsps( void )
  19083. {
  19084. - DSP_Free( idsp_room );
  19085. - idsp_room = 0;
  19086. -
  19087. - DSP_FreeAll();
  19088. + SX_Init();
  19089. +
  19090. + return 1;
  19091. }
  19092.  
  19093. -// alloc dsp processors
  19094. -qboolean AllocDsps( void )
  19095. +/*
  19096. +===========
  19097. +FreeDsps
  19098. +
  19099. +(xash dsp interface)
  19100. +===========
  19101. +*/
  19102. +void FreeDsps( void )
  19103. {
  19104. - DSP_InitAll();
  19105. + SX_Free();
  19106. +}
  19107.  
  19108. - idsp_room = -1.0;
  19109. +/*
  19110. +===========
  19111. +CheckNewDspPresets
  19112. +
  19113. +(xash dsp interface)
  19114. +===========
  19115. +*/
  19116. +void CheckNewDspPresets( void )
  19117. +{
  19118. + if( dsp_off->value != 0.0f )
  19119. + return;
  19120.  
  19121. - // initialize DSP cvars
  19122. - dsp_room = Cvar_Get( "dsp_room", "0", 0, "room dsp preset - sounds more distant from player (1ch)" );
  19123. - dsp_room_type = Cvar_Get( "room_type", "0", 0, "duplicate for dsp_room cvar for backward compatibility" );
  19124. - dsp_stereo = Cvar_Get( "dsp_stereo", "0", 0, "set to 1 for true stereo processing. 2x perf hits" );
  19125. + if( s_listener.waterlevel > 2 )
  19126. + idsp_room = roomwater_type->value;
  19127. + else idsp_room = room_type->value;
  19128.  
  19129. - // alloc dsp room channel (mono, stereo if dsp_stereo is 1)
  19130. + if( hisound->modified )
  19131. + {
  19132. + sxhires = hisound->integer;
  19133. + hisound->modified = false;
  19134. + }
  19135.  
  19136. - // dsp room is mono, 300ms fade time
  19137. - idsp_room = DSP_Alloc( dsp_room->integer, 300, dsp_stereo->integer * 2 );
  19138. + if( idsp_room == room_typeprev && idsp_room == 0 )
  19139. + return;
  19140.  
  19141. - // init prev values
  19142. - ipset_room_prev = dsp_room->integer;
  19143. - ipset_room_typeprev = dsp_room_type->integer;
  19144. + if( idsp_room > MAX_ROOM_TYPES )
  19145. + return;
  19146.  
  19147. - if( idsp_room < 0 )
  19148. + if( idsp_room != room_typeprev )
  19149. {
  19150. - MsgDev( D_WARN, "DSP processor failed to initialize! \n" );
  19151. + const sx_preset_t *cur = rgsxpre + idsp_room;
  19152.  
  19153. - FreeDsps();
  19154. - return false;
  19155. + Cvar_SetFloat( "room_lp", cur->room_lp );
  19156. + Cvar_SetFloat( "room_mod", cur->room_mod );
  19157. + Cvar_SetFloat( "room_size", cur->room_size );
  19158. + Cvar_SetFloat( "room_refl", cur->room_refl );
  19159. + Cvar_SetFloat( "room_rvblp", cur->room_rvblp );
  19160. + Cvar_SetFloat( "room_delay", cur->room_delay );
  19161. + Cvar_SetFloat( "room_feedback", cur->room_feedback );
  19162. + Cvar_SetFloat( "room_dlylp", cur->room_dlylp );
  19163. + Cvar_SetFloat( "room_left", cur->room_left );
  19164. }
  19165. - return true;
  19166. +
  19167. + room_typeprev = idsp_room;
  19168. +
  19169. + RVB_CheckNewReverbVal( );
  19170. + DLY_CheckNewDelayVal( );
  19171. + DLY_CheckNewStereoDelayVal();
  19172. }
  19173.  
  19174. +/*
  19175. +===========
  19176. +DSP_GetGain
  19177.  
  19178. -// Helper to check for change in preset of any of 4 processors
  19179. -// if switching to a new preset, alloc new preset, simulate both presets in DSP_Process & xfade,
  19180. -void CheckNewDspPresets( void )
  19181. +(xash dsp interface)
  19182. +===========
  19183. +*/
  19184. +float DSP_GetGain( int idsp )
  19185. {
  19186. - int iroomtype = dsp_room_type->integer;
  19187. - int iroom;
  19188. + return 1.0f;
  19189. +}
  19190.  
  19191. - if( dsp_off->integer )
  19192. - return;
  19193. +void SX_Profiling_f( void )
  19194. +{
  19195. + portable_samplepair_t testbuffer[512];
  19196. + int i, calls = 10000;
  19197. + double start, end;
  19198. + float oldroom = room_type->value;
  19199.  
  19200. - if( s_listener.waterlevel > 2 )
  19201. - iroom = 15;
  19202. - else if( s_listener.inmenu )
  19203. - iroom = 0;
  19204. - else iroom = dsp_room->integer;
  19205. + for( i = 0; i < 512; i++ )
  19206. + {
  19207. + testbuffer[i].left = Com_RandomLong( 0, 3000 );
  19208. + testbuffer[i].right = Com_RandomLong( 0, 3000 );
  19209. + }
  19210.  
  19211. - // legacy code support for "room_type" Cvar
  19212. - if( iroomtype != ipset_room_typeprev )
  19213. + if( Cmd_Argc() > 1 )
  19214. {
  19215. - // force dsp_room = room_type
  19216. - ipset_room_typeprev = iroomtype;
  19217. - Cvar_SetFloat( "dsp_room", iroomtype );
  19218. + Cvar_SetFloat( "room_type", Q_atof( Cmd_Argv( 1 )));
  19219. + SX_ReloadRoomFX();
  19220. + CheckNewDspPresets(); // we just need idsp_room immediately, for message below
  19221. }
  19222.  
  19223. - if( iroom != ipset_room_prev )
  19224. + MsgDev( D_INFO, "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room );
  19225. +
  19226. + start = Sys_DoubleTime();
  19227. + for( ; calls; calls-- )
  19228. {
  19229. - DSP_SetPreset( idsp_room, iroom );
  19230. - ipset_room_prev = iroom;
  19231. + DSP_Process( idsp_room, testbuffer, 512 );
  19232. + }
  19233. + end = Sys_DoubleTime();
  19234.  
  19235. - // force room_type = dsp_room
  19236. - Cvar_SetFloat( "room_type", iroom );
  19237. - ipset_room_typeprev = iroom;
  19238. + MsgDev( D_INFO, "----------\nTook %g seconds.\n", end - start );
  19239. +
  19240. + if( Cmd_Argc() > 1 )
  19241. + {
  19242. + Cvar_SetFloat( "room_type", oldroom );
  19243. + SX_ReloadRoomFX();
  19244. + CheckNewDspPresets();
  19245. }
  19246. }
  19247. \ No newline at end of file
  19248. diff --git b/engine/client/s_load.c a/engine/client/s_load.c
  19249. index e9e90ac..0a0ed45 100644
  19250. --- b/engine/client/s_load.c
  19251. +++ a/engine/client/s_load.c
  19252. @@ -68,8 +68,8 @@ void S_SoundList_f( void )
  19253. // return true if char 'c' is one of 1st 2 characters in pch
  19254. qboolean S_TestSoundChar( const char *pch, char c )
  19255. {
  19256. - int i;
  19257. char *pcht = (char *)pch;
  19258. + int i;
  19259.  
  19260. if( !pch || !*pch )
  19261. return false;
  19262. @@ -141,15 +141,11 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
  19263.  
  19264. if( sc->rate < SOUND_11k ) // some bad sounds
  19265. Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
  19266. -#if SOUND_DMA_SPEED > SOUND_11k
  19267. else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
  19268. Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
  19269. -#endif
  19270. -
  19271. -#if SOUND_DMA_SPEED > SOUND_32k
  19272. else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
  19273. Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
  19274. -#endif
  19275. +
  19276. sfx->cache = sc;
  19277.  
  19278. return sfx->cache;
  19279. @@ -201,9 +197,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
  19280.  
  19281. // find a free sfx slot spot
  19282. for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++)
  19283. - {
  19284. if( !sfx->name[0] ) break; // free spot
  19285. - }
  19286.  
  19287. if( i == s_numSfx )
  19288. {
  19289. diff --git b/engine/client/s_main.c a/engine/client/s_main.c
  19290. index ab9386c..85c71d8 100644
  19291. --- b/engine/client/s_main.c
  19292. +++ a/engine/client/s_main.c
  19293. @@ -20,7 +20,6 @@ GNU General Public License for more details.
  19294. #include "ref_params.h"
  19295. #include "pm_local.h"
  19296.  
  19297. -#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
  19298. #define SND_CLIP_DISTANCE (float)(GI->soundclip_dist)
  19299.  
  19300. dma_t dma;
  19301. @@ -28,6 +27,7 @@ byte *sndpool;
  19302. static soundfade_t soundfade;
  19303. channel_t channels[MAX_CHANNELS];
  19304. sound_t ambient_sfx[NUM_AMBIENTS];
  19305. +rawchan_t *raw_channels[MAX_RAW_CHANNELS];
  19306. qboolean snd_ambient = false;
  19307. listener_t s_listener;
  19308. int total_channels;
  19309. @@ -35,6 +35,7 @@ int soundtime; // sample PAIRS
  19310. int paintedtime; // sample PAIRS
  19311. static int trace_count = 0;
  19312. static int last_trace_chan = 0;
  19313. +static byte s_fatphs[MAX_MAP_LEAFS/8]; // PHS array for snd module
  19314.  
  19315. convar_t *s_volume;
  19316. convar_t *s_musicvolume;
  19317. @@ -51,7 +52,6 @@ convar_t *snd_gain_max;
  19318. convar_t *snd_gain_min;
  19319. convar_t *s_refdist;
  19320. convar_t *s_refdb;
  19321. -convar_t *dsp_off; // set to 1 to disable all dsp processing
  19322. convar_t *s_cull; // cull sounds by geometry
  19323. convar_t *s_test; // cvar for testing new effects
  19324. convar_t *s_phs;
  19325. @@ -356,21 +356,8 @@ already playing.
  19326. channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
  19327. {
  19328. channel_t *ch = NULL;
  19329. - int i, dupe = 0;
  19330. -
  19331. -#if 1
  19332. - // TODO: remove this code when predicting is will be done
  19333. - // check for duplicate sounds
  19334. - for( i = 0; i < total_channels; i++ )
  19335. - {
  19336. - if( channels[i].sfx == sfx && VectorCompare( channels[i].origin, pos ))
  19337. - dupe++;
  19338. - }
  19339. + int i;
  19340.  
  19341. - // check for duplicated static channels (same origin and same sfx)
  19342. - if( dupe > MAX_DUPLICATED_CHANNELS )
  19343. - return NULL;
  19344. -#endif
  19345. // check for replacement sound, or find the best one to replace
  19346. for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ )
  19347. {
  19348. @@ -703,27 +690,26 @@ float SND_GetGain( channel_t *ch, qboolean fplayersound, qboolean flooping, floa
  19349. return gain;
  19350. }
  19351.  
  19352. +/*
  19353. +=================
  19354. +SND_CheckPHS
  19355. +
  19356. +using a 'fat' radius
  19357. +=================
  19358. +*/
  19359. qboolean SND_CheckPHS( channel_t *ch )
  19360. {
  19361. mleaf_t *leaf;
  19362. - int leafnum;
  19363. - byte *mask = NULL;
  19364.  
  19365. - // cull sounds by PHS
  19366. - if( !s_phs->integer )
  19367. - return true;
  19368. + if( !ch->dist_mult || !s_phs->integer )
  19369. + return true; // no attenuation
  19370.  
  19371. leaf = Mod_PointInLeaf( ch->origin, cl.worldmodel->nodes );
  19372. - mask = Mod_LeafPHS( leaf, cl.worldmodel );
  19373.  
  19374. - if( mask )
  19375. - {
  19376. - leafnum = Mod_PointLeafnum( s_listener.origin ) - 1;
  19377. + if( CHECKVISBIT( s_listener.pasbytes, leaf->cluster ))
  19378. + return true;
  19379.  
  19380. - if( leafnum != -1 && (!(mask[leafnum>>3] & (1<<( leafnum & 7 )))))
  19381. - return false;
  19382. - }
  19383. - return true;
  19384. + return false;
  19385. }
  19386.  
  19387. /*
  19388. @@ -1369,7 +1355,7 @@ void S_UpdateAmbientSounds( void )
  19389. if( !chan->sfx ) continue;
  19390.  
  19391. vol = s_ambient_level->value * leaf->ambient_sound_level[ambient_channel];
  19392. - if( vol < 8 ) vol = 0;
  19393. + if( vol < 0 ) vol = 0;
  19394.  
  19395. // don't adjust volume too fast
  19396. if( chan->master_vol < vol )
  19397. @@ -1388,13 +1374,369 @@ void S_UpdateAmbientSounds( void )
  19398. }
  19399.  
  19400. /*
  19401. +=============================================================================
  19402. +
  19403. + SOUND STREAM RAW SAMPLES
  19404. +
  19405. +=============================================================================
  19406. +*/
  19407. +/*
  19408. +===================
  19409. +S_FindRawChannel
  19410. +===================
  19411. +*/
  19412. +rawchan_t *S_FindRawChannel( int entnum, qboolean create )
  19413. +{
  19414. + int i, free;
  19415. + int best, best_time;
  19416. + size_t raw_samples = 0;
  19417. + rawchan_t *ch;
  19418. +
  19419. + if( !entnum ) return NULL; // world is unused
  19420. +
  19421. + // check for replacement sound, or find the best one to replace
  19422. + best_time = 0x7fffffff;
  19423. + best = free = -1;
  19424. +
  19425. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  19426. + {
  19427. + ch = raw_channels[i];
  19428. +
  19429. + if( free < 0 && !ch )
  19430. + {
  19431. + free = i;
  19432. + }
  19433. + else if( ch )
  19434. + {
  19435. + int time;
  19436. +
  19437. + // exact match
  19438. + if( ch->entnum == entnum )
  19439. + return ch;
  19440. +
  19441. + time = ch->s_rawend - paintedtime;
  19442. + if( time < best_time )
  19443. + {
  19444. + best = i;
  19445. + best_time = time;
  19446. + }
  19447. + }
  19448. + }
  19449. +
  19450. + if( !create ) return NULL;
  19451. +
  19452. + if( free >= 0 ) best = free;
  19453. + if( best < 0 ) return NULL; // no free slots
  19454. +
  19455. + if( !raw_channels[best] )
  19456. + {
  19457. + raw_samples = MAX_RAW_SAMPLES;
  19458. + raw_channels[best] = Mem_Alloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * ( raw_samples - 1 ));
  19459. + }
  19460. +
  19461. + ch = raw_channels[best];
  19462. + ch->max_samples = raw_samples;
  19463. + ch->entnum = entnum;
  19464. + ch->s_rawend = 0;
  19465. +
  19466. + return ch;
  19467. +}
  19468. +
  19469. +/*
  19470. +===================
  19471. +S_RawSamplesStereo
  19472. +===================
  19473. +*/
  19474. +static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
  19475. +{
  19476. + uint fracstep, samplefrac;
  19477. + uint src, dst;
  19478. +
  19479. + if( rawend < paintedtime )
  19480. + rawend = paintedtime;
  19481. +
  19482. + fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS);
  19483. + samplefrac = 0;
  19484. +
  19485. + if( width == 2 )
  19486. + {
  19487. + const short *in = (const short *)data;
  19488. +
  19489. + if( channels == 2 )
  19490. + {
  19491. + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
  19492. + {
  19493. + dst = rawend++ & ( max_samples - 1 );
  19494. + rawsamples[dst].left = in[src*2+0];
  19495. + rawsamples[dst].right = in[src*2+1];
  19496. + }
  19497. + }
  19498. + else
  19499. + {
  19500. + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
  19501. + {
  19502. + dst = rawend++ & ( max_samples - 1 );
  19503. + rawsamples[dst].left = in[src];
  19504. + rawsamples[dst].right = in[src];
  19505. + }
  19506. + }
  19507. + }
  19508. + else
  19509. + {
  19510. + if( channels == 2 )
  19511. + {
  19512. + const char *in = (const char *)data;
  19513. +
  19514. + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
  19515. + {
  19516. + dst = rawend++ & ( max_samples - 1 );
  19517. + rawsamples[dst].left = in[src*2+0] << 8;
  19518. + rawsamples[dst].right = in[src*2+1] << 8;
  19519. + }
  19520. + }
  19521. + else
  19522. + {
  19523. + for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
  19524. + {
  19525. + dst = rawend++ & ( max_samples - 1 );
  19526. + rawsamples[dst].left = ( data[src] - 128 ) << 8;
  19527. + rawsamples[dst].right = ( data[src] - 128 ) << 8;
  19528. + }
  19529. + }
  19530. + }
  19531. +
  19532. + return rawend;
  19533. +}
  19534. +
  19535. +/*
  19536. +===================
  19537. +S_RawEntSamples
  19538. +===================
  19539. +*/
  19540. +static void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
  19541. +{
  19542. + rawchan_t *ch;
  19543. +
  19544. + if( snd_vol < 0 )
  19545. + snd_vol = 0;
  19546. +
  19547. + if( !( ch = S_FindRawChannel( entnum, true )))
  19548. + return;
  19549. +
  19550. + ch->master_vol = snd_vol;
  19551. + ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE);
  19552. + ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
  19553. + ch->leftvol = ch->rightvol = snd_vol;
  19554. +}
  19555. +
  19556. +/*
  19557. +===================
  19558. +S_RawSamples
  19559. +===================
  19560. +*/
  19561. +void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum )
  19562. +{
  19563. + int snd_vol;
  19564. +
  19565. + if( entnum < 0 ) snd_vol = 128; // bg track or movie track
  19566. + if( snd_vol < 0 ) snd_vol = 0; // fixup negative values
  19567. +
  19568. + S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
  19569. +}
  19570. +
  19571. +/*
  19572. +===================
  19573. +S_PositionedRawSamples
  19574. +===================
  19575. +*/
  19576. +static void S_PositionedRawSamples( int entnum, float fvol, float attn, uint samples, uint rate, word width, word channels, const byte *data )
  19577. +{
  19578. + rawchan_t *ch;
  19579. +
  19580. + if( entnum < 0 || entnum >= GI->max_edicts )
  19581. + return;
  19582. +
  19583. + if( !( ch = S_FindRawChannel( entnum, true )))
  19584. + return;
  19585. +
  19586. + ch->master_vol = bound( 0, fvol * 255, 255 );
  19587. + ch->dist_mult = (attn / SND_CLIP_DISTANCE);
  19588. + ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, samples, rate, width, channels, data );
  19589. +}
  19590. +
  19591. +/*
  19592. +===================
  19593. +S_GetRawSamplesLength
  19594. +===================
  19595. +*/
  19596. +uint S_GetRawSamplesLength( int entnum )
  19597. +{
  19598. + rawchan_t *ch;
  19599. +
  19600. + if( !( ch = S_FindRawChannel( entnum, false )))
  19601. + return 0;
  19602. +
  19603. + return ch->s_rawend <= paintedtime ? 0 : (float)(ch->s_rawend - paintedtime) * DMA_MSEC_PER_SAMPLE;
  19604. +}
  19605. +
  19606. +/*
  19607. +===================
  19608. +S_ClearRawChannel
  19609. +===================
  19610. +*/
  19611. +void S_ClearRawChannel( int entnum )
  19612. +{
  19613. + rawchan_t *ch;
  19614. +
  19615. + if( !( ch = S_FindRawChannel( entnum, false )))
  19616. + return;
  19617. +
  19618. + ch->s_rawend = 0;
  19619. +}
  19620. +
  19621. +/*
  19622. +===================
  19623. +S_FreeIdleRawChannels
  19624. +
  19625. +Free raw channel that have been idling for too long.
  19626. +===================
  19627. +*/
  19628. +static void S_FreeIdleRawChannels( void )
  19629. +{
  19630. + int i;
  19631. +
  19632. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  19633. + {
  19634. + rawchan_t *ch = raw_channels[i];
  19635. +
  19636. + if( !ch ) continue;
  19637. +
  19638. + if( ch->s_rawend >= paintedtime )
  19639. + continue;
  19640. +
  19641. + if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
  19642. + {
  19643. + raw_channels[i] = NULL;
  19644. + Mem_Free( ch );
  19645. + }
  19646. + }
  19647. +}
  19648. +
  19649. +/*
  19650. +===================
  19651. +S_ClearRawChannels
  19652. +===================
  19653. +*/
  19654. +static void S_ClearRawChannels( void )
  19655. +{
  19656. + int i;
  19657. +
  19658. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  19659. + {
  19660. + rawchan_t *ch = raw_channels[i];
  19661. +
  19662. + if( !ch ) continue;
  19663. + ch->s_rawend = 0;
  19664. + }
  19665. +}
  19666. +
  19667. +/*
  19668. +===================
  19669. +S_SpatializeRawChannels
  19670. +===================
  19671. +*/
  19672. +static void S_SpatializeRawChannels( void )
  19673. +{
  19674. + int i;
  19675. +
  19676. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  19677. + {
  19678. + rawchan_t *ch = raw_channels[i];
  19679. + vec3_t source_vec;
  19680. + float dist, dot;
  19681. +
  19682. + if( !ch ) continue;
  19683. +
  19684. + if( ch->s_rawend < paintedtime )
  19685. + {
  19686. + ch->leftvol = ch->rightvol = 0;
  19687. + continue;
  19688. + }
  19689. +
  19690. + // spatialization
  19691. + if( !S_IsClient( ch->entnum ) && ch->dist_mult && ch->entnum >= 0 && ch->entnum < GI->max_edicts )
  19692. + {
  19693. + if( !CL_GetEntitySpatialization( ch->entnum, ch->origin, &ch->radius ))
  19694. + {
  19695. + // origin is null and entity not exist on client
  19696. + ch->leftvol = ch->rightvol = 0;
  19697. + }
  19698. + else
  19699. + {
  19700. + VectorSubtract( ch->origin, s_listener.origin, source_vec );
  19701. +
  19702. + // normalize source_vec and get distance from listener to source
  19703. + dist = VectorNormalizeLength( source_vec );
  19704. + dot = DotProduct( s_listener.right, source_vec );
  19705. +
  19706. + // for sounds with a radius, spatialize left/right evenly within the radius
  19707. + if( ch->radius > 0 && dist < ch->radius )
  19708. + {
  19709. + float interval = ch->radius * 0.5f;
  19710. + float blend = dist - interval;
  19711. +
  19712. + if( blend < 0 ) blend = 0;
  19713. + blend /= interval;
  19714. +
  19715. + // blend is 0.0 - 1.0, from 50% radius -> 100% radius
  19716. + // at radius * 0.5, dot is 0 (ie: sound centered left/right)
  19717. + // at radius dot == dot
  19718. + dot *= blend;
  19719. + }
  19720. +
  19721. + // don't pan sounds with no attenuation
  19722. + if( ch->dist_mult <= 0.0f ) dot = 0.0f;
  19723. +
  19724. + // fill out channel volumes for single location
  19725. + S_SpatializeChannel( &ch->leftvol, &ch->rightvol, ch->master_vol, 1.0f, dot, dist * ch->dist_mult );
  19726. + }
  19727. + }
  19728. + else
  19729. + {
  19730. + ch->leftvol = ch->rightvol = ch->master_vol;
  19731. + }
  19732. + }
  19733. +}
  19734. +
  19735. +/*
  19736. +===================
  19737. +S_FreeRawChannels
  19738. +===================
  19739. +*/
  19740. +static void S_FreeRawChannels( void )
  19741. +{
  19742. + int i;
  19743. +
  19744. + // free raw samples
  19745. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  19746. + {
  19747. + if( raw_channels[i] )
  19748. + Mem_Free( raw_channels[i] );
  19749. + }
  19750. +
  19751. + memset( raw_channels, 0, sizeof( raw_channels ));
  19752. +}
  19753. +
  19754. +//=============================================================================
  19755. +
  19756. +/*
  19757. ==================
  19758. S_ClearBuffer
  19759. ==================
  19760. */
  19761. void S_ClearBuffer( void )
  19762. {
  19763. - s_rawend = 0;
  19764. + S_ClearRawChannels();
  19765.  
  19766. SNDDMA_BeginPainting ();
  19767. if( dma.buffer ) memset( dma.buffer, 0, dma.samples * 2 );
  19768. @@ -1520,6 +1862,9 @@ void S_RenderFrame( ref_params_t *fd )
  19769. // update any client side sound fade
  19770. S_UpdateSoundFade();
  19771.  
  19772. + // release raw-channels that no longer used more than 10 secs
  19773. + S_FreeIdleRawChannels();
  19774. +
  19775. s_listener.entnum = fd->viewentity; // can be camera entity too
  19776. s_listener.frametime = fd->frametime;
  19777. s_listener.waterlevel = fd->waterlevel;
  19778. @@ -1531,6 +1876,9 @@ void S_RenderFrame( ref_params_t *fd )
  19779. VectorCopy( fd->simvel, s_listener.velocity );
  19780. AngleVectors( fd->viewangles, s_listener.forward, s_listener.right, s_listener.up );
  19781.  
  19782. + if( cl.worldmodel != NULL )
  19783. + Mod_FatPVS( s_listener.origin, FATPHS_RADIUS, s_listener.pasbytes, world.visbytes, false, !s_phs->integer );
  19784. +
  19785. // update general area ambient sound sources
  19786. S_UpdateAmbientSounds();
  19787.  
  19788. @@ -1585,6 +1933,8 @@ void S_RenderFrame( ref_params_t *fd )
  19789. }
  19790. }
  19791.  
  19792. + S_SpatializeRawChannels();
  19793. +
  19794. // debugging output
  19795. if( s_show->value )
  19796. {
  19797. @@ -1605,11 +1955,16 @@ void S_RenderFrame( ref_params_t *fd )
  19798. }
  19799.  
  19800. // to differentiate modes
  19801. - if( s_cull->integer ) VectorSet( info.color, 0.0f, 1.0f, 0.0f );
  19802. + if( s_cull->integer && s_phs->integer )
  19803. + VectorSet( info.color, 0.0f, 1.0f, 0.0f );
  19804. + else if( s_phs->integer )
  19805. + VectorSet( info.color, 1.0f, 1.0f, 0.0f );
  19806. + else if( s_cull->integer )
  19807. + VectorSet( info.color, 1.0f, 0.0f, 0.0f );
  19808. else VectorSet( info.color, 1.0f, 1.0f, 1.0f );
  19809. info.index = 0;
  19810.  
  19811. - Con_NXPrintf( &info, "----(%i)---- painted: %i\n", total - 1, paintedtime );
  19812. + Con_NXPrintf( &info, "room_type: %i ----(%i)---- painted: %i\n", idsp_room, total - 1, paintedtime );
  19813. }
  19814.  
  19815. S_StreamBackgroundTrack ();
  19816. @@ -1773,9 +2128,8 @@ qboolean S_Init( void )
  19817. s_mixahead = Cvar_Get( "_snd_mixahead", "0.12", 0, "how much sound to mix ahead of time" );
  19818. s_show = Cvar_Get( "s_show", "0", CVAR_ARCHIVE, "show playing sounds" );
  19819. s_lerping = Cvar_Get( "s_lerping", "0", CVAR_ARCHIVE, "apply interpolation to sound output" );
  19820. - dsp_off = Cvar_Get( "dsp_off", "0", CVAR_ARCHIVE, "set to 1 to disable all dsp processing" );
  19821. - s_ambient_level = Cvar_Get( "ambient_level", "0.3", 0, "volume of environment noises (water and wind)" );
  19822. - s_ambient_fade = Cvar_Get( "ambient_fade", "100", 0, "rate of volume fading when client is moving" );
  19823. + s_ambient_level = Cvar_Get( "ambient_level", "0.3", CVAR_ARCHIVE, "volume of environment noises (water and wind)" );
  19824. + s_ambient_fade = Cvar_Get( "ambient_fade", "1000", CVAR_ARCHIVE, "rate of volume fading when client is moving" );
  19825. s_combine_sounds = Cvar_Get( "s_combine_channels", "1", CVAR_ARCHIVE, "combine channels with same sounds" );
  19826. snd_foliage_db_loss = Cvar_Get( "snd_foliage_db_loss", "4", 0, "foliage loss factor" );
  19827. snd_gain_max = Cvar_Get( "snd_gain_max", "1", 0, "gain maximal threshold" );
  19828. @@ -1836,10 +2190,11 @@ void S_Shutdown( void )
  19829. Cmd_RemoveCommand( "s_info" );
  19830. Cmd_RemoveCommand( "+voicerecord" );
  19831. Cmd_RemoveCommand( "-voicerecord" );
  19832. - Cmd_RemoveCommand( "spk" );
  19833. Cmd_RemoveCommand( "speak" );
  19834. + Cmd_RemoveCommand( "spk" );
  19835.  
  19836. S_StopAllSounds ();
  19837. + S_FreeRawChannels ();
  19838. S_FreeSounds ();
  19839. VOX_Shutdown ();
  19840. FreeDsps ();
  19841. diff --git b/engine/client/s_mix.c a/engine/client/s_mix.c
  19842. index 9a4a899..a902fcc 100644
  19843. --- b/engine/client/s_mix.c
  19844. +++ a/engine/client/s_mix.c
  19845. @@ -216,8 +216,8 @@ CHANNEL MIXING
  19846. */
  19847. void S_PaintMonoFrom8( portable_samplepair_t *pbuf, int *volume, byte *pData, int outCount )
  19848. {
  19849. - int i, data;
  19850. int *lscale, *rscale;
  19851. + int i, data;
  19852.  
  19853. lscale = snd_scaletable[volume[0] >> SND_SCALE_SHIFT];
  19854. rscale = snd_scaletable[volume[1] >> SND_SCALE_SHIFT];
  19855. @@ -252,8 +252,8 @@ void S_PaintStereoFrom8( portable_samplepair_t *pbuf, int *volume, byte *pData,
  19856.  
  19857. void S_PaintMonoFrom16( portable_samplepair_t *pbuf, int *volume, short *pData, int outCount )
  19858. {
  19859. - int i, data;
  19860. int left, right;
  19861. + int i, data;
  19862.  
  19863. for( i = 0; i < outCount; i++ )
  19864. {
  19865. @@ -473,20 +473,13 @@ int S_MixDataToDevice( channel_t *pChannel, int sampleCount, int outputRate, int
  19866.  
  19867. for( i = 0; i < CPAINTBUFFERS; i++ )
  19868. {
  19869. - if( paintbuffers[i].factive )
  19870. - {
  19871. - // mix chan into all active paintbuffers
  19872. - MIX_SetCurrentPaintbuffer( i );
  19873. -
  19874. - S_MixChannel(
  19875. - pChannel, // Channel.
  19876. - pData, // Input buffer.
  19877. - outputOffset, // Output position.
  19878. - FIX_FLOAT( sampleFraction ), // Iterators.
  19879. - FIX_FLOAT( rate ),
  19880. - outputSampleCount
  19881. - );
  19882. - }
  19883. + if( !paintbuffers[i].factive )
  19884. + continue;
  19885. +
  19886. + // mix chan into all active paintbuffers
  19887. + MIX_SetCurrentPaintbuffer( i );
  19888. +
  19889. + S_MixChannel( pChannel, pData, outputOffset, FIX_FLOAT( sampleFraction ), FIX_FLOAT( rate ), outputSampleCount );
  19890. }
  19891.  
  19892. MIX_SetCurrentPaintbuffer( j );
  19893. @@ -692,7 +685,7 @@ void S_Interpolate2xCubic( portable_samplepair_t *pbuffer, portable_samplepair_t
  19894. {
  19895. // get source sample pointer
  19896. psamp0 = S_GetNextpFilter( i-1, pbuffer, pfiltermem );
  19897. - psamp1 = S_GetNextpFilter( i, pbuffer, pfiltermem );
  19898. + psamp1 = S_GetNextpFilter( i+0, pbuffer, pfiltermem );
  19899. psamp2 = S_GetNextpFilter( i+1, pbuffer, pfiltermem );
  19900. psamp3 = S_GetNextpFilter( i+2, pbuffer, pfiltermem );
  19901.  
  19902. @@ -778,9 +771,9 @@ void S_Interpolate2xLinear( portable_samplepair_t *pbuffer, portable_samplepair_
  19903. // filtertype: FILTERTYPE_NONE, _LINEAR, _CUBIC etc. Must match prevfilter.
  19904. void S_MixBufferUpsample2x( int count, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem, int cfltmem, int filtertype )
  19905. {
  19906. - int i, j;
  19907. int upCount = count<<1;
  19908. -
  19909. + int i, j;
  19910. +
  19911. // reverse through buffer, duplicating contents for 'count' samples
  19912. for( i = upCount - 1, j = count - 1; j >= 0; i-=2, j-- )
  19913. {
  19914. @@ -893,57 +886,16 @@ void S_MixUpsample( int sampleCount, int filtertype )
  19915. ppaint->ifilter++;
  19916. }
  19917.  
  19918. -// mix and upsample channels to 44khz 'ipaintbuffer'
  19919. -// mix channels matching 'flags' (SOUND_MIX_DRY or SOUND_MIX_WET) into specified paintbuffer
  19920. -// upsamples 11khz, 22khz channels to 44khz.
  19921. -
  19922. -// NOTE: only call this on channels that will be mixed into only 1 paintbuffer
  19923. -// and that will not be mixed until the next mix pass! otherwise, MIX_MixChannelsToPaintbuffer
  19924. -// will advance any internal pointers on mixed channels; subsequent calls will be at
  19925. -// incorrect offset.
  19926. -void MIX_MixUpsampleBuffer( int ipaintbuffer, int end, int count )
  19927. -{
  19928. - int ipaintcur = MIX_GetCurrentPaintbufferIndex(); // save current paintbuffer
  19929. -
  19930. - // reset paintbuffer upsampling filter index
  19931. - MIX_ResetPaintbufferFilterCounter( ipaintbuffer );
  19932. -
  19933. - // prevent other paintbuffers from being mixed
  19934. - MIX_DeactivateAllPaintbuffers();
  19935. -
  19936. - MIX_ActivatePaintbuffer( ipaintbuffer ); // operates on MIX_MixChannelsToPaintbuffer
  19937. - MIX_SetCurrentPaintbuffer( ipaintbuffer ); // operates on MixUpSample
  19938. -
  19939. - // mix 11khz channels to buffer
  19940. - MIX_MixChannelsToPaintbuffer( end, SOUND_11k, SOUND_11k );
  19941. -
  19942. - // upsample 11khz buffer by 2x
  19943. - S_MixUpsample( count / (SOUND_DMA_SPEED / SOUND_11k), FILTERTYPE_LINEAR );
  19944. -
  19945. - // mix 22khz channels to buffer
  19946. - MIX_MixChannelsToPaintbuffer( end, SOUND_22k, SOUND_22k );
  19947. -
  19948. - // upsample 22khz buffer by 2x
  19949. -#if (SOUND_DMA_SPEED > SOUND_22k)
  19950. - S_MixUpsample( count / (SOUND_DMA_SPEED / SOUND_22k), FILTERTYPE_LINEAR );
  19951. -#endif
  19952. - // mix 44khz channels to buffer
  19953. - MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED );
  19954. -
  19955. - MIX_DeactivateAllPaintbuffers();
  19956. -
  19957. - // restore previous paintbuffer
  19958. - MIX_SetCurrentPaintbuffer( ipaintcur );
  19959. -}
  19960. -
  19961. void MIX_MixStreamBuffer( int end )
  19962. {
  19963. portable_samplepair_t *pbuf;
  19964. + rawchan_t *ch;
  19965.  
  19966. pbuf = MIX_GetPFrontFromIPaint( ISTREAMBUFFER );
  19967. + ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, false );
  19968.  
  19969. // clear the paint buffer
  19970. - if( s_listener.paused || s_rawend < paintedtime )
  19971. + if( s_listener.paused || !ch || ch->s_rawend < paintedtime )
  19972. {
  19973. memset( pbuf, 0, (end - paintedtime) * sizeof( portable_samplepair_t ));
  19974. }
  19975. @@ -952,18 +904,54 @@ void MIX_MixStreamBuffer( int end )
  19976. int i, stop;
  19977.  
  19978. // copy from the streaming sound source
  19979. - stop = (end < s_rawend) ? end : s_rawend;
  19980. + stop = (end < ch->s_rawend) ? end : ch->s_rawend;
  19981.  
  19982. for( i = paintedtime; i < stop; i++ )
  19983. - pbuf[i - paintedtime] = s_rawsamples[i & (MAX_RAW_SAMPLES - 1)];
  19984. -
  19985. + {
  19986. + pbuf[i-paintedtime].left = ( ch->rawsamples[i & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
  19987. + pbuf[i-paintedtime].right = ( ch->rawsamples[i & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
  19988. + }
  19989. +
  19990. for( ; i < end; i++ )
  19991. pbuf[i-paintedtime].left = pbuf[i-paintedtime].right = 0;
  19992. }
  19993. }
  19994.  
  19995. +void MIX_MixRawSamplesBuffer( int end )
  19996. +{
  19997. + portable_samplepair_t *pbuf;
  19998. + uint i, j, stop;
  19999. +
  20000. + pbuf = MIX_GetCurrentPaintbufferPtr()->pbuf;
  20001. +
  20002. + if( s_listener.paused ) return;
  20003. +
  20004. + // paint in the raw channels
  20005. + for( i = 0; i < MAX_RAW_CHANNELS; i++ )
  20006. + {
  20007. + // copy from the streaming sound source
  20008. + rawchan_t *ch = raw_channels[i];
  20009. +
  20010. + // background track should be mixing into another buffer
  20011. + if( !ch || ch->entnum == S_RAW_SOUND_BACKGROUNDTRACK )
  20012. + continue;
  20013. +
  20014. + // not audible
  20015. + if( !ch->leftvol && !ch->rightvol )
  20016. + continue;
  20017. +
  20018. + stop = (end < ch->s_rawend) ? end : ch->s_rawend;
  20019. +
  20020. + for( j = paintedtime; j < stop; j++ )
  20021. + {
  20022. + pbuf[j-paintedtime].left += ( ch->rawsamples[j & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
  20023. + pbuf[j-paintedtime].right += ( ch->rawsamples[j & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
  20024. + }
  20025. + }
  20026. +}
  20027. +
  20028. // upsample and mix sounds into final 44khz versions of:
  20029. -// IROOMBUFFER, IFACINGBUFFER, IFACINGAWAY, IDRYBUFFER
  20030. +// IROOMBUFFER, IFACINGBUFFER, IFACINGAWAY
  20031. // dsp fx are then applied to these buffers by the caller.
  20032. // caller also remixes all into final IPAINTBUFFER output.
  20033. void MIX_UpsampleAllPaintbuffers( int end, int count )
  20034. @@ -1000,14 +988,17 @@ void MIX_UpsampleAllPaintbuffers( int end, int count )
  20035. MIX_MixChannelsToPaintbuffer( end, SOUND_22k, SOUND_22k );
  20036.  
  20037. // upsample all 22khz buffers by 2x
  20038. -#if (SOUND_DMA_SPEED > SOUND_22k)
  20039. // only upsample roombuffer if dsp fx are on KDB: perf
  20040. MIX_SetCurrentPaintbuffer( IROOMBUFFER );
  20041. S_MixUpsample( count / ( SOUND_DMA_SPEED / SOUND_22k ), FILTERTYPE_LINEAR );
  20042. -#endif
  20043. +
  20044. // mix all 44khz sounds to all active paintbuffers
  20045. MIX_MixChannelsToPaintbuffer( end, SOUND_44k, SOUND_DMA_SPEED );
  20046.  
  20047. + // mix raw samples from the video streams
  20048. + MIX_SetCurrentPaintbuffer( IROOMBUFFER );
  20049. + MIX_MixRawSamplesBuffer( end );
  20050. +
  20051. MIX_DeactivateAllPaintbuffers();
  20052. MIX_SetCurrentPaintbuffer( IPAINTBUFFER );
  20053. }
  20054. diff --git b/engine/client/s_mouth.c a/engine/client/s_mouth.c
  20055. index 41b88ea..c242f8b 100644
  20056. --- b/engine/client/s_mouth.c
  20057. +++ a/engine/client/s_mouth.c
  20058. @@ -32,8 +32,8 @@ void SND_InitMouth( int entnum, int entchannel )
  20059. if( clientEntity )
  20060. {
  20061. clientEntity->mouth.mouthopen = 0;
  20062. - clientEntity->mouth.sndavg = 0;
  20063. clientEntity->mouth.sndcount = 0;
  20064. + clientEntity->mouth.sndavg = 0;
  20065. }
  20066. }
  20067. }
  20068. @@ -59,8 +59,8 @@ void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count )
  20069. cl_entity_t *clientEntity;
  20070. char *pdata = NULL;
  20071. mouth_t *pMouth = NULL;
  20072. - int savg, data;
  20073. int scount, pos = 0;
  20074. + int savg, data;
  20075. uint i;
  20076.  
  20077. clientEntity = CL_GetEntityByIndex( ch->entnum );
  20078. diff --git b/engine/client/s_stream.c a/engine/client/s_stream.c
  20079. index 2be6e30..84886d8 100644
  20080. --- b/engine/client/s_stream.c
  20081. +++ a/engine/client/s_stream.c
  20082. @@ -17,11 +17,14 @@ GNU General Public License for more details.
  20083. #include "sound.h"
  20084. #include "client.h"
  20085.  
  20086. -portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
  20087. static bg_track_t s_bgTrack;
  20088. static musicfade_t musicfade; // controlled by game dlls
  20089. -int s_rawend;
  20090.  
  20091. +/*
  20092. +=================
  20093. +S_PrintBackgroundTrackState
  20094. +=================
  20095. +*/
  20096. void S_PrintBackgroundTrackState( void )
  20097. {
  20098. if( s_bgTrack.current[0] && s_bgTrack.loopName[0] )
  20099. @@ -32,18 +35,6 @@ void S_PrintBackgroundTrackState( void )
  20100. Msg( "BackgroundTrack: %s [loop]\n", s_bgTrack.loopName );
  20101. }
  20102.  
  20103. -void S_CheckLerpingState( void )
  20104. -{
  20105. - wavdata_t *info;
  20106. -
  20107. - s_listener.lerping = false;
  20108. - if( !s_bgTrack.stream ) return;
  20109. - info = FS_StreamInfo( s_bgTrack.stream );
  20110. -
  20111. - if( info && ((float)info->rate / SOUND_DMA_SPEED ) >= 1.0f )
  20112. - s_listener.lerping = s_lerping->integer;
  20113. -}
  20114. -
  20115. /*
  20116. =================
  20117. S_FadeMusicVolume
  20118. @@ -68,6 +59,7 @@ float S_GetMusicVolume( void )
  20119. scale = bound( 0.0f, musicfade.percent / 100.0f, 1.0f );
  20120. scale = 1.0f - scale;
  20121. }
  20122. +
  20123. return s_musicvolume->value * scale;
  20124. }
  20125.  
  20126. @@ -109,10 +101,13 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, long
  20127. // restore message, update song position
  20128. FS_SetStreamPos( s_bgTrack.stream, position );
  20129. }
  20130. -
  20131. - S_CheckLerpingState();
  20132. }
  20133.  
  20134. +/*
  20135. +=================
  20136. +S_StopBackgroundTrack
  20137. +=================
  20138. +*/
  20139. void S_StopBackgroundTrack( void )
  20140. {
  20141. s_listener.stream_paused = false;
  20142. @@ -123,10 +118,13 @@ void S_StopBackgroundTrack( void )
  20143. FS_FreeStream( s_bgTrack.stream );
  20144. memset( &s_bgTrack, 0, sizeof( bg_track_t ));
  20145. memset( &musicfade, 0, sizeof( musicfade ));
  20146. - s_listener.lerping = false;
  20147. - s_rawend = 0;
  20148. }
  20149.  
  20150. +/*
  20151. +=================
  20152. +S_StreamSetPause
  20153. +=================
  20154. +*/
  20155. void S_StreamSetPause( int pause )
  20156. {
  20157. s_listener.stream_paused = pause;
  20158. @@ -175,10 +173,10 @@ void S_StreamBackgroundTrack( void )
  20159. int fileSamples;
  20160. byte raw[MAX_RAW_SAMPLES];
  20161. int r, fileBytes;
  20162. + rawchan_t *ch = NULL;
  20163.  
  20164. - if( !dma.initialized ) return;
  20165. - if( !s_bgTrack.stream ) return;
  20166. - if( s_listener.streaming ) return; // we are playing movie or somewhat
  20167. + if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming )
  20168. + return;
  20169.  
  20170. // don't bother playing anything if musicvolume is 0
  20171. if( !s_musicvolume->value || s_listener.paused || s_listener.stream_paused )
  20172. @@ -193,15 +191,19 @@ void S_StreamBackgroundTrack( void )
  20173. else if( cls.key_dest == key_console )
  20174. return;
  20175.  
  20176. + ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, true );
  20177. +
  20178. + ASSERT( ch != NULL );
  20179. +
  20180. // see how many samples should be copied into the raw buffer
  20181. - if( s_rawend < soundtime )
  20182. - s_rawend = soundtime;
  20183. + if( ch->s_rawend < soundtime )
  20184. + ch->s_rawend = soundtime;
  20185.  
  20186. - while( s_rawend < soundtime + MAX_RAW_SAMPLES )
  20187. + while( ch->s_rawend < soundtime + ch->max_samples )
  20188. {
  20189. wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
  20190.  
  20191. - bufferSamples = MAX_RAW_SAMPLES - (s_rawend - soundtime);
  20192. + bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
  20193.  
  20194. // decide how much data needs to be read from the file
  20195. fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
  20196. @@ -228,7 +230,7 @@ void S_StreamBackgroundTrack( void )
  20197. if( r > 0 )
  20198. {
  20199. // add to raw buffer
  20200. - S_StreamRawSamples( fileSamples, info->rate, info->width, info->channels, raw );
  20201. + S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_BACKGROUNDTRACK );
  20202. }
  20203. else
  20204. {
  20205. @@ -240,7 +242,6 @@ void S_StreamBackgroundTrack( void )
  20206. Q_strncpy( s_bgTrack.current, s_bgTrack.loopName, sizeof( s_bgTrack.current ));
  20207.  
  20208. if( !s_bgTrack.stream ) return;
  20209. - S_CheckLerpingState();
  20210. }
  20211. else
  20212. {
  20213. @@ -262,7 +263,6 @@ void S_StartStreaming( void )
  20214. if( !dma.initialized ) return;
  20215. // begin streaming movie soundtrack
  20216. s_listener.streaming = true;
  20217. - s_listener.lerping = false;
  20218. }
  20219.  
  20220. /*
  20221. @@ -274,8 +274,6 @@ void S_StopStreaming( void )
  20222. {
  20223. if( !dma.initialized ) return;
  20224. s_listener.streaming = false;
  20225. - s_listener.lerping = false;
  20226. - s_rawend = 0;
  20227. }
  20228.  
  20229. /*
  20230. @@ -289,19 +287,26 @@ void S_StreamSoundTrack( void )
  20231. int fileSamples;
  20232. byte raw[MAX_RAW_SAMPLES];
  20233. int r, fileBytes;
  20234. + rawchan_t *ch = NULL;
  20235.  
  20236. - if( !dma.initialized ) return;
  20237. - if( !s_listener.streaming || s_listener.paused ) return;
  20238. + if( !dma.initialized || !s_listener.streaming || s_listener.paused )
  20239. + return;
  20240. +
  20241. + ch = S_FindRawChannel( S_RAW_SOUND_SOUNDTRACK, true );
  20242. +
  20243. + ASSERT( ch != NULL );
  20244.  
  20245. // see how many samples should be copied into the raw buffer
  20246. - if( s_rawend < soundtime )
  20247. - s_rawend = soundtime;
  20248. + if( ch->s_rawend < soundtime )
  20249. + ch->s_rawend = soundtime;
  20250.  
  20251. - while( s_rawend < soundtime + MAX_RAW_SAMPLES )
  20252. + while( ch->s_rawend < soundtime + ch->max_samples )
  20253. {
  20254. wavdata_t *info = SCR_GetMovieInfo();
  20255.  
  20256. - bufferSamples = MAX_RAW_SAMPLES - (s_rawend - soundtime);
  20257. + if( !info ) break; // bad soundtrack?
  20258. +
  20259. + bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
  20260.  
  20261. // decide how much data needs to be read from the file
  20262. fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
  20263. @@ -328,68 +333,8 @@ void S_StreamSoundTrack( void )
  20264. if( r > 0 )
  20265. {
  20266. // add to raw buffer
  20267. - S_StreamRawSamples( fileSamples, info->rate, info->width, info->channels, raw );
  20268. + S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_SOUNDTRACK );
  20269. }
  20270. else break; // no more samples for this frame
  20271. }
  20272. -}
  20273. -
  20274. -/*
  20275. -============
  20276. -S_StreamRawSamples
  20277. -
  20278. -Cinematic streaming and voice over network
  20279. -============
  20280. -*/
  20281. -void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data )
  20282. -{
  20283. - int i, a, b, src, dst;
  20284. - int fracstep, samplefrac;
  20285. - int incount, outcount;
  20286. -
  20287. - src = 0;
  20288. - samplefrac = 0;
  20289. - fracstep = (((double)rate) / (double)SOUND_DMA_SPEED) * 256.0;
  20290. - outcount = (double)samples * (double)SOUND_DMA_SPEED / (double)rate;
  20291. - incount = samples * channels;
  20292. -
  20293. -#define TAKE_SAMPLE( s ) (sizeof(*in) == 1 ? (a = (in[src+(s)]-128)<<8,\
  20294. - b = (src < incount - channels) ? (in[src+channels+(s)]-128)<<8 : 128) : \
  20295. - (a = in[src+(s)],\
  20296. - b = (src < incount - channels) ? (in[src+channels+(s)]) : 0))
  20297. -
  20298. - // NOTE: disable lerping for cinematic sountracks
  20299. -#define LERP_SAMPLE s_listener.lerping ? (((((b - a) * (samplefrac & 255)) >> 8) + a)) : a
  20300. -
  20301. -#define RESAMPLE_RAW \
  20302. - if( channels == 2 ) { \
  20303. - for( i = 0; i < outcount; i++, samplefrac += fracstep, src = (samplefrac >> 8) << 1 ) { \
  20304. - dst = s_rawend++ & (MAX_RAW_SAMPLES - 1); \
  20305. - TAKE_SAMPLE(0); \
  20306. - s_rawsamples[dst].left = LERP_SAMPLE; \
  20307. - TAKE_SAMPLE(1); \
  20308. - s_rawsamples[dst].right = LERP_SAMPLE; \
  20309. - } \
  20310. - } else { \
  20311. - for( i = 0; i < outcount; i++, samplefrac += fracstep, src = (samplefrac >> 8) << 0 ) { \
  20312. - dst = s_rawend++ & (MAX_RAW_SAMPLES - 1); \
  20313. - TAKE_SAMPLE(0); \
  20314. - s_rawsamples[dst].left = LERP_SAMPLE; \
  20315. - s_rawsamples[dst].right = s_rawsamples[dst].left; \
  20316. - } \
  20317. - }
  20318. -
  20319. - if( s_rawend < paintedtime )
  20320. - s_rawend = paintedtime;
  20321. -
  20322. - if( width == 2 )
  20323. - {
  20324. - short *in = (short *)data;
  20325. - RESAMPLE_RAW
  20326. - }
  20327. - else
  20328. - {
  20329. - byte *in = (unsigned char *)data;
  20330. - RESAMPLE_RAW
  20331. - }
  20332. }
  20333. \ No newline at end of file
  20334. diff --git b/engine/client/s_utils.c a/engine/client/s_utils.c
  20335. index 8e065cb..24c046c 100644
  20336. --- b/engine/client/s_utils.c
  20337. +++ a/engine/client/s_utils.c
  20338. @@ -35,7 +35,7 @@ float S_SimpleSpline( float value )
  20339. float valueSquared = value * value;
  20340.  
  20341. // nice little ease-in, ease-out spline-like curve
  20342. - return (3 * valueSquared - 2 * valueSquared * value);
  20343. + return (3.0f * valueSquared - 2.0f * valueSquared * value);
  20344. }
  20345.  
  20346. //-----------------------------------------------------------------------------
  20347. diff --git b/engine/client/s_vox.c a/engine/client/s_vox.c
  20348. index 2601301..8889d45 100644
  20349. --- b/engine/client/s_vox.c
  20350. +++ a/engine/client/s_vox.c
  20351. @@ -383,17 +383,17 @@ void VOX_FreeWord( channel_t *pchan )
  20352. pchan->currentWord = NULL; // sentence is finished
  20353. memset( &pchan->pMixer, 0, sizeof( pchan->pMixer ));
  20354.  
  20355. -#if 0 // release unused sounds ?
  20356. + // release unused sounds
  20357. if( pchan->words[pchan->wordIndex].sfx )
  20358. {
  20359. // If this wave wasn't precached by the game code
  20360. if( !pchan->words[pchan->wordIndex].fKeepCached )
  20361. {
  20362. - S_FreeSound( pchan->words[pchan->wordIndex].sfx );
  20363. + FS_FreeSound( pchan->words[pchan->wordIndex].sfx->cache );
  20364. + pchan->words[pchan->wordIndex].sfx->cache = NULL;
  20365. pchan->words[pchan->wordIndex].sfx = NULL;
  20366. }
  20367. }
  20368. -#endif
  20369. }
  20370.  
  20371. void VOX_LoadFirstWord( channel_t *pchan, voxword_t *pwords )
  20372. diff --git b/engine/client/sound.h a/engine/client/sound.h
  20373. index e69f736..23479f9 100644
  20374. --- b/engine/client/sound.h
  20375. +++ a/engine/client/sound.h
  20376. @@ -20,17 +20,14 @@ extern byte *sndpool;
  20377.  
  20378. #include "mathlib.h"
  20379.  
  20380. -// local flags (never sending acorss the net)
  20381. -#define SND_LOCALSOUND (1<<9) // not paused, not looped, for internal use
  20382. -#define SND_STOP_LOOPING (1<<10) // stop all looping sounds on the entity.
  20383. -
  20384. // sound engine rate defines
  20385. -#define SOUND_DMA_SPEED 44100 // hardware playback rate
  20386. -#define SOUND_11k 11025 // 11khz sample rate
  20387. -#define SOUND_16k 16000 // 16khz sample rate
  20388. -#define SOUND_22k 22050 // 22khz sample rate
  20389. -#define SOUND_32k 32000 // 32khz sample rate
  20390. -#define SOUND_44k 44100 // 44khz sample rate
  20391. +#define SOUND_DMA_SPEED 44100 // hardware playback rate
  20392. +#define SOUND_11k 11025 // 11khz sample rate
  20393. +#define SOUND_16k 16000 // 16khz sample rate
  20394. +#define SOUND_22k 22050 // 22khz sample rate
  20395. +#define SOUND_32k 32000 // 32khz sample rate
  20396. +#define SOUND_44k 44100 // 44khz sample rate
  20397. +#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
  20398.  
  20399. #define SND_TRACE_UPDATE_MAX 2 // max of N channels may be checked for obscured source per frame
  20400. #define SND_RADIUS_MAX 240.0f // max sound source radius
  20401. @@ -50,14 +47,14 @@ extern byte *sndpool;
  20402. #define SND_GAIN_PLAYER_WEAPON_DB 2.0f // increase player weapon gain by N dB
  20403.  
  20404. // fixed point stuff for real-time resampling
  20405. -#define FIX_BITS 28
  20406. -#define FIX_SCALE (1 << FIX_BITS)
  20407. -#define FIX_MASK ((1 << FIX_BITS)-1)
  20408. -#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
  20409. -#define FIX(a) (((int)(a)) << FIX_BITS)
  20410. -#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
  20411. -#define FIX_FRACTION(a,b) (FIX(a)/(b))
  20412. -#define FIX_FRACPART(a) ((a) & FIX_MASK)
  20413. +#define FIX_BITS 28
  20414. +#define FIX_SCALE (1 << FIX_BITS)
  20415. +#define FIX_MASK ((1 << FIX_BITS)-1)
  20416. +#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
  20417. +#define FIX(a) (((int)(a)) << FIX_BITS)
  20418. +#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
  20419. +#define FIX_FRACTION(a,b) (FIX(a)/(b))
  20420. +#define FIX_FRACPART(a) ((a) & FIX_MASK)
  20421.  
  20422. #define SNDLVL_TO_DIST_MULT( sndlvl ) \
  20423. ( sndlvl ? ((pow( 10, s_refdb->value / 20 ) / pow( 10, (float)sndlvl / 20 )) / s_refdist->value ) : 0 )
  20424. @@ -66,26 +63,30 @@ extern byte *sndpool;
  20425. (int)( dist_mult ? ( 20 * log10( pow( 10, s_refdb->value / 20 ) / (dist_mult * s_refdist->value ))) : 0 )
  20426.  
  20427. // NOTE: clipped sound at 32760 to avoid overload
  20428. -#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
  20429. -#define SWAP( a, b, t ) {(t) = (a); (a) = (b); (b) = (t);}
  20430. -#define AVG( a, b ) (((a) + (b)) >> 1 )
  20431. -#define AVG4( a, b, c, d ) (((a) + (b) + (c) + (d)) >> 2 )
  20432. -
  20433. -#define PAINTBUFFER_SIZE 1024 // 44k: was 512
  20434. -#define PAINTBUFFER (g_curpaintbuffer)
  20435. -#define CPAINTBUFFERS 3
  20436. +#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
  20437. +#define SWAP( a, b, t ) {(t) = (a); (a) = (b); (b) = (t);}
  20438. +#define AVG( a, b ) (((a) + (b)) >> 1 )
  20439. +#define AVG4( a, b, c, d ) (((a) + (b) + (c) + (d)) >> 2 )
  20440.  
  20441. -typedef struct
  20442. -{
  20443. - int left;
  20444. - int right;
  20445. -} portable_samplepair_t;
  20446. +#define PAINTBUFFER_SIZE 1024 // 44k: was 512
  20447. +#define PAINTBUFFER (g_curpaintbuffer)
  20448. +#define CPAINTBUFFERS 3
  20449.  
  20450. // sound mixing buffer
  20451. -
  20452. #define CPAINTFILTERMEM 3
  20453. #define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
  20454.  
  20455. +#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
  20456. +#define S_RAW_SOUND_BACKGROUNDTRACK -2
  20457. +#define S_RAW_SOUND_SOUNDTRACK -1
  20458. +#define S_RAW_SAMPLES_PRECISION_BITS 14
  20459. +
  20460. +typedef struct
  20461. +{
  20462. + int left;
  20463. + int right;
  20464. +} portable_samplepair_t;
  20465. +
  20466. typedef struct
  20467. {
  20468. qboolean factive; // if true, mix to this paintbuffer using flags
  20469. @@ -104,7 +105,6 @@ typedef struct sfx_s
  20470. struct sfx_s *hashNext;
  20471. } sfx_t;
  20472.  
  20473. -extern portable_samplepair_t drybuffer[];
  20474. extern portable_samplepair_t paintbuffer[];
  20475. extern portable_samplepair_t roombuffer[];
  20476. extern portable_samplepair_t temppaintbuffer[];
  20477. @@ -146,6 +146,20 @@ typedef struct
  20478. qboolean finished;
  20479. } mixer_t;
  20480.  
  20481. +typedef struct
  20482. +{
  20483. + int entnum;
  20484. + int master_vol;
  20485. + int leftvol; // 0-255 left volume
  20486. + int rightvol; // 0-255 right volume
  20487. + float dist_mult; // distance multiplier (attenuation/clipK)
  20488. + vec3_t origin; // only use if fixed_origin is set
  20489. + float radius; // radius of this sound effect
  20490. + volatile uint s_rawend;
  20491. + size_t max_samples; // buffer length
  20492. + portable_samplepair_t rawsamples[1]; // variable sized
  20493. +} rawchan_t;
  20494. +
  20495. typedef struct channel_s
  20496. {
  20497. char name[16]; // keept sentence name
  20498. @@ -196,8 +210,9 @@ typedef struct
  20499. qboolean inmenu; // listener in-menu ?
  20500. qboolean paused;
  20501. qboolean streaming; // playing AVI-file
  20502. - qboolean lerping; // lerp stream ?
  20503. qboolean stream_paused; // pause only background track
  20504. +
  20505. + byte pasbytes[(MAX_MAP_LEAFS+7)/8];// actual PHS for current frame
  20506. } listener_t;
  20507.  
  20508. typedef struct
  20509. @@ -226,18 +241,19 @@ void SNDDMA_Submit( void );
  20510.  
  20511. #define MAX_DYNAMIC_CHANNELS (28 + NUM_AMBIENTS)
  20512. #define MAX_CHANNELS (128 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
  20513. +#define MAX_RAW_CHANNELS 16
  20514. #define MAX_RAW_SAMPLES 8192
  20515.  
  20516. extern sound_t ambient_sfx[NUM_AMBIENTS];
  20517. extern qboolean snd_ambient;
  20518. extern channel_t channels[MAX_CHANNELS];
  20519. +extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
  20520. extern int total_channels;
  20521. extern int paintedtime;
  20522. -extern int s_rawend;
  20523. extern int soundtime;
  20524. -extern dma_t dma;
  20525. extern listener_t s_listener;
  20526. extern int idsp_room;
  20527. +extern dma_t dma;
  20528.  
  20529. extern convar_t *s_volume;
  20530. extern convar_t *s_musicvolume;
  20531. @@ -245,10 +261,7 @@ extern convar_t *s_show;
  20532. extern convar_t *s_mixahead;
  20533. extern convar_t *s_lerping;
  20534. extern convar_t *dsp_off;
  20535. -extern convar_t *s_test;
  20536. -extern convar_t *s_phs;
  20537. -
  20538. -extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
  20539. +extern convar_t *s_test; // cvar to testify new effects
  20540.  
  20541. void S_InitScaletable( void );
  20542. wavdata_t *S_LoadSound( sfx_t *sfx );
  20543. @@ -296,7 +309,11 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos );
  20544. int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
  20545. int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
  20546. sfx_t *S_GetSfxByHandle( sound_t handle );
  20547. +rawchan_t *S_FindRawChannel( int entnum, qboolean create );
  20548. +void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
  20549. void S_StopSound( int entnum, int channel, const char *soundname );
  20550. +uint S_GetRawSamplesLength( int entnum );
  20551. +void S_ClearRawChannel( int entnum );
  20552. void S_StopAllSounds( void );
  20553. void S_FreeSounds( void );
  20554.  
  20555. diff --git b/engine/client/vgui/utlvector.h a/engine/client/vgui/utlvector.h
  20556. index 86554e3..4bbaac5 100644
  20557. --- b/engine/client/vgui/utlvector.h
  20558. +++ a/engine/client/vgui/utlvector.h
  20559. @@ -332,7 +332,7 @@ void CUtlVector<T>::ShiftElementsLeft( int elem, int num )
  20560. memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
  20561.  
  20562. #ifdef _DEBUG
  20563. - Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
  20564. + memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
  20565. #endif
  20566. }
  20567. }
  20568. diff --git b/engine/client/vgui/vgui_draw.c a/engine/client/vgui/vgui_draw.c
  20569. index 2afaa8d..3eca12e 100644
  20570. --- b/engine/client/vgui/vgui_draw.c
  20571. +++ a/engine/client/vgui/vgui_draw.c
  20572. @@ -32,7 +32,7 @@ Startup VGUI backend
  20573. */
  20574. void VGUI_DrawInit( void )
  20575. {
  20576. - Q_memset( g_textures, 0, sizeof( g_textures ));
  20577. + memset( g_textures, 0, sizeof( g_textures ));
  20578. g_textureId = g_iBoundTexture = 0;
  20579.  
  20580. vgui_colorstrings = Cvar_Get( "vgui_colorstrings", "0", CVAR_ARCHIVE, "allow colorstrings in VGUI texts" );
  20581. @@ -65,7 +65,7 @@ generate unique texture number
  20582. int VGUI_GenerateTexture( void )
  20583. {
  20584. if( ++g_textureId >= VGUI_MAX_TEXTURES )
  20585. - Sys_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
  20586. + Host_Error( "VGUI_GenerateTexture: VGUI_MAX_TEXTURES limit exceeded\n" );
  20587. return g_textureId;
  20588. }
  20589.  
  20590. @@ -88,7 +88,7 @@ void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
  20591. }
  20592.  
  20593. Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
  20594. - Q_memset( &r_image, 0, sizeof( r_image ));
  20595. + memset( &r_image, 0, sizeof( r_image ));
  20596.  
  20597. r_image.width = width;
  20598. r_image.height = height;
  20599. @@ -98,7 +98,6 @@ void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
  20600. r_image.buffer = (byte *)buffer;
  20601.  
  20602. g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE, false );
  20603. - GL_SetTextureType( g_textures[id], TEX_VGUI );
  20604. g_iBoundTexture = id;
  20605. }
  20606.  
  20607. @@ -121,7 +120,7 @@ void VGUI_CreateTexture( int id, int width, int height )
  20608. }
  20609.  
  20610. Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
  20611. - Q_memset( &r_image, 0, sizeof( r_image ));
  20612. + memset( &r_image, 0, sizeof( r_image ));
  20613.  
  20614. r_image.width = width;
  20615. r_image.height = height;
  20616. @@ -131,7 +130,6 @@ void VGUI_CreateTexture( int id, int width, int height )
  20617. r_image.buffer = NULL;
  20618.  
  20619. g_textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE|TF_NEAREST, false );
  20620. - GL_SetTextureType( g_textures[id], TEX_VGUI );
  20621. g_iBoundTexture = id;
  20622. }
  20623.  
  20624. @@ -233,7 +231,8 @@ generic method to fill rectangle
  20625. */
  20626. void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
  20627. {
  20628. - ASSERT( ul != NULL && lr != NULL );
  20629. + Assert( ul != NULL );
  20630. + Assert( lr != NULL );
  20631.  
  20632. pglBegin( GL_QUADS );
  20633. pglTexCoord2f( ul->coord[0], ul->coord[1] );
  20634. diff --git b/engine/client/vgui/vgui_draw.h a/engine/client/vgui/vgui_draw.h
  20635. index fa1da80..a40225e 100644
  20636. --- b/engine/client/vgui/vgui_draw.h
  20637. +++ a/engine/client/vgui/vgui_draw.h
  20638. @@ -46,7 +46,7 @@ void VGUI_EnableTexture( qboolean enable );
  20639. void VGUI_CreateTexture( int id, int width, int height );
  20640. void VGUI_UploadTexture( int id, const char *buffer, int width, int height );
  20641. void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight );
  20642. -long VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  20643. +LONG VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  20644. void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
  20645. void VGUI_GetTextureSizes( int *width, int *height );
  20646. int VGUI_GenerateTexture( void );
  20647. diff --git b/engine/client/vgui/vgui_input.cpp a/engine/client/vgui/vgui_input.cpp
  20648. index f05ee2f..1ac8e2f 100644
  20649. --- b/engine/client/vgui/vgui_input.cpp
  20650. +++ a/engine/client/vgui/vgui_input.cpp
  20651. @@ -106,7 +106,7 @@ void VGUI_InitKeyTranslationTable( void )
  20652. bInitted = true;
  20653.  
  20654. // set virtual key translation table
  20655. - Q_memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ));
  20656. + memset( s_pVirtualKeyTrans, -1, sizeof( s_pVirtualKeyTrans ));
  20657.  
  20658. s_pVirtualKeyTrans['0'] = KEY_0;
  20659. s_pVirtualKeyTrans['1'] = KEY_1;
  20660. @@ -217,9 +217,9 @@ KeyCode VGUI_MapKey( int keyCode )
  20661. {
  20662. VGUI_InitKeyTranslationTable();
  20663.  
  20664. - if( keyCode < 0 || keyCode >= sizeof( s_pVirtualKeyTrans ) / sizeof( s_pVirtualKeyTrans[0] ))
  20665. + if( keyCode < 0 || keyCode >= ARRAYSIZE( s_pVirtualKeyTrans ))
  20666. {
  20667. - Assert( false );
  20668. + Assert( 0 );
  20669. return (KeyCode)-1;
  20670. }
  20671. else
  20672. @@ -228,7 +228,7 @@ KeyCode VGUI_MapKey( int keyCode )
  20673. }
  20674. }
  20675.  
  20676. -long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  20677. +LONG VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  20678. {
  20679. SurfaceBase *surface = NULL;
  20680. CEnginePanel *panel = NULL;
  20681. @@ -238,11 +238,13 @@ long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  20682. return 0;
  20683.  
  20684. panel = (CEnginePanel *)VGui_GetPanel();
  20685. + ASSERT( panel != NULL );
  20686. +
  20687. surface = panel->getSurfaceBase();
  20688. - pApp = panel->getApp();
  20689. + ASSERT( surface != NULL );
  20690.  
  20691. + pApp = panel->getApp();
  20692. ASSERT( pApp != NULL );
  20693. - ASSERT( surface != NULL );
  20694.  
  20695. switch( uMsg )
  20696. {
  20697. @@ -284,7 +286,7 @@ long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  20698. break;
  20699. case WM_KEYDOWN:
  20700. case WM_SYSKEYDOWN:
  20701. - if(!( lParam & ( 1 << 30 )))
  20702. + if( !FBitSet( lParam, BIT( 30 )))
  20703. pApp->internalKeyPressed( VGUI_MapKey( wParam ), surface );
  20704. pApp->internalKeyTyped( VGUI_MapKey( wParam ), surface );
  20705. break;
  20706. diff --git b/engine/client/vgui/vgui_int.cpp a/engine/client/vgui/vgui_int.cpp
  20707. index a461670..bb30f94 100644
  20708. --- b/engine/client/vgui/vgui_int.cpp
  20709. +++ a/engine/client/vgui/vgui_int.cpp
  20710. @@ -68,7 +68,7 @@ void VGui_Startup( void )
  20711. {
  20712. if( rootpanel )
  20713. {
  20714. - rootpanel->setSize( menu.globals->scrWidth, menu.globals->scrHeight );
  20715. + rootpanel->setSize( gameui.globals->scrWidth, gameui.globals->scrHeight );
  20716. return;
  20717. }
  20718.  
  20719. diff --git b/engine/client/vgui/vgui_main.h a/engine/client/vgui/vgui_main.h
  20720. index 8c354d8..788010b 100644
  20721. --- b/engine/client/vgui/vgui_main.h
  20722. +++ a/engine/client/vgui/vgui_main.h
  20723. @@ -19,6 +19,8 @@ GNU General Public License for more details.
  20724. #include "utlvector.h"
  20725. #include "utlrbtree.h"
  20726.  
  20727. +//#define NEW_VGUI_DLL
  20728. +
  20729. #include<VGUI.h>
  20730. #include<VGUI_App.h>
  20731. #include<VGUI_Font.h>
  20732. @@ -127,6 +129,9 @@ public:
  20733. virtual void setTitle( const char *title ) { }
  20734. virtual void createPopup( Panel* embeddedPanel ) { }
  20735. virtual bool isWithin( int x, int y ) { return true; }
  20736. +#ifdef NEW_VGUI_DLL
  20737. + virtual void GetMousePos( int &x, int &y );
  20738. +#endif
  20739. virtual bool hasFocus( void );
  20740. protected:
  20741. virtual int createNewTextureID( void );
  20742. diff --git b/engine/client/vgui/vgui_surf.cpp a/engine/client/vgui/vgui_surf.cpp
  20743. index d240012..1a73772 100644
  20744. --- b/engine/client/vgui/vgui_surf.cpp
  20745. +++ a/engine/client/vgui/vgui_surf.cpp
  20746. @@ -27,8 +27,8 @@ CEngineSurface :: CEngineSurface( Panel *embeddedPanel ):SurfaceBase( embeddedPa
  20747. _drawTextColor[0] = _drawTextColor[1] = _drawTextColor[2] = _drawTextColor[3] = 255;
  20748.  
  20749. _surfaceExtents[0] = _surfaceExtents[1] = 0;
  20750. - _surfaceExtents[2] = menu.globals->scrWidth;
  20751. - _surfaceExtents[3] = menu.globals->scrHeight;
  20752. + _surfaceExtents[2] = gameui.globals->scrWidth;
  20753. + _surfaceExtents[3] = gameui.globals->scrHeight;
  20754. _drawTextPos[0] = _drawTextPos[1] = 0;
  20755. _hCurrentFont = null;
  20756.  
  20757. @@ -56,6 +56,19 @@ void CEngineSurface :: setCursor( Cursor *cursor )
  20758. VGUI_CursorSelect( cursor );
  20759. }
  20760.  
  20761. +#ifdef NEW_VGUI_DLL
  20762. +void CEngineSurface :: GetMousePos( int &x, int &y )
  20763. +{
  20764. + POINT curpos;
  20765. +
  20766. + GetCursorPos( &curpos );
  20767. + ScreenToClient( host.hWnd, &curpos );
  20768. +
  20769. + x = curpos.x;
  20770. + y = curpos.y;
  20771. +}
  20772. +#endif
  20773. +
  20774. void CEngineSurface :: SetupPaintState( const paintState_t &paintState )
  20775. {
  20776. _translateX = paintState.iTranslateX;
  20777. diff --git b/engine/common/avikit.c a/engine/common/avikit.c
  20778. index 44976c4..c3fc08d 100644
  20779. --- b/engine/common/avikit.c
  20780. +++ a/engine/common/avikit.c
  20781. @@ -139,8 +139,6 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
  20782. dword dest_length;
  20783. short bits;
  20784.  
  20785. - ASSERT( Avi != NULL );
  20786. -
  20787. // WMA codecs, both versions - they simply don't work.
  20788. if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
  20789. {
  20790. @@ -249,8 +247,6 @@ qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
  20791.  
  20792. qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration )
  20793. {
  20794. - ASSERT( Avi != NULL );
  20795. -
  20796. if( !Avi->active )
  20797. return false;
  20798.  
  20799. @@ -269,8 +265,6 @@ qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *du
  20800. // returns a unique frame identifier
  20801. long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
  20802. {
  20803. - ASSERT( Avi != NULL );
  20804. -
  20805. if( !Avi->active )
  20806. return 0;
  20807.  
  20808. @@ -284,8 +278,6 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
  20809. byte *frame_raw, *tmp;
  20810. int i;
  20811.  
  20812. - ASSERT( Avi != NULL );
  20813. -
  20814. if( !Avi->active ) return NULL;
  20815.  
  20816. if( frame >= Avi->video_frames )
  20817. @@ -310,8 +302,6 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame )
  20818.  
  20819. qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
  20820. {
  20821. - ASSERT( Avi != NULL );
  20822. -
  20823. if( !Avi->active || Avi->audio_stream == NULL || snd_info == NULL )
  20824. {
  20825. return false;
  20826. @@ -335,8 +325,6 @@ qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
  20827. {
  20828. int breaker;
  20829.  
  20830. - ASSERT( Avi != NULL );
  20831. -
  20832. if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
  20833. {
  20834. if( Avi->cpa_blockoffset - offset < 500000 )
  20835. @@ -382,12 +370,10 @@ qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
  20836. }
  20837.  
  20838. // get a chunk of audio from the stream (in bytes)
  20839. -fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length )
  20840. +long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length )
  20841. {
  20842. - int i;
  20843. long result = 0;
  20844. -
  20845. - ASSERT( Avi != NULL );
  20846. + int i;
  20847.  
  20848. // zero data past the end of the file
  20849. if( offset + length > Avi->audio_length )
  20850. @@ -457,8 +443,6 @@ fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset,
  20851.  
  20852. void AVI_CloseVideo( movie_state_t *Avi )
  20853. {
  20854. - ASSERT( Avi != NULL );
  20855. -
  20856. if( Avi->active )
  20857. {
  20858. pAVIStreamGetFrameClose( Avi->video_getframe );
  20859. @@ -494,8 +478,6 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
  20860. long opened_streams = 0;
  20861. LONG hr;
  20862.  
  20863. - ASSERT( Avi != NULL );
  20864. -
  20865. // default state: non-working.
  20866. Avi->active = false;
  20867. Avi->quiet = quiet;
  20868. diff --git b/engine/common/build.c a/engine/common/build.c
  20869. index b34aa6a..d227ac7 100644
  20870. --- b/engine/common/build.c
  20871. +++ a/engine/common/build.c
  20872. @@ -48,6 +48,6 @@ int Q_buildnum( void )
  20873.  
  20874. return b;
  20875. #else
  20876. - return 3366;
  20877. + return 3598;
  20878. #endif
  20879. }
  20880. \ No newline at end of file
  20881. diff --git b/engine/common/cmd.c a/engine/common/cmd.c
  20882. index 4ad5be6..c6236e8 100644
  20883. --- b/engine/common/cmd.c
  20884. +++ a/engine/common/cmd.c
  20885. @@ -17,8 +17,8 @@ GNU General Public License for more details.
  20886. #include "client.h"
  20887. #include "server.h"
  20888.  
  20889. -#define MAX_CMD_BUFFER 16384
  20890. -#define MAX_CMD_LINE 1024
  20891. +#define MAX_CMD_BUFFER 32768
  20892. +#define MAX_CMD_LINE 2048
  20893.  
  20894. typedef struct
  20895. {
  20896. @@ -31,6 +31,8 @@ qboolean cmd_wait;
  20897. cmdbuf_t cmd_text;
  20898. byte cmd_text_buf[MAX_CMD_BUFFER];
  20899. cmdalias_t *cmd_alias;
  20900. +uint cmd_condition;
  20901. +int cmd_condlevel;
  20902.  
  20903. /*
  20904. =============================================================================
  20905. @@ -92,17 +94,16 @@ Adds command text at the end of the buffer
  20906. */
  20907. void Cbuf_AddText( const char *text )
  20908. {
  20909. - int l;
  20910. -
  20911. - l = Q_strlen( text );
  20912. + int l = Q_strlen( text );
  20913.  
  20914. if( cmd_text.cursize + l >= cmd_text.maxsize )
  20915. {
  20916. MsgDev( D_WARN, "Cbuf_AddText: overflow\n" );
  20917. - return;
  20918. }
  20919. -
  20920. - memcpy( Cbuf_GetSpace( &cmd_text, l ), text, l );
  20921. + else
  20922. + {
  20923. + memcpy( Cbuf_GetSpace( &cmd_text, l ), text, l );
  20924. + }
  20925. }
  20926.  
  20927. /*
  20928. @@ -115,28 +116,17 @@ Adds a \n to the text
  20929. */
  20930. void Cbuf_InsertText( const char *text )
  20931. {
  20932. - char *temp;
  20933. - int templen;
  20934. -
  20935. - // copy off any commands still remaining in the exec buffer
  20936. - templen = cmd_text.cursize;
  20937. + int l = Q_strlen( text );
  20938.  
  20939. - if( templen )
  20940. + if( cmd_text.cursize + l >= cmd_text.maxsize )
  20941. {
  20942. - temp = Z_Malloc( templen );
  20943. - memcpy( temp, cmd_text.data, templen );
  20944. - cmd_text.cursize = 0;
  20945. + MsgDev( D_WARN, "Cbuf_InsertText: overflow\n" );
  20946. }
  20947. - else temp = NULL;
  20948. -
  20949. - // add the entire text of the file
  20950. - Cbuf_AddText( text );
  20951. -
  20952. - // add the copied off data
  20953. - if( templen )
  20954. + else
  20955. {
  20956. - memcpy( Cbuf_GetSpace( &cmd_text, templen ), temp, templen );
  20957. - Z_Free( temp );
  20958. + memmove( cmd_text.data + l, cmd_text.data, cmd_text.cursize );
  20959. + memcpy( cmd_text.data, text, l );
  20960. + cmd_text.cursize += l;
  20961. }
  20962. }
  20963.  
  20964. @@ -150,28 +140,50 @@ void Cbuf_Execute( void )
  20965. char *text;
  20966. char line[MAX_CMD_LINE];
  20967. int i, quotes;
  20968. + char *comment;
  20969.  
  20970. while( cmd_text.cursize )
  20971. {
  20972. // find a \n or ; line break
  20973. text = (char *)cmd_text.data;
  20974.  
  20975. - quotes = 0;
  20976. + quotes = false;
  20977. + comment = NULL;
  20978.  
  20979. for( i = 0; i < cmd_text.cursize; i++ )
  20980. {
  20981. - if( text[i] == '"' ) quotes++;
  20982. - if(!( quotes & 1 ) && text[i] == ';' )
  20983. - break; // don't break if inside a quoted string
  20984. + if( !comment )
  20985. + {
  20986. + if( text[i] == '"' ) quotes = !quotes;
  20987. +
  20988. + if( quotes )
  20989. + {
  20990. + // make sure i doesn't get > cursize which causes a negative size in memmove, which is fatal --blub
  20991. + if( i < ( cmd_text.cursize - 1 ) && ( text[i+0] == '\\' && (text[i+1] == '"' || text[i+1] == '\\')))
  20992. + i++;
  20993. + }
  20994. + else
  20995. + {
  20996. + if( text[i+0] == '/' && text[i+1] == '/' && ( i == 0 || (byte)text[i - 1] <= ' ' ))
  20997. + comment = &text[i];
  20998. + if( text[i] == ';' ) break; // don't break if inside a quoted string or comment
  20999. + }
  21000. + }
  21001. +
  21002. if( text[i] == '\n' || text[i] == '\r' )
  21003. break;
  21004. }
  21005.  
  21006. if( i >= ( MAX_CMD_LINE - 1 ))
  21007. - Sys_Error( "Cbuf_Execute: command string owerflow\n" );
  21008. -
  21009. - memcpy( line, text, i );
  21010. - line[i] = 0;
  21011. + {
  21012. + MsgDev( D_ERROR, "Cbuf_Execute: command string owerflow\n" );
  21013. + line[0] = 0;
  21014. + }
  21015. + else
  21016. + {
  21017. + memcpy( line, text, comment ? (comment - text) : i );
  21018. + line[comment ? (comment - text) : i] = 0;
  21019. + }
  21020.  
  21021. // delete the text from the command buffer and move remaining commands down
  21022. // this is necessary because commands (exec) can insert data at the
  21023. @@ -184,11 +196,11 @@ void Cbuf_Execute( void )
  21024. {
  21025. i++;
  21026. cmd_text.cursize -= i;
  21027. - memcpy( text, text + i, cmd_text.cursize );
  21028. + memmove( cmd_text.data, text + i, cmd_text.cursize );
  21029. }
  21030.  
  21031. // execute the command line
  21032. - Cmd_ExecuteString( line, src_command );
  21033. + Cmd_ExecuteString( line );
  21034.  
  21035. if( cmd_wait )
  21036. {
  21037. @@ -332,7 +344,7 @@ void Cmd_Alias_f( void )
  21038. return;
  21039. }
  21040.  
  21041. - // if the alias allready exists, reuse it
  21042. + // if the alias already exists, reuse it
  21043. for( a = cmd_alias; a; a = a->next )
  21044. {
  21045. if( !Q_strcmp( s, a->name ))
  21046. @@ -344,12 +356,19 @@ void Cmd_Alias_f( void )
  21047.  
  21048. if( !a )
  21049. {
  21050. + cmdalias_t *cur, *prev;
  21051. +
  21052. a = Z_Malloc( sizeof( cmdalias_t ));
  21053. - a->next = cmd_alias;
  21054. - cmd_alias = a;
  21055. - }
  21056.  
  21057. - Q_strncpy( a->name, s, sizeof( a->name ));
  21058. + Q_strncpy( a->name, s, sizeof( a->name ));
  21059. +
  21060. + // insert it at the right alphanumeric position
  21061. + for( prev = NULL, cur = cmd_alias; cur && Q_strcmp( cur->name, a->name ) < 0; prev = cur, cur = cur->next );
  21062. +
  21063. + if( prev ) prev->next = a;
  21064. + else cmd_alias = a;
  21065. + a->next = cur;
  21066. + }
  21067.  
  21068. // copy the rest of the command line
  21069. cmd[0] = 0; // start out with a null string
  21070. @@ -358,15 +377,56 @@ void Cmd_Alias_f( void )
  21071.  
  21072. for( i = 2; i < c; i++ )
  21073. {
  21074. - Q_strcat( cmd, Cmd_Argv( i ));
  21075. - if( i != c ) Q_strcat( cmd, " " );
  21076. + if( i != 2 ) Q_strncat( cmd, " ", sizeof( cmd ));
  21077. + Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd ));
  21078. }
  21079.  
  21080. - Q_strcat( cmd, "\n" );
  21081. + Q_strncat( cmd, "\n", sizeof( cmd ));
  21082. a->value = copystring( cmd );
  21083. }
  21084.  
  21085. /*
  21086. +===============
  21087. +Cmd_UnAlias_f
  21088. +
  21089. +Remove existing aliases.
  21090. +===============
  21091. +*/
  21092. +static void Cmd_UnAlias_f ( void )
  21093. +{
  21094. + cmdalias_t *a, *p;
  21095. + const char *s;
  21096. + int i;
  21097. +
  21098. + if( Cmd_Argc() == 1 )
  21099. + {
  21100. + Msg( "Usage: unalias alias1 [alias2 ...]\n" );
  21101. + return;
  21102. + }
  21103. +
  21104. + for( i = 1; i < Cmd_Argc(); i++ )
  21105. + {
  21106. + s = Cmd_Argv( i );
  21107. + p = NULL;
  21108. +
  21109. + for( a = cmd_alias; a; p = a, a = a->next )
  21110. + {
  21111. + if( !Q_strcmp( s, a->name ))
  21112. + {
  21113. + if( a == cmd_alias )
  21114. + cmd_alias = a->next;
  21115. + if( p ) p->next = a->next;
  21116. + Mem_Free( a->value );
  21117. + Mem_Free( a );
  21118. + break;
  21119. + }
  21120. + }
  21121. +
  21122. + if( !a ) Msg( "unalias: %s alias not found\n", s );
  21123. + }
  21124. +}
  21125. +
  21126. +/*
  21127. =============================================================================
  21128.  
  21129. COMMAND EXECUTION
  21130. @@ -387,7 +447,6 @@ static char *cmd_args = NULL;
  21131. static char *cmd_argv[MAX_CMD_TOKENS];
  21132. static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted
  21133. static cmd_t *cmd_functions; // possible commands to execute
  21134. -cmd_source_t cmd_source;
  21135.  
  21136. /*
  21137. ============
  21138. @@ -489,12 +548,14 @@ void Cmd_TokenizeString( char *text )
  21139. while( 1 )
  21140. {
  21141. // skip whitespace up to a /n
  21142. - while( *text && ((byte)*text) <= ' ' && *text != '\n' )
  21143. + while( *text && ((byte)*text) <= ' ' && *text != '\r' && *text != '\n' )
  21144. text++;
  21145. -
  21146. - if( *text == '\n' )
  21147. - {
  21148. +
  21149. + if( *text == '\n' || *text == '\r' )
  21150. + {
  21151. // a newline seperates commands in the buffer
  21152. + if( *text == '\r' && text[1] == '\n' )
  21153. + text++;
  21154. text++;
  21155. break;
  21156. }
  21157. @@ -516,7 +577,6 @@ void Cmd_TokenizeString( char *text )
  21158. }
  21159. }
  21160.  
  21161. -
  21162. /*
  21163. ============
  21164. Cmd_AddCommand
  21165. @@ -524,7 +584,7 @@ Cmd_AddCommand
  21166. */
  21167. void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
  21168. {
  21169. - cmd_t *cmd;
  21170. + cmd_t *cmd, *cur, *prev;
  21171.  
  21172. // fail if the command is a variable name
  21173. if( Cvar_FindVar( cmd_name ))
  21174. @@ -545,41 +605,57 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_
  21175. cmd->name = copystring( cmd_name );
  21176. cmd->desc = copystring( cmd_desc );
  21177. cmd->function = function;
  21178. - cmd->next = cmd_functions;
  21179. - cmd_functions = cmd;
  21180. +
  21181. + // insert it at the right alphanumeric position
  21182. + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
  21183. +
  21184. + if( prev ) prev->next = cmd;
  21185. + else cmd_functions = cmd;
  21186. + cmd->next = cur;
  21187. }
  21188.  
  21189. /*
  21190. ============
  21191. -Cmd_AddGameCommand
  21192. +Cmd_AddServerCommand
  21193. ============
  21194. */
  21195. -void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function )
  21196. +void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
  21197. {
  21198. - cmd_t *cmd;
  21199. + cmd_t *cmd, *cur, *prev;
  21200. +
  21201. + if( !cmd_name || !*cmd_name )
  21202. + {
  21203. + MsgDev( D_INFO, "Cmd_AddServerCommand: NULL name\n" );
  21204. + return;
  21205. + }
  21206.  
  21207. // fail if the command is a variable name
  21208. if( Cvar_FindVar( cmd_name ))
  21209. {
  21210. - MsgDev( D_INFO, "Cmd_AddCommand: %s already defined as a var\n", cmd_name );
  21211. + MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined as a var\n", cmd_name );
  21212. return;
  21213. }
  21214.  
  21215. // fail if the command already exists
  21216. if( Cmd_Exists( cmd_name ))
  21217. {
  21218. - MsgDev(D_INFO, "Cmd_AddCommand: %s already defined\n", cmd_name);
  21219. + MsgDev( D_ERROR, "Cmd_AddServerCommand: %s already defined\n", cmd_name );
  21220. return;
  21221. }
  21222.  
  21223. // use a small malloc to avoid zone fragmentation
  21224. cmd = Z_Malloc( sizeof( cmd_t ));
  21225. cmd->name = copystring( cmd_name );
  21226. - cmd->desc = copystring( "game command" );
  21227. + cmd->desc = copystring( "server command" );
  21228. cmd->function = function;
  21229. - cmd->flags = CMD_EXTDLL;
  21230. - cmd->next = cmd_functions;
  21231. - cmd_functions = cmd;
  21232. + cmd->flags = CMD_SERVERDLL;
  21233. +
  21234. + // insert it at the right alphanumeric position
  21235. + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
  21236. +
  21237. + if( prev ) prev->next = cmd;
  21238. + else cmd_functions = cmd;
  21239. + cmd->next = cur;
  21240. }
  21241.  
  21242. /*
  21243. @@ -587,22 +663,28 @@ void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function )
  21244. Cmd_AddClientCommand
  21245. ============
  21246. */
  21247. -void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
  21248. +int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
  21249. {
  21250. - cmd_t *cmd;
  21251. + cmd_t *cmd, *cur, *prev;
  21252. +
  21253. + if( !cmd_name || !*cmd_name )
  21254. + {
  21255. + MsgDev( D_INFO, "Cmd_AddClientCommand: NULL name\n" );
  21256. + return 0;
  21257. + }
  21258.  
  21259. // fail if the command is a variable name
  21260. if( Cvar_FindVar( cmd_name ))
  21261. {
  21262. - MsgDev( D_INFO, "Cmd_AddCommand: %s already defined as a var\n", cmd_name );
  21263. - return;
  21264. + MsgDev( D_INFO, "Cmd_AddClientCommand: %s already defined as a var\n", cmd_name );
  21265. + return 0;
  21266. }
  21267.  
  21268. // fail if the command already exists
  21269. if( Cmd_Exists( cmd_name ))
  21270. {
  21271. - MsgDev(D_INFO, "Cmd_AddCommand: %s already defined\n", cmd_name);
  21272. - return;
  21273. + MsgDev(D_INFO, "Cmd_AddClientCommand: %s already defined\n", cmd_name );
  21274. + return 0;
  21275. }
  21276.  
  21277. // use a small malloc to avoid zone fragmentation
  21278. @@ -611,8 +693,61 @@ void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
  21279. cmd->desc = copystring( "client command" );
  21280. cmd->function = function;
  21281. cmd->flags = CMD_CLIENTDLL;
  21282. - cmd->next = cmd_functions;
  21283. - cmd_functions = cmd;
  21284. +
  21285. + // insert it at the right alphanumeric position
  21286. + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
  21287. +
  21288. + if( prev ) prev->next = cmd;
  21289. + else cmd_functions = cmd;
  21290. + cmd->next = cur;
  21291. +
  21292. + return 1;
  21293. +}
  21294. +
  21295. +/*
  21296. +============
  21297. +Cmd_AddGameUICommand
  21298. +============
  21299. +*/
  21300. +int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
  21301. +{
  21302. + cmd_t *cmd, *cur, *prev;
  21303. +
  21304. + if( !cmd_name || !*cmd_name )
  21305. + {
  21306. + MsgDev( D_INFO, "Cmd_AddGameUICommand: NULL name\n" );
  21307. + return 0;
  21308. + }
  21309. +
  21310. + // fail if the command is a variable name
  21311. + if( Cvar_FindVar( cmd_name ))
  21312. + {
  21313. + MsgDev( D_INFO, "Cmd_AddGameUICommand: %s already defined as a var\n", cmd_name );
  21314. + return 0;
  21315. + }
  21316. +
  21317. + // fail if the command already exists
  21318. + if( Cmd_Exists( cmd_name ))
  21319. + {
  21320. + MsgDev(D_INFO, "Cmd_AddGameUICommand: %s already defined\n", cmd_name );
  21321. + return 0;
  21322. + }
  21323. +
  21324. + // use a small malloc to avoid zone fragmentation
  21325. + cmd = Z_Malloc( sizeof( cmd_t ));
  21326. + cmd->name = copystring( cmd_name );
  21327. + cmd->desc = copystring( "GameUI command" );
  21328. + cmd->function = function;
  21329. + cmd->flags = CMD_GAMEUIDLL;
  21330. +
  21331. + // insert it at the right alphanumeric position
  21332. + for( prev = NULL, cur = cmd_functions; cur && Q_strcmp( cur->name, cmd_name ) < 0; prev = cur, cur = cur->next );
  21333. +
  21334. + if( prev ) prev->next = cmd;
  21335. + else cmd_functions = cmd;
  21336. + cmd->next = cur;
  21337. +
  21338. + return 1;
  21339. }
  21340.  
  21341. /*
  21342. @@ -693,25 +828,143 @@ qboolean Cmd_Exists( const char *cmd_name )
  21343.  
  21344. /*
  21345. ============
  21346. +Cmd_If_f
  21347. +
  21348. +Compare and et condition bit if true
  21349. +============
  21350. +*/
  21351. +void Cmd_If_f( void )
  21352. +{
  21353. + // reset bit first
  21354. + cmd_condition &= ~BIT( cmd_condlevel );
  21355. +
  21356. + // usage
  21357. + if( cmd_argc == 1 )
  21358. + {
  21359. + Msg( "Usage: if <op1> [ <operator> <op2> ]\n");
  21360. + Msg( ":<action1>\n" );
  21361. + Msg( ":<action2>\n" );
  21362. + Msg( "else\n" );
  21363. + Msg( ":<action3>\n" );
  21364. + Msg( "operands are string or float values\n" );
  21365. + Msg( "and substituted cvars like '$cl_lw'\n" );
  21366. + Msg( "operator is '='', '==', '>', '<', '>=', '<=' or '!='\n" );
  21367. + return;
  21368. + }
  21369. +
  21370. + // one argument - check if nonzero
  21371. + if( cmd_argc == 2 )
  21372. + {
  21373. + if( Q_atof( cmd_argv[1] ))
  21374. + cmd_condition |= BIT( cmd_condlevel );
  21375. + }
  21376. + else if( cmd_argc == 4 )
  21377. + {
  21378. + // simple compare
  21379. + float f1 = Q_atof( cmd_argv[1] );
  21380. + float f2 = Q_atof( cmd_argv[3] );
  21381. +
  21382. + if( !cmd_argv[2][0] ) // this is wrong
  21383. + return;
  21384. +
  21385. + if(( cmd_argv[2][0] == '=' ) || ( cmd_argv[2][1] == '=' )) // =, ==, >=, <=
  21386. + {
  21387. + if( !Q_strcmp( cmd_argv[1], cmd_argv[3] ) || (( f1 || f2 ) && ( f1 == f2 )))
  21388. + cmd_condition |= BIT( cmd_condlevel );
  21389. + }
  21390. +
  21391. + if( cmd_argv[2][0] == '!' ) // !=
  21392. + {
  21393. + cmd_condition ^= BIT( cmd_condlevel );
  21394. + return;
  21395. + }
  21396. +
  21397. + if(( cmd_argv[2][0] == '>' ) && ( f1 > f2 )) // >, >=
  21398. + cmd_condition |= BIT( cmd_condlevel );
  21399. +
  21400. + if(( cmd_argv[2][0] == '<' ) && ( f1 < f2 )) // <, <=
  21401. + cmd_condition |= BIT( cmd_condlevel );
  21402. + }
  21403. +}
  21404. +
  21405. +/*
  21406. +============
  21407. +Cmd_Else_f
  21408. +
  21409. +Invert condition bit
  21410. +============
  21411. +*/
  21412. +void Cmd_Else_f( void )
  21413. +{
  21414. + cmd_condition ^= BIT( cmd_condlevel );
  21415. +}
  21416. +
  21417. +/*
  21418. +============
  21419. Cmd_ExecuteString
  21420.  
  21421. A complete command line has been parsed, so try to execute it
  21422. ============
  21423. */
  21424. -void Cmd_ExecuteString( char *text, cmd_source_t src )
  21425. +void Cmd_ExecuteString( char *text )
  21426. {
  21427. - cmd_t *cmd;
  21428. + cmd_t *cmd;
  21429. cmdalias_t *a;
  21430. + char command[MAX_CMD_LINE];
  21431. + char *pcmd = command;
  21432. + int len = 0;
  21433. +
  21434. + cmd_condlevel = 0;
  21435. +
  21436. + // cvar value substitution
  21437. + if( cmd_scripting && cmd_scripting->integer )
  21438. + {
  21439. + while( *text )
  21440. + {
  21441. + // check for escape
  21442. + if(( *text == '\\' || *text == '$' ) && (*( text + 1 ) == '$' ))
  21443. + {
  21444. + text ++;
  21445. + }
  21446. + else if( *text == '$' )
  21447. + {
  21448. + char token[MAX_CMD_LINE];
  21449. + char *ptoken = token;
  21450. +
  21451. + // check for correct cvar name
  21452. + text++;
  21453. + while(( *text >= '0' && *text <= '9' ) || ( *text >= 'A' && *text <= 'Z' ) || ( *text >= 'a' && *text <= 'z' ) || ( *text == '_' ))
  21454. + *ptoken++ = *text++;
  21455. + *ptoken = 0;
  21456. +
  21457. + len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len );
  21458. + pcmd = command + len;
  21459. +
  21460. + if( !*text ) break;
  21461. + }
  21462. +
  21463. + *pcmd++ = *text++;
  21464. + len++;
  21465. + }
  21466. +
  21467. + *pcmd = 0;
  21468. + text = command;
  21469. +
  21470. + while( *text == ':' )
  21471. + {
  21472. + if( !FBitSet( cmd_condition, BIT( cmd_condlevel )))
  21473. + return;
  21474. + cmd_condlevel++;
  21475. + text++;
  21476. + }
  21477. + }
  21478.  
  21479. - // set cmd source
  21480. - cmd_source = src;
  21481. -
  21482. // execute the command line
  21483. Cmd_TokenizeString( text );
  21484.  
  21485. if( !Cmd_Argc()) return; // no tokens
  21486.  
  21487. - // check alias
  21488. + // check aliases
  21489. for( a = cmd_alias; a; a = a->next )
  21490. {
  21491. if( !Q_stricmp( cmd_argv[0], a->name ))
  21492. @@ -735,13 +988,10 @@ void Cmd_ExecuteString( char *text, cmd_source_t src )
  21493. if( Cvar_Command( )) return;
  21494.  
  21495. // forward the command line to the server, so the entity DLL can parse it
  21496. - if( cmd_source == src_command && host.type == HOST_NORMAL )
  21497. + if( host.type == HOST_NORMAL )
  21498. {
  21499. if( cls.state >= ca_connected )
  21500. - {
  21501. Cmd_ForwardToServer();
  21502. - return;
  21503. - }
  21504. }
  21505. else if( text[0] != '@' && host.type == HOST_NORMAL )
  21506. {
  21507. @@ -808,11 +1058,16 @@ void Cmd_List_f( void )
  21508.  
  21509. for( cmd = cmd_functions; cmd; cmd = cmd->next )
  21510. {
  21511. + if( cmd->name[0] == '@' )
  21512. + continue; // never show system cmds
  21513. +
  21514. if( match && !Q_stricmpext( match, cmd->name ))
  21515. continue;
  21516. - Msg( "%10s %s\n", cmd->name, cmd->desc );
  21517. +
  21518. + Msg( " %-*s ^3%s^7\n", 32, cmd->name, cmd->desc );
  21519. i++;
  21520. }
  21521. +
  21522. Msg( "%i commands\n", i );
  21523. }
  21524.  
  21525. @@ -820,7 +1075,7 @@ void Cmd_List_f( void )
  21526. ============
  21527. Cmd_Unlink
  21528.  
  21529. -unlink all commands with flag CVAR_EXTDLL
  21530. +unlink all commands with specified flag
  21531. ============
  21532. */
  21533. void Cmd_Unlink( int group )
  21534. @@ -829,15 +1084,21 @@ void Cmd_Unlink( int group )
  21535. cmd_t **prev;
  21536. int count = 0;
  21537.  
  21538. - if( Cvar_VariableInteger( "host_gameloaded" ) && ( group & CMD_EXTDLL ))
  21539. + if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, CMD_SERVERDLL ))
  21540. + {
  21541. + MsgDev( D_INFO, "can't unlink commands while server is loaded\n" );
  21542. + return;
  21543. + }
  21544. +
  21545. + if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, CMD_CLIENTDLL ))
  21546. {
  21547. - Msg( "can't unlink cvars while game is loaded\n" );
  21548. + MsgDev( D_INFO, "can't unlink commands while client is loaded\n" );
  21549. return;
  21550. }
  21551.  
  21552. - if( Cvar_VariableInteger( "host_clientloaded" ) && ( group & CMD_CLIENTDLL ))
  21553. + if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, CMD_GAMEUIDLL ))
  21554. {
  21555. - Msg( "can't unlink cvars while client is loaded\n" );
  21556. + MsgDev( D_INFO, "can't unlink commands while GameUI is loaded\n" );
  21557. return;
  21558. }
  21559.  
  21560. @@ -847,7 +1108,8 @@ void Cmd_Unlink( int group )
  21561. cmd = *prev;
  21562. if( !cmd ) break;
  21563.  
  21564. - if( group && !( cmd->flags & group ))
  21565. + // do filter by specified group
  21566. + if( group && !FBitSet( cmd->flags, group ))
  21567. {
  21568. prev = &cmd->next;
  21569. continue;
  21570. @@ -855,11 +1117,8 @@ void Cmd_Unlink( int group )
  21571.  
  21572. *prev = cmd->next;
  21573.  
  21574. - if( cmd->name )
  21575. - Mem_Free( cmd->name );
  21576. -
  21577. - if( cmd->desc )
  21578. - Mem_Free( cmd->desc );
  21579. + if( cmd->name ) Mem_Free( cmd->name );
  21580. + if( cmd->desc ) Mem_Free( cmd->desc );
  21581.  
  21582. Mem_Free( cmd );
  21583. count++;
  21584. @@ -885,13 +1144,21 @@ Cmd_Init
  21585. void Cmd_Init( void )
  21586. {
  21587. Cbuf_Init();
  21588. +
  21589. cmd_functions = NULL;
  21590. + cmd_condition = 0;
  21591. + cmd_alias = NULL;
  21592. + cmd_args = NULL;
  21593. + cmd_argc = 0;
  21594.  
  21595. // register our commands
  21596. - Cmd_AddCommand ("echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" );
  21597. - Cmd_AddCommand ("wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
  21598. - Cmd_AddCommand ("cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
  21599. - Cmd_AddCommand ("stuffcmds", Cmd_StuffCmds_f, va( "execute commandline parameters (must be present in %s.rc script)", SI.ModuleName ));
  21600. - Cmd_AddCommand ("cmd", Cmd_ForwardToServer, "send a console commandline to the server" );
  21601. - Cmd_AddCommand ("alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
  21602. + Cmd_AddCommand( "echo", Cmd_Echo_f, "print a message to the console (useful in scripts)" );
  21603. + Cmd_AddCommand( "wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
  21604. + Cmd_AddCommand( "cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
  21605. + Cmd_AddCommand( "stuffcmds", Cmd_StuffCmds_f, va( "execute commandline parameters (must be present in %s.rc script)", SI.ModuleName ));
  21606. + Cmd_AddCommand( "cmd", Cmd_ForwardToServer, "send a console commandline to the server" );
  21607. + Cmd_AddCommand( "alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
  21608. + Cmd_AddCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
  21609. + Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" );
  21610. + Cmd_AddCommand( "else", Cmd_Else_f, "invert condition bit" );
  21611. }
  21612. \ No newline at end of file
  21613. diff --git b/engine/common/common.c a/engine/common/common.c
  21614. index a15e971..559aba6 100644
  21615. --- b/engine/common/common.c
  21616. +++ a/engine/common/common.c
  21617. @@ -22,6 +22,39 @@ GNU General Public License for more details.
  21618.  
  21619. /*
  21620. ==============
  21621. +COM_IsSingleChar
  21622. +
  21623. +interpert this character as single
  21624. +==============
  21625. +*/
  21626. +static int COM_IsSingleChar( char c )
  21627. +{
  21628. + if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
  21629. + return true;
  21630. +
  21631. + if( host.com_handlecolon && c == ':' )
  21632. + return true;
  21633. +
  21634. + return false;
  21635. +}
  21636. +
  21637. +/*
  21638. +==============
  21639. +COM_IsWhiteSpace
  21640. +
  21641. +interpret symbol as whitespace
  21642. +==============
  21643. +*/
  21644. +
  21645. +static int COM_IsWhiteSpace( char space )
  21646. +{
  21647. + if( space == ' ' || space == '\t' || space == '\r' || space == '\n' )
  21648. + return 1;
  21649. + return 0;
  21650. +}
  21651. +
  21652. +/*
  21653. +==============
  21654. COM_ParseFile
  21655.  
  21656. text parser
  21657. @@ -74,7 +107,7 @@ skipwhite:
  21658. }
  21659.  
  21660. // parse single characters
  21661. - if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
  21662. + if( COM_IsSingleChar( c ))
  21663. {
  21664. token[len] = c;
  21665. len++;
  21666. @@ -90,7 +123,7 @@ skipwhite:
  21667. len++;
  21668. c = ((byte)*data);
  21669.  
  21670. - if( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' )
  21671. + if( COM_IsSingleChar( c ))
  21672. break;
  21673. } while( c > 32 );
  21674.  
  21675. @@ -100,6 +133,56 @@ skipwhite:
  21676. }
  21677.  
  21678. /*
  21679. +================
  21680. +COM_ParseVector
  21681. +
  21682. +================
  21683. +*/
  21684. +qboolean COM_ParseVector( char **pfile, float *v, size_t size )
  21685. +{
  21686. + string token;
  21687. + qboolean bracket = false;
  21688. + char *saved;
  21689. + uint i;
  21690. +
  21691. + if( v == NULL || size == 0 )
  21692. + return false;
  21693. +
  21694. + memset( v, 0, sizeof( *v ) * size );
  21695. +
  21696. + if( size == 1 )
  21697. + {
  21698. + *pfile = COM_ParseFile( *pfile, token );
  21699. + v[0] = Q_atof( token );
  21700. + return true;
  21701. + }
  21702. +
  21703. + saved = *pfile;
  21704. +
  21705. + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
  21706. + return false;
  21707. +
  21708. + if( token[0] == '(' )
  21709. + bracket = true;
  21710. + else *pfile = saved; // restore token to right get it again
  21711. +
  21712. + for( i = 0; i < size; i++ )
  21713. + {
  21714. + *pfile = COM_ParseFile( *pfile, token );
  21715. + v[i] = Q_atof( token );
  21716. + }
  21717. +
  21718. + if( !bracket ) return true; // done
  21719. +
  21720. + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
  21721. + return false;
  21722. +
  21723. + if( token[0] == ')' )
  21724. + return true;
  21725. + return false;
  21726. +}
  21727. +
  21728. +/*
  21729. =============
  21730. COM_FileSize
  21731.  
  21732. @@ -164,6 +247,39 @@ int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBu
  21733. }
  21734.  
  21735. /*
  21736. +=============
  21737. +COM_TrimSpace
  21738. +
  21739. +trims all whitespace from the front
  21740. +and end of a string
  21741. +=============
  21742. +*/
  21743. +void COM_TrimSpace( const char *source, char *dest )
  21744. +{
  21745. + int start, end, length;
  21746. +
  21747. + start = 0;
  21748. + end = Q_strlen( source );
  21749. +
  21750. + while( source[start] && COM_IsWhiteSpace( source[start] ))
  21751. + start++;
  21752. + end--;
  21753. +
  21754. + while( end > 0 && COM_IsWhiteSpace( source[end] ))
  21755. + end--;
  21756. + end++;
  21757. +
  21758. + length = end - start;
  21759. +
  21760. + if( length > 0 )
  21761. + memcpy( dest, source + start, length );
  21762. + else length = 0;
  21763. +
  21764. + // terminate the dest string
  21765. + dest[length] = 0;
  21766. +}
  21767. +
  21768. +/*
  21769. ============
  21770. COM_FixSlashes
  21771.  
  21772. @@ -213,7 +329,6 @@ char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, i
  21773. i++;
  21774. }
  21775.  
  21776. -
  21777. // if we actually advanced the pointer, copy it over
  21778. if( i != *filePos )
  21779. {
  21780. @@ -266,7 +381,8 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
  21781.  
  21782. if( !filename || !*filename )
  21783. {
  21784. - if( pLength ) *pLength = 0;
  21785. + if( pLength )
  21786. + *pLength = 0;
  21787. return NULL;
  21788. }
  21789.  
  21790. @@ -279,8 +395,11 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
  21791. if( pfile )
  21792. {
  21793. file = malloc( iLength + 1 );
  21794. - memcpy( file, pfile, iLength );
  21795. - file[iLength] = '\0';
  21796. + if( file != NULL )
  21797. + {
  21798. + memcpy( file, pfile, iLength );
  21799. + file[iLength] = '\0';
  21800. + }
  21801. Mem_Free( pfile );
  21802. pfile = file;
  21803. }
  21804. @@ -296,34 +415,26 @@ COM_LoadFile
  21805. */
  21806. byte *COM_LoadFile( const char *filename, int usehunk, int *pLength )
  21807. {
  21808. - string name;
  21809. - byte *file, *pfile;
  21810. - int iLength;
  21811. + return COM_LoadFileForMe( filename, pLength );
  21812. +}
  21813.  
  21814. - ASSERT( usehunk == 5 );
  21815. +/*
  21816. +=============
  21817. +COM_LoadFile
  21818.  
  21819. +=============
  21820. +*/
  21821. +int COM_SaveFile( const char *filename, const void *data, long len )
  21822. +{
  21823. + // check for empty filename
  21824. if( !filename || !*filename )
  21825. - {
  21826. - if( pLength ) *pLength = 0;
  21827. - return NULL;
  21828. - }
  21829. -
  21830. - Q_strncpy( name, filename, sizeof( name ));
  21831. - COM_FixSlashes( name );
  21832. + return false;
  21833.  
  21834. - pfile = FS_LoadFile( name, &iLength, false );
  21835. - if( pLength ) *pLength = iLength;
  21836. -
  21837. - if( pfile )
  21838. - {
  21839. - file = malloc( iLength + 1 );
  21840. - memcpy( file, pfile, iLength );
  21841. - file[iLength] = '\0';
  21842. - Mem_Free( pfile );
  21843. - pfile = file;
  21844. - }
  21845. + // check for null data
  21846. + if( !data || len <= 0 )
  21847. + return false;
  21848.  
  21849. - return pfile;
  21850. + return FS_WriteFile( filename, data, len );
  21851. }
  21852.  
  21853. /*
  21854. @@ -339,6 +450,25 @@ void COM_FreeFile( void *buffer )
  21855.  
  21856. /*
  21857. =============
  21858. +COM_NormalizeAngles
  21859. +
  21860. +=============
  21861. +*/
  21862. +void COM_NormalizeAngles( vec3_t angles )
  21863. +{
  21864. + int i;
  21865. +
  21866. + for( i = 0; i < 3; i++ )
  21867. + {
  21868. + if( angles[i] > 180.0f )
  21869. + angles[i] -= 360.0f;
  21870. + else if( angles[i] < -180.0f )
  21871. + angles[i] += 360.0f;
  21872. + }
  21873. +}
  21874. +
  21875. +/*
  21876. +=============
  21877. pfnGetModelType
  21878.  
  21879. =============
  21880. @@ -376,42 +506,36 @@ pfnCvar_RegisterVariable
  21881.  
  21882. =============
  21883. */
  21884. -cvar_t *pfnCvar_RegisterVariable( const char *szName, const char *szValue, int flags )
  21885. +cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
  21886. {
  21887. + if( FBitSet( flags, FCVAR_GLCONFIG ))
  21888. + return (cvar_t *)Cvar_Get( szName, szValue, flags, va( "enable or disable %s", szName ));
  21889. return (cvar_t *)Cvar_Get( szName, szValue, flags|CVAR_CLIENTDLL, "client cvar" );
  21890. }
  21891.  
  21892. /*
  21893. =============
  21894. -pfnCVarGetPointer
  21895. +pfnCvar_RegisterVariable
  21896.  
  21897. -can return NULL
  21898. =============
  21899. */
  21900. -cvar_t *pfnCVarGetPointer( const char *szVarName )
  21901. +cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
  21902. {
  21903. - cvar_t *cvPtr;
  21904. -
  21905. - cvPtr = (cvar_t *)Cvar_FindVar( szVarName );
  21906. -
  21907. - return cvPtr;
  21908. + if( FBitSet( flags, FCVAR_GLCONFIG ))
  21909. + return (cvar_t *)Cvar_Get( szName, szValue, flags, va( "enable or disable %s", szName ));
  21910. + return (cvar_t *)Cvar_Get( szName, szValue, flags|CVAR_GAMEUIDLL, "GameUI cvar" );
  21911. }
  21912.  
  21913. /*
  21914. =============
  21915. -pfnAddClientCommand
  21916. +pfnCVarGetPointer
  21917.  
  21918. +can return NULL
  21919. =============
  21920. */
  21921. -int pfnAddClientCommand( const char *cmd_name, xcommand_t func )
  21922. +cvar_t *pfnCVarGetPointer( const char *szVarName )
  21923. {
  21924. - if( !cmd_name || !*cmd_name )
  21925. - return 0;
  21926. -
  21927. - // NOTE: if( func == NULL ) cmd will be forwarded to a server
  21928. - Cmd_AddClientCommand( cmd_name, func );
  21929. -
  21930. - return 1;
  21931. + return (cvar_t *)Cvar_FindVar( szVarName );
  21932. }
  21933.  
  21934. /*
  21935. @@ -429,7 +553,7 @@ void Con_Printf( char *szFmt, ... )
  21936. return;
  21937.  
  21938. va_start( args, szFmt );
  21939. - Q_vsnprintf( buffer, 16384, szFmt, args );
  21940. + Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
  21941. va_end( args );
  21942.  
  21943. Sys_Print( buffer );
  21944. @@ -450,7 +574,7 @@ void Con_DPrintf( char *szFmt, ... )
  21945. return;
  21946.  
  21947. va_start( args, szFmt );
  21948. - Q_vsnprintf( buffer, 16384, szFmt, args );
  21949. + Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
  21950. va_end( args );
  21951.  
  21952. Sys_Print( buffer );
  21953. diff --git b/engine/common/common.h a/engine/common/common.h
  21954. index 7fcf37f..6149c0b 100644
  21955. --- b/engine/common/common.h
  21956. +++ a/engine/common/common.h
  21957. @@ -36,9 +36,15 @@ extern "C" {
  21958. #define MAX_STRING 256 // generic string
  21959. #define MAX_INFO_STRING 256 // infostrings are transmitted across network
  21960. #define MAX_SYSPATH 1024 // system filepath
  21961. +#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Msg or MsgDev
  21962. #define MAX_MODS 512 // environment games that engine can keep visible
  21963. #define EXPORT __declspec( dllexport )
  21964. #define BIT( n ) (1<<( n ))
  21965. +#define GAMMA ( 2.2 ) // Valve Software gamma
  21966. +#define INVGAMMA ( 1.0 / 2.2 ) // back to 1.0
  21967. +#define SetBits( iBitVector, bits ) ((iBitVector) = (iBitVector) | (bits))
  21968. +#define ClearBits( iBitVector, bits ) ((iBitVector) = (iBitVector) & ~(bits))
  21969. +#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
  21970.  
  21971. #ifndef __cplusplus
  21972. #define NULL ((void *)0)
  21973. @@ -53,7 +59,6 @@ extern "C" {
  21974. typedef unsigned long dword;
  21975. typedef unsigned int uint;
  21976. typedef char string[MAX_STRING];
  21977. -typedef long fs_offset_t;
  21978. typedef struct file_s file_t; // normal file
  21979. typedef struct wfile_s wfile_t; // wad file
  21980. typedef struct stream_s stream_t; // sound stream for background music playing
  21981. @@ -70,7 +75,7 @@ enum
  21982. D_INFO = 1, // "-dev 1", shows various system messages
  21983. D_WARN, // "-dev 2", shows not critical system warnings
  21984. D_ERROR, // "-dev 3", shows critical warnings
  21985. - D_AICONSOLE, // "-dev 4", special case for game aiconsole
  21986. + D_REPORT, // "-dev 4", special case for game reports
  21987. D_NOTE // "-dev 5", show system notifications for engine developers
  21988. };
  21989.  
  21990. @@ -88,12 +93,19 @@ typedef enum
  21991. #define XASH_VERSION 0.98f // engine current version
  21992.  
  21993. // PERFORMANCE INFO
  21994. -#define MIN_FPS 15.0 // host minimum fps value for maxfps.
  21995. +#define MIN_FPS 20.0 // host minimum fps value for maxfps.
  21996. #define MAX_FPS 500.0 // upper limit for maxfps.
  21997.  
  21998. #define MAX_FRAMETIME 0.1
  21999. #define MIN_FRAMETIME 0.000001
  22000.  
  22001. +// HOST_FIXED_FRAMERATE stuff
  22002. +#define HOST_MINFPS 20.0
  22003. +#define HOST_MAXFPS 72.0
  22004. +#define GAME_FPS 20.0
  22005. +#define HOST_FPS 60.0 // client and the server clamped at 60.0 fps max. Render clamped at fps_max cvar
  22006. +#define HOST_FRAMETIME ( 1.0 / HOST_FPS )
  22007. +
  22008. #define MAX_CMD_TOKENS 80 // cmd tokens
  22009. #define MAX_ENTNUMBER 99999 // for server and client parsing
  22010. #define MAX_HEARTBEAT -99999 // connection time
  22011. @@ -133,6 +145,7 @@ extern convar_t *scr_width;
  22012. extern convar_t *scr_height;
  22013. extern convar_t *scr_loading;
  22014. extern convar_t *scr_download;
  22015. +extern convar_t *cmd_scripting;
  22016. extern convar_t *cl_allow_levelshots;
  22017. extern convar_t *mod_allow_materials;
  22018. extern convar_t *host_limitlocal;
  22019. @@ -214,7 +227,6 @@ typedef enum
  22020. HOST_ERR_FATAL, // sys error
  22021. HOST_SLEEP, // sleeped by different reason, e.g. minimize window
  22022. HOST_NOFOCUS, // same as HOST_FRAME, but disable mouse
  22023. - HOST_RESTART, // during the changes video mode
  22024. HOST_CRASHED // an exception handler called
  22025. } host_state;
  22026.  
  22027. @@ -267,6 +279,11 @@ typedef struct host_redirect_s
  22028. void (*flush)( netadr_t adr, rdtype_t target, char *buffer );
  22029. } host_redirect_t;
  22030.  
  22031. +// local flags (never sending acorss the net)
  22032. +#define SND_LOCALSOUND (1<<9) // not paused, not looped, for internal use
  22033. +#define SND_STOP_LOOPING (1<<10) // stop all looping sounds on the entity.
  22034. +#define SND_FILTER_CLIENT (1<<11) // don't send sound from local player if prediction was enabled
  22035. +
  22036. typedef struct
  22037. {
  22038. char name[64];
  22039. @@ -315,6 +332,7 @@ typedef struct host_parm_s
  22040. qboolean key_overstrike; // key overstrike mode
  22041. qboolean stuffcmdsrun; // execute stuff commands
  22042. qboolean con_showalways; // show console always (developer and dedicated)
  22043. + qboolean com_handlecolon; // allow COM_ParseFile to handle colon as single char
  22044. qboolean change_game; // initialize when game is changed
  22045. qboolean mouse_visible; // vgui override cursor control
  22046. qboolean input_enabled; // vgui override mouse & keyboard input
  22047. @@ -338,9 +356,6 @@ typedef struct host_parm_s
  22048.  
  22049. struct decallist_s *decalList; // used for keep decals, when renderer is restarted or changed
  22050. int numdecals;
  22051. -
  22052. - soundlist_t *soundList; // used for keep ambient sounds, when renderer or sound is restarted
  22053. - int numsounds;
  22054. } host_parm_t;
  22055.  
  22056. extern host_parm_t host;
  22057. @@ -361,43 +376,45 @@ void FS_LoadGameInfo( const char *rootfolder );
  22058. void FS_FileBase( const char *in, char *out );
  22059. const char *FS_FileExtension( const char *in );
  22060. void FS_DefaultExtension( char *path, const char *extension );
  22061. -void FS_ExtractFilePath( const char* const path, char* dest );
  22062. +void FS_ExtractFilePath( const char *path, char *dest );
  22063. const char *FS_GetDiskPath( const char *name, qboolean gamedironly );
  22064. const char *FS_FileWithoutPath( const char *in );
  22065. -wfile_t *W_Open( const char *filename, const char *mode );
  22066. +wfile_t *W_Open( const char *filename, const char *mode, int *errorcode );
  22067. byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type );
  22068. void W_Close( wfile_t *wad );
  22069. -file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
  22070. -byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
  22071. -qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
  22072. +file_t *FS_OpenFile( const char *path, long *filesizeptr, qboolean gamedironly );
  22073. +byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
  22074. +qboolean FS_WriteFile( const char *filename, const void *data, long len );
  22075. +qboolean COM_ParseVector( char **pfile, float *v, size_t size );
  22076. +void COM_NormalizeAngles( vec3_t angles );
  22077. int COM_FileSize( const char *filename );
  22078. void COM_FixSlashes( char *pname );
  22079. void COM_FreeFile( void *buffer );
  22080. int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
  22081. search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
  22082. file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
  22083. -fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
  22084. -fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
  22085. +long FS_Write( file_t *file, const void *data, size_t datasize );
  22086. +long FS_Read( file_t *file, void *buffer, size_t buffersize );
  22087. int FS_VPrintf( file_t *file, const char *format, va_list ap );
  22088. -int FS_Seek( file_t *file, fs_offset_t offset, int whence );
  22089. +int FS_Seek( file_t *file, long offset, int whence );
  22090. int FS_Gets( file_t *file, byte *string, size_t bufsize );
  22091. int FS_Printf( file_t *file, const char *format, ... );
  22092. -fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly );
  22093. -fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly );
  22094. +long FS_FileSize( const char *filename, qboolean gamedironly );
  22095. +long FS_FileTime( const char *filename, qboolean gamedironly );
  22096. int FS_Print( file_t *file, const char *msg );
  22097. qboolean FS_Rename( const char *oldname, const char *newname );
  22098. qboolean FS_FileExists( const char *filename, qboolean gamedironly );
  22099. -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
  22100. +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
  22101. qboolean FS_Delete( const char *path );
  22102. int FS_UnGetc( file_t *file, byte c );
  22103. void FS_StripExtension( char *path );
  22104. -fs_offset_t FS_Tell( file_t *file );
  22105. +long FS_Tell( file_t *file );
  22106. qboolean FS_Eof( file_t *file );
  22107. void FS_Purge( file_t *file );
  22108. int FS_Close( file_t *file );
  22109. int FS_Getc( file_t *file );
  22110. qboolean FS_Eof( file_t *file );
  22111. -fs_offset_t FS_FileLength( file_t *f );
  22112. +long FS_FileLength( file_t *f );
  22113.  
  22114. //
  22115. // network.c
  22116. @@ -424,6 +441,7 @@ typically expanded to rgba buffer
  22117. NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == PF_RGB_888
  22118. ========================================================================
  22119. */
  22120. +#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24)
  22121. #define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5)
  22122.  
  22123. typedef enum
  22124. @@ -435,9 +453,9 @@ typedef enum
  22125. PF_BGRA_32, // big endian RGBA (MacOS)
  22126. PF_RGB_24, // uncompressed dds or another 24-bit image
  22127. PF_BGR_24, // big-endian RGB (MacOS)
  22128. - PF_DXT1, // nvidia DXT1 format
  22129. - PF_DXT3, // nvidia DXT3 format
  22130. - PF_DXT5, // nvidia DXT5 format
  22131. + PF_DXT1, // s3tc DXT1 format
  22132. + PF_DXT3, // s3tc DXT3 format
  22133. + PF_DXT5, // s3tc DXT5 format
  22134. PF_TOTALCOUNT, // must be last
  22135. } pixformat_t;
  22136.  
  22137. @@ -483,6 +501,7 @@ typedef enum
  22138. IMAGE_SKYBOX = BIT(5), // only used by FS_SaveImage - for write right suffixes
  22139. IMAGE_QUAKESKY = BIT(6), // it's a quake sky double layered clouds (so keep it as 8 bit)
  22140. IMAGE_DDS_FORMAT = BIT(7), // a hint for GL loader
  22141. + IMAGE_MULTILAYER = BIT(8), // to differentiate from 3D texture
  22142.  
  22143. // Image_Process manipulation flags
  22144. IMAGE_FLIP_X = BIT(16), // flip the image by width
  22145. @@ -679,15 +698,17 @@ qboolean SV_Active( void );
  22146.  
  22147. ==============================================================
  22148. */
  22149. -cvar_t *pfnCvar_RegisterVariable( const char *szName, const char *szValue, int flags );
  22150. +cvar_t *pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags );
  22151. +cvar_t *pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags );
  22152. char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
  22153. +int COM_SaveFile( const char *filename, const void *data, long len );
  22154. byte* COM_LoadFileForMe( const char *filename, int *pLength );
  22155. cvar_t *pfnCVarGetPointer( const char *szVarName );
  22156. int pfnDrawConsoleString( int x, int y, char *string );
  22157. void pfnDrawSetTextColor( float r, float g, float b );
  22158. void pfnDrawConsoleStringLen( const char *pText, int *length, int *height );
  22159. -int pfnAddClientCommand( const char *cmd_name, xcommand_t func );
  22160. void *Cache_Check( byte *mempool, struct cache_user_s *c );
  22161. +void COM_TrimSpace( const char *source, char *dest );
  22162. edict_t* pfnPEntityOfEntIndex( int iEntIndex );
  22163. void pfnGetModelBounds( model_t *mod, float *mins, float *maxs );
  22164. void pfnGetGameDir( char *szGetGameDir );
  22165. @@ -773,7 +794,7 @@ long AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
  22166. byte *AVI_GetVideoFrame( movie_state_t *Avi, long frame );
  22167. qboolean AVI_GetVideoInfo( movie_state_t *Avi, long *xres, long *yres, float *duration );
  22168. qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info );
  22169. -fs_offset_t AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length );
  22170. +long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long length );
  22171. void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, qboolean ignore_hwgamma, int quiet );
  22172. movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio, qboolean ignore_hwgamma );
  22173. movie_state_t *AVI_LoadVideoNoSound( const char *filename, qboolean ignore_hwgamma );
  22174. @@ -803,12 +824,13 @@ void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appNam
  22175. int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBufferSize );
  22176. struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe );
  22177. void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
  22178. -void SV_StartMusic( const char *curtrack, const char *looptrack, fs_offset_t position );
  22179. +void SV_StartMusic( const char *curtrack, const char *looptrack, long position );
  22180. void SV_CreateDecal( struct sizebuf_s *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
  22181. void SV_CreateStudioDecal( struct sizebuf_s *msg, const float *origin, const float *start, int decalIndex, int entityIndex, int modelIndex,
  22182. int flags, struct modelstate_s *state );
  22183. struct sizebuf_s *SV_GetReliableDatagram( void );
  22184. qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
  22185. +void SV_BroadcastPrintf( struct sv_client_s *ignore, int level, char *fmt, ... );
  22186. int R_CreateDecalList( struct decallist_s *pList, qboolean changelevel );
  22187. void R_ClearAllDecals( void );
  22188. void R_ClearStaticEntities( void );
  22189. diff --git b/engine/common/con_utils.c a/engine/common/con_utils.c
  22190. index 115ebae..2ce6ef3 100644
  22191. --- b/engine/common/con_utils.c
  22192. +++ a/engine/common/con_utils.c
  22193. @@ -67,7 +67,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
  22194. int ver = -1, mapver = -1, lumpofs = 0, lumplen = 0;
  22195. const char *ext = FS_FileExtension( t->filenames[i] );
  22196. char *ents = NULL, *pfile;
  22197. - qboolean paranoia = false;
  22198. + int version = 0;
  22199. qboolean gearbox = false;
  22200.  
  22201. if( Q_stricmp( ext, "bsp" )) continue;
  22202. @@ -108,8 +108,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
  22203. hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader31_t ));
  22204. else hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t ));
  22205.  
  22206. - if( hdrext->id == IDEXTRAHEADER && hdrext->version == EXTRA_VERSION )
  22207. - paranoia = true;
  22208. + if( hdrext->id == IDEXTRAHEADER ) version = hdrext->version;
  22209.  
  22210. Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename ));
  22211. FS_StripExtension( entfilename );
  22212. @@ -163,11 +162,17 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
  22213. break;
  22214. case HLBSP_VERSION:
  22215. if( gearbox ) Q_strncpy( buf, "Blue-Shift", sizeof( buf ));
  22216. - else if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf ));
  22217. + else if( version == 1 ) Q_strncpy( buf, "XashXT old format", sizeof( buf ));
  22218. + else if( version == 2 ) Q_strncpy( buf, "Paranoia 2: Savior", sizeof( buf ));
  22219. + else if( version == 3 ) Q_strncpy( buf, "not supported", sizeof( buf ));
  22220. + else if( version == 4 ) Q_strncpy( buf, "Half-Life extended", sizeof( buf ));
  22221. else Q_strncpy( buf, "Half-Life", sizeof( buf ));
  22222. break;
  22223. case XTBSP_VERSION:
  22224. - if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf ));
  22225. + if( version == 1 ) Q_strncpy( buf, "XashXT old format", sizeof( buf ));
  22226. + else if( version == 2 ) Q_strncpy( buf, "Paranoia 2: Savior", sizeof( buf ));
  22227. + else if( version == 3 ) Q_strncpy( buf, "not supported", sizeof( buf ));
  22228. + else if( version == 4 ) Q_strncpy( buf, "Xash3D extended", sizeof( buf ));
  22229. else Q_strncpy( buf, "Xash3D", sizeof( buf ));
  22230. break;
  22231. default: Q_strncpy( buf, "??", sizeof( buf )); break;
  22232. @@ -304,8 +309,8 @@ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length )
  22233. {
  22234. const char *ext = FS_FileExtension( t->filenames[i] );
  22235.  
  22236. - if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" ));
  22237. - else continue;
  22238. + if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
  22239. + continue;
  22240.  
  22241. FS_FileBase( t->filenames[i], matchbuf );
  22242. Msg( "%16s\n", matchbuf );
  22243. @@ -563,46 +568,40 @@ qboolean Cmd_GetCustomList( const char *s, char *completedname, int length )
  22244.  
  22245. /*
  22246. =====================================
  22247. -Cmd_GetTexturemodes
  22248. +Cmd_GetGameList
  22249.  
  22250. -Prints or complete sound filename
  22251. +Prints or complete gamedir name
  22252. =====================================
  22253. */
  22254. -qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
  22255. +qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
  22256. {
  22257. - int i, numtexturemodes;
  22258. - string texturemodes[6]; // keep an actual ( sizeof( gl_texturemode) / sizeof( gl_texturemode[0] ))
  22259. + int i, numgamedirs;
  22260. + string gamedirs[MAX_MODS];
  22261. string matchbuf;
  22262.  
  22263. - const char *gl_texturemode[] =
  22264. - {
  22265. - "GL_LINEAR",
  22266. - "GL_LINEAR_MIPMAP_LINEAR",
  22267. - "GL_LINEAR_MIPMAP_NEAREST",
  22268. - "GL_NEAREST",
  22269. - "GL_NEAREST_MIPMAP_LINEAR",
  22270. - "GL_NEAREST_MIPMAP_NEAREST",
  22271. - };
  22272. + // stand-alone games doesn't have cmd "game"
  22273. + if( !Cmd_Exists( "game" ))
  22274. + return false;
  22275.  
  22276. // compare gamelist with current keyword
  22277. - for( i = 0, numtexturemodes = 0; i < 6; i++ )
  22278. + for( i = 0, numgamedirs = 0; i < SI.numgames; i++ )
  22279. {
  22280. - if(( *s == '*' ) || !Q_strnicmp( gl_texturemode[i], s, Q_strlen( s )))
  22281. - Q_strcpy( texturemodes[numtexturemodes++], gl_texturemode[i] );
  22282. + if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, Q_strlen( s )))
  22283. + Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder );
  22284. }
  22285.  
  22286. - if( !numtexturemodes ) return false;
  22287. - Q_strncpy( matchbuf, gl_texturemode[0], MAX_STRING );
  22288. + if( !numgamedirs ) return false;
  22289. + Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
  22290. if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
  22291. - if( numtexturemodes == 1 ) return true;
  22292. + if( numgamedirs == 1 ) return true;
  22293.  
  22294. - for( i = 0; i < numtexturemodes; i++ )
  22295. + for( i = 0; i < numgamedirs; i++ )
  22296. {
  22297. - Q_strncpy( matchbuf, texturemodes[i], MAX_STRING );
  22298. + Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
  22299. Msg( "%16s\n", matchbuf );
  22300. }
  22301.  
  22302. - Msg( "\n^3 %i filters found.\n", numtexturemodes );
  22303. + Msg( "\n^3 %i games found.\n", numgamedirs );
  22304.  
  22305. // cut shortestMatch to the amount common with s
  22306. if( completedname && length )
  22307. @@ -618,40 +617,48 @@ qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
  22308.  
  22309. /*
  22310. =====================================
  22311. -Cmd_GetGameList
  22312. +Cmd_GetCDList
  22313.  
  22314. -Prints or complete gamedir name
  22315. +Prints or complete CD command name
  22316. =====================================
  22317. */
  22318. -qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
  22319. +qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
  22320. {
  22321. - int i, numgamedirs;
  22322. - string gamedirs[MAX_MODS];
  22323. + int i, numcdcommands;
  22324. + string cdcommands[8];
  22325. string matchbuf;
  22326.  
  22327. - // stand-alone games doesn't have cmd "game"
  22328. - if( !Cmd_Exists( "game" ))
  22329. - return false;
  22330. + const char *cd_command[] =
  22331. + {
  22332. + "info",
  22333. + "loop",
  22334. + "off",
  22335. + "on",
  22336. + "pause",
  22337. + "play",
  22338. + "resume",
  22339. + "stop",
  22340. + };
  22341.  
  22342. - // compare gamelist with current keyword
  22343. - for( i = 0, numgamedirs = 0; i < SI.numgames; i++ )
  22344. + // compare CD command list with current keyword
  22345. + for( i = 0, numcdcommands = 0; i < 8; i++ )
  22346. {
  22347. - if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, Q_strlen( s )))
  22348. - Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder );
  22349. + if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, Q_strlen( s )))
  22350. + Q_strcpy( cdcommands[numcdcommands++], cd_command[i] );
  22351. }
  22352.  
  22353. - if( !numgamedirs ) return false;
  22354. - Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
  22355. + if( !numcdcommands ) return false;
  22356. + Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
  22357. if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
  22358. - if( numgamedirs == 1 ) return true;
  22359. + if( numcdcommands == 1 ) return true;
  22360.  
  22361. - for( i = 0; i < numgamedirs; i++ )
  22362. + for( i = 0; i < numcdcommands; i++ )
  22363. {
  22364. - Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
  22365. + Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
  22366. Msg( "%16s\n", matchbuf );
  22367. }
  22368.  
  22369. - Msg( "\n^3 %i games found.\n", numgamedirs );
  22370. + Msg( "\n^3 %i commands found.\n", numcdcommands );
  22371.  
  22372. // cut shortestMatch to the amount common with s
  22373. if( completedname && length )
  22374. @@ -815,7 +822,6 @@ qboolean Cmd_CheckMapsList( qboolean fRefresh )
  22375.  
  22376. autocomplete_list_t cmd_list[] =
  22377. {
  22378. -{ "gl_texturemode", Cmd_GetTexturemodes },
  22379. { "map_background", Cmd_GetMapList },
  22380. { "changelevel", Cmd_GetMapList },
  22381. { "playdemo", Cmd_GetDemoList, },
  22382. @@ -832,6 +838,7 @@ autocomplete_list_t cmd_list[] =
  22383. { "load", Cmd_GetSavesList },
  22384. { "play", Cmd_GetSoundList },
  22385. { "map", Cmd_GetMapList },
  22386. +{ "cd", Cmd_GetCDList },
  22387. { NULL }, // termiantor
  22388. };
  22389.  
  22390. diff --git b/engine/common/console.c a/engine/common/console.c
  22391. index c4fa2e6..d7e1e9a 100644
  22392. --- b/engine/common/console.c
  22393. +++ a/engine/common/console.c
  22394. @@ -25,26 +25,31 @@ convar_t *con_notifytime;
  22395. convar_t *scr_conspeed;
  22396. convar_t *con_fontsize;
  22397.  
  22398. -#define CON_TIMES 5 // need for 4 lines
  22399. +#define CON_TIMES 4 // notify lines
  22400. #define COLOR_DEFAULT '7'
  22401. #define CON_HISTORY 64
  22402. #define MAX_DBG_NOTIFY 128
  22403. #define CON_MAXCMDS 4096 // auto-complete intermediate list
  22404. #define CON_NUMFONTS 3 // maxfonts
  22405.  
  22406. -#define CON_TEXTSIZE 131072 // 128 kb buffer
  22407. +#define CON_LINES( i ) (con.lines[(con.lines_first + (i)) % con.maxlines])
  22408. +#define CON_LINES_COUNT con.lines_count
  22409. +#define CON_LINES_LAST() CON_LINES( CON_LINES_COUNT - 1 )
  22410. +
  22411. +#define CON_TEXTSIZE 1048576 // max scrollback buffer characters in console (1 Mb)
  22412. +#define CON_MAXLINES 16384 // max scrollback buffer lines in console
  22413.  
  22414. // console color typeing
  22415. rgba_t g_color_table[8] =
  22416. {
  22417. -{ 0, 0, 0, 255}, // black
  22418. -{255, 0, 0, 255}, // red
  22419. -{ 0, 255, 0, 255}, // green
  22420. -{255, 255, 0, 255}, // yellow
  22421. -{ 0, 0, 255, 255}, // blue
  22422. -{ 0, 255, 255, 255}, // cyan
  22423. -{255, 0, 255, 255}, // magenta
  22424. -{240, 180, 24, 255}, // default color (can be changed by user)
  22425. +{ 0, 0, 0, 255 }, // black
  22426. +{ 255, 0, 0, 255 }, // red
  22427. +{ 0, 255, 0, 255 }, // green
  22428. +{ 255, 255, 0, 255 }, // yellow
  22429. +{ 0, 0, 255, 255 }, // blue
  22430. +{ 0, 255, 255, 255 }, // cyan
  22431. +{ 255, 0, 255, 255 }, // magenta
  22432. +{ 240, 180, 24, 255 }, // default color (can be changed by user)
  22433. };
  22434.  
  22435. typedef struct
  22436. @@ -63,29 +68,38 @@ typedef struct
  22437. int key_dest;
  22438. } notify_t;
  22439.  
  22440. +typedef struct con_lineinfo_s
  22441. +{
  22442. + char *start;
  22443. + size_t length;
  22444. + double addtime; // notify stuff
  22445. +} con_lineinfo_t;
  22446. +
  22447. typedef struct
  22448. {
  22449. qboolean initialized;
  22450.  
  22451. - short text[CON_TEXTSIZE];
  22452. - int current; // line where next message will be printed
  22453. - int display; // bottom of console displays this line
  22454. - int x; // offset in current line for next print
  22455. + // conbuffer
  22456. + char *buffer; // common buffer for all console lines
  22457. + int bufsize; // CON_TEXSIZE
  22458. + con_lineinfo_t *lines; // console lines
  22459. + int maxlines; // CON_MAXLINES
  22460.  
  22461. - int linewidth; // characters across screen
  22462. - int totallines; // total lines in console scrollback
  22463. + int lines_first; // cyclic buffer
  22464. + int lines_count;
  22465.  
  22466. - float displayFrac; // aproaches finalFrac at scr_conspeed
  22467. - float finalFrac; // 0.0 to 1.0 lines of console to display
  22468. + // console scroll
  22469. + int backscroll; // lines up from bottom to display
  22470. + int linewidth; // characters across screen
  22471.  
  22472. + // console animation
  22473. + int showlines; // how many lines we should display
  22474. int vislines; // in scanlines
  22475. - double times[CON_TIMES]; // host.realtime the line was generated for transparent notify lines
  22476. - rgba_t color;
  22477.  
  22478. // console images
  22479. int background; // console background
  22480.  
  22481. - // conchars
  22482. + // console fonts
  22483. cl_font_t chars[CON_NUMFONTS];// fonts.wad/font1.fnt
  22484. cl_font_t *curFont, *lastUsedFont;
  22485.  
  22486. @@ -108,6 +122,7 @@ typedef struct
  22487. string shortestMatch;
  22488. field_t *completionField; // con.input or dedicated server fake field-line
  22489. char *completionString;
  22490. + char *completionBuffer;
  22491. char *cmds[CON_MAXCMDS];
  22492. int matchCount;
  22493. } console_t;
  22494. @@ -123,11 +138,8 @@ Con_Clear_f
  22495. */
  22496. void Con_Clear_f( void )
  22497. {
  22498. - int i;
  22499. -
  22500. - for( i = 0; i < CON_TEXTSIZE; i++ )
  22501. - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
  22502. - con.display = con.current; // go to end
  22503. + con.lines_count = 0;
  22504. + con.backscroll = 0; // go to end
  22505. }
  22506.  
  22507. /*
  22508. @@ -168,8 +180,8 @@ void Con_ClearNotify( void )
  22509. {
  22510. int i;
  22511.  
  22512. - for( i = 0; i < CON_TIMES; i++ )
  22513. - con.times[i] = 0;
  22514. + for( i = 0; i < CON_LINES_COUNT; i++ )
  22515. + CON_LINES( i ).addtime = 0.0;
  22516. }
  22517.  
  22518. /*
  22519. @@ -272,9 +284,8 @@ Con_ToggleConsole_f
  22520. */
  22521. void Con_ToggleConsole_f( void )
  22522. {
  22523. - if( !host.developer ) return; // disabled
  22524. -
  22525. - if( UI_CreditsActive( )) return; // disabled by final credits
  22526. + if( !host.developer || UI_CreditsActive( ))
  22527. + return; // disabled
  22528.  
  22529. // show console only in game or by special call from menu
  22530. if( cls.state != ca_active || cls.key_dest == key_menu )
  22531. @@ -298,69 +309,157 @@ void Con_ToggleConsole_f( void )
  22532.  
  22533. /*
  22534. ================
  22535. -Con_CheckResize
  22536. +Con_FixTimes
  22537.  
  22538. -If the line width has changed, reformat the buffer.
  22539. +Notifies the console code about the current time
  22540. +(and shifts back times of other entries when the time
  22541. +went backwards)
  22542. ================
  22543. */
  22544. -void Con_CheckResize( void )
  22545. +void Con_FixTimes( void )
  22546. {
  22547. - int i, j, width, numlines, numchars;
  22548. - int oldwidth, oldtotallines;
  22549. - short tbuf[CON_TEXTSIZE];
  22550. - int charWidth = 8;
  22551. + double diff;
  22552. + int i;
  22553.  
  22554. - if( con.curFont && con.curFont->hFontTexture )
  22555. - charWidth = con.curFont->charWidths['M'] - 1;
  22556. + if( con.lines_count <= 0 ) return;
  22557.  
  22558. - width = ( scr_width->integer / charWidth );
  22559. + diff = cl.time - CON_LINES_LAST().addtime;
  22560. + if( diff >= 0.0 ) return; // nothing to fix
  22561.  
  22562. - if( width == con.linewidth )
  22563. + for( i = 0; i < con.lines_count; i++ )
  22564. + CON_LINES( i ).addtime += diff;
  22565. +}
  22566. +
  22567. +/*
  22568. +================
  22569. +Con_DeleteLine
  22570. +
  22571. +Deletes the first line from the console history.
  22572. +================
  22573. +*/
  22574. +void Con_DeleteLine( void )
  22575. +{
  22576. + if( con.lines_count == 0 )
  22577. return;
  22578. + con.lines_count--;
  22579. + con.lines_first = (con.lines_first + 1) % con.maxlines;
  22580. +}
  22581.  
  22582. - if( !glw_state.initialized )
  22583. - {
  22584. - // video hasn't been initialized yet
  22585. - con.linewidth = width;
  22586. - con.totallines = CON_TEXTSIZE / con.linewidth;
  22587. +/*
  22588. +================
  22589. +Con_DeleteLastLine
  22590. +
  22591. +Deletes the last line from the console history.
  22592. +================
  22593. +*/
  22594. +void Con_DeleteLastLine( void )
  22595. +{
  22596. + if( con.lines_count == 0 )
  22597. + return;
  22598. + con.lines_count--;
  22599. +}
  22600.  
  22601. - for( i = 0; i < CON_TEXTSIZE; i++ )
  22602. - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
  22603. +/*
  22604. +================
  22605. +Con_BytesLeft
  22606. +
  22607. +Checks if there is space for a line of the given length, and if yes, returns a
  22608. +pointer to the start of such a space, and NULL otherwise.
  22609. +================
  22610. +*/
  22611. +static char *Con_BytesLeft( int length )
  22612. +{
  22613. + if( length > con.bufsize )
  22614. + return NULL;
  22615. +
  22616. + if( con.lines_count == 0 )
  22617. + {
  22618. + return con.buffer;
  22619. }
  22620. else
  22621. {
  22622. - oldwidth = con.linewidth;
  22623. - con.linewidth = width;
  22624. - oldtotallines = con.totallines;
  22625. - con.totallines = CON_TEXTSIZE / con.linewidth;
  22626. - numlines = oldtotallines;
  22627. + char *firstline_start = con.lines[con.lines_first].start;
  22628. + char *lastline_onepastend = CON_LINES_LAST().start + CON_LINES_LAST().length;
  22629.  
  22630. - if( con.totallines < numlines )
  22631. - numlines = con.totallines;
  22632. + // the buffer is cyclic, so we first have two cases...
  22633. + if( firstline_start < lastline_onepastend ) // buffer is contiguous
  22634. + {
  22635. + // put at end?
  22636. + if( length <= con.buffer + con.bufsize - lastline_onepastend )
  22637. + return lastline_onepastend;
  22638. + // put at beginning?
  22639. + else if( length <= firstline_start - con.buffer )
  22640. + return con.buffer;
  22641. +
  22642. + return NULL;
  22643. + }
  22644. + else
  22645. + {
  22646. + // buffer has a contiguous hole
  22647. + if( length <= firstline_start - lastline_onepastend )
  22648. + return lastline_onepastend;
  22649.  
  22650. - numchars = oldwidth;
  22651. -
  22652. - if( con.linewidth < numchars )
  22653. - numchars = con.linewidth;
  22654. + return NULL;
  22655. + }
  22656. + }
  22657. +}
  22658.  
  22659. - memcpy( tbuf, con.text, CON_TEXTSIZE * sizeof( short ));
  22660. +/*
  22661. +================
  22662. +Con_AddLine
  22663.  
  22664. - for( i = 0; i < CON_TEXTSIZE; i++ )
  22665. - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
  22666. +Appends a given string as a new line to the console.
  22667. +================
  22668. +*/
  22669. +void Con_AddLine( const char *line, int length )
  22670. +{
  22671. + byte *putpos;
  22672. + con_lineinfo_t *p;
  22673.  
  22674. - for( i = 0; i < numlines; i++ )
  22675. - {
  22676. - for( j = 0; j < numchars; j++ )
  22677. - {
  22678. - con.text[(con.totallines - 1 - i) * con.linewidth + j] =
  22679. - tbuf[((con.current - i + oldtotallines) % oldtotallines) * oldwidth + j + con.x];
  22680. - }
  22681. - }
  22682. - Con_ClearNotify ();
  22683. - }
  22684. + if( !con.initialized ) return;
  22685. +
  22686. + Con_FixTimes();
  22687. + length++; // reserve space for term
  22688. +
  22689. + ASSERT( length < CON_TEXTSIZE );
  22690. +
  22691. + while( !( putpos = Con_BytesLeft( length )) || con.lines_count >= con.maxlines )
  22692. + Con_DeleteLine();
  22693.  
  22694. - con.current = con.totallines - 1;
  22695. - con.display = con.current;
  22696. + memcpy( putpos, line, length );
  22697. + putpos[length - 1] = '\0';
  22698. + con.lines_count++;
  22699. +
  22700. + p = &CON_LINES_LAST();
  22701. + p->start = putpos;
  22702. + p->length = length;
  22703. + p->addtime = cl.time;
  22704. +}
  22705. +
  22706. +/*
  22707. +================
  22708. +Con_CheckResize
  22709. +
  22710. +If the line width has changed, reformat the buffer.
  22711. +================
  22712. +*/
  22713. +void Con_CheckResize( void )
  22714. +{
  22715. + int charWidth = 8;
  22716. + int i, width;
  22717. +
  22718. + if( con.curFont && con.curFont->hFontTexture )
  22719. + charWidth = con.curFont->charWidths['M'] - 1;
  22720. +
  22721. + width = ( scr_width->integer / charWidth ) - 2;
  22722. + if( !glw_state.initialized ) width = 78;
  22723. +
  22724. + if( width == con.linewidth )
  22725. + return;
  22726. +
  22727. + Con_ClearNotify();
  22728. + con.linewidth = width;
  22729. + con.backscroll = 0;
  22730.  
  22731. con.input.widthInChars = con.linewidth;
  22732.  
  22733. @@ -375,10 +474,7 @@ Con_PageUp
  22734. */
  22735. void Con_PageUp( int lines )
  22736. {
  22737. - con.display -= abs( lines );
  22738. -
  22739. - if( con.current - con.display >= con.totallines )
  22740. - con.display = con.current - con.totallines + 1;
  22741. + con.backscroll += abs( lines );
  22742. }
  22743.  
  22744. /*
  22745. @@ -388,10 +484,7 @@ Con_PageDown
  22746. */
  22747. void Con_PageDown( int lines )
  22748. {
  22749. - con.display += abs( lines );
  22750. -
  22751. - if( con.display > con.current )
  22752. - con.display = con.current;
  22753. + con.backscroll -= abs( lines );
  22754. }
  22755.  
  22756. /*
  22757. @@ -401,10 +494,7 @@ Con_Top
  22758. */
  22759. void Con_Top( void )
  22760. {
  22761. - con.display = con.totallines;
  22762. -
  22763. - if( con.current - con.display >= con.totallines )
  22764. - con.display = con.current - con.totallines + 1;
  22765. + con.backscroll = CON_MAXLINES;
  22766. }
  22767.  
  22768. /*
  22769. @@ -414,7 +504,7 @@ Con_Bottom
  22770. */
  22771. void Con_Bottom( void )
  22772. {
  22773. - con.display = con.current;
  22774. + con.backscroll = 0;
  22775. }
  22776.  
  22777. /*
  22778. @@ -424,7 +514,7 @@ Con_Visible
  22779. */
  22780. qboolean Con_Visible( void )
  22781. {
  22782. - return (con.displayFrac != 0.0f);
  22783. + return (con.vislines > 0);
  22784. }
  22785.  
  22786. /*
  22787. @@ -436,8 +526,6 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
  22788. {
  22789. int fontWidth;
  22790.  
  22791. - ASSERT( font != NULL );
  22792. -
  22793. if( font->valid ) return; // already loaded
  22794.  
  22795. // loading conchars
  22796. @@ -501,6 +589,36 @@ static void Con_LoadConchars( void )
  22797.  
  22798. }
  22799.  
  22800. +/*
  22801. +====================
  22802. +Con_TextAdjustSize
  22803. +
  22804. +draw charcters routine
  22805. +====================
  22806. +*/
  22807. +static void Con_TextAdjustSize( int *x, int *y, int *w, int *h )
  22808. +{
  22809. + float xscale, yscale;
  22810. +
  22811. + if( !x && !y && !w && !h ) return;
  22812. +
  22813. + // scale for screen sizes
  22814. + xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
  22815. + yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
  22816. +
  22817. + if( x ) *x *= xscale;
  22818. + if( y ) *y *= yscale;
  22819. + if( w ) *w *= xscale;
  22820. + if( h ) *h *= yscale;
  22821. +}
  22822. +
  22823. +/*
  22824. +====================
  22825. +Con_DrawGenericChar
  22826. +
  22827. +draw console single character
  22828. +====================
  22829. +*/
  22830. static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
  22831. {
  22832. int width, height;
  22833. @@ -529,36 +647,73 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
  22834. width = rc->right - rc->left;
  22835. height = rc->bottom - rc->top;
  22836.  
  22837. - TextAdjustSize( &x, &y, &width, &height );
  22838. + if( clgame.ds.adjust_size )
  22839. + Con_TextAdjustSize( &x, &y, &width, &height );
  22840. R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, con.curFont->hFontTexture );
  22841. pglColor4ub( 255, 255, 255, 255 ); // don't forget reset color
  22842.  
  22843. return con.curFont->charWidths[number];
  22844. }
  22845.  
  22846. +/*
  22847. +====================
  22848. +Con_SetFont
  22849. +
  22850. +choose font size
  22851. +====================
  22852. +*/
  22853. void Con_SetFont( int fontNum )
  22854. {
  22855. fontNum = bound( 0, fontNum, 2 );
  22856. con.curFont = &con.chars[fontNum];
  22857. }
  22858.  
  22859. +/*
  22860. +====================
  22861. +Con_RestoreFont
  22862. +
  22863. +restore auto-selected console font
  22864. +(that based on screen resolution)
  22865. +====================
  22866. +*/
  22867. void Con_RestoreFont( void )
  22868. {
  22869. con.curFont = con.lastUsedFont;
  22870. }
  22871.  
  22872. +/*
  22873. +====================
  22874. +Con_DrawCharacter
  22875. +
  22876. +client version of routine
  22877. +====================
  22878. +*/
  22879. int Con_DrawCharacter( int x, int y, int number, rgba_t color )
  22880. {
  22881. GL_SetRenderMode( kRenderTransTexture );
  22882. return Con_DrawGenericChar( x, y, number, color );
  22883. }
  22884.  
  22885. +/*
  22886. +====================
  22887. +Con_DrawCharacterLen
  22888. +
  22889. +returns character sizes in screen pixels
  22890. +====================
  22891. +*/
  22892. void Con_DrawCharacterLen( int number, int *width, int *height )
  22893. {
  22894. if( width && con.curFont ) *width = con.curFont->charWidths[number];
  22895. if( height && con.curFont ) *height = con.curFont->charHeight;
  22896. }
  22897.  
  22898. +/*
  22899. +====================
  22900. +Con_DrawStringLen
  22901. +
  22902. +compute string width and height in screen pixels
  22903. +====================
  22904. +*/
  22905. void Con_DrawStringLen( const char *pText, int *length, int *height )
  22906. {
  22907. int curLength = 0;
  22908. @@ -613,10 +768,10 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb
  22909. if( !con.curFont ) return 0; // no font set
  22910.  
  22911. // draw the colored text
  22912. - s = string;
  22913. *(uint *)color = *(uint *)setColor;
  22914. + s = string;
  22915.  
  22916. - while ( *s )
  22917. + while( *s )
  22918. {
  22919. if( *s == '\n' )
  22920. {
  22921. @@ -652,6 +807,13 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb
  22922. return drawLen;
  22923. }
  22924.  
  22925. +/*
  22926. +====================
  22927. +Con_DrawString
  22928. +
  22929. +client version of routine
  22930. +====================
  22931. +*/
  22932. int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
  22933. {
  22934. return Con_DrawGenericString( x, y, string, setColor, false, -1 );
  22935. @@ -669,10 +831,17 @@ void Con_Init( void )
  22936. // must be init before startup video subsystem
  22937. scr_width = Cvar_Get( "width", "640", 0, "screen width" );
  22938. scr_height = Cvar_Get( "height", "480", 0, "screen height" );
  22939. - scr_conspeed = Cvar_Get( "scr_conspeed", "600", 0, "console moving speed" );
  22940. - con_notifytime = Cvar_Get( "con_notifytime", "3", 0, "notify time to live" );
  22941. + scr_conspeed = Cvar_Get( "scr_conspeed", "600", CVAR_ARCHIVE, "console moving speed" );
  22942. + con_notifytime = Cvar_Get( "con_notifytime", "3", CVAR_ARCHIVE, "notify time to live" );
  22943. con_fontsize = Cvar_Get( "con_fontsize", "1", CVAR_ARCHIVE, "console font number (0, 1 or 2)" );
  22944.  
  22945. + // init the console buffer
  22946. + con.bufsize = CON_TEXTSIZE;
  22947. + con.buffer = (char *)Z_Malloc( con.bufsize );
  22948. + con.maxlines = CON_MAXLINES;
  22949. + con.lines = (con_lineinfo_t *)Z_Malloc( con.maxlines * sizeof( *con.lines ));
  22950. + con.lines_first = con.lines_count = 0;
  22951. +
  22952. Con_CheckResize();
  22953.  
  22954. Con_ClearField( &con.input );
  22955. @@ -697,28 +866,23 @@ void Con_Init( void )
  22956. con.initialized = true;
  22957. }
  22958.  
  22959. -
  22960. /*
  22961. -===============
  22962. -Con_Linefeed
  22963. -===============
  22964. +================
  22965. +Con_Shutdown
  22966. +================
  22967. */
  22968. -void Con_Linefeed( void )
  22969. +void Con_Shutdown( void )
  22970. {
  22971. - int i;
  22972. + con.initialized = false;
  22973.  
  22974. - // mark time for transparent overlay
  22975. - if( con.current >= 0 )
  22976. - con.times[con.current % CON_TIMES] = host.realtime;
  22977. + if( con.buffer )
  22978. + Mem_Free( con.buffer );
  22979.  
  22980. - con.x = 0;
  22981. - if( con.display == con.current )
  22982. - con.display++;
  22983. + if( con.lines )
  22984. + Mem_Free( con.lines );
  22985.  
  22986. - con.current++;
  22987. -
  22988. - for( i = 0; i < con.linewidth; i++ )
  22989. - con.text[(con.current % con.totallines) * con.linewidth+i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' ';
  22990. + con.buffer = NULL;
  22991. + con.lines = NULL;
  22992. }
  22993.  
  22994. /*
  22995. @@ -726,63 +890,52 @@ void Con_Linefeed( void )
  22996. Con_Print
  22997.  
  22998. Handles cursor positioning, line wrapping, etc
  22999. -All console printing must go through this in order to be logged to disk
  23000. -If no console is visible, the text will appear at the top of the game window
  23001. +All console printing must go through this in order to be displayed
  23002. +If no console is visible, the notify window will pop up.
  23003. ================
  23004. */
  23005. void Con_Print( const char *txt )
  23006. {
  23007. - int y, c, l, color;
  23008. + static int cr_pending = 0;
  23009. + static char buf[MAX_PRINT_MSG];
  23010. + static int bufpos = 0;
  23011.  
  23012. // client not running
  23013. - if( host.type == HOST_DEDICATED ) return;
  23014. - if( !con.initialized ) return;
  23015. -
  23016. - color = ColorIndex( COLOR_DEFAULT );
  23017. + if( !con.initialized || !con.buffer || host.type == HOST_DEDICATED )
  23018. + return;
  23019.  
  23020. - while(( c = *txt ) != 0 )
  23021. + for( ; *txt; txt++ )
  23022. {
  23023. - if( IsColorString( txt ))
  23024. + if( cr_pending )
  23025. {
  23026. - color = ColorIndex( *( txt + 1 ));
  23027. - txt += 2;
  23028. - continue;
  23029. + Con_DeleteLastLine();
  23030. + cr_pending = 0;
  23031. }
  23032.  
  23033. - // count word length
  23034. - for( l = 0; l < con.linewidth; l++ )
  23035. - {
  23036. - if( txt[l] <= ' ')
  23037. - break;
  23038. - }
  23039. -#if 0
  23040. - // g-cont. experiment from SDLash3D
  23041. - // word wrap
  23042. - if( l != con.linewidth && ( con.x + l >= con.linewidth ))
  23043. - Con_Linefeed();
  23044. -#endif
  23045. - txt++;
  23046. -
  23047. - switch( c )
  23048. + switch( *txt )
  23049. {
  23050. - case '\n':
  23051. - Con_Linefeed();
  23052. + case '\0':
  23053. break;
  23054. case '\r':
  23055. - con.x = 0;
  23056. + Con_AddLine( buf, bufpos );
  23057. + cr_pending = 1;
  23058. + bufpos = 0;
  23059. break;
  23060. - default: // display character and advance
  23061. - y = con.current % con.totallines;
  23062. - con.text[y*con.linewidth+con.x] = (color << 8) | c;
  23063. - con.x++;
  23064. - if( con.x >= con.linewidth )
  23065. + case '\n':
  23066. + Con_AddLine( buf, bufpos );
  23067. + bufpos = 0;
  23068. + break;
  23069. + default:
  23070. + buf[bufpos++] = *txt;
  23071. + if(( bufpos >= sizeof( buf ) - 1 ) || bufpos >= ( con.linewidth - 1 ))
  23072. {
  23073. - Con_Linefeed();
  23074. - con.x = 0;
  23075. + Con_AddLine( buf, bufpos );
  23076. + bufpos = 0;
  23077. }
  23078. break;
  23079. }
  23080. }
  23081. +
  23082. }
  23083.  
  23084. /*
  23085. @@ -949,7 +1102,7 @@ static int Con_SortCmds( const char **arg1, const char **arg2 )
  23086.  
  23087. /*
  23088. ===============
  23089. -pfnPrintMatches
  23090. +Con_PrintMatches
  23091. ===============
  23092. */
  23093. static void Con_PrintMatches( const char *s, const char *unused1, const char *m, void *unused2 )
  23094. @@ -961,7 +1114,12 @@ static void Con_PrintMatches( const char *s, const char *unused1, const char *m,
  23095. }
  23096. }
  23097.  
  23098. -static void ConcatRemaining( const char *src, const char *start )
  23099. +/*
  23100. +===============
  23101. +Con_ConcatRemaining
  23102. +===============
  23103. +*/
  23104. +static void Con_ConcatRemaining( const char *src, const char *start )
  23105. {
  23106. char *arg;
  23107. int i;
  23108. @@ -1018,11 +1176,16 @@ void Con_CompleteCommand( field_t *field )
  23109. nextcmd = ( con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ' ) ? true : false;
  23110.  
  23111. con.completionString = Cmd_Argv( 0 );
  23112. + con.completionBuffer = Cmd_Argv( 1 );
  23113.  
  23114. // skip backslash
  23115. while( *con.completionString && ( *con.completionString == '\\' || *con.completionString == '/' ))
  23116. con.completionString++;
  23117.  
  23118. + // skip backslash
  23119. + while( *con.completionBuffer && ( *con.completionBuffer == '\\' || *con.completionBuffer == '/' ))
  23120. + con.completionBuffer++;
  23121. +
  23122. if( !Q_strlen( con.completionString ))
  23123. return;
  23124.  
  23125. @@ -1051,12 +1214,15 @@ void Con_CompleteCommand( field_t *field )
  23126. {
  23127. qboolean result = false;
  23128.  
  23129. + if( !Q_strlen( con.completionBuffer ))
  23130. + return;
  23131. +
  23132. // autocomplete second arg
  23133. for( list = cmd_list; list->name; list++ )
  23134. {
  23135. if( Cmd_CheckName( list->name ))
  23136. {
  23137. - result = list->func( Cmd_Argv( 1 ), filename, MAX_STRING );
  23138. + result = list->func( con.completionBuffer, filename, MAX_STRING );
  23139. break;
  23140. }
  23141. }
  23142. @@ -1080,7 +1246,7 @@ void Con_CompleteCommand( field_t *field )
  23143. {
  23144. Q_sprintf( con.completionField->buffer, "\\%s", con.cmds[0] );
  23145. if( Cmd_Argc() == 1 ) Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
  23146. - else ConcatRemaining( temp.buffer, con.completionString );
  23147. + else Con_ConcatRemaining( temp.buffer, con.completionString );
  23148. con.completionField->cursor = Q_strlen( con.completionField->buffer );
  23149. }
  23150. else
  23151. @@ -1108,7 +1274,7 @@ void Con_CompleteCommand( field_t *field )
  23152. // multiple matches, complete to shortest
  23153. Q_sprintf( con.completionField->buffer, "\\%s", con.shortestMatch );
  23154. con.completionField->cursor = Q_strlen( con.completionField->buffer );
  23155. - ConcatRemaining( temp.buffer, con.completionString );
  23156. + Con_ConcatRemaining( temp.buffer, con.completionString );
  23157.  
  23158. Msg( "]%s\n", con.completionField->buffer );
  23159.  
  23160. @@ -1135,7 +1301,6 @@ void Field_Paste( field_t *edit )
  23161. pasteLen = Q_strlen( cbd );
  23162. for( i = 0; i < pasteLen; i++ )
  23163. Field_CharEvent( edit, cbd[i] );
  23164. - Mem_Free( cbd );
  23165. }
  23166.  
  23167. /*
  23168. @@ -1313,7 +1478,7 @@ void Field_DrawInputLine( int x, int y, field_t *edit )
  23169. drawLen = len - prestep;
  23170.  
  23171. // extract <drawLen> characters from the field at <prestep>
  23172. - ASSERT( drawLen < MAX_SYSPATH );
  23173. + drawLen = Q_min( drawLen, MAX_SYSPATH - 1 );
  23174.  
  23175. memcpy( str, edit->buffer + prestep, drawLen );
  23176. str[drawLen] = 0;
  23177. @@ -1370,7 +1535,7 @@ void Key_Console( int key )
  23178. }
  23179.  
  23180. // enter finishes the line
  23181. - if ( key == K_ENTER || key == K_KP_ENTER )
  23182. + if( key == K_ENTER || key == K_KP_ENTER )
  23183. {
  23184. // if not in the game explicitly prepent a slash if needed
  23185. if( cls.state != ca_active && con.input.buffer[0] != '\\' && con.input.buffer[0] != '/' )
  23186. @@ -1418,9 +1583,7 @@ void Key_Console( int key )
  23187. if(( key == K_MWHEELUP && Key_IsDown( K_SHIFT )) || ( key == K_UPARROW ) || (( Q_tolower(key) == 'p' ) && Key_IsDown( K_CTRL )))
  23188. {
  23189. if( con.nextHistoryLine - con.historyLine < CON_HISTORY && con.historyLine > 0 )
  23190. - {
  23191. con.historyLine--;
  23192. - }
  23193. con.input = con.historyLines[con.historyLine % CON_HISTORY];
  23194. return;
  23195. }
  23196. @@ -1436,13 +1599,13 @@ void Key_Console( int key )
  23197. // console scrolling
  23198. if( key == K_PGUP )
  23199. {
  23200. - Con_PageUp( 2 );
  23201. + Con_PageUp( 1 );
  23202. return;
  23203. }
  23204.  
  23205. if( key == K_PGDN )
  23206. {
  23207. - Con_PageDown( 2 );
  23208. + Con_PageDown( 1 );
  23209. return;
  23210. }
  23211.  
  23212. @@ -1528,21 +1691,17 @@ Con_DrawInput
  23213. The input line scrolls horizontally if typing goes beyond the right edge
  23214. ================
  23215. */
  23216. -void Con_DrawInput( void )
  23217. +void Con_DrawInput( int lines )
  23218. {
  23219. - byte *colorDefault;
  23220. - int x, y;
  23221. + int y;
  23222.  
  23223. // don't draw anything (always draw if not active)
  23224. - if( cls.key_dest != key_console ) return;
  23225. - if( !con.curFont ) return;
  23226. -
  23227. - x = QCHAR_WIDTH; // room for ']'
  23228. - y = con.vislines - ( con.curFont->charHeight * 2 );
  23229. - colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
  23230. + if( cls.key_dest != key_console || !con.curFont )
  23231. + return;
  23232.  
  23233. - Con_DrawCharacter( QCHAR_WIDTH >> 1, y, ']', colorDefault );
  23234. - Field_DrawInputLine( x, y, &con.input );
  23235. + y = lines - ( con.curFont->charHeight * 2 );
  23236. + Con_DrawCharacter( 8, y, ']', g_color_table[7] );
  23237. + Field_DrawInputLine( 16, y, &con.input );
  23238. }
  23239.  
  23240. /*
  23241. @@ -1555,8 +1714,8 @@ Custom debug messages
  23242. int Con_DrawDebugLines( void )
  23243. {
  23244. int i, count = 0;
  23245. - int y = 20;
  23246. int defaultX;
  23247. + int y = 20;
  23248.  
  23249. defaultX = glState.width / 4;
  23250.  
  23251. @@ -1568,7 +1727,7 @@ int Con_DrawDebugLines( void )
  23252. int fontTall;
  23253.  
  23254. Con_DrawStringLen( con.notify[i].szNotify, &len, &fontTall );
  23255. - x = scr_width->integer - max( defaultX, len ) - 10;
  23256. + x = scr_width->integer - Q_max( defaultX, len ) - 10;
  23257. fontTall += 1;
  23258.  
  23259. if( y + fontTall > (int)scr_height->integer - 20 )
  23260. @@ -1611,38 +1770,24 @@ Draws the last few lines of output transparently over the game top
  23261. */
  23262. void Con_DrawNotify( void )
  23263. {
  23264. - int i, x, v = 0;
  23265. - int start, currentColor;
  23266. - short *text;
  23267. - float time;
  23268. + double time = cl.time;
  23269. + int i, x, y = 0;
  23270.  
  23271. if( !con.curFont ) return;
  23272.  
  23273. + x = con.curFont->charWidths[' ']; // offset one space at left screen side
  23274. +
  23275. if( host.developer && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
  23276. {
  23277. - currentColor = 7;
  23278. - pglColor4ubv( g_color_table[currentColor] );
  23279. -
  23280. - for( i = con.current - CON_TIMES + 1; i <= con.current; i++ )
  23281. + for( i = CON_LINES_COUNT - CON_TIMES; i < CON_LINES_COUNT; i++ )
  23282. {
  23283. - if( i < 0 ) continue;
  23284. - time = con.times[i % CON_TIMES];
  23285. - if( time == 0 ) continue;
  23286. - time = host.realtime - time;
  23287. + con_lineinfo_t *l = &CON_LINES( i );
  23288.  
  23289. - if( time > con_notifytime->value )
  23290. - continue; // expired
  23291. + if( l->addtime < ( time - con_notifytime->value ))
  23292. + continue;
  23293.  
  23294. - text = con.text + (i % con.totallines) * con.linewidth;
  23295. - start = con.curFont->charWidths[' ']; // offset one space at left screen side
  23296. -
  23297. - for( x = 0; x < con.linewidth; x++ )
  23298. - {
  23299. - if((( text[x] >> 8 ) & 7 ) != currentColor )
  23300. - currentColor = ( text[x] >> 8 ) & 7;
  23301. - start += Con_DrawCharacter( start, v, text[x] & 0xFF, g_color_table[currentColor] );
  23302. - }
  23303. - v += con.curFont->charHeight;
  23304. + Con_DrawString( x, y, l->start, g_color_table[7] );
  23305. + y += con.curFont->charHeight;
  23306. }
  23307. }
  23308.  
  23309. @@ -1651,21 +1796,16 @@ void Con_DrawNotify( void )
  23310. string buf;
  23311. int len;
  23312.  
  23313. - currentColor = 7;
  23314. - pglColor4ubv( g_color_table[currentColor] );
  23315. -
  23316. - start = con.curFont->charWidths[' ']; // offset one space at left screen side
  23317. -
  23318. // update chatline position from client.dll
  23319. if( clgame.dllFuncs.pfnChatInputPosition )
  23320. - clgame.dllFuncs.pfnChatInputPosition( &start, &v );
  23321. + clgame.dllFuncs.pfnChatInputPosition( &x, &y );
  23322.  
  23323. Q_snprintf( buf, sizeof( buf ), "%s: ", con.chat_cmd );
  23324.  
  23325. Con_DrawStringLen( buf, &len, NULL );
  23326. - Con_DrawString( start, v, buf, g_color_table[7] );
  23327. + Con_DrawString( x, y, buf, g_color_table[7] );
  23328.  
  23329. - Field_DrawInputLine( start + len, v, &con.chat );
  23330. + Field_DrawInputLine( x + len, y, &con.chat );
  23331. }
  23332.  
  23333. pglColor4ub( 255, 255, 255, 255 );
  23334. @@ -1673,98 +1813,135 @@ void Con_DrawNotify( void )
  23335.  
  23336. /*
  23337. ================
  23338. +Con_DrawConsoleLine
  23339. +
  23340. +Draws a line of the console; returns its height in lines.
  23341. +If alpha is 0, the line is not drawn, but still wrapped and its height
  23342. +returned.
  23343. +================
  23344. +*/
  23345. +int Con_DrawConsoleLine( int y, int lineno )
  23346. +{
  23347. + con_lineinfo_t *li = &CON_LINES( lineno );
  23348. +
  23349. + if( y >= con.curFont->charHeight )
  23350. + Con_DrawGenericString( con.curFont->charWidths[' '], y, li->start, g_color_table[7], false, -1 );
  23351. +
  23352. + return con.curFont->charHeight;
  23353. +}
  23354. +
  23355. +/*
  23356. +================
  23357. +Con_LastVisibleLine
  23358. +
  23359. +Calculates the last visible line index and how much to show
  23360. +of it based on con.backscroll.
  23361. +================
  23362. +*/
  23363. +static void Con_LastVisibleLine( int *lastline )
  23364. +{
  23365. + int i, lines_seen = 0;
  23366. +
  23367. + con.backscroll = Q_max( 0, con.backscroll );
  23368. + *lastline = 0;
  23369. +
  23370. + // now count until we saw con_backscroll actual lines
  23371. + for( i = CON_LINES_COUNT - 1; i >= 0; i-- )
  23372. + {
  23373. + // line is the last visible line?
  23374. + *lastline = i;
  23375. +
  23376. + if( lines_seen + 1 > con.backscroll && lines_seen <= con.backscroll )
  23377. + return;
  23378. +
  23379. + lines_seen += 1;
  23380. + }
  23381. +
  23382. + // if we get here, no line was on screen - scroll so that one line is visible then.
  23383. + con.backscroll = lines_seen - 1;
  23384. +}
  23385. +
  23386. +/*
  23387. +================
  23388. Con_DrawConsole
  23389.  
  23390. Draws the console with the solid background
  23391. ================
  23392. */
  23393. -void Con_DrawSolidConsole( float frac )
  23394. +void Con_DrawSolidConsole( int lines )
  23395. {
  23396. int i, x, y;
  23397. - int rows;
  23398. - short *text;
  23399. - int row;
  23400. - int lines, start;
  23401. - int currentColor;
  23402. - string curbuild;
  23403. + float fraction;
  23404. + int start;
  23405.  
  23406. - lines = scr_height->integer * frac;
  23407. if( lines <= 0 ) return;
  23408. - if( lines > scr_height->integer )
  23409. - lines = scr_height->integer;
  23410.  
  23411. // draw the background
  23412. - y = frac * scr_height->integer;
  23413. + GL_SetRenderMode( kRenderNormal );
  23414. + pglColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade
  23415. + R_DrawStretchPic( 0, lines - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background );
  23416.  
  23417. - if( y >= 1 )
  23418. - {
  23419. - GL_SetRenderMode( kRenderNormal );
  23420. - R_DrawStretchPic( 0, y - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background );
  23421. - }
  23422. - else y = 0;
  23423. + if( !con.curFont || host.developer <= 0 )
  23424. + return; // nothing to draw
  23425.  
  23426. - if( !con.curFont ) return; // nothing to draw
  23427. -
  23428. - if( host.developer )
  23429. + if( host.developer > 0 )
  23430. {
  23431. // draw current version
  23432. - byte *color = g_color_table[7];
  23433. int stringLen, width = 0, charH;
  23434. + string curbuild;
  23435. + byte color[4];
  23436. +
  23437. + memcpy( color, g_color_table[7], sizeof( color ));
  23438.  
  23439. Q_snprintf( curbuild, MAX_STRING, "Xash3D %i/%g (hw build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ));
  23440. Con_DrawStringLen( curbuild, &stringLen, &charH );
  23441. start = scr_width->integer - stringLen;
  23442. stringLen = Con_StringLength( curbuild );
  23443.  
  23444. + fraction = lines / (float)scr_height->integer;
  23445. + color[3] = Q_min( fraction * 2.0f, 1.0f ) * 255; // fadeout version number
  23446. +
  23447. for( i = 0; i < stringLen; i++ )
  23448. width += Con_DrawCharacter( start + width, 0, curbuild[i], color );
  23449. }
  23450.  
  23451. // draw the text
  23452. - con.vislines = lines;
  23453. - rows = ( lines - QCHAR_WIDTH ) / QCHAR_WIDTH; // rows of text to draw
  23454. - y = lines - ( con.curFont->charHeight * 3 );
  23455. -
  23456. - // draw from the bottom up
  23457. - if( con.display != con.current )
  23458. + if( CON_LINES_COUNT > 0 )
  23459. {
  23460. - start = con.curFont->charWidths[' ']; // offset one space at left screen side
  23461. -
  23462. - // draw red arrows to show the buffer is backscrolled
  23463. - for( x = 0; x < con.linewidth; x += 4 )
  23464. - Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] );
  23465. - y -= con.curFont->charHeight;
  23466. - rows--;
  23467. - }
  23468. -
  23469. - row = con.display;
  23470. - if( con.x == 0 ) row--;
  23471. + int ymax = lines - (con.curFont->charHeight * 2.0f);
  23472. + int lastline;
  23473.  
  23474. - currentColor = 7;
  23475. - pglColor4ubv( g_color_table[currentColor] );
  23476. + Con_LastVisibleLine( &lastline );
  23477. + y = ymax - con.curFont->charHeight;
  23478.  
  23479. - for( i = 0; i < rows; i++, y -= con.curFont->charHeight, row-- )
  23480. - {
  23481. - if( row < 0 ) break;
  23482. - if( con.current - row >= con.totallines )
  23483. + if( con.backscroll )
  23484. {
  23485. - // past scrollback wrap point
  23486. - continue;
  23487. - }
  23488. + start = con.curFont->charWidths[' ']; // offset one space at left screen side
  23489.  
  23490. - text = con.text + ( row % con.totallines ) * con.linewidth;
  23491. - start = con.curFont->charWidths[' ']; // offset one space at left screen side
  23492. + // draw red arrows to show the buffer is backscrolled
  23493. + for( x = 0; x < con.linewidth; x += 4 )
  23494. + Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] );
  23495. + y -= con.curFont->charHeight;
  23496. + }
  23497. + x = lastline;
  23498.  
  23499. - for( x = 0; x < con.linewidth; x++ )
  23500. + while( 1 )
  23501. {
  23502. - if((( text[x] >> 8 ) & 7 ) != currentColor )
  23503. - currentColor = ( text[x] >> 8 ) & 7;
  23504. - start += Con_DrawCharacter( start, y, text[x] & 0xFF, g_color_table[currentColor] );
  23505. + y -= Con_DrawConsoleLine( y, x );
  23506. +
  23507. + // top of console buffer or console window
  23508. + if( x == 0 || y < con.curFont->charHeight )
  23509. + break;
  23510. + x--;
  23511. }
  23512. }
  23513.  
  23514. // draw the input prompt, user text, and cursor if desired
  23515. - Con_DrawInput();
  23516. + Con_DrawInput( lines );
  23517. +
  23518. + y = lines - ( con.curFont->charHeight * 1.2f );
  23519. + SCR_DrawFPS( max( y, 4 )); // to avoid to hide fps counter
  23520. +
  23521. pglColor4ub( 255, 255, 255, 255 );
  23522. }
  23523.  
  23524. @@ -1787,18 +1964,18 @@ void Con_DrawConsole( void )
  23525. if( !cl_allow_levelshots->integer )
  23526. {
  23527. if(( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" )) && cls.key_dest != key_console )
  23528. - con.displayFrac = con.finalFrac = 0.0f;
  23529. - else con.displayFrac = con.finalFrac = 1.0f;
  23530. + con.vislines = con.showlines = 0;
  23531. + else con.vislines = con.showlines = scr_height->integer;
  23532. }
  23533. else
  23534. {
  23535. if( host.developer >= 4 )
  23536. {
  23537. - con.displayFrac = 0.5f; // keep console open
  23538. + con.vislines = (scr_height->integer >> 1); // keep console open
  23539. }
  23540. else
  23541. {
  23542. - con.finalFrac = 0.0f;
  23543. + con.showlines = 0;
  23544. Con_RunConsole();
  23545.  
  23546. if( host.developer >= 2 )
  23547. @@ -1815,31 +1992,37 @@ void Con_DrawConsole( void )
  23548. case ca_disconnected:
  23549. if( cls.key_dest != key_menu && host.developer )
  23550. {
  23551. - Con_DrawSolidConsole( 1.0f );
  23552. + Con_DrawSolidConsole( scr_height->integer );
  23553. Key_SetKeyDest( key_console );
  23554. }
  23555. break;
  23556. case ca_connected:
  23557. case ca_connecting:
  23558. // force to show console always for -dev 3 and higher
  23559. - if( con.displayFrac ) Con_DrawSolidConsole( con.displayFrac );
  23560. + if( con.vislines )
  23561. + {
  23562. + GL_CleanupAllTextureUnits(); // ugly hack to remove blinking voiceicon.spr during loading
  23563. + Con_DrawSolidConsole( con.vislines );
  23564. + }
  23565. break;
  23566. case ca_active:
  23567. case ca_cinematic:
  23568. if( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
  23569. {
  23570. if( cls.key_dest == key_console )
  23571. - Con_DrawSolidConsole( 1.0f );
  23572. + Con_DrawSolidConsole( scr_height->integer );
  23573. }
  23574. else
  23575. {
  23576. - if( con.displayFrac )
  23577. - Con_DrawSolidConsole( con.displayFrac );
  23578. + if( con.vislines )
  23579. + Con_DrawSolidConsole( con.vislines );
  23580. else if( cls.state == ca_active && ( cls.key_dest == key_game || cls.key_dest == key_message ))
  23581. Con_DrawNotify(); // draw notify lines
  23582. }
  23583. break;
  23584. }
  23585. +
  23586. + if( !Con_Visible( )) SCR_DrawFPS( 4 );
  23587. }
  23588.  
  23589. /*
  23590. @@ -1893,30 +2076,38 @@ Scroll it up or down
  23591. */
  23592. void Con_RunConsole( void )
  23593. {
  23594. + int lines_per_frame;
  23595. +
  23596. // decide on the destination height of the console
  23597. if( host.developer && cls.key_dest == key_console )
  23598. {
  23599. if( cls.state == ca_disconnected )
  23600. - con.finalFrac = 1.0f;// full screen
  23601. - else con.finalFrac = 0.5f; // half screen
  23602. + con.showlines = scr_height->integer; // full screen
  23603. + else con.showlines = (scr_height->integer >> 1); // half screen
  23604. }
  23605. - else con.finalFrac = 0; // none visible
  23606. + else con.showlines = 0; // none visible
  23607.  
  23608. // when level is loading frametime may be is wrong
  23609. if( cls.state == ca_connecting || cls.state == ca_connected )
  23610. - host.realframetime = ( MAX_FPS / host_maxfps->value ) * MIN_FRAMETIME;
  23611. + {
  23612. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  23613. + host.realframetime = ( MAX_FPS / host_maxfps->value ) * MIN_FRAMETIME;
  23614. + else host.realframetime = HOST_FRAMETIME;
  23615. + }
  23616. +
  23617. + lines_per_frame = bound( 1, fabs( scr_conspeed->value ) * host.realframetime, scr_height->integer );
  23618.  
  23619. - if( con.finalFrac < con.displayFrac )
  23620. + if( con.showlines < con.vislines )
  23621. {
  23622. - con.displayFrac -= fabs( scr_conspeed->value ) * 0.002f * host.realframetime;
  23623. - if( con.finalFrac > con.displayFrac )
  23624. - con.displayFrac = con.finalFrac;
  23625. + con.vislines -= lines_per_frame;
  23626. + if( con.showlines > con.vislines )
  23627. + con.vislines = con.showlines;
  23628. }
  23629. - else if( con.finalFrac > con.displayFrac )
  23630. + else if( con.showlines > con.vislines )
  23631. {
  23632. - con.displayFrac += fabs( scr_conspeed->value ) * 0.002f * host.realframetime;
  23633. - if( con.finalFrac < con.displayFrac )
  23634. - con.displayFrac = con.finalFrac;
  23635. + con.vislines += lines_per_frame;
  23636. + if( con.showlines < con.vislines )
  23637. + con.vislines = con.showlines;
  23638. }
  23639. }
  23640.  
  23641. @@ -1947,6 +2138,14 @@ void Con_CharEvent( int key )
  23642. }
  23643. }
  23644.  
  23645. +/*
  23646. +=========
  23647. +Con_VidInit
  23648. +
  23649. +reload background
  23650. +resize console
  23651. +=========
  23652. +*/
  23653. void Con_VidInit( void )
  23654. {
  23655. Con_CheckResize();
  23656. @@ -1954,42 +2153,62 @@ void Con_VidInit( void )
  23657. // loading console image
  23658. if( host.developer )
  23659. {
  23660. - if( scr_width->integer < 640 )
  23661. - {
  23662. - if( FS_FileExists( "cached/conback400", false ))
  23663. - con.background = GL_LoadTexture( "cached/conback400", NULL, 0, TF_IMAGE, NULL );
  23664. - else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
  23665. - }
  23666. - else
  23667. + // trying to load truecolor image first
  23668. + if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
  23669. + con.background = GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE, NULL );
  23670. +
  23671. + if( !con.background )
  23672. {
  23673. - if( FS_FileExists( "cached/conback640", false ))
  23674. - con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE, NULL );
  23675. - else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
  23676. + if( scr_width->integer < 640 )
  23677. + {
  23678. + if( FS_FileExists( "cached/conback400", false ))
  23679. + con.background = GL_LoadTexture( "cached/conback400", NULL, 0, TF_IMAGE, NULL );
  23680. + else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
  23681. + }
  23682. + else
  23683. + {
  23684. + if( FS_FileExists( "cached/conback640", false ))
  23685. + con.background = GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE, NULL );
  23686. + else con.background = GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE, NULL );
  23687. + }
  23688. }
  23689. }
  23690. else
  23691. {
  23692. - if( scr_width->integer < 640 )
  23693. - {
  23694. - if( FS_FileExists( "cached/loading400", false ))
  23695. - con.background = GL_LoadTexture( "cached/loading400", NULL, 0, TF_IMAGE, NULL );
  23696. - else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
  23697. - }
  23698. - else
  23699. + // trying to load truecolor image first
  23700. + if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
  23701. + con.background = GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE, NULL );
  23702. +
  23703. + if( !con.background )
  23704. {
  23705. - if( FS_FileExists( "cached/loading640", false ))
  23706. - con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE, NULL );
  23707. - else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
  23708. + if( scr_width->integer < 640 )
  23709. + {
  23710. + if( FS_FileExists( "cached/loading400", false ))
  23711. + con.background = GL_LoadTexture( "cached/loading400", NULL, 0, TF_IMAGE, NULL );
  23712. + else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
  23713. + }
  23714. + else
  23715. + {
  23716. + if( FS_FileExists( "cached/loading640", false ))
  23717. + con.background = GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE, NULL );
  23718. + else con.background = GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE, NULL );
  23719. + }
  23720. }
  23721. }
  23722.  
  23723. - // missed console image will be replaced as white (GoldSrc rules)
  23724. + // missed console image will be replaced as gray background like X-Ray or Crysis
  23725. if( con.background == tr.defaultTexture || con.background == 0 )
  23726. - con.background = tr.whiteTexture;
  23727. + con.background = tr.grayTexture;
  23728.  
  23729. Con_LoadConchars();
  23730. }
  23731.  
  23732. +/*
  23733. +=========
  23734. +Con_InvalidateFonts
  23735. +
  23736. +=========
  23737. +*/
  23738. void Con_InvalidateFonts( void )
  23739. {
  23740. memset( con.chars, 0, sizeof( con.chars ));
  23741. @@ -2022,12 +2241,19 @@ void Cmd_AutoComplete( char *complete_string )
  23742. else Q_strncpy( complete_string, input.buffer, sizeof( input.buffer ));
  23743. }
  23744.  
  23745. -void Con_Close( void )
  23746. +/*
  23747. +=========
  23748. +Con_FastClose
  23749. +
  23750. +immediately close the console
  23751. +=========
  23752. +*/
  23753. +void Con_FastClose( void )
  23754. {
  23755. Con_ClearField( &con.input );
  23756. Con_ClearNotify();
  23757. - con.finalFrac = 0.0f; // none visible
  23758. - con.displayFrac = 0.0f;
  23759. + con.showlines = 0;
  23760. + con.vislines = 0;
  23761. }
  23762.  
  23763. /*
  23764. diff --git b/engine/common/crtlib.c a/engine/common/crtlib.c
  23765. index 9a3c348..8a44b25 100644
  23766. --- b/engine/common/crtlib.c
  23767. +++ a/engine/common/crtlib.c
  23768. @@ -71,6 +71,29 @@ int Q_strlen( const char *string )
  23769. return len;
  23770. }
  23771.  
  23772. +int Q_colorstr( const char *string )
  23773. +{
  23774. + int len;
  23775. + const char *p;
  23776. +
  23777. + if( !string ) return 0;
  23778. +
  23779. + len = 0;
  23780. + p = string;
  23781. + while( *p )
  23782. + {
  23783. + if( IsColorString( p ))
  23784. + {
  23785. + len += 2;
  23786. + p += 2;
  23787. + continue;
  23788. + }
  23789. + p++;
  23790. + }
  23791. +
  23792. + return len;
  23793. +}
  23794. +
  23795. char Q_toupper( const char in )
  23796. {
  23797. char out;
  23798. @@ -572,6 +595,26 @@ int Q_sprintf( char *buffer, const char *format, ... )
  23799. return result;
  23800. }
  23801.  
  23802. +uint Q_hashkey( const char *string, uint hashSize, qboolean caseinsensitive )
  23803. +{
  23804. + uint i, hashKey = 0;
  23805. +
  23806. + if( caseinsensitive )
  23807. + {
  23808. + for( i = 0; string[i]; i++)
  23809. + hashKey += (i * 119) * Q_tolower( string[i] );
  23810. + }
  23811. + else
  23812. + {
  23813. + for( i = 0; string[i]; i++ )
  23814. + hashKey += (i + 119) * (int)string[i];
  23815. + }
  23816. +
  23817. + hashKey = ((hashKey ^ (hashKey >> 10)) ^ (hashKey >> 20)) & (hashSize - 1);
  23818. +
  23819. + return hashKey;
  23820. +}
  23821. +
  23822. char *Q_pretifymem( float value, int digitsafterdecimal )
  23823. {
  23824. static char output[8][32];
  23825. @@ -666,36 +709,4 @@ char *va( const char *format, ... )
  23826. va_end( argptr );
  23827.  
  23828. return s;
  23829. -}
  23830. -
  23831. -void _memcpy( void *dest, const void *src, size_t count, const char *filename, int fileline )
  23832. -{
  23833. - if( src == NULL || count <= 0 ) return; // nothing to copy
  23834. - if( dest == NULL ) Sys_Error( "memcpy: dest == NULL (called at %s:%i)\n", filename, fileline );
  23835. - memcpy( dest, src, count );
  23836. -}
  23837. -
  23838. -void _memset( void *dest, int set, size_t count, const char *filename, int fileline )
  23839. -{
  23840. - if( dest == NULL ) Sys_Error( "memset: dest == NULL (called at %s:%i)\n", filename, fileline );
  23841. - memset( dest, set, count );
  23842. -}
  23843. -
  23844. -int _memcmp( const void *src0, const void *src1, size_t count, const char *filename, int fileline )
  23845. -{
  23846. - if( src0 == NULL ) Sys_Error( "memcmp: src1 == NULL (called at %s:%i)\n", filename, fileline );
  23847. - if( src1 == NULL ) Sys_Error( "memcmp: src2 == NULL (called at %s:%i)\n", filename, fileline );
  23848. - return memcmp( src0, src1, count );
  23849. -}
  23850. -
  23851. -void _memmove( void *dest, const void *src, size_t count, const char *filename, int fileline )
  23852. -{
  23853. - if( src == NULL || count <= 0 ) return; // nothing to move
  23854. - if( dest == NULL ) Sys_Error( "memmove: dest == NULL (called at %s:%i)\n", filename, fileline );
  23855. - memmove( dest, src, count );
  23856. -}
  23857. -
  23858. -void CRT_Init( void )
  23859. -{
  23860. - Memory_Init();
  23861. }
  23862. \ No newline at end of file
  23863. diff --git b/engine/common/crtlib.h a/engine/common/crtlib.h
  23864. index 012d4e0..d4c994e 100644
  23865. --- b/engine/common/crtlib.h
  23866. +++ a/engine/common/crtlib.h
  23867. @@ -27,21 +27,13 @@ enum
  23868. TIME_FILENAME,
  23869. };
  23870.  
  23871. -#define CMD_EXTDLL BIT( 0 ) // added by game.dll
  23872. +#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
  23873. #define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
  23874. +#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
  23875.  
  23876. typedef void (*setpair_t)( const char *key, const char *value, void *buffer, void *numpairs );
  23877. typedef void (*xcommand_t)( void );
  23878.  
  23879. -typedef enum
  23880. -{
  23881. - src_client, // came in over a net connection as a clc_stringcmd
  23882. - // host_client will be valid during this state.
  23883. - src_command // from the command buffer
  23884. -} cmd_source_t;
  23885. -
  23886. -extern cmd_source_t cmd_source;
  23887. -
  23888. // NOTE: if this is changed, it must be changed in cvardef.h too
  23889. typedef struct convar_s
  23890. {
  23891. @@ -63,25 +55,26 @@ typedef struct convar_s
  23892. // cvar flags
  23893. typedef enum
  23894. {
  23895. - CVAR_ARCHIVE = BIT(0), // set to cause it to be saved to config.cfg
  23896. - CVAR_USERINFO = BIT(1), // added to userinfo when changed
  23897. - CVAR_SERVERNOTIFY = BIT(2), // notifies players when changed
  23898. - CVAR_EXTDLL = BIT(3), // defined by external DLL
  23899. - CVAR_CLIENTDLL = BIT(4), // defined by the client dll
  23900. - CVAR_PROTECTED = BIT(5), // it's a server cvar, but we don't send the data since it's a password, etc.
  23901. - CVAR_SPONLY = BIT(6), // this cvar cannot be changed by clients connected to a multiplayer server.
  23902. - CVAR_PRINTABLEONLY = BIT(7), // this cvar's string cannot contain unprintable characters ( player name )
  23903. - CVAR_UNLOGGED = BIT(8), // if this is a FCVAR_SERVER, don't log changes to the log file / console
  23904. - CVAR_SERVERINFO = BIT(9), // added to serverinfo when changed
  23905. - CVAR_PHYSICINFO = BIT(10),// added to physinfo when changed
  23906. - CVAR_RENDERINFO = BIT(11),// save to a seperate config called opengl.cfg
  23907. - CVAR_CHEAT = BIT(12),// can not be changed if cheats are disabled
  23908. - CVAR_INIT = BIT(13),// don't allow change from console at all, but can be set from the command line
  23909. - CVAR_LATCH = BIT(14),// save changes until server restart
  23910. - CVAR_READ_ONLY = BIT(15),// display only, cannot be set by user at all
  23911. - CVAR_LATCH_VIDEO = BIT(16),// save changes until render restart
  23912. - CVAR_USER_CREATED = BIT(17),// created by a set command (dll's used)
  23913. - CVAR_GLCONFIG = BIT(18),// set to cause it to be saved to opengl.cfg
  23914. + CVAR_ARCHIVE = BIT( 0 ), // set to cause it to be saved to config.cfg
  23915. + CVAR_USERINFO = BIT( 1 ), // added to userinfo when changed
  23916. + CVAR_SERVERNOTIFY = BIT( 2 ), // notifies players when changed
  23917. + CVAR_SERVERDLL = BIT( 3 ), // defined by the server DLL
  23918. + CVAR_CLIENTDLL = BIT( 4 ), // defined by the client dll
  23919. + CVAR_PROTECTED = BIT( 5 ), // it's a server cvar, but we don't send the data since it's a password, etc.
  23920. + CVAR_SPONLY = BIT( 6 ), // this cvar cannot be changed by clients connected to a multiplayer server.
  23921. + CVAR_PRINTABLEONLY = BIT( 7 ), // this cvar's string cannot contain unprintable characters ( player name )
  23922. + CVAR_UNLOGGED = BIT( 8 ), // if this is a FCVAR_SERVER, don't log changes to the log file / console
  23923. + CVAR_NOWHITEPACE = BIT( 9 ), // strip trailing/leading white space from this cvar
  23924. + CVAR_SERVERINFO = BIT( 10 ), // added to serverinfo when changed
  23925. + CVAR_PHYSICINFO = BIT( 11 ), // added to physinfo when changed
  23926. + CVAR_RENDERINFO = BIT( 12 ), // save to a seperate config called opengl.cfg
  23927. + CVAR_CHEAT = BIT( 13 ), // can not be changed if cheats are disabled
  23928. + CVAR_INIT = BIT( 14 ), // don't allow change from console at all, but can be set from the command line
  23929. + CVAR_LATCH = BIT( 15 ), // save changes until server restart
  23930. + CVAR_READ_ONLY = BIT( 16 ), // display only, cannot be set by user at all
  23931. + CVAR_GAMEUIDLL = BIT( 17 ), // defined by the GameUI DLL
  23932. + CVAR_GLCONFIG = BIT( 18 ), // set to cause it to be saved to opengl.cfg
  23933. + CVAR_USER_CREATED = BIT( 19 ), // created by a set command (dll's used)
  23934. } cvar_flags_t;
  23935.  
  23936. #include "cvardef.h"
  23937. @@ -109,7 +102,7 @@ void Cvar_WriteVariables( file_t *f );
  23938. void Cvar_Init( void );
  23939. char *Cvar_Userinfo( void );
  23940. char *Cvar_Serverinfo( void );
  23941. -void Cvar_Unlink( void );
  23942. +void Cvar_Unlink( int group );
  23943.  
  23944. //
  23945. // cmd.c
  23946. @@ -125,8 +118,9 @@ char *Cmd_Argv( int arg );
  23947. void Cmd_Init( void );
  23948. void Cmd_Unlink( int group );
  23949. void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
  23950. -void Cmd_AddGameCommand( const char *cmd_name, xcommand_t function );
  23951. -void Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
  23952. +void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
  23953. +int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
  23954. +int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
  23955. void Cmd_RemoveCommand( const char *cmd_name );
  23956. qboolean Cmd_Exists( const char *cmd_name );
  23957. void Cmd_LookupCmds( char *buffer, void *ptr, setpair_t callback );
  23958. @@ -134,7 +128,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length );
  23959. qboolean Cmd_GetDemoList( const char *s, char *completedname, int length );
  23960. qboolean Cmd_GetMovieList( const char *s, char *completedname, int length );
  23961. void Cmd_TokenizeString( char *text );
  23962. -void Cmd_ExecuteString( char *text, cmd_source_t src );
  23963. +void Cmd_ExecuteString( char *text );
  23964. void Cmd_ForwardToServer( void );
  23965.  
  23966. //
  23967. @@ -145,6 +139,7 @@ void Q_strnupr( const char *in, char *out, size_t size_out );
  23968. #define Q_strlwr( int, out ) Q_strnlwr( in, out, 99999 )
  23969. void Q_strnlwr( const char *in, char *out, size_t size_out );
  23970. int Q_strlen( const char *string );
  23971. +int Q_colorstr( const char *string );
  23972. char Q_toupper( const char in );
  23973. char Q_tolower( const char in );
  23974. #define Q_strcat( dst, src ) Q_strncat( dst, src, 99999 )
  23975. @@ -153,6 +148,7 @@ size_t Q_strncat( char *dst, const char *src, size_t siz );
  23976. size_t Q_strncpy( char *dst, const char *src, size_t siz );
  23977. #define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ )
  23978. char *_copystring( byte *mempool, const char *s, const char *filename, int fileline );
  23979. +uint Q_hashkey( const char *string, uint hashSize, qboolean caseinsensitive );
  23980. qboolean Q_isdigit( const char *str );
  23981. int Q_atoi( const char *str );
  23982. float Q_atof( const char *str );
  23983. @@ -174,14 +170,6 @@ int Q_sprintf( char *buffer, const char *format, ... );
  23984. #define Q_memprint( val ) Q_pretifymem( val, 2 )
  23985. char *Q_pretifymem( float value, int digitsafterdecimal );
  23986. char *va( const char *format, ... );
  23987. -#define Q_memcpy( dest, src, size ) _Q_memcpy( dest, src, size, __FILE__, __LINE__ )
  23988. -#define Q_memset( dest, val, size ) _Q_memset( dest, val, size, __FILE__, __LINE__ )
  23989. -#define Q_memcmp( src0, src1, siz ) _Q_memcmp( src0, src1, siz, __FILE__, __LINE__ )
  23990. -#define Q_memmove( dest, src, size ) _Q_memmove( dest, src, size, __FILE__, __LINE__ )
  23991. -void _Q_memset( void *dest, int set, size_t count, const char *filename, int fileline );
  23992. -void _Q_memcpy( void *dest, const void *src, size_t count, const char *filename, int fileline );
  23993. -int _Q_memcmp( const void *src0, const void *src1, size_t count, const char *filename, int fileline );
  23994. -void _Q_memmove( void *dest, const void *src, size_t count, const char *filename, int fileline );
  23995.  
  23996. //
  23997. // zone.c
  23998. @@ -206,7 +194,5 @@ void Mem_PrintStats( void );
  23999. #define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
  24000. #define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
  24001. #define Mem_Check() _Mem_Check( __FILE__, __LINE__ )
  24002. -
  24003. -void CRT_Init( void ); // must be call first
  24004.  
  24005. #endif//STDLIB_H
  24006. \ No newline at end of file
  24007. diff --git b/engine/common/cvar.c a/engine/common/cvar.c
  24008. index cb7f6b6..6b93895 100644
  24009. --- b/engine/common/cvar.c
  24010. +++ a/engine/common/cvar.c
  24011. @@ -17,6 +17,7 @@ GNU General Public License for more details.
  24012.  
  24013. convar_t *cvar_vars; // head of list
  24014. convar_t *userinfo, *physinfo, *serverinfo, *renderinfo;
  24015. +convar_t *cmd_scripting;
  24016.  
  24017. /*
  24018. ============
  24019. @@ -139,7 +140,7 @@ void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback
  24020. else
  24021. {
  24022. // NOTE: dlls cvars doesn't have description
  24023. - if( cvar->flags & CVAR_EXTDLL )
  24024. + if( FBitSet( cvar->flags, CVAR_SERVERDLL ))
  24025. callback( cvar->name, cvar->string, "game cvar", ptr );
  24026. else callback( cvar->name, cvar->string, cvar->description, ptr );
  24027. }
  24028. @@ -156,18 +157,25 @@ The flags will be or'ed in if the variable exists.
  24029. */
  24030. convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, const char *var_desc )
  24031. {
  24032. - convar_t *var;
  24033. + convar_t *cur, *find, *var;
  24034.  
  24035. if( !var_name )
  24036. {
  24037. - Sys_Error( "Cvar_Get: passed NULL name\n" );
  24038. + MsgDev( D_ERROR, "Cvar_Get: passed NULL name\n" );
  24039. + return NULL;
  24040. + }
  24041. +
  24042. + // check for command coexisting
  24043. + if( Cmd_Exists( var_name ))
  24044. + {
  24045. + MsgDev( D_ERROR, "Cvar_Get: %s is a command\n", var_name );
  24046. return NULL;
  24047. }
  24048.  
  24049. if( !var_value ) var_value = "0"; // just apply default value
  24050.  
  24051. // all broadcast cvars must be passed this check
  24052. - if( flags & ( CVAR_USERINFO|CVAR_SERVERINFO|CVAR_PHYSICINFO ))
  24053. + if( FBitSet( flags, CVAR_USERINFO|CVAR_SERVERINFO|CVAR_PHYSICINFO ))
  24054. {
  24055. if( !Cvar_ValidateString( var_name, false ))
  24056. {
  24057. @@ -182,37 +190,30 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
  24058. }
  24059. }
  24060.  
  24061. - // check for command coexisting
  24062. - if( Cmd_Exists( var_name ))
  24063. - {
  24064. - MsgDev( D_ERROR, "Cvar_Get: %s is a command\n", var_name );
  24065. - return NULL;
  24066. - }
  24067. -
  24068. var = Cvar_FindVar( var_name );
  24069.  
  24070. if( var )
  24071. {
  24072. // fast check for short cvars
  24073. - if( var->flags & CVAR_EXTDLL )
  24074. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24075. {
  24076. - var->flags |= flags;
  24077. + SetBits( var->flags, flags );
  24078. return var;
  24079. }
  24080.  
  24081. // if the C code is now specifying a variable that the user already
  24082. // set a value for, take the new value as the reset value
  24083. - if(( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED ) && var_value[0] )
  24084. + if( FBitSet( var->flags, CVAR_USER_CREATED ) && !FBitSet( flags, CVAR_USER_CREATED ) && var_value[0] )
  24085. {
  24086. - var->flags &= ~CVAR_USER_CREATED;
  24087. Mem_Free( var->reset_string );
  24088. var->reset_string = copystring( var_value );
  24089. + ClearBits( var->flags, CVAR_USER_CREATED );
  24090. }
  24091.  
  24092. - var->flags |= flags;
  24093. + SetBits( var->flags, flags );
  24094.  
  24095. // only allow one non-empty reset string without a warning
  24096. - if( !var->reset_string[0] )
  24097. + if( var->reset_string != NULL && !var->reset_string[0] )
  24098. {
  24099. // we don't have a reset string yet
  24100. Mem_Free( var->reset_string );
  24101. @@ -220,7 +221,7 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
  24102. }
  24103.  
  24104. // if we have a latched string, take that value now
  24105. - if( var->latched_string )
  24106. + if( var->latched_string != NULL )
  24107. {
  24108. char *s = var->latched_string;
  24109. var->latched_string = NULL; // otherwise cvar_set2 would free it
  24110. @@ -228,12 +229,13 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
  24111. Mem_Free( s );
  24112. }
  24113.  
  24114. - if( var_desc )
  24115. + if( var_desc != NULL )
  24116. {
  24117. // update description if needs
  24118. if( var->description ) Mem_Free( var->description );
  24119. var->description = copystring( var_desc );
  24120. }
  24121. +
  24122. return var;
  24123. }
  24124.  
  24125. @@ -248,9 +250,24 @@ convar_t *Cvar_Get( const char *var_name, const char *var_value, int flags, cons
  24126. var->modified = true;
  24127. var->flags = flags;
  24128.  
  24129. - // link the variable in
  24130. - var->next = cvar_vars;
  24131. - cvar_vars = var;
  24132. + // link the variable in alphanumerical order
  24133. + for( cur = NULL, find = cvar_vars; find && Q_strcmp( find->name, var->name ) < 0; cur = find, find = find->next );
  24134. +
  24135. + if( cur ) cur->next = var;
  24136. + else cvar_vars = var;
  24137. + var->next = find;
  24138. +
  24139. + if( var->flags & CVAR_USERINFO )
  24140. + userinfo->modified = true; // transmit at next oportunity
  24141. +
  24142. + if( var->flags & CVAR_PHYSICINFO )
  24143. + physinfo->modified = true; // transmit at next oportunity
  24144. +
  24145. + if( var->flags & CVAR_SERVERINFO )
  24146. + serverinfo->modified = true; // transmit at next oportunity
  24147. +
  24148. + if( var->flags & CVAR_RENDERINFO )
  24149. + renderinfo->modified = true; // transmit at next oportunity
  24150.  
  24151. return var;
  24152. }
  24153. @@ -264,7 +281,7 @@ Adds a freestanding variable to the variable list.
  24154. */
  24155. void Cvar_RegisterVariable( cvar_t *var )
  24156. {
  24157. - convar_t **prev, *cur = NULL;
  24158. + convar_t *cur = NULL;
  24159. convar_t *find;
  24160.  
  24161. ASSERT( var != NULL );
  24162. @@ -281,65 +298,67 @@ void Cvar_RegisterVariable( cvar_t *var )
  24163. {
  24164. // this cvar is already registered with Cvar_RegisterVariable
  24165. // so we can't replace it
  24166. - if( cur->flags & CVAR_EXTDLL )
  24167. + if( FBitSet( cur->flags, CVAR_SERVERDLL ))
  24168. {
  24169. MsgDev( D_ERROR, "can't register variable %s, allready defined\n", var->name );
  24170. return;
  24171. }
  24172. - }
  24173. -
  24174. - if( cur )
  24175. - {
  24176. - prev = &cvar_vars;
  24177. -
  24178. - while( 1 )
  24179. + else
  24180. {
  24181. - find = *prev;
  24182. + var->string = cur->string; // we already have right string
  24183. + var->value = Q_atof( var->string );
  24184. + SetBits( var->flags, CVAR_SERVERDLL ); // all cvars passed this function are game cvars
  24185. + var->next = (cvar_t *)cur->next;
  24186.  
  24187. - ASSERT( find != NULL );
  24188. -
  24189. - if( cur == cvar_vars )
  24190. + if( cvar_vars == cur )
  24191. {
  24192. // relink at tail
  24193. cvar_vars = (convar_t *)var;
  24194. - break;
  24195. }
  24196. -
  24197. - // search for previous cvar
  24198. - if( cur != find->next )
  24199. + else
  24200. {
  24201. - prev = &find->next;
  24202. - continue;
  24203. + // otherwise find it somewhere in the list
  24204. + for( find = cvar_vars; find->next != cur; find = find->next );
  24205. +
  24206. + ASSERT( find != NULL );
  24207. +
  24208. + find->next = (convar_t *)var;
  24209. }
  24210.  
  24211. - // link new variable
  24212. - find->next = (convar_t *)var;
  24213. - break;
  24214. + // release current cvar (but keep string)
  24215. + if( cur->name ) Mem_Free( cur->name );
  24216. + if( cur->latched_string ) Mem_Free( cur->latched_string );
  24217. + if( cur->reset_string ) Mem_Free( cur->reset_string );
  24218. + if( cur->description ) Mem_Free( cur->description );
  24219. + Mem_Free( cur );
  24220. }
  24221. -
  24222. - var->string = cur->string; // we already have right string
  24223. - var->value = Q_atof( var->string );
  24224. - var->flags |= CVAR_EXTDLL; // all cvars passed this function are game cvars
  24225. - var->next = (cvar_t *)cur->next;
  24226. -
  24227. - // release current cvar (but keep string)
  24228. - if( cur->name ) Mem_Free( cur->name );
  24229. - if( cur->latched_string ) Mem_Free( cur->latched_string );
  24230. - if( cur->reset_string ) Mem_Free( cur->reset_string );
  24231. - if( cur->description ) Mem_Free( cur->description );
  24232. - Mem_Free( cur );
  24233. }
  24234. else
  24235. {
  24236. // copy the value off, because future sets will Z_Free it
  24237. var->string = copystring( var->string );
  24238. var->value = Q_atof( var->string );
  24239. - var->flags |= CVAR_EXTDLL; // all cvars passed this function are game cvars
  24240. + SetBits( var->flags, CVAR_SERVERDLL ); // all cvars passed this function are game cvars
  24241. +
  24242. + // link the variable in alphanumerical order
  24243. + for( cur = NULL, find = cvar_vars; find && Q_strcmp( find->name, var->name ) < 0; cur = find, find = find->next );
  24244.  
  24245. - // link the variable in
  24246. - var->next = (cvar_t *)cvar_vars;
  24247. - cvar_vars = (convar_t *)var;
  24248. + if( cur ) cur->next = (convar_t *)var;
  24249. + else cvar_vars = (convar_t *)var;
  24250. + var->next = (cvar_t *)find;
  24251. }
  24252. +
  24253. + if( var->flags & CVAR_USERINFO )
  24254. + userinfo->modified = true; // transmit at next oportunity
  24255. +
  24256. + if( var->flags & CVAR_PHYSICINFO )
  24257. + physinfo->modified = true; // transmit at next oportunity
  24258. +
  24259. + if( var->flags & CVAR_SERVERINFO )
  24260. + serverinfo->modified = true; // transmit at next oportunity
  24261. +
  24262. + if( var->flags & CVAR_RENDERINFO )
  24263. + renderinfo->modified = true; // transmit at next oportunity
  24264. }
  24265.  
  24266. /*
  24267. @@ -352,7 +371,6 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24268. convar_t *var;
  24269. const char *pszValue;
  24270. char szNew[MAX_SYSPATH];
  24271. - qboolean dll_variable = false;
  24272.  
  24273. if( !Cvar_ValidateString( var_name, false ))
  24274. {
  24275. @@ -361,6 +379,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24276. }
  24277.  
  24278. var = Cvar_FindVar( var_name );
  24279. +
  24280. if( !var )
  24281. {
  24282. // create it
  24283. @@ -369,14 +388,10 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24284.  
  24285. }
  24286.  
  24287. - // use this check to prevent acessing for unexisting fields
  24288. - // for cvar_t: latched_string, description, etc
  24289. - if( var->flags & CVAR_EXTDLL )
  24290. - dll_variable = true;
  24291. -
  24292. if( !value )
  24293. {
  24294. - if( dll_variable ) value = "0";
  24295. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24296. + value = "0";
  24297. else value = var->reset_string;
  24298. }
  24299.  
  24300. @@ -384,23 +399,24 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24301. return var;
  24302.  
  24303. // any latched values not allowed for game cvars
  24304. - if( dll_variable ) force = true;
  24305. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24306. + force = true;
  24307.  
  24308. if( !force )
  24309. {
  24310. - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG ))
  24311. + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG ))
  24312. {
  24313. MsgDev( D_INFO, "%s is read only.\n", var_name );
  24314. return var;
  24315. }
  24316.  
  24317. - if( var->flags & CVAR_INIT )
  24318. + if( FBitSet( var->flags, CVAR_INIT ))
  24319. {
  24320. MsgDev( D_INFO, "%s is write protected.\n", var_name );
  24321. return var;
  24322. }
  24323.  
  24324. - if( var->flags & ( CVAR_LATCH|CVAR_LATCH_VIDEO ))
  24325. + if( FBitSet( var->flags, CVAR_LATCH ))
  24326. {
  24327. if( var->latched_string )
  24328. {
  24329. @@ -414,16 +430,11 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24330. return var;
  24331. }
  24332.  
  24333. - if( var->flags & CVAR_LATCH && Cvar_VariableInteger( "host_serverstate" ))
  24334. + if( FBitSet( var->flags, CVAR_LATCH ) && Cvar_VariableInteger( "host_serverstate" ))
  24335. {
  24336. MsgDev( D_INFO, "%s will be changed upon restarting.\n", var->name );
  24337. var->latched_string = copystring( value );
  24338. }
  24339. - else if( var->flags & CVAR_LATCH_VIDEO )
  24340. - {
  24341. - MsgDev( D_INFO, "%s will be changed upon restarting video.\n", var->name );
  24342. - var->latched_string = copystring( value );
  24343. - }
  24344. else
  24345. {
  24346. Mem_Free( var->string ); // free the old value string
  24347. @@ -436,7 +447,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24348. return var;
  24349. }
  24350.  
  24351. - if(( var->flags & CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
  24352. + if( FBitSet( var->flags, CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
  24353. {
  24354. MsgDev( D_INFO, "%s is cheat protected.\n", var_name );
  24355. return var;
  24356. @@ -444,7 +455,7 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24357. }
  24358. else
  24359. {
  24360. - if( !dll_variable && var->latched_string )
  24361. + if( !FBitSet( var->flags, CVAR_SERVERDLL ) && var->latched_string )
  24362. {
  24363. Mem_Free( var->latched_string );
  24364. var->latched_string = NULL;
  24365. @@ -453,39 +464,32 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24366.  
  24367. pszValue = value;
  24368.  
  24369. - // This cvar's string must only contain printable characters.
  24370. - // Strip out any other crap.
  24371. - // We'll fill in "empty" if nothing is left
  24372. - if( var->flags & CVAR_PRINTABLEONLY )
  24373. + // this cvar's string must only contain printable characters.
  24374. + // strip out any other crap.
  24375. + // we'll fill in "empty" if nothing is left
  24376. + if( FBitSet( var->flags, CVAR_PRINTABLEONLY ))
  24377. {
  24378. - const char *pS;
  24379. - char *pD;
  24380. + const char *s;
  24381. + char *d;
  24382.  
  24383. - // clear out new string
  24384. szNew[0] = '\0';
  24385. -
  24386. - pS = pszValue;
  24387. - pD = szNew;
  24388. + s = pszValue;
  24389. + d = szNew;
  24390.  
  24391. // step through the string, only copying back in characters that are printable
  24392. - while( *pS )
  24393. + while( *s )
  24394. {
  24395. - if( ((byte)*pS) < 32 || ((byte)*pS) > 255 )
  24396. + if( ((byte)*s) < 32 )
  24397. {
  24398. - pS++;
  24399. + s++;
  24400. continue;
  24401. }
  24402. - *pD++ = *pS++;
  24403. + *d++ = *s++;
  24404. }
  24405. + *d = '\0';
  24406.  
  24407. - // terminate the new string
  24408. - *pD = '\0';
  24409. -
  24410. - // if it's empty, then insert a marker string
  24411. if( !Q_strlen( szNew ))
  24412. - {
  24413. - Q_strcpy( szNew, "default" );
  24414. - }
  24415. + Q_strncpy( szNew, "default", sizeof( szNew ));
  24416.  
  24417. // point the value here.
  24418. pszValue = szNew;
  24419. @@ -495,24 +499,39 @@ convar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force )
  24420. if( !Q_strcmp( pszValue, var->string ))
  24421. return var;
  24422.  
  24423. - if( var->flags & CVAR_USERINFO )
  24424. - userinfo->modified = true; // transmit at next oportunity
  24425. + if( FBitSet( var->flags, CVAR_SERVERNOTIFY ))
  24426. + {
  24427. + if( !FBitSet( var->flags, CVAR_UNLOGGED ))
  24428. + {
  24429. + if( FBitSet( var->flags, CVAR_PROTECTED ))
  24430. + {
  24431. + SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, "***PROTECTED***" );
  24432. + }
  24433. + else
  24434. + {
  24435. + SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, pszValue );
  24436. + }
  24437. + }
  24438. + }
  24439.  
  24440. - if( var->flags & CVAR_PHYSICINFO )
  24441. - physinfo->modified = true; // transmit at next oportunity
  24442. + if( FBitSet( var->flags, CVAR_USERINFO ))
  24443. + userinfo->modified = true; // transmit at next oportunity
  24444.  
  24445. - if( var->flags & CVAR_SERVERINFO )
  24446. - serverinfo->modified = true; // transmit at next oportunity
  24447. + if( FBitSet( var->flags, CVAR_PHYSICINFO ))
  24448. + physinfo->modified = true; // transmit at next oportunity
  24449.  
  24450. - if( var->flags & CVAR_RENDERINFO )
  24451. - renderinfo->modified = true; // transmit at next oportunity
  24452. + if( FBitSet( var->flags, CVAR_SERVERINFO ))
  24453. + serverinfo->modified = true; // transmit at next oportunity
  24454. +
  24455. + if( FBitSet( var->flags, CVAR_RENDERINFO ))
  24456. + renderinfo->modified = true; // transmit at next oportunity
  24457.  
  24458. // free the old value string
  24459. Mem_Free( var->string );
  24460. var->string = copystring( pszValue );
  24461. var->value = Q_atof( var->string );
  24462.  
  24463. - if( !dll_variable )
  24464. + if( !FBitSet( var->flags, CVAR_SERVERDLL ))
  24465. {
  24466. var->integer = Q_atoi( var->string );
  24467. var->modified = true;
  24468. @@ -549,53 +568,33 @@ Cvar_FullSet
  24469. void Cvar_FullSet( const char *var_name, const char *value, int flags )
  24470. {
  24471. convar_t *var;
  24472. - qboolean dll_variable = false;
  24473.  
  24474. - var = Cvar_FindVar( var_name );
  24475. - if( !var )
  24476. + if(( var = Cvar_FindVar( var_name )) == NULL )
  24477. {
  24478. // create it
  24479. Cvar_Get( var_name, value, flags, "" );
  24480. return;
  24481. }
  24482.  
  24483. - // use this check to prevent acessing for unexisting fields
  24484. - // for cvar_t: latechd_string, description, etc
  24485. - if( var->flags & CVAR_EXTDLL )
  24486. - {
  24487. - dll_variable = true;
  24488. - }
  24489. + if( FBitSet( var->flags, CVAR_USERINFO ))
  24490. + userinfo->modified = true; // transmit at next oportunity
  24491.  
  24492. - if( var->flags & CVAR_USERINFO )
  24493. - {
  24494. - // transmit at next oportunity
  24495. - userinfo->modified = true;
  24496. - }
  24497. + if( FBitSet( var->flags, CVAR_PHYSICINFO ))
  24498. + physinfo->modified = true; // transmit at next oportunity
  24499.  
  24500. - if( var->flags & CVAR_PHYSICINFO )
  24501. - {
  24502. - // transmit at next oportunity
  24503. - physinfo->modified = true;
  24504. - }
  24505. + if( FBitSet( var->flags, CVAR_SERVERINFO ))
  24506. + serverinfo->modified = true; // transmit at next oportunity
  24507.  
  24508. - if( var->flags & CVAR_SERVERINFO )
  24509. - {
  24510. - // transmit at next oportunity
  24511. - serverinfo->modified = true;
  24512. - }
  24513. -
  24514. - if( var->flags & CVAR_RENDERINFO )
  24515. - {
  24516. - // transmit at next oportunity
  24517. - renderinfo->modified = true;
  24518. - }
  24519. + if( FBitSet( var->flags, CVAR_RENDERINFO ))
  24520. + renderinfo->modified = true; // transmit at next oportunity
  24521.  
  24522. Mem_Free( var->string ); // free the old value string
  24523. var->string = copystring( value );
  24524. var->value = Q_atof( var->string );
  24525. var->flags = flags;
  24526.  
  24527. - if( dll_variable ) return; // below fields doesn't exist in cvar_t
  24528. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24529. + return; // below fields doesn't exist in cvar_t
  24530.  
  24531. var->integer = Q_atoi( var->string );
  24532. var->modified = true;
  24533. @@ -608,15 +607,17 @@ Cvar_DirectSet
  24534. */
  24535. void Cvar_DirectSet( cvar_t *var, const char *value )
  24536. {
  24537. - cvar_t *test;
  24538. const char *pszValue;
  24539. char szNew[MAX_SYSPATH];
  24540.  
  24541. if( !var ) return; // GET_CVAR_POINTER is failed ?
  24542.  
  24543. // make sure what is really pointer to the cvar
  24544. - test = (cvar_t *)Cvar_FindVar( var->name );
  24545. - ASSERT( var == test );
  24546. + if( var != (cvar_t *)Cvar_FindVar( var->name ))
  24547. + {
  24548. + MsgDev( D_ERROR, "Cvar_DirectSet: invalid pointer to cvar\n" );
  24549. + return;
  24550. + }
  24551.  
  24552. if( value && !Cvar_ValidateString( value, true ))
  24553. {
  24554. @@ -624,60 +625,59 @@ void Cvar_DirectSet( cvar_t *var, const char *value )
  24555. value = "0";
  24556. }
  24557.  
  24558. - if( !value ) value = "0";
  24559. + if( !value )
  24560. + {
  24561. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24562. + value = "0";
  24563. + else value = ((convar_t *)var)->reset_string;
  24564. + }
  24565.  
  24566. - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_LATCH|CVAR_LATCH_VIDEO ))
  24567. + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_LATCH ))
  24568. {
  24569. // Cvar_DirectSet cannot change these cvars at all
  24570. return;
  24571. }
  24572.  
  24573. - if(( var->flags & CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
  24574. + if( FBitSet( var->flags, CVAR_CHEAT ) && !Cvar_VariableInteger( "sv_cheats" ))
  24575. {
  24576. - // cheats are disabled
  24577. + MsgDev( D_INFO, "%s is cheat protected.\n", var->name );
  24578. return;
  24579. }
  24580.  
  24581. pszValue = value;
  24582.  
  24583. - // This cvar's string must only contain printable characters.
  24584. - // Strip out any other crap.
  24585. - // We'll fill in "empty" if nothing is left
  24586. - if( var->flags & CVAR_PRINTABLEONLY )
  24587. + // this cvar's string must only contain printable characters.
  24588. + // strip out any other crap.
  24589. + // we'll fill in "empty" if nothing is left
  24590. + if( FBitSet( var->flags, CVAR_PRINTABLEONLY ))
  24591. {
  24592. - const char *pS;
  24593. - char *pD;
  24594. + const char *s;
  24595. + char *d;
  24596.  
  24597. - // clear out new string
  24598. szNew[0] = '\0';
  24599. -
  24600. - pS = pszValue;
  24601. - pD = szNew;
  24602. + s = pszValue;
  24603. + d = szNew;
  24604.  
  24605. // step through the string, only copying back in characters that are printable
  24606. - while( *pS )
  24607. + while( *s )
  24608. {
  24609. - if( *pS < 32 || *pS > 255 )
  24610. + if( ((byte)*s) < 32 )
  24611. {
  24612. - pS++;
  24613. + s++;
  24614. continue;
  24615. }
  24616. - *pD++ = *pS++;
  24617. + *d++ = *s++;
  24618. }
  24619. + *d = '\0';
  24620.  
  24621. - // terminate the new string
  24622. - *pD = '\0';
  24623. -
  24624. - // if it's empty, then insert a marker string
  24625. if( !Q_strlen( szNew ))
  24626. - {
  24627. - Q_strcpy( szNew, "default" );
  24628. - }
  24629. + Q_strncpy( szNew, "default", sizeof( szNew ));
  24630.  
  24631. // point the value here.
  24632. pszValue = szNew;
  24633. }
  24634.  
  24635. + // nothing to change
  24636. if( !Q_strcmp( pszValue, var->string ))
  24637. return;
  24638.  
  24639. @@ -697,6 +697,12 @@ void Cvar_DirectSet( cvar_t *var, const char *value )
  24640. Mem_Free( var->string );
  24641. var->string = copystring( pszValue );
  24642. var->value = Q_atof( var->string );
  24643. +
  24644. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24645. + return; // below fields doesn't exist in cvar_t
  24646. +
  24647. + ((convar_t *)var)->integer = Q_atoi( var->string );
  24648. + ((convar_t *)var)->modified = true;
  24649. }
  24650.  
  24651. /*
  24652. @@ -739,10 +745,10 @@ void Cvar_SetCheatState( void )
  24653. for( var = cvar_vars; var; var = var->next )
  24654. {
  24655. // can't process dll cvars - missed latched_string, reset_string
  24656. - if( var->flags & CVAR_EXTDLL )
  24657. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24658. continue;
  24659.  
  24660. - if( var->flags & CVAR_CHEAT )
  24661. + if( FBitSet( var->flags, CVAR_CHEAT ))
  24662. {
  24663. // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
  24664. // because of a different var->latched_string
  24665. @@ -753,9 +759,7 @@ void Cvar_SetCheatState( void )
  24666. }
  24667.  
  24668. if( Q_strcmp( var->reset_string, var->string ))
  24669. - {
  24670. Cvar_Set( var->name, var->reset_string );
  24671. - }
  24672. }
  24673. }
  24674. }
  24675. @@ -778,7 +782,8 @@ qboolean Cvar_Command( void )
  24676. // perform a variable print or set
  24677. if( Cmd_Argc() == 1 )
  24678. {
  24679. - if( v->flags & ( CVAR_INIT|CVAR_EXTDLL )) Msg( "%s: %s\n", v->name, v->string );
  24680. + if( FBitSet( v->flags, CVAR_INIT|CVAR_SERVERDLL ))
  24681. + Msg( "%s: %s\n", v->name, v->string );
  24682. else Msg( "%s: %s ( ^3%s^7 )\n", v->name, v->string, v->reset_string );
  24683. return true;
  24684. }
  24685. @@ -805,8 +810,7 @@ void Cvar_Toggle_f( void )
  24686. return;
  24687. }
  24688.  
  24689. - v = Cvar_VariableValue( Cmd_Argv( 1 ));
  24690. - v = !v;
  24691. + v = !Cvar_VariableInteger( Cmd_Argv( 1 ));
  24692.  
  24693. Cvar_Set2( Cmd_Argv( 1 ), va( "%i", v ), false );
  24694. }
  24695. @@ -825,16 +829,18 @@ void Cvar_Set_f( void )
  24696. char combined[MAX_CMD_TOKENS];
  24697.  
  24698. c = Cmd_Argc();
  24699. +
  24700. if( c < 3 )
  24701. {
  24702. Msg( "Usage: set <variable> <value>\n" );
  24703. return;
  24704. }
  24705. - combined[0] = 0;
  24706. +
  24707. + combined[0] = '\0';
  24708.  
  24709. for( i = 2; i < c; i++ )
  24710. {
  24711. - len = Q_strlen( Cmd_Argv(i) + 1 );
  24712. + len = Q_strlen( Cmd_Argv( i ) + 1 );
  24713. if( l + len >= MAX_CMD_TOKENS - 2 )
  24714. break;
  24715. Q_strcat( combined, Cmd_Argv( i ));
  24716. @@ -866,7 +872,7 @@ void Cvar_SetU_f( void )
  24717. v = Cvar_FindVar( Cmd_Argv( 1 ));
  24718.  
  24719. if( !v ) return;
  24720. - v->flags |= CVAR_USERINFO;
  24721. + SetBits( v->flags, CVAR_USERINFO );
  24722. }
  24723.  
  24724. /*
  24725. @@ -890,7 +896,7 @@ void Cvar_SetP_f( void )
  24726. v = Cvar_FindVar( Cmd_Argv( 1 ));
  24727.  
  24728. if( !v ) return;
  24729. - v->flags |= CVAR_PHYSICINFO;
  24730. + SetBits( v->flags, CVAR_PHYSICINFO );
  24731. }
  24732.  
  24733. /*
  24734. @@ -909,11 +915,12 @@ void Cvar_SetS_f( void )
  24735. Msg( "Usage: sets <variable> <value>\n" );
  24736. return;
  24737. }
  24738. +
  24739. Cvar_Set_f();
  24740. v = Cvar_FindVar( Cmd_Argv( 1 ));
  24741.  
  24742. if( !v ) return;
  24743. - v->flags |= CVAR_SERVERINFO;
  24744. + SetBits( v->flags, CVAR_SERVERINFO );
  24745. }
  24746.  
  24747. /*
  24748. @@ -937,7 +944,7 @@ void Cvar_SetA_f( void )
  24749. v = Cvar_FindVar( Cmd_Argv( 1 ));
  24750.  
  24751. if( !v ) return;
  24752. - v->flags |= CVAR_ARCHIVE;
  24753. + SetBits( v->flags, CVAR_ARCHIVE );
  24754. }
  24755.  
  24756. /*
  24757. @@ -988,6 +995,7 @@ void Cvar_Reset_f( void )
  24758. Msg( "Usage: reset <variable>\n" );
  24759. return;
  24760. }
  24761. +
  24762. Cvar_Reset( Cmd_Argv( 1 ));
  24763. }
  24764.  
  24765. @@ -1000,12 +1008,13 @@ void Cvar_List_f( void )
  24766. {
  24767. convar_t *var;
  24768. char *match = NULL;
  24769. - int i = 0, j = 0;
  24770. + char *value;
  24771. + int i = 0;
  24772.  
  24773. if( Cmd_Argc() > 1 )
  24774. match = Cmd_Argv( 1 );
  24775.  
  24776. - for( var = cvar_vars; var; var = var->next, i++ )
  24777. + for( var = cvar_vars; var; var = var->next )
  24778. {
  24779. if( var->name[0] == '@' )
  24780. continue; // never shows system cvars
  24781. @@ -1013,44 +1022,17 @@ void Cvar_List_f( void )
  24782. if( match && !Q_stricmpext( match, var->name ))
  24783. continue;
  24784.  
  24785. - if( var->flags & CVAR_SERVERINFO ) Msg( "SV " );
  24786. - else Msg( " " );
  24787. -
  24788. - if( var->flags & CVAR_USERINFO ) Msg( "USER " );
  24789. - else Msg( " " );
  24790. -
  24791. - if( var->flags & CVAR_PHYSICINFO ) Msg( "PHYS " );
  24792. - else Msg( " " );
  24793. -
  24794. - if( var->flags & CVAR_READ_ONLY ) Msg( "READ " );
  24795. - else Msg( " " );
  24796. -
  24797. - if( var->flags & CVAR_INIT ) Msg( "INIT " );
  24798. - else Msg( " " );
  24799. -
  24800. - if( var->flags & CVAR_ARCHIVE ) Msg( "ARCH " );
  24801. - else Msg( " " );
  24802. + if( Q_colorstr( var->string ))
  24803. + value = va( "\"%s\"", var->string );
  24804. + else value = va( "\"^2%s^7\"", var->string );
  24805.  
  24806. - if( var->flags & CVAR_LATCH ) Msg( "LATCH " );
  24807. - else Msg( " " );
  24808. -
  24809. - if( var->flags & CVAR_LATCH_VIDEO ) Msg( "VIDEO " );
  24810. - else Msg( " " );
  24811. -
  24812. - if( var->flags & CVAR_GLCONFIG ) Msg( "OPENGL" );
  24813. - else Msg( " " );
  24814. -
  24815. - if( var->flags & CVAR_CHEAT ) Msg( "CHEAT " );
  24816. - else Msg( " " );
  24817. -
  24818. - if( var->flags & CVAR_EXTDLL )
  24819. - Msg(" %s \"%s\" %s\n", var->name, var->string, "game cvar" );
  24820. - else Msg(" %s \"%s\" %s\n", var->name, var->string, var->description );
  24821. - j++;
  24822. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24823. + Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, "server cvar" );
  24824. + else Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, var->description );
  24825. + i++;
  24826. }
  24827.  
  24828. - Msg( "\n%i cvars\n", j );
  24829. - Msg( "%i total cvars\n", i );
  24830. + Msg( "\n%i cvars\n", i );
  24831. }
  24832.  
  24833. /*
  24834. @@ -1072,16 +1054,15 @@ void Cvar_Restart_f( void )
  24835. var = *prev;
  24836. if( !var ) break;
  24837.  
  24838. - // don't mess with rom values, or some inter-module
  24839. - // communication will get broken (cl.active, etc)
  24840. - if( var->flags & ( CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_EXTDLL ))
  24841. + // don't mess with rom values, or some inter-module communication will get broken (cl.active, etc)
  24842. + if( FBitSet( var->flags, CVAR_READ_ONLY|CVAR_GLCONFIG|CVAR_INIT|CVAR_RENDERINFO|CVAR_SERVERDLL ))
  24843. {
  24844. prev = &var->next;
  24845. continue;
  24846. }
  24847.  
  24848. // throw out any variables the user created
  24849. - if( var->flags & CVAR_USER_CREATED )
  24850. + if( FBitSet( var->flags, CVAR_USER_CREATED ))
  24851. {
  24852. *prev = var->next;
  24853. if( var->name ) Mem_Free( var->name );
  24854. @@ -1118,113 +1099,51 @@ void Cvar_Latched_f( void )
  24855. var = *prev;
  24856. if( !var ) break;
  24857.  
  24858. - if( var->flags & CVAR_EXTDLL )
  24859. + if( FBitSet( var->flags, CVAR_SERVERDLL ))
  24860. {
  24861. prev = &var->next;
  24862. continue;
  24863. }
  24864.  
  24865. - if( var->flags & CVAR_LATCH && var->latched_string )
  24866. + if( FBitSet( var->flags, CVAR_LATCH ) && var->latched_string )
  24867. {
  24868. Cvar_FullSet( var->name, var->latched_string, var->flags );
  24869. Mem_Free( var->latched_string );
  24870. var->latched_string = NULL;
  24871. }
  24872. - prev = &var->next;
  24873. - }
  24874. -}
  24875. -
  24876. -/*
  24877. -============
  24878. -Cvar_LatchedVideo_f
  24879. -
  24880. -Now all latched video strings is valid
  24881. -============
  24882. -*/
  24883. -void Cvar_LatchedVideo_f( void )
  24884. -{
  24885. - convar_t *var;
  24886. - convar_t **prev;
  24887. -
  24888. - prev = &cvar_vars;
  24889. -
  24890. - while ( 1 )
  24891. - {
  24892. - var = *prev;
  24893. - if( !var ) break;
  24894. -
  24895. - if( var->flags & CVAR_EXTDLL )
  24896. - {
  24897. - prev = &var->next;
  24898. - continue;
  24899. - }
  24900.  
  24901. - if( var->flags & CVAR_LATCH_VIDEO && var->latched_string )
  24902. - {
  24903. - Cvar_FullSet( var->name, var->latched_string, var->flags );
  24904. - Mem_Free( var->latched_string );
  24905. - var->latched_string = NULL;
  24906. - }
  24907. prev = &var->next;
  24908. }
  24909. }
  24910.  
  24911. /*
  24912. ============
  24913. -Cvar_Unlink_f
  24914. +Cvar_Unlink
  24915.  
  24916. -unlink all cvars with flag CVAR_EXTDLL
  24917. +unlink all cvars with specified flag
  24918. ============
  24919. */
  24920. -void Cvar_Unlink_f( void )
  24921. +void Cvar_Unlink( int group )
  24922. {
  24923. convar_t *var;
  24924. convar_t **prev;
  24925. int count = 0;
  24926.  
  24927. - if( Cvar_VariableInteger( "host_gameloaded" ))
  24928. + if( Cvar_VariableInteger( "host_gameloaded" ) && FBitSet( group, CVAR_SERVERDLL ))
  24929. {
  24930. - MsgDev( D_NOTE, "can't unlink cvars while game is loaded\n" );
  24931. + MsgDev( D_INFO, "can't unlink variables while server is loaded\n" );
  24932. return;
  24933. }
  24934.  
  24935. - prev = &cvar_vars;
  24936. -
  24937. - while( 1 )
  24938. + if( Cvar_VariableInteger( "host_clientloaded" ) && FBitSet( group, CVAR_CLIENTDLL ))
  24939. {
  24940. - var = *prev;
  24941. - if( !var ) break;
  24942. -
  24943. - // ignore all non-game cvars
  24944. - if( !( var->flags & CVAR_EXTDLL ))
  24945. - {
  24946. - prev = &var->next;
  24947. - continue;
  24948. - }
  24949. -
  24950. - // throw out any variables the game created
  24951. - *prev = var->next;
  24952. - if( var->string ) Mem_Free( var->string );
  24953. - count++;
  24954. + MsgDev( D_INFO, "can't unlink variables while client is loaded\n" );
  24955. + return;
  24956. }
  24957. -}
  24958. -
  24959. -/*
  24960. -============
  24961. -Cvar_Unlink
  24962. -
  24963. -unlink all cvars with flag CVAR_CLIENTDLL
  24964. -============
  24965. -*/
  24966. -void Cvar_Unlink( void )
  24967. -{
  24968. - convar_t *var;
  24969. - convar_t **prev;
  24970. - int count = 0;
  24971.  
  24972. - if( Cvar_VariableInteger( "host_clientloaded" ))
  24973. + if( Cvar_VariableInteger( "host_gameuiloaded" ) && FBitSet( group, CVAR_GAMEUIDLL ))
  24974. {
  24975. - MsgDev( D_NOTE, "can't unlink cvars while client is loaded\n" );
  24976. + MsgDev( D_INFO, "can't unlink variables while GameUI is loaded\n" );
  24977. return;
  24978. }
  24979.  
  24980. @@ -1235,8 +1154,8 @@ void Cvar_Unlink( void )
  24981. var = *prev;
  24982. if( !var ) break;
  24983.  
  24984. - // ignore all non-client cvars
  24985. - if(!( var->flags & CVAR_CLIENTDLL ))
  24986. + // do filter by specified group
  24987. + if( group && !FBitSet( var->flags, group ))
  24988. {
  24989. prev = &var->next;
  24990. continue;
  24991. @@ -1244,12 +1163,17 @@ void Cvar_Unlink( void )
  24992.  
  24993. // throw out any variables the game created
  24994. *prev = var->next;
  24995. - if( var->name ) Mem_Free( var->name );
  24996. if( var->string ) Mem_Free( var->string );
  24997. - if( var->latched_string ) Mem_Free( var->latched_string );
  24998. - if( var->reset_string ) Mem_Free( var->reset_string );
  24999. - if( var->description ) Mem_Free( var->description );
  25000. - Mem_Free( var );
  25001. +
  25002. + if( !FBitSet( var->flags, CVAR_SERVERDLL ))
  25003. + {
  25004. + if( var->name ) Mem_Free( var->name );
  25005. + if( var->latched_string ) Mem_Free( var->latched_string );
  25006. + if( var->reset_string ) Mem_Free( var->reset_string );
  25007. + if( var->description ) Mem_Free( var->description );
  25008. + Mem_Free( var );
  25009. + }
  25010. +
  25011. count++;
  25012. }
  25013. }
  25014. @@ -1268,19 +1192,18 @@ void Cvar_Init( void )
  25015. physinfo = Cvar_Get( "@physinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
  25016. serverinfo = Cvar_Get( "@serverinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
  25017. renderinfo = Cvar_Get( "@renderinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only
  25018. -
  25019. - Cmd_AddCommand ("toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
  25020. - Cmd_AddCommand ("set", Cvar_Set_f, "create or change the value of a console variable" );
  25021. - Cmd_AddCommand ("sets", Cvar_SetS_f, "create or change the value of a serverinfo variable" );
  25022. - Cmd_AddCommand ("setu", Cvar_SetU_f, "create or change the value of a userinfo variable" );
  25023. - Cmd_AddCommand ("setp", Cvar_SetP_f, "create or change the value of a physicinfo variable" );
  25024. - Cmd_AddCommand ("setr", Cvar_SetR_f, "create or change the value of a renderinfo variable" );
  25025. - Cmd_AddCommand ("setgl", Cvar_SetGL_f, "create or change the value of a opengl variable" );
  25026. - Cmd_AddCommand ("seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg" );
  25027. - Cmd_AddCommand ("reset", Cvar_Reset_f, "reset any type variable to initial value" );
  25028. - Cmd_AddCommand ("latch", Cvar_Latched_f, "apply latched values" );
  25029. - Cmd_AddCommand ("vidlatch", Cvar_LatchedVideo_f, "apply latched values for video subsystem" );
  25030. - Cmd_AddCommand ("cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
  25031. - Cmd_AddCommand ("unsetall", Cvar_Restart_f, "reset all console variables to their default values" );
  25032. - Cmd_AddCommand ("@unlink", Cvar_Unlink_f, "unlink static cvars defined in gamedll" );
  25033. -}
  25034. + cmd_scripting = Cvar_Get( "cmd_scripting", "0", CVAR_ARCHIVE, "enable simple condition checking and variable operations" );
  25035. +
  25036. + Cmd_AddCommand( "toggle", Cvar_Toggle_f, "toggles a console variable's values (use for more info)" );
  25037. + Cmd_AddCommand( "set", Cvar_Set_f, "create or change the value of a console variable" );
  25038. + Cmd_AddCommand( "sets", Cvar_SetS_f, "create or change the value of a serverinfo variable" );
  25039. + Cmd_AddCommand( "setu", Cvar_SetU_f, "create or change the value of a userinfo variable" );
  25040. + Cmd_AddCommand( "setp", Cvar_SetP_f, "create or change the value of a physicinfo variable" );
  25041. + Cmd_AddCommand( "setr", Cvar_SetR_f, "create or change the value of a renderinfo variable" );
  25042. + Cmd_AddCommand( "setgl", Cvar_SetGL_f, "create or change the value of a opengl variable" );
  25043. + Cmd_AddCommand( "seta", Cvar_SetA_f, "create or change the value of a console variable that will be saved to config.cfg" );
  25044. + Cmd_AddCommand( "reset", Cvar_Reset_f, "reset any type variable to initial value" );
  25045. + Cmd_AddCommand( "latch", Cvar_Latched_f, "apply latched values" );
  25046. + Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
  25047. + Cmd_AddCommand( "unsetall", Cvar_Restart_f, "reset all console variables to their default values" );
  25048. +}
  25049. \ No newline at end of file
  25050. diff --git b/engine/common/filesystem.c a/engine/common/filesystem.c
  25051. index a32fa7c..0a184ab 100644
  25052. --- b/engine/common/filesystem.c
  25053. +++ a/engine/common/filesystem.c
  25054. @@ -24,14 +24,26 @@ GNU General Public License for more details.
  25055. #include "library.h"
  25056. #include "mathlib.h"
  25057.  
  25058. -#define FILE_BUFF_SIZE 2048
  25059. +#define FILE_COPY_SIZE (1024 * 1024)
  25060. +#define FILE_BUFF_SIZE (65535)
  25061. +
  25062. +// PAK errors
  25063. #define PAK_LOAD_OK 0
  25064. #define PAK_LOAD_COULDNT_OPEN 1
  25065. #define PAK_LOAD_BAD_HEADER 2
  25066. #define PAK_LOAD_BAD_FOLDERS 3
  25067. #define PAK_LOAD_TOO_MANY_FILES 4
  25068. #define PAK_LOAD_NO_FILES 5
  25069. -#define PAK_LOAD_CORRUPTED 6
  25070. +#define PAK_LOAD_CORRUPTED 6
  25071. +
  25072. +// WAD errors
  25073. +#define WAD_LOAD_OK 0
  25074. +#define WAD_LOAD_COULDNT_OPEN 1
  25075. +#define WAD_LOAD_BAD_HEADER 2
  25076. +#define WAD_LOAD_BAD_FOLDERS 3
  25077. +#define WAD_LOAD_TOO_MANY_FILES 4
  25078. +#define WAD_LOAD_NO_FILES 5
  25079. +#define WAD_LOAD_CORRUPTED 6
  25080.  
  25081. typedef struct stringlist_s
  25082. {
  25083. @@ -50,19 +62,19 @@ typedef struct wadtype_s
  25084. typedef struct file_s
  25085. {
  25086. int handle; // file descriptor
  25087. - fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
  25088. - fs_offset_t position; // current position in the file
  25089. - fs_offset_t offset; // offset into the package (0 if external file)
  25090. + long real_length; // uncompressed file size (for files opened in "read" mode)
  25091. + long position; // current position in the file
  25092. + long offset; // offset into the package (0 if external file)
  25093. int ungetc; // single stored character from ungetc, cleared to EOF when read
  25094. time_t filetime; // pak, wad or real filetime
  25095. - // Contents buffer
  25096. - fs_offset_t buff_ind, buff_len; // buffer current index and length
  25097. + // contents buffer
  25098. + long buff_ind, buff_len; // buffer current index and length
  25099. byte buff[FILE_BUFF_SIZE]; // intermediate buffer
  25100. };
  25101.  
  25102. typedef struct wfile_s
  25103. {
  25104. - char filename[MAX_SYSPATH];
  25105. + string filename;
  25106. int infotableofs;
  25107. byte *mempool; // W_ReadLump temp buffers
  25108. int numlumps;
  25109. @@ -72,47 +84,41 @@ typedef struct wfile_s
  25110. time_t filetime;
  25111. };
  25112.  
  25113. -typedef struct packfile_s
  25114. -{
  25115. - char name[56];
  25116. - fs_offset_t offset;
  25117. - fs_offset_t realsize; // real file size (uncompressed)
  25118. -} packfile_t;
  25119. -
  25120. typedef struct pack_s
  25121. {
  25122. - char filename[MAX_SYSPATH];
  25123. + string filename;
  25124. int handle;
  25125. int numfiles;
  25126. time_t filetime; // common for all packed files
  25127. - packfile_t *files;
  25128. + dpackfile_t *files;
  25129. } pack_t;
  25130.  
  25131. typedef struct searchpath_s
  25132. {
  25133. - char filename[MAX_SYSPATH];
  25134. + string filename;
  25135. pack_t *pack;
  25136. wfile_t *wad;
  25137. int flags;
  25138. struct searchpath_s *next;
  25139. } searchpath_t;
  25140.  
  25141. -byte *fs_mempool;
  25142. -searchpath_t *fs_searchpaths = NULL;
  25143. -searchpath_t fs_directpath; // static direct path
  25144. -char fs_rootdir[MAX_SYSPATH]; // engine root directory
  25145. -char fs_basedir[MAX_SYSPATH]; // base directory of game
  25146. -char fs_falldir[MAX_SYSPATH]; // game falling directory
  25147. -char fs_gamedir[MAX_SYSPATH]; // game current directory
  25148. -char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too)
  25149. -qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
  25150. +byte *fs_mempool;
  25151. +searchpath_t *fs_searchpaths = NULL; // chain
  25152. +searchpath_t fs_directpath; // static direct path
  25153. +char fs_rootdir[MAX_SYSPATH]; // engine root directory
  25154. +char fs_basedir[MAX_SYSPATH]; // base directory of game
  25155. +char fs_falldir[MAX_SYSPATH]; // game falling directory
  25156. +char fs_gamedir[MAX_SYSPATH]; // game current directory
  25157. +char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too)
  25158. +qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
  25159. +static const wadtype_t wad_hints[10];
  25160.  
  25161. static void FS_InitMemory( void );
  25162. const char *FS_FileExtension( const char *in );
  25163. static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
  25164. static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype );
  25165. -static packfile_t* FS_AddFileToPack( const char* name, pack_t *pack, fs_offset_t offset, fs_offset_t size );
  25166. -static byte *W_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
  25167. +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size );
  25168. +static byte *W_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
  25169. static qboolean FS_SysFileExists( const char *path );
  25170. static qboolean FS_SysFolderExists( const char *path );
  25171. static long FS_SysFileTime( const char *filename );
  25172. @@ -126,56 +132,53 @@ FILEMATCH COMMON SYSTEM
  25173.  
  25174. =============================================================================
  25175. */
  25176. -int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive )
  25177. +int matchpattern( const char *str, const char *cmp, qboolean caseinsensitive )
  25178. {
  25179. int c1, c2;
  25180.  
  25181. - while( *pattern )
  25182. + while( *cmp )
  25183. {
  25184. - switch( *pattern )
  25185. + switch( *cmp )
  25186. {
  25187. case 0: return 1; // end of pattern
  25188. case '?': // match any single character
  25189. - if( *in == 0 || *in == '/' || *in == '\\' || *in == ':' )
  25190. + if( *str == 0 || *str == '/' || *str == '\\' || *str == ':' )
  25191. return 0; // no match
  25192. - in++;
  25193. - pattern++;
  25194. + str++;
  25195. + cmp++;
  25196. break;
  25197. case '*': // match anything until following string
  25198. - if( !*in ) return 1; // match
  25199. - pattern++;
  25200. - while( *in )
  25201. + if( !*str ) return 1; // match
  25202. + cmp++;
  25203. + while( *str )
  25204. {
  25205. - if( *in == '/' || *in == '\\' || *in == ':' )
  25206. + if( *str == '/' || *str == '\\' || *str == ':' )
  25207. break;
  25208. // see if pattern matches at this offset
  25209. - if( matchpattern( in, pattern, caseinsensitive ))
  25210. + if( matchpattern( str, cmp, caseinsensitive ))
  25211. return 1;
  25212. // nope, advance to next offset
  25213. - in++;
  25214. + str++;
  25215. }
  25216. break;
  25217. default:
  25218. - if( *in != *pattern )
  25219. + if( *str != *cmp )
  25220. {
  25221. if( !caseinsensitive )
  25222. return 0; // no match
  25223. - c1 = *in;
  25224. - if( c1 >= 'A' && c1 <= 'Z' )
  25225. - c1 += 'a' - 'A';
  25226. - c2 = *pattern;
  25227. - if( c2 >= 'A' && c2 <= 'Z' )
  25228. - c2 += 'a' - 'A';
  25229. - if( c1 != c2) return 0; // no match
  25230. + c1 = Q_tolower( *str );
  25231. + c2 = Q_tolower( *cmp );
  25232. + if( c1 != c2 ) return 0; // no match
  25233. }
  25234. - in++;
  25235. - pattern++;
  25236. +
  25237. + str++;
  25238. + cmp++;
  25239. break;
  25240. }
  25241. }
  25242.  
  25243. - if( *in ) return 0; // reached end of pattern but not end of input
  25244. - return 1; // success
  25245. + // reached end of pattern but not end of input?
  25246. + return (*str) ? 0 : 1;
  25247. }
  25248.  
  25249. void stringlistinit( stringlist_t *list )
  25250. @@ -194,23 +197,25 @@ void stringlistfreecontents( stringlist_t *list )
  25251. list->strings[i] = NULL;
  25252. }
  25253.  
  25254. + if( list->strings )
  25255. + Mem_Free( list->strings );
  25256. +
  25257. list->numstrings = 0;
  25258. list->maxstrings = 0;
  25259. - if( list->strings ) Mem_Free( list->strings );
  25260. + list->strings = NULL;
  25261. }
  25262.  
  25263. void stringlistappend( stringlist_t *list, char *text )
  25264. {
  25265. size_t textlen;
  25266. - char **oldstrings;
  25267. +
  25268. + if( !Q_stricmp( text, "." ) || !Q_stricmp( text, ".." ))
  25269. + return; // ignore the virtual directories
  25270.  
  25271. if( list->numstrings >= list->maxstrings )
  25272. {
  25273. - oldstrings = list->strings;
  25274. list->maxstrings += 4096;
  25275. - list->strings = Mem_Alloc( fs_mempool, list->maxstrings * sizeof( *list->strings ));
  25276. - if( list->numstrings ) memcpy( list->strings, oldstrings, list->numstrings * sizeof( *list->strings ));
  25277. - if( oldstrings ) Mem_Free( oldstrings );
  25278. + list->strings = Mem_Realloc( fs_mempool, list->strings, list->maxstrings * sizeof( *list->strings ));
  25279. }
  25280.  
  25281. textlen = Q_strlen( text ) + 1;
  25282. @@ -221,8 +226,8 @@ void stringlistappend( stringlist_t *list, char *text )
  25283.  
  25284. void stringlistsort( stringlist_t *list )
  25285. {
  25286. - int i, j;
  25287. char *temp;
  25288. + int i, j;
  25289.  
  25290. // this is a selection sort (finds the best entry for each slot)
  25291. for( i = 0; i < list->numstrings - 1; i++ )
  25292. @@ -241,10 +246,11 @@ void stringlistsort( stringlist_t *list )
  25293.  
  25294. void listdirectory( stringlist_t *list, const char *path )
  25295. {
  25296. - int i;
  25297. - char pattern[4096], *c;
  25298. + char pattern[4096];
  25299. struct _finddata_t n_file;
  25300. long hFile;
  25301. + char *c;
  25302. + int i;
  25303.  
  25304. Q_strncpy( pattern, path, sizeof( pattern ));
  25305. Q_strncat( pattern, "*", sizeof( pattern ));
  25306. @@ -264,10 +270,7 @@ void listdirectory( stringlist_t *list, const char *path )
  25307. for( i = 0; i < list->numstrings; i++ )
  25308. {
  25309. for( c = list->strings[i]; *c; c++ )
  25310. - {
  25311. - if( *c >= 'A' && *c <= 'Z' )
  25312. - *c += 'a' - 'A';
  25313. - }
  25314. + *c = Q_tolower( *c );
  25315. }
  25316. }
  25317.  
  25318. @@ -285,10 +288,10 @@ FS_AddFileToPack
  25319. Add a file to the list of files contained into a package
  25320. ====================
  25321. */
  25322. -static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t size )
  25323. +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset, long size )
  25324. {
  25325. int left, right, middle;
  25326. - packfile_t *pfile;
  25327. + dpackfile_t *pfile;
  25328.  
  25329. // look for the slot we should put that file into (binary search)
  25330. left = 0;
  25331. @@ -301,7 +304,7 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t
  25332. diff = Q_stricmp( pack->files[middle].name, name );
  25333.  
  25334. // If we found the file, there's a problem
  25335. - if( !diff ) MsgDev( D_NOTE, "Package %s contains the file %s several times\n", pack->filename, name );
  25336. + if( !diff ) MsgDev( D_WARN, "Package %s contains the file %s several times\n", pack->filename, name );
  25337.  
  25338. // If we're too far in the list
  25339. if( diff > 0 ) right = middle - 1;
  25340. @@ -314,8 +317,8 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t
  25341. pack->numfiles++;
  25342.  
  25343. Q_strncpy( pfile->name, name, sizeof( pfile->name ));
  25344. - pfile->offset = offset;
  25345. - pfile->realsize = size;
  25346. + pfile->filepos = offset;
  25347. + pfile->filelen = size;
  25348.  
  25349. return pfile;
  25350. }
  25351. @@ -363,7 +366,8 @@ void FS_Path_f( void )
  25352. else if( s->wad ) Msg( "%s (%i files)", s->wad->filename, s->wad->numlumps );
  25353. else Msg( "%s", s->filename );
  25354.  
  25355. - if( s->flags & FS_GAMEDIR_PATH ) Msg( " ^2gamedir^7\n" );
  25356. + if( FBitSet( s->flags, FS_GAMEDIR_PATH ))
  25357. + Msg( " ^2gamedir^7\n" );
  25358. else Msg( "\n" );
  25359. }
  25360. }
  25361. @@ -436,8 +440,8 @@ of the list so they override previous pack files.
  25362. pack_t *FS_LoadPackPAK( const char *packfile, int *error )
  25363. {
  25364. dpackheader_t header;
  25365. - int i, numpackfiles;
  25366. int packhandle;
  25367. + int i, numpackfiles;
  25368. pack_t *pack;
  25369. dpackfile_t *info;
  25370.  
  25371. @@ -500,16 +504,14 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
  25372.  
  25373. pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t ));
  25374. Q_strncpy( pack->filename, packfile, sizeof( pack->filename ));
  25375. + pack->files = (dpackfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( dpackfile_t ));
  25376. + pack->filetime = FS_SysFileTime( packfile );
  25377. pack->handle = packhandle;
  25378. pack->numfiles = 0;
  25379. - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t ));
  25380. - pack->filetime = FS_SysFileTime( packfile );
  25381.  
  25382. // parse the directory
  25383. for( i = 0; i < numpackfiles; i++ )
  25384. - {
  25385. FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen );
  25386. - }
  25387.  
  25388. MsgDev( D_NOTE, "Adding packfile: %s (%i files)\n", packfile, numpackfiles );
  25389. if( error ) *error = PAK_LOAD_OK;
  25390. @@ -520,7 +522,7 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
  25391.  
  25392. /*
  25393. ================
  25394. -FS_AddPack_Fullpath
  25395. +FS_AddPak_Fullpath
  25396.  
  25397. Adds the given pack to the search path.
  25398. The pack type is autodetected by the file extension.
  25399. @@ -532,7 +534,7 @@ If keep_plain_dirs is set, the pack will be added AFTER the first sequence of
  25400. plain directories.
  25401. ================
  25402. */
  25403. -static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
  25404. +static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
  25405. {
  25406. searchpath_t *search;
  25407. pack_t *pak = NULL;
  25408. @@ -558,7 +560,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
  25409. if( keep_plain_dirs )
  25410. {
  25411. // find the first item whose next one is a pack or NULL
  25412. - searchpath_t *insertion_point = 0;
  25413. + searchpath_t *insertion_point = NULL;
  25414. if( fs_searchpaths && !fs_searchpaths->pack )
  25415. {
  25416. insertion_point = fs_searchpaths;
  25417. @@ -603,7 +605,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
  25418. else
  25419. {
  25420. if( errorcode != PAK_LOAD_NO_FILES )
  25421. - MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile );
  25422. + MsgDev( D_ERROR, "FS_AddPak_Fullpath: unable to load pak \"%s\"\n", pakfile );
  25423. return false;
  25424. }
  25425. }
  25426. @@ -613,11 +615,12 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load
  25427. FS_AddWad_Fullpath
  25428. ====================
  25429. */
  25430. -static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs )
  25431. +static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags )
  25432. {
  25433. searchpath_t *search;
  25434. wfile_t *wad = NULL;
  25435. const char *ext = FS_FileExtension( wadfile );
  25436. + int errorcode = WAD_LOAD_COULDNT_OPEN;
  25437.  
  25438. for( search = fs_searchpaths; search; search = search->next )
  25439. {
  25440. @@ -629,7 +632,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
  25441. }
  25442.  
  25443. if( already_loaded ) *already_loaded = false;
  25444. - if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb" );
  25445. + if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb", &errorcode );
  25446. else MsgDev( D_ERROR, "\"%s\" doesn't have a wad extension\n", wadfile );
  25447.  
  25448. if( wad )
  25449. @@ -656,6 +659,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
  25450. search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
  25451. search->wad = wad;
  25452. search->next = fs_searchpaths;
  25453. + search->flags |= flags;
  25454. fs_searchpaths = search;
  25455. }
  25456. else // otherwise we want to append directly after insertion_point.
  25457. @@ -663,6 +667,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
  25458. search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
  25459. search->wad = wad;
  25460. search->next = insertion_point->next;
  25461. + search->flags |= flags;
  25462. insertion_point->next = search;
  25463. }
  25464. }
  25465. @@ -671,6 +676,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
  25466. search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t ));
  25467. search->wad = wad;
  25468. search->next = fs_searchpaths;
  25469. + search->flags |= flags;
  25470. fs_searchpaths = search;
  25471. }
  25472.  
  25473. @@ -679,7 +685,8 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade
  25474. }
  25475. else
  25476. {
  25477. - MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
  25478. + if( errorcode != WAD_LOAD_NO_FILES )
  25479. + MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
  25480. return false;
  25481. }
  25482. }
  25483. @@ -699,7 +706,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
  25484. string fullpath;
  25485. int i;
  25486.  
  25487. - if(!( flags & FS_NOWRITE_PATH ))
  25488. + if( !FBitSet( flags, FS_NOWRITE_PATH ))
  25489. Q_strncpy( fs_gamedir, dir, sizeof( fs_gamedir ));
  25490.  
  25491. stringlistinit( &list );
  25492. @@ -712,7 +719,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
  25493. if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "pak" ))
  25494. {
  25495. Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
  25496. - FS_AddPack_Fullpath( fullpath, NULL, false, flags );
  25497. + FS_AddPak_Fullpath( fullpath, NULL, false, flags );
  25498. }
  25499. }
  25500.  
  25501. @@ -722,7 +729,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
  25502. if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "wad" ))
  25503. {
  25504. Q_sprintf( fullpath, "%s%s", dir, list.strings[i] );
  25505. - FS_AddWad_Fullpath( fullpath, NULL, false );
  25506. + FS_AddWad_Fullpath( fullpath, NULL, false, flags );
  25507. }
  25508. }
  25509.  
  25510. @@ -761,13 +768,20 @@ const char *FS_FileExtension( const char *in )
  25511.  
  25512. separator = Q_strrchr( in, '/' );
  25513. backslash = Q_strrchr( in, '\\' );
  25514. - if( !separator || separator < backslash ) separator = backslash;
  25515. +
  25516. + if( !separator || separator < backslash )
  25517. + separator = backslash;
  25518. +
  25519. colon = Q_strrchr( in, ':' );
  25520. - if( !separator || separator < colon ) separator = colon;
  25521. +
  25522. + if( !separator || separator < colon )
  25523. + separator = colon;
  25524.  
  25525. dot = Q_strrchr( in, '.' );
  25526. +
  25527. if( dot == NULL || ( separator && ( dot < separator )))
  25528. return "";
  25529. +
  25530. return dot + 1;
  25531. }
  25532.  
  25533. @@ -782,9 +796,15 @@ const char *FS_FileWithoutPath( const char *in )
  25534.  
  25535. separator = Q_strrchr( in, '/' );
  25536. backslash = Q_strrchr( in, '\\' );
  25537. - if( !separator || separator < backslash ) separator = backslash;
  25538. +
  25539. + if( !separator || separator < backslash )
  25540. + separator = backslash;
  25541. +
  25542. colon = Q_strrchr( in, ':' );
  25543. - if( !separator || separator < colon ) separator = colon;
  25544. +
  25545. + if( !separator || separator < colon )
  25546. + separator = colon;
  25547. +
  25548. return separator ? separator + 1 : in;
  25549. }
  25550.  
  25551. @@ -793,10 +813,9 @@ const char *FS_FileWithoutPath( const char *in )
  25552. FS_ExtractFilePath
  25553. ============
  25554. */
  25555. -void FS_ExtractFilePath( const char* const path, char* dest )
  25556. +void FS_ExtractFilePath( const char *path, char *dest )
  25557. {
  25558. - const char *src;
  25559. - src = path + Q_strlen( path ) - 1;
  25560. + const char *src = path + Q_strlen( path ) - 1;
  25561.  
  25562. // back up until a \ or the start
  25563. while( src != path && !(*(src - 1) == '\\' || *(src - 1) == '/' ))
  25564. @@ -821,7 +840,9 @@ void FS_ClearSearchPath( void )
  25565. {
  25566. searchpath_t *search = fs_searchpaths;
  25567.  
  25568. - if( search->flags & FS_STATIC_PATH )
  25569. + if( !search ) break;
  25570. +
  25571. + if( FBitSet( search->flags, FS_STATIC_PATH ))
  25572. {
  25573. // skip read-only pathes
  25574. if( search->next )
  25575. @@ -841,7 +862,7 @@ void FS_ClearSearchPath( void )
  25576. W_Close( search->wad );
  25577. }
  25578.  
  25579. - if( search ) Mem_Free( search );
  25580. + Mem_Free( search );
  25581. }
  25582. }
  25583.  
  25584. @@ -874,15 +895,7 @@ int FS_CheckNastyPath( const char *path, qboolean isgamedir )
  25585.  
  25586. // Windows and UNIXes: don't allow absolute paths
  25587. if( path[0] == '/' && !fs_ext_path ) return 2; // attempt to go outside the game directory
  25588. -#if 0
  25589. - // all: don't allow . characters before the last slash (it should only be used in filenames, not path elements),
  25590. - // this catches all imaginable cases of ./, ../, .../, etc
  25591. - if( Q_strchr( path, '.' ) && !fs_ext_path )
  25592. - {
  25593. - if( isgamedir ) return 2; // gamedir is entirely path elements, so simply forbid . entirely
  25594. - if( Q_strchr( path, '.' ) < Q_strrchr( path, '/' )) return 2; // possible attempt to go outside the game directory
  25595. - }
  25596. -#endif
  25597. +
  25598. // all: forbid trailing slash on gamedir
  25599. if( isgamedir && !fs_ext_path && path[Q_strlen( path )-1] == '/' ) return 2;
  25600.  
  25601. @@ -912,55 +925,16 @@ void FS_Rescan( void )
  25602. FS_AddGameHierarchy( GI->gamedir, FS_GAMEDIR_PATH );
  25603. }
  25604.  
  25605. +/*
  25606. +================
  25607. +FS_Rescan_f
  25608. +================
  25609. +*/
  25610. void FS_Rescan_f( void )
  25611. {
  25612. FS_Rescan();
  25613. }
  25614.  
  25615. -static qboolean FS_ParseVector( char **pfile, float *v, size_t size )
  25616. -{
  25617. - string token;
  25618. - qboolean bracket = false;
  25619. - char *saved;
  25620. - uint i;
  25621. -
  25622. - if( v == NULL || size == 0 )
  25623. - return false;
  25624. -
  25625. - memset( v, 0, sizeof( *v ) * size );
  25626. -
  25627. - if( size == 1 )
  25628. - {
  25629. - *pfile = COM_ParseFile( *pfile, token );
  25630. - v[0] = Q_atof( token );
  25631. - return true;
  25632. - }
  25633. -
  25634. - saved = *pfile;
  25635. -
  25636. - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
  25637. - return false;
  25638. -
  25639. - if( token[0] == '(' )
  25640. - bracket = true;
  25641. - else *pfile = saved; // restore token to right get it again
  25642. -
  25643. - for( i = 0; i < size; i++ )
  25644. - {
  25645. - *pfile = COM_ParseFile( *pfile, token );
  25646. - v[i] = Q_atof( token );
  25647. - }
  25648. -
  25649. - if( !bracket ) return true; // done
  25650. -
  25651. - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL )
  25652. - return false;
  25653. -
  25654. - if( token[0] == ')' )
  25655. - return true;
  25656. - return false;
  25657. -}
  25658. -
  25659. /*
  25660. ================
  25661. FS_WriteGameInfo
  25662. @@ -1113,6 +1087,11 @@ void FS_CreateDefaultGameInfo( const char *filename )
  25663. FS_WriteGameInfo( filename, &defGI );
  25664. }
  25665.  
  25666. +/*
  25667. +================
  25668. +FS_ParseLiblistGam
  25669. +================
  25670. +*/
  25671. static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo )
  25672. {
  25673. char *afile, *pfile;
  25674. @@ -1461,8 +1440,8 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo )
  25675. }
  25676. else
  25677. {
  25678. - FS_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 );
  25679. - FS_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 );
  25680. + COM_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 );
  25681. + COM_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 );
  25682. }
  25683. }
  25684. else if( !Q_strnicmp( token, "ambient", 7 ))
  25685. @@ -1657,18 +1636,22 @@ static file_t* FS_SysOpen( const char* filepath, const char* mode )
  25686. // Parse the mode string
  25687. switch( mode[0] )
  25688. {
  25689. - case 'r':
  25690. + case 'r': // read
  25691. mod = O_RDONLY;
  25692. opt = 0;
  25693. break;
  25694. - case 'w':
  25695. + case 'w': // write
  25696. mod = O_WRONLY;
  25697. opt = O_CREAT | O_TRUNC;
  25698. break;
  25699. - case 'a':
  25700. + case 'a': // append
  25701. mod = O_WRONLY;
  25702. opt = O_CREAT | O_APPEND;
  25703. break;
  25704. + case 'e': // edit
  25705. + mod = O_WRONLY;
  25706. + opt = O_CREAT;
  25707. + break;
  25708. default:
  25709. MsgDev( D_ERROR, "FS_SysOpen(%s, %s): invalid mode\n", filepath, mode );
  25710. return NULL;
  25711. @@ -1720,13 +1703,13 @@ Open a packed file using its package file descriptor
  25712. */
  25713. file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
  25714. {
  25715. - packfile_t *pfile;
  25716. + dpackfile_t *pfile;
  25717. int dup_handle;
  25718. file_t *file;
  25719.  
  25720. pfile = &pack->files[pack_ind];
  25721.  
  25722. - if( lseek( pack->handle, pfile->offset, SEEK_SET ) == -1 )
  25723. + if( lseek( pack->handle, pfile->filepos, SEEK_SET ) == -1 )
  25724. return NULL;
  25725.  
  25726. dup_handle = dup( pack->handle );
  25727. @@ -1735,10 +1718,9 @@ file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
  25728. return NULL;
  25729.  
  25730. file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file ));
  25731. - memset( file, 0, sizeof( *file ));
  25732. file->handle = dup_handle;
  25733. - file->real_length = pfile->realsize;
  25734. - file->offset = pfile->offset;
  25735. + file->real_length = pfile->filelen;
  25736. + file->offset = pfile->filepos;
  25737. file->position = 0;
  25738. file->ungetc = EOF;
  25739.  
  25740. @@ -1755,10 +1737,10 @@ Look for a file in the filesystem only
  25741. qboolean FS_SysFileExists( const char *path )
  25742. {
  25743. int desc;
  25744. -
  25745. - desc = open( path, O_RDONLY|O_BINARY );
  25746.  
  25747. - if( desc < 0 ) return false;
  25748. + if(( desc = open( path, O_RDONLY|O_BINARY )) < 0 )
  25749. + return false;
  25750. +
  25751. close( desc );
  25752. return true;
  25753. }
  25754. @@ -1774,7 +1756,7 @@ qboolean FS_SysFolderExists( const char *path )
  25755. {
  25756. DWORD dwFlags = GetFileAttributes( path );
  25757.  
  25758. - return ( dwFlags != -1 ) && ( dwFlags & FILE_ATTRIBUTE_DIRECTORY );
  25759. + return ( dwFlags != -1 ) && FBitSet( dwFlags, FILE_ATTRIBUTE_DIRECTORY );
  25760. }
  25761.  
  25762. /*
  25763. @@ -1796,7 +1778,7 @@ static searchpath_t *FS_FindFile( const char *name, int* index, qboolean gamedir
  25764. // search through the path, one element at a time
  25765. for( search = fs_searchpaths; search; search = search->next )
  25766. {
  25767. - if( gamedironly & !( search->flags & FS_GAMEDIR_PATH ))
  25768. + if( gamedironly & !FBitSet( search->flags, FS_GAMEDIR_PATH ))
  25769. continue;
  25770.  
  25771. // is the element a pak file?
  25772. @@ -1987,7 +1969,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
  25773. return NULL;
  25774.  
  25775. // if the file is opened in "write", "append", or "read/write" mode
  25776. - if( mode[0] == 'w' || mode[0] == 'a' || Q_strchr( mode, '+' ))
  25777. + if( mode[0] == 'w' || mode[0] == 'a'|| mode[0] == 'e' || Q_strchr( mode, '+' ))
  25778. {
  25779. char real_path[MAX_SYSPATH];
  25780.  
  25781. @@ -2024,9 +2006,9 @@ FS_Write
  25782. Write "datasize" bytes into a file
  25783. ====================
  25784. */
  25785. -fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize )
  25786. +long FS_Write( file_t *file, const void *data, size_t datasize )
  25787. {
  25788. - fs_offset_t result;
  25789. + long result;
  25790.  
  25791. if( !file ) return 0;
  25792.  
  25793. @@ -2038,7 +2020,7 @@ fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize )
  25794. FS_Purge( file );
  25795.  
  25796. // write the buffer and update the position
  25797. - result = write( file->handle, data, (fs_offset_t)datasize );
  25798. + result = write( file->handle, data, (long)datasize );
  25799. file->position = lseek( file->handle, 0, SEEK_CUR );
  25800. if( file->real_length < file->position )
  25801. file->real_length = file->position;
  25802. @@ -2055,10 +2037,10 @@ FS_Read
  25803. Read up to "buffersize" bytes from a file
  25804. ====================
  25805. */
  25806. -fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
  25807. +long FS_Read( file_t *file, void *buffer, size_t buffersize )
  25808. {
  25809. - fs_offset_t count, done;
  25810. - fs_offset_t nb;
  25811. + long count, done;
  25812. + long nb;
  25813.  
  25814. // nothing to copy
  25815. if( buffersize == 0 ) return 1;
  25816. @@ -2078,7 +2060,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
  25817. {
  25818. count = file->buff_len - file->buff_ind;
  25819.  
  25820. - done += ((fs_offset_t)buffersize > count ) ? count : (fs_offset_t)buffersize;
  25821. + done += ((long)buffersize > count ) ? count : (long)buffersize;
  25822. memcpy( buffer, &file->buff[file->buff_ind], done );
  25823. file->buff_ind += done;
  25824.  
  25825. @@ -2095,8 +2077,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
  25826. // if we have a lot of data to get, put them directly into "buffer"
  25827. if( buffersize > sizeof( file->buff ) / 2 )
  25828. {
  25829. - if( count > (fs_offset_t)buffersize )
  25830. - count = (fs_offset_t)buffersize;
  25831. + if( count > (long)buffersize )
  25832. + count = (long)buffersize;
  25833. lseek( file->handle, file->offset + file->position, SEEK_SET );
  25834. nb = read (file->handle, &((byte *)buffer)[done], count );
  25835.  
  25836. @@ -2104,14 +2086,14 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
  25837. {
  25838. done += nb;
  25839. file->position += nb;
  25840. - // Purge cached data
  25841. + // purge cached data
  25842. FS_Purge( file );
  25843. }
  25844. }
  25845. else
  25846. {
  25847. - if( count > (fs_offset_t)sizeof( file->buff ))
  25848. - count = (fs_offset_t)sizeof( file->buff );
  25849. + if( count > (long)sizeof( file->buff ))
  25850. + count = (long)sizeof( file->buff );
  25851. lseek( file->handle, file->offset + file->position, SEEK_SET );
  25852. nb = read( file->handle, file->buff, count );
  25853.  
  25854. @@ -2121,7 +2103,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
  25855. file->position += nb;
  25856.  
  25857. // copy the requested data in "buffer" (as much as we can)
  25858. - count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize;
  25859. + count = (long)buffersize > file->buff_len ? file->buff_len : (long)buffersize;
  25860. memcpy( &((byte *)buffer)[done], file->buff, count );
  25861. file->buff_ind = count;
  25862. done += count;
  25863. @@ -2171,9 +2153,9 @@ Print a string into a file
  25864. */
  25865. int FS_VPrintf( file_t *file, const char* format, va_list ap )
  25866. {
  25867. - int len;
  25868. - fs_offset_t buff_size = MAX_SYSPATH;
  25869. - char *tempbuff;
  25870. + int len;
  25871. + long buff_size = MAX_SYSPATH;
  25872. + char *tempbuff;
  25873.  
  25874. if( !file ) return 0;
  25875.  
  25876. @@ -2181,7 +2163,10 @@ int FS_VPrintf( file_t *file, const char* format, va_list ap )
  25877. {
  25878. tempbuff = (char *)Mem_Alloc( fs_mempool, buff_size );
  25879. len = Q_vsprintf( tempbuff, format, ap );
  25880. - if( len >= 0 && len < buff_size ) break;
  25881. +
  25882. + if( len >= 0 && len < buff_size )
  25883. + break;
  25884. +
  25885. Mem_Free( tempbuff );
  25886. buff_size *= 2;
  25887. }
  25888. @@ -2251,7 +2236,8 @@ int FS_Gets( file_t *file, byte *string, size_t bufsize )
  25889. if( c == '\r' )
  25890. {
  25891. c = FS_Getc( file );
  25892. - if( c != '\n' ) FS_UnGetc( file, (byte)c );
  25893. + if( c != '\n' )
  25894. + FS_UnGetc( file, (byte)c );
  25895. }
  25896.  
  25897. return c;
  25898. @@ -2264,7 +2250,7 @@ FS_Seek
  25899. Move the position index in a file
  25900. ====================
  25901. */
  25902. -int FS_Seek( file_t *file, fs_offset_t offset, int whence )
  25903. +int FS_Seek( file_t *file, long offset, int whence )
  25904. {
  25905. // compute the file offset
  25906. switch( whence )
  25907. @@ -2281,7 +2267,7 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
  25908. return -1;
  25909. }
  25910.  
  25911. - if( offset < 0 || offset > (long)file->real_length )
  25912. + if( offset < 0 || offset > file->real_length )
  25913. return -1;
  25914.  
  25915. // if we have the data in our read buffer, we don't need to actually seek
  25916. @@ -2308,7 +2294,7 @@ FS_Tell
  25917. Give the current position in a file
  25918. ====================
  25919. */
  25920. -fs_offset_t FS_Tell( file_t* file )
  25921. +long FS_Tell( file_t* file )
  25922. {
  25923. if( !file ) return 0;
  25924. return file->position - file->buff_len + file->buff_ind;
  25925. @@ -2349,11 +2335,11 @@ Filename are relative to the xash directory.
  25926. Always appends a 0 byte.
  25927. ============
  25928. */
  25929. -byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
  25930. +byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly )
  25931. {
  25932. - file_t *file;
  25933. - byte *buf = NULL;
  25934. - fs_offset_t filesize = 0;
  25935. + file_t *file;
  25936. + byte *buf = NULL;
  25937. + long filesize = 0;
  25938.  
  25939. file = FS_Open( path, "rb", gamedironly );
  25940.  
  25941. @@ -2383,7 +2369,7 @@ FS_OpenFile
  25942. Simply version of FS_Open
  25943. ============
  25944. */
  25945. -file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
  25946. +file_t *FS_OpenFile( const char *path, long *filesizeptr, qboolean gamedironly )
  25947. {
  25948. file_t *file = FS_Open( path, "rb", gamedironly );
  25949.  
  25950. @@ -2402,7 +2388,7 @@ FS_WriteFile
  25951. The filename will be prefixed by the current game directory
  25952. ============
  25953. */
  25954. -qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len )
  25955. +qboolean FS_WriteFile( const char *filename, const void *data, long len )
  25956. {
  25957. file_t *file;
  25958.  
  25959. @@ -2414,8 +2400,9 @@ qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len )
  25960. return false;
  25961. }
  25962.  
  25963. - FS_Write (file, data, len);
  25964. - FS_Close (file);
  25965. + FS_Write( file, data, len );
  25966. + FS_Close( file );
  25967. +
  25968. return true;
  25969. }
  25970.  
  25971. @@ -2493,18 +2480,16 @@ const char *FS_GetDiskPath( const char *name, qboolean gamedironly )
  25972. {
  25973. int index;
  25974. searchpath_t *search;
  25975. -
  25976. +
  25977. search = FS_FindFile( name, &index, gamedironly );
  25978.  
  25979. if( search )
  25980. {
  25981. - if( index != -1 )
  25982. - {
  25983. - // file in pack or wad
  25984. + if( index != -1 ) // file in pack or wad
  25985. return NULL;
  25986. - }
  25987. return va( "%s%s", search->filename, name );
  25988. }
  25989. +
  25990. return NULL;
  25991. }
  25992.  
  25993. @@ -2611,7 +2596,7 @@ FS_FileSize
  25994. return size of file in bytes
  25995. ==================
  25996. */
  25997. -fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly )
  25998. +long FS_FileSize( const char *filename, qboolean gamedironly )
  25999. {
  26000. file_t *fp;
  26001. int length = 0;
  26002. @@ -2635,7 +2620,7 @@ FS_FileLength
  26003. return size of file in bytes
  26004. ==================
  26005. */
  26006. -fs_offset_t FS_FileLength( file_t *f )
  26007. +long FS_FileLength( file_t *f )
  26008. {
  26009. if( !f ) return 0;
  26010. return f->real_length;
  26011. @@ -2648,7 +2633,7 @@ FS_FileTime
  26012. return time of creation file in seconds
  26013. ==================
  26014. */
  26015. -fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly )
  26016. +long FS_FileTime( const char *filename, qboolean gamedironly )
  26017. {
  26018. searchpath_t *search;
  26019. int pack_ind;
  26020. @@ -2725,22 +2710,32 @@ FS_FileCopy
  26021.  
  26022. ==================
  26023. */
  26024. -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
  26025. +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
  26026. {
  26027. - char buf[MAX_SYSPATH]; // A small buffer for the copy
  26028. - int size;
  26029. + char *buf = Mem_Alloc( fs_mempool, FILE_COPY_SIZE );
  26030. + int size, readSize;
  26031. + qboolean done = true;
  26032.  
  26033. while( fileSize > 0 )
  26034. {
  26035. - if( fileSize > MAX_SYSPATH )
  26036. - size = MAX_SYSPATH;
  26037. + if( fileSize > FILE_COPY_SIZE )
  26038. + size = FILE_COPY_SIZE;
  26039. else size = fileSize;
  26040.  
  26041. - FS_Read( pInput, buf, size );
  26042. - FS_Write( pOutput, buf, size );
  26043. -
  26044. + if(( readSize = FS_Read( pInput, buf, size )) < size )
  26045. + {
  26046. + MsgDev( D_ERROR, "FS_FileCopy: unexpected end of input file\n" );
  26047. + fileSize = 0;
  26048. + done = false;
  26049. + break;
  26050. + }
  26051. +
  26052. + FS_Write( pOutput, buf, readSize );
  26053. fileSize -= size;
  26054. }
  26055. +
  26056. + Mem_Free( buf );
  26057. + return done;
  26058. }
  26059.  
  26060. /*
  26061. @@ -2787,7 +2782,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
  26062. // search through the path, one element at a time
  26063. for( searchpath = fs_searchpaths; searchpath; searchpath = searchpath->next )
  26064. {
  26065. - if( gamedironly && !( searchpath->flags & FS_GAMEDIR_PATH ))
  26066. + if( gamedironly && !FBitSet( searchpath->flags, FS_GAMEDIR_PATH ))
  26067. continue;
  26068.  
  26069. // is the element a pak file?
  26070. @@ -2809,9 +2804,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
  26071. }
  26072.  
  26073. if( resultlistindex == resultlist.numstrings )
  26074. - {
  26075. stringlistappend( &resultlist, temp );
  26076. - }
  26077. }
  26078. // strip off one path element at a time until empty
  26079. // this way directories are added to the listing if they match the pattern
  26080. @@ -2866,7 +2859,9 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
  26081. if( type != TYP_ANY && wad->lumps[i].type != type )
  26082. continue;
  26083.  
  26084. - Q_strncpy( temp, wad->lumps[i].name, sizeof( temp ));
  26085. + // build the lumpname with image suffix (if present)
  26086. + Q_snprintf( temp, sizeof( temp ), "%s%s", wad->lumps[i].name, wad_hints[wad->lumps[i].img_type].ext );
  26087. +
  26088. while( temp[0] )
  26089. {
  26090. if( matchpattern( temp, wadpattern, true ))
  26091. @@ -2920,11 +2915,10 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
  26092. }
  26093.  
  26094. if( resultlistindex == resultlist.numstrings )
  26095. - {
  26096. stringlistappend( &resultlist, temp );
  26097. - }
  26098. }
  26099. }
  26100. +
  26101. stringlistfreecontents( &dirlist );
  26102. }
  26103. }
  26104. @@ -3006,6 +3000,13 @@ static const wadtype_t wad_hints[10] =
  26105. { NULL, 0 } // terminator
  26106. };
  26107.  
  26108. +/*
  26109. +===========
  26110. +W_TypeFromExt
  26111. +
  26112. +Extracts file type from extension
  26113. +===========
  26114. +*/
  26115. static char W_TypeFromExt( const char *lumpname )
  26116. {
  26117. const char *ext = FS_FileExtension( lumpname );
  26118. @@ -3057,11 +3058,17 @@ char W_HintFromSuf( const char *lumpname )
  26119. {
  26120. char barename[64];
  26121. char suffix[8];
  26122. + size_t namelen;
  26123. const wadtype_t *hint;
  26124.  
  26125. // trying to extract hint from the name
  26126. FS_FileBase( lumpname, barename );
  26127. - Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix ));
  26128. + namelen = Q_strlen( barename );
  26129. +
  26130. + if( namelen <= HINT_NAMELEN )
  26131. + return IMG_DIFFUSE;
  26132. +
  26133. + Q_strncpy( suffix, barename + namelen - HINT_NAMELEN, sizeof( suffix ));
  26134.  
  26135. // we not known about filetype, so match only by filename
  26136. for( hint = wad_hints; hint->ext; hint++ )
  26137. @@ -3074,11 +3081,19 @@ char W_HintFromSuf( const char *lumpname )
  26138. return IMG_DIFFUSE;
  26139. }
  26140.  
  26141. +/*
  26142. +===========
  26143. +W_FindLump
  26144. +
  26145. +Serach for already existed lump
  26146. +===========
  26147. +*/
  26148. static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype )
  26149. {
  26150. char img_type = IMG_DIFFUSE;
  26151. char barename[64], suffix[8];
  26152. int left, right;
  26153. + size_t namelen;
  26154. const wadtype_t *hint;
  26155.  
  26156. if( !wad || !wad->lumps || matchtype == TYP_NONE )
  26157. @@ -3086,20 +3101,25 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match
  26158.  
  26159. // trying to extract hint from the name
  26160. FS_FileBase( name, barename );
  26161. - Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix ));
  26162. + namelen = Q_strlen( barename );
  26163.  
  26164. - // we not known about filetype, so match only by filename
  26165. - for( hint = wad_hints; hint->ext; hint++ )
  26166. + if( namelen > HINT_NAMELEN )
  26167. {
  26168. - if( !Q_stricmp( suffix, hint->ext ))
  26169. + Q_strncpy( suffix, barename + namelen - HINT_NAMELEN, sizeof( suffix ));
  26170. +
  26171. + // we not known about filetype, so match only by filename
  26172. + for( hint = wad_hints; hint->ext; hint++ )
  26173. {
  26174. - img_type = hint->type;
  26175. - break;
  26176. + if( !Q_stricmp( suffix, hint->ext ))
  26177. + {
  26178. + img_type = hint->type;
  26179. + break;
  26180. + }
  26181. }
  26182. - }
  26183.  
  26184. - if( img_type != IMG_DIFFUSE )
  26185. - barename[Q_strlen( barename ) - HINT_NAMELEN] = '\0'; // kill the suffix
  26186. + if( img_type != IMG_DIFFUSE )
  26187. + barename[namelen - HINT_NAMELEN] = '\0'; // kill the suffix
  26188. + }
  26189.  
  26190. // look for the file (binary search)
  26191. left = 0;
  26192. @@ -3135,9 +3155,10 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match
  26193.  
  26194. /*
  26195. ====================
  26196. -FS_AddFileToWad
  26197. +W_AddFileToWad
  26198.  
  26199. Add a file to the list of files contained into a package
  26200. +and sort LAT in alpha-bethical order
  26201. ====================
  26202. */
  26203. static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t *newlump )
  26204. @@ -3145,14 +3166,6 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
  26205. int left, right;
  26206. dlumpinfo_t *plump;
  26207.  
  26208. - // convert all qmip types to miptex
  26209. - if( newlump->type == TYP_RAWDATA )
  26210. - newlump->type = TYP_MIPTEX;
  26211. -
  26212. - // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic)
  26213. - if( !Q_stricmp( newlump->name, "conchars" ) && newlump->type == TYP_RAWDATA )
  26214. - newlump->type = TYP_GFXPIC;
  26215. -
  26216. // look for the slot we should put that file into (binary search)
  26217. left = 0;
  26218. right = wad->numlumps - 1;
  26219. @@ -3172,7 +3185,7 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
  26220. diff = 1;
  26221. else if( wad->lumps[middle].type > newlump->type )
  26222. diff = -1;
  26223. - else MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name );
  26224. + else MsgDev( D_WARN, "Wad %s contains the file %s several times\n", wad->filename, name );
  26225. }
  26226.  
  26227. // If we're too far in the list
  26228. @@ -3191,53 +3204,17 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t
  26229. return plump;
  26230. }
  26231.  
  26232. -static qboolean W_ReadLumpTable( wfile_t *wad )
  26233. -{
  26234. - size_t lat_size;
  26235. - dlumpinfo_t *srclumps;
  26236. - int i, k, numlumps;
  26237. -
  26238. - // nothing to convert ?
  26239. - if( !wad || !wad->numlumps )
  26240. - return false;
  26241. -
  26242. - lat_size = wad->numlumps * sizeof( dlumpinfo_t );
  26243. - srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
  26244. - numlumps = wad->numlumps;
  26245. - wad->numlumps = 0; // reset it
  26246. -
  26247. - if( read( wad->handle, srclumps, lat_size ) != lat_size )
  26248. - {
  26249. - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
  26250. - W_Close( wad );
  26251. - return false;
  26252. - }
  26253. -
  26254. - // swap everything
  26255. - for( i = 0; i < numlumps; i++ )
  26256. - {
  26257. - char name[16];
  26258. -
  26259. - // cleanup lumpname
  26260. - Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name ));
  26261. -
  26262. - // check for '*' symbol issues
  26263. - k = Q_strlen( Q_strrchr( name, '*' ));
  26264. - if( k ) name[Q_strlen( name ) - k] = '!'; // quake1 issues (can't save images that contain '*' symbol)
  26265. -
  26266. - W_AddFileToWad( name, wad, &srclumps[i] );
  26267. - }
  26268. -
  26269. - // release source lumps
  26270. - Mem_Free( srclumps );
  26271. -
  26272. - return true;
  26273. -}
  26274. +/*
  26275. +===========
  26276. +W_ReadLump
  26277.  
  26278. -byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
  26279. +reading lump into temp buffer
  26280. +===========
  26281. +*/
  26282. +byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, long *lumpsizeptr )
  26283. {
  26284. + size_t oldpos, size = 0;
  26285. byte *buf;
  26286. - size_t size = 0;
  26287.  
  26288. // assume error
  26289. if( lumpsizeptr ) *lumpsizeptr = 0;
  26290. @@ -3245,9 +3222,12 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
  26291. // no wads loaded
  26292. if( !wad || !lump ) return NULL;
  26293.  
  26294. + oldpos = tell( wad->handle ); // don't forget restore original position
  26295. +
  26296. if( lseek( wad->handle, lump->filepos, SEEK_SET ) == -1 )
  26297. {
  26298. MsgDev( D_ERROR, "W_ReadLump: %s is corrupted\n", lump->name );
  26299. + lseek( wad->handle, oldpos, SEEK_SET );
  26300. return NULL;
  26301. }
  26302.  
  26303. @@ -3256,47 +3236,129 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr )
  26304. if( size < lump->disksize )
  26305. {
  26306. MsgDev( D_WARN, "W_ReadLump: %s is probably corrupted\n", lump->name );
  26307. + lseek( wad->handle, oldpos, SEEK_SET );
  26308. Mem_Free( buf );
  26309. return NULL;
  26310. }
  26311.  
  26312. +
  26313. if( lumpsizeptr ) *lumpsizeptr = lump->size;
  26314. + lseek( wad->handle, oldpos, SEEK_SET );
  26315. +
  26316. return buf;
  26317. }
  26318.  
  26319. /*
  26320. +===========
  26321. +W_WriteLump
  26322. +
  26323. +compress and write lump
  26324. +===========
  26325. +*/
  26326. +qboolean W_WriteLump( wfile_t *wad, dlumpinfo_t *lump, const void *data, size_t datasize )
  26327. +{
  26328. + if( !wad || !lump ) return false;
  26329. +
  26330. + if( !data || !datasize )
  26331. + {
  26332. + MsgDev( D_WARN, "W_WriteLump: ignore blank lump %s - nothing to save\n", lump->name );
  26333. + return false;
  26334. + }
  26335. +
  26336. + if( wad->mode == O_RDONLY )
  26337. + {
  26338. + MsgDev( D_ERROR, "W_WriteLump: %s opened in readonly mode\n", wad->filename );
  26339. + return false;
  26340. + }
  26341. +
  26342. + lump->size = lump->disksize = datasize;
  26343. +
  26344. + if( write( wad->handle, data, datasize ) == datasize )
  26345. + return true;
  26346. + return false;
  26347. +}
  26348. +
  26349. +/*
  26350. =============================================================================
  26351.  
  26352. WADSYSTEM PUBLIC BASE FUNCTIONS
  26353.  
  26354. =============================================================================
  26355. */
  26356. -wfile_t *W_Open( const char *filename, const char *mode )
  26357. +/*
  26358. +===========
  26359. +W_Open
  26360. +
  26361. +open the wad for reading & writing
  26362. +===========
  26363. +*/
  26364. +wfile_t *W_Open( const char *filename, const char *mode, int *error )
  26365. {
  26366. dwadinfo_t header;
  26367. wfile_t *wad = (wfile_t *)Mem_Alloc( fs_mempool, sizeof( wfile_t ));
  26368. - const char *comment = "Generated by Xash WadLib. ";
  26369. + const char *comment = "Created by Xash3D Engine.\0";
  26370. + int i, ind, mod, opt, lumpcount;
  26371. + size_t wadsize, lat_size;
  26372. + dlumpinfo_t *srclumps;
  26373.  
  26374. - if( mode[0] == 'a' ) wad->handle = open( filename, O_RDWR|O_BINARY, 0x666 );
  26375. - else if( mode[0] == 'w' ) wad->handle = open( filename, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0x666 );
  26376. - else if( mode[0] == 'r' ) wad->handle = open( filename, O_RDONLY|O_BINARY, 0x666 );
  26377. + // parse the mode string
  26378. + switch( mode[0] )
  26379. + {
  26380. + case 'r':
  26381. + mod = O_RDONLY;
  26382. + opt = 0;
  26383. + break;
  26384. + case 'w':
  26385. + mod = O_WRONLY;
  26386. + opt = O_CREAT|O_TRUNC;
  26387. + break;
  26388. + case 'a':
  26389. + mod = O_WRONLY;
  26390. + opt = O_CREAT;
  26391. + break;
  26392. + default:
  26393. + MsgDev( D_ERROR, "W_Open(%s, %s): invalid mode\n", filename, mode );
  26394. + return NULL;
  26395. + }
  26396. +
  26397. + for( ind = 1; mode[ind] != '\0'; ind++ )
  26398. + {
  26399. + switch( mode[ind] )
  26400. + {
  26401. + case '+':
  26402. + mod = O_RDWR;
  26403. + break;
  26404. + case 'b':
  26405. + opt |= O_BINARY;
  26406. + break;
  26407. + default:
  26408. + MsgDev( D_ERROR, "W_Open: %s: unknown char in mode (%c)\n", filename, mode, mode[ind] );
  26409. + break;
  26410. + }
  26411. + }
  26412. +
  26413. + wad->handle = open( filename, mod|opt, 0666 );
  26414.  
  26415. if( wad->handle < 0 )
  26416. {
  26417. - W_Close( wad );
  26418. MsgDev( D_ERROR, "W_Open: couldn't open %s\n", filename );
  26419. + if( error ) *error = WAD_LOAD_COULDNT_OPEN;
  26420. + W_Close( wad );
  26421. return NULL;
  26422. }
  26423.  
  26424. // copy wad name
  26425. Q_strncpy( wad->filename, filename, sizeof( wad->filename ));
  26426. - wad->mempool = Mem_AllocPool( filename );
  26427. wad->filetime = FS_SysFileTime( filename );
  26428. + wad->mempool = Mem_AllocPool( filename );
  26429. +
  26430. + wadsize = lseek( wad->handle, 0, SEEK_END );
  26431. + lseek( wad->handle, 0, SEEK_SET );
  26432.  
  26433. // if the file is opened in "write", "append", or "read/write" mode
  26434. - if( mode[0] == 'w' )
  26435. + if( mod == O_WRONLY || !wadsize )
  26436. {
  26437. - dwadinfo_t hdr;
  26438. + dwadinfo_t hdr;
  26439.  
  26440. wad->numlumps = 0; // blank wad
  26441. wad->lumps = NULL; //
  26442. @@ -3310,95 +3372,122 @@ wfile_t *W_Open( const char *filename, const char *mode )
  26443. write( wad->handle, comment, Q_strlen( comment ) + 1 );
  26444. wad->infotableofs = tell( wad->handle );
  26445. }
  26446. - else if( mode[0] == 'r' || mode[0] == 'a' )
  26447. + else if( mod == O_RDWR || mod == O_RDONLY )
  26448. {
  26449. - if( mode[0] == 'a' )
  26450. - {
  26451. - lseek( wad->handle, 0, SEEK_SET );
  26452. + if( mod == O_RDWR )
  26453. wad->mode = O_APPEND;
  26454. - }
  26455. + else wad->mode = O_RDONLY;
  26456.  
  26457. if( read( wad->handle, &header, sizeof( dwadinfo_t )) != sizeof( dwadinfo_t ))
  26458. {
  26459. MsgDev( D_ERROR, "W_Open: %s can't read header\n", filename );
  26460. + if( error ) *error = WAD_LOAD_BAD_HEADER;
  26461. W_Close( wad );
  26462. return NULL;
  26463. }
  26464.  
  26465. - switch( header.ident )
  26466. + if( header.ident != IDWAD3HEADER )
  26467. {
  26468. - case IDWAD2HEADER:
  26469. - case IDWAD3HEADER:
  26470. - break; // WAD2, WAD3 allow r\w mode
  26471. - default:
  26472. - MsgDev( D_ERROR, "W_Open: %s unknown wadtype\n", filename );
  26473. + MsgDev( D_ERROR, "W_Open: %s is not a WAD3 file\n", filename );
  26474. + if( error ) *error = WAD_LOAD_BAD_HEADER;
  26475. W_Close( wad );
  26476. return NULL;
  26477. }
  26478.  
  26479. - wad->numlumps = header.numlumps;
  26480. - if( wad->numlumps >= MAX_FILES_IN_WAD && wad->mode == O_APPEND )
  26481. + lumpcount = header.numlumps;
  26482. +
  26483. + if( lumpcount >= MAX_FILES_IN_WAD && wad->mode == O_APPEND )
  26484. {
  26485. - MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", wad->numlumps );
  26486. + MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", filename, lumpcount );
  26487. + if( error ) *error = WAD_LOAD_TOO_MANY_FILES;
  26488. wad->mode = O_RDONLY; // set read-only mode
  26489. }
  26490. + else if( lumpcount <= 0 && wad->mode == O_RDONLY )
  26491. + {
  26492. + MsgDev( D_ERROR, "W_Open: %s has no lumps\n", filename );
  26493. + if( error ) *error = WAD_LOAD_NO_FILES;
  26494. + W_Close( wad );
  26495. + return NULL;
  26496. + }
  26497. + else if( error ) *error = WAD_LOAD_OK;
  26498. +
  26499. wad->infotableofs = header.infotableofs; // save infotableofs position
  26500. +
  26501. if( lseek( wad->handle, wad->infotableofs, SEEK_SET ) == -1 )
  26502. {
  26503. MsgDev( D_ERROR, "W_Open: %s can't find lump allocation table\n", filename );
  26504. + if( error ) *error = WAD_LOAD_BAD_FOLDERS;
  26505. W_Close( wad );
  26506. return NULL;
  26507. }
  26508.  
  26509. + lat_size = lumpcount * sizeof( dlumpinfo_t );
  26510. +
  26511. // NOTE: lumps table can be reallocated for O_APPEND mode
  26512. - wad->lumps = Mem_Alloc( wad->mempool, wad->numlumps * sizeof( dlumpinfo_t ));
  26513. + srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
  26514.  
  26515. - if( wad->mode == O_APPEND )
  26516. - {
  26517. - size_t lat_size = wad->numlumps * sizeof( dlumpinfo_t );
  26518. + if( read( wad->handle, srclumps, lat_size ) != lat_size )
  26519. + {
  26520. + MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
  26521. + if( error ) *error = WAD_LOAD_CORRUPTED;
  26522. + Mem_Free( srclumps );
  26523. + W_Close( wad );
  26524. + return NULL;
  26525. + }
  26526.  
  26527. - if( read( wad->handle, wad->lumps, lat_size ) != lat_size )
  26528. - {
  26529. - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
  26530. - W_Close( wad );
  26531. - return NULL;
  26532. - }
  26533. + // starting to add lumps
  26534. + wad->lumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size );
  26535. + wad->numlumps = 0;
  26536.  
  26537. - // if we are in append mode - we need started from infotableofs poisition
  26538. - // overwrite lumptable as well, we have her copy in wad->lumps
  26539. - lseek( wad->handle, wad->infotableofs, SEEK_SET );
  26540. - }
  26541. - else
  26542. + // sort lumps for binary search
  26543. + for( i = 0; i < lumpcount; i++ )
  26544. {
  26545. - // setup lump allocation table
  26546. - switch( header.ident )
  26547. - {
  26548. - case IDWAD2HEADER:
  26549. - case IDWAD3HEADER:
  26550. - if(!W_ReadLumpTable( wad ))
  26551. - return NULL;
  26552. - break;
  26553. - }
  26554. + char name[16];
  26555. + int k;
  26556. +
  26557. + // cleanup lumpname
  26558. + Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name ));
  26559. +
  26560. + // check for '*' symbol issues (quake1)
  26561. + k = Q_strlen( Q_strrchr( name, '*' ));
  26562. + if( k ) name[Q_strlen( name ) - k] = '!';
  26563. +
  26564. + W_AddFileToWad( name, wad, &srclumps[i] );
  26565. }
  26566. +
  26567. + // release source lumps
  26568. + Mem_Free( srclumps );
  26569. +
  26570. + // if we are in append mode - we need started from infotableofs poisition
  26571. + // overwrite lumptable as well, we have her copy in wad->lumps
  26572. + if( wad->mode == O_APPEND )
  26573. + lseek( wad->handle, wad->infotableofs, SEEK_SET );
  26574. }
  26575. - // and leaves the file open
  26576. +
  26577. + // and leave the file open
  26578. return wad;
  26579. }
  26580.  
  26581. +/*
  26582. +===========
  26583. +W_Close
  26584. +
  26585. +finalize wad or just close
  26586. +===========
  26587. +*/
  26588. void W_Close( wfile_t *wad )
  26589. {
  26590. - fs_offset_t ofs;
  26591. -
  26592. if( !wad ) return;
  26593.  
  26594. if( wad->handle >= 0 && ( wad->mode == O_APPEND || wad->mode == O_WRONLY ))
  26595. {
  26596. dwadinfo_t hdr;
  26597. + long ofs;
  26598.  
  26599. // write the lumpinfo
  26600. ofs = tell( wad->handle );
  26601. write( wad->handle, wad->lumps, wad->numlumps * sizeof( dlumpinfo_t ));
  26602. -
  26603. +
  26604. // write the header
  26605. hdr.ident = IDWAD3HEADER;
  26606. hdr.numlumps = wad->numlumps;
  26607. @@ -3409,7 +3498,9 @@ void W_Close( wfile_t *wad )
  26608. }
  26609.  
  26610. Mem_FreePool( &wad->mempool );
  26611. - if( wad->handle >= 0 ) close( wad->handle );
  26612. + if( wad->handle >= 0 )
  26613. + close( wad->handle );
  26614. +
  26615. Mem_Free( wad ); // free himself
  26616. }
  26617.  
  26618. @@ -3420,7 +3511,127 @@ FILESYSTEM IMPLEMENTATION
  26619.  
  26620. =============================================================================
  26621. */
  26622. -static byte *W_LoadFile( const char *path, fs_offset_t *lumpsizeptr, qboolean gamedironly )
  26623. +/*
  26624. +===========
  26625. +W_SaveLump
  26626. +
  26627. +write new or replace existed lump
  26628. +===========
  26629. +*/
  26630. +size_t W_SaveFile( wfile_t *wad, const char *lump, const void *data, size_t datasize, char type, qboolean replace )
  26631. +{
  26632. + dlumpinfo_t *find, newlump;
  26633. + size_t lat_size, oldpos;
  26634. + char hint, lumpname[64];
  26635. +
  26636. + if( !wad || !lump ) return -1;
  26637. +
  26638. + if( !data || !datasize )
  26639. + {
  26640. + MsgDev( D_WARN, "W_SaveLump: ignore blank lump %s - nothing to save\n", lump );
  26641. + return -1;
  26642. + }
  26643. +
  26644. + if( wad->mode == O_RDONLY )
  26645. + {
  26646. + MsgDev( D_ERROR, "W_SaveLump: %s opened in readonly mode\n", wad->filename );
  26647. + return -1;
  26648. + }
  26649. +
  26650. + if( wad->numlumps >= MAX_FILES_IN_WAD )
  26651. + {
  26652. + MsgDev( D_ERROR, "W_SaveLump: %s is full\n", wad->filename );
  26653. + return -1;
  26654. + }
  26655. +
  26656. + find = W_FindLump( wad, lump, type );
  26657. +
  26658. + if( find != NULL && replace )
  26659. + {
  26660. + if( FBitSet( find->attribs, ATTR_READONLY ))
  26661. + {
  26662. + // g-cont. i left this limitation as a protect of the replacement of compressed lumps
  26663. + MsgDev( D_ERROR, "W_ReplaceLump: %s is read-only\n", find->name );
  26664. + return -1;
  26665. + }
  26666. +
  26667. + if( datasize != find->size )
  26668. + {
  26669. + MsgDev( D_ERROR, "W_ReplaceLump: %s [%s] should be [%s]\n",
  26670. + lumpname, Q_memprint( datasize ), Q_memprint( find->size ));
  26671. + return -1;
  26672. + }
  26673. +
  26674. + oldpos = tell( wad->handle ); // don't forget restore original position
  26675. +
  26676. + if( lseek( wad->handle, find->filepos, SEEK_SET ) == -1 )
  26677. + {
  26678. + MsgDev( D_ERROR, "W_ReplaceLump: %s is corrupted\n", find->name );
  26679. + lseek( wad->handle, oldpos, SEEK_SET );
  26680. + return -1;
  26681. + }
  26682. +
  26683. + if( write( wad->handle, data, datasize ) != find->disksize )
  26684. + MsgDev( D_WARN, "W_ReplaceLump: %s probably replaced with errors\n", find->name );
  26685. +
  26686. + // restore old position
  26687. + lseek( wad->handle, oldpos, SEEK_SET );
  26688. +
  26689. + return wad->numlumps;
  26690. + }
  26691. + else
  26692. + {
  26693. + MsgDev( D_ERROR, "W_SaveLump: %s already exist\n", lump );
  26694. + return -1;
  26695. + }
  26696. +
  26697. + // prepare lump name
  26698. + Q_strncpy( lumpname, lump, sizeof( lumpname ));
  26699. +
  26700. + // extract image hint
  26701. + hint = W_HintFromSuf( lumpname );
  26702. +
  26703. + if( hint != IMG_DIFFUSE )
  26704. + lumpname[Q_strlen( lumpname ) - HINT_NAMELEN] = '\0'; // kill the suffix
  26705. +
  26706. + if( Q_strlen( lumpname ) >= WAD3_NAMELEN )
  26707. + {
  26708. + // name is too long
  26709. + MsgDev( D_ERROR, "W_SaveLump: %s more than %i symbols\n", lumpname, WAD3_NAMELEN );
  26710. + return -1;
  26711. + }
  26712. +
  26713. + lat_size = sizeof( dlumpinfo_t ) * (wad->numlumps + 1);
  26714. +
  26715. + // reallocate lumptable
  26716. + wad->lumps = (dlumpinfo_t *)Mem_Realloc( wad->mempool, wad->lumps, lat_size );
  26717. +
  26718. + memset( &newlump, 0, sizeof( newlump ));
  26719. +
  26720. + // write header
  26721. + Q_strnupr( lumpname, newlump.name, WAD3_NAMELEN );
  26722. + newlump.filepos = tell( wad->handle );
  26723. + newlump.attribs = ATTR_NONE;
  26724. + newlump.img_type = hint;
  26725. + newlump.type = type;
  26726. +
  26727. + if( !W_WriteLump( wad, &newlump, data, datasize ))
  26728. + return -1;
  26729. +
  26730. + // record entry and re-sort table
  26731. + W_AddFileToWad( lumpname, wad, &newlump );
  26732. +
  26733. + return wad->numlumps;
  26734. +}
  26735. +
  26736. +/*
  26737. +===========
  26738. +W_LoadFile
  26739. +
  26740. +loading lump into the tmp buffer
  26741. +===========
  26742. +*/
  26743. +static byte *W_LoadFile( const char *path, long *lumpsizeptr, qboolean gamedironly )
  26744. {
  26745. searchpath_t *search;
  26746. int index;
  26747. diff --git b/engine/common/filesystem.h a/engine/common/filesystem.h
  26748. index a5bf2cc..9f5cbeb 100644
  26749. --- b/engine/common/filesystem.h
  26750. +++ a/engine/common/filesystem.h
  26751. @@ -58,9 +58,6 @@ file_n: byte[dwadinfo_t[num]->disksize]
  26752. infotable dlumpinfo_t[dwadinfo_t->numlumps]
  26753. ========================================================================
  26754. */
  26755. -#define IDWAD2HEADER (('2'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD2" quake1 gfx.wad
  26756. -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads
  26757. -
  26758. #define WAD3_NAMELEN 16
  26759. #define HINT_NAMELEN 5 // e.g. _mask, _norm
  26760. #define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount
  26761. @@ -73,9 +70,9 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps]
  26762.  
  26763. typedef struct
  26764. {
  26765. - int ident; // should be IWAD, WAD2 or WAD3
  26766. + int ident; // should be WAD3
  26767. int numlumps; // num files
  26768. - int infotableofs;
  26769. + int infotableofs; // LUT offset
  26770. } dwadinfo_t;
  26771.  
  26772. typedef struct
  26773. diff --git b/engine/common/host.c a/engine/common/host.c
  26774. index 84b5468..cb32669 100644
  26775. --- b/engine/common/host.c
  26776. +++ a/engine/common/host.c
  26777. @@ -39,8 +39,6 @@ convar_t *host_framerate;
  26778. convar_t *con_gamemaps;
  26779. convar_t *build, *ver;
  26780.  
  26781. -static int num_decals;
  26782. -
  26783. // these cvars will be duplicated on each client across network
  26784. int Host_ServerState( void )
  26785. {
  26786. @@ -74,23 +72,26 @@ Host_PrintEngineFeatures
  26787. */
  26788. void Host_PrintEngineFeatures( void )
  26789. {
  26790. - if( host.features & ENGINE_WRITE_LARGE_COORD )
  26791. - MsgDev( D_AICONSOLE, "^3EXT:^7 big world support enabled\n" );
  26792. + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
  26793. + MsgDev( D_REPORT, "^3EXT:^7 big world support enabled\n" );
  26794. +
  26795. + if( FBitSet( host.features, ENGINE_BUILD_SURFMESHES ))
  26796. + MsgDev( D_REPORT, "^3EXT:^7 surfmeshes enabled\n" );
  26797.  
  26798. - if( host.features & ENGINE_BUILD_SURFMESHES )
  26799. - MsgDev( D_AICONSOLE, "^3EXT:^7 surfmeshes enabled\n" );
  26800. + if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
  26801. + MsgDev( D_REPORT, "^3EXT:^7 deluxemap support enabled\n" );
  26802.  
  26803. - if( host.features & ENGINE_LOAD_DELUXEDATA )
  26804. - MsgDev( D_AICONSOLE, "^3EXT:^7 deluxemap support enabled\n" );
  26805. + if( FBitSet( host.features, ENGINE_TRANSFORM_TRACE_AABB ))
  26806. + MsgDev( D_REPORT, "^3EXT:^7 Transform trace AABB enabled\n" );
  26807.  
  26808. - if( host.features & ENGINE_TRANSFORM_TRACE_AABB )
  26809. - MsgDev( D_AICONSOLE, "^3EXT:^7 Transform trace AABB enabled\n" );
  26810. + if( FBitSet( host.features, ENGINE_LARGE_LIGHTMAPS ))
  26811. + MsgDev( D_REPORT, "^3EXT:^7 Large lightmaps enabled\n" );
  26812.  
  26813. - if( host.features & ENGINE_LARGE_LIGHTMAPS )
  26814. - MsgDev( D_AICONSOLE, "^3EXT:^7 Large lightmaps enabled\n" );
  26815. + if( FBitSet( host.features, ENGINE_COMPENSATE_QUAKE_BUG ))
  26816. + MsgDev( D_REPORT, "^3EXT:^7 Compensate quake bug enabled\n" );
  26817.  
  26818. - if( host.features & ENGINE_COMPENSATE_QUAKE_BUG )
  26819. - MsgDev( D_AICONSOLE, "^3EXT:^7 Compensate quake bug enabled\n" );
  26820. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  26821. + MsgDev( D_REPORT, "^3EXT:^7 fixed main cycle\n" );
  26822. }
  26823.  
  26824. /*
  26825. @@ -118,7 +119,7 @@ void Host_EndGame( const char *message, ... )
  26826. static char string[MAX_SYSPATH];
  26827.  
  26828. va_start( argptr, message );
  26829. - Q_vsprintf( string, message, argptr );
  26830. + Q_vsnprintf( string, sizeof( string ), message, argptr );
  26831. va_end( argptr );
  26832.  
  26833. MsgDev( D_INFO, "Host_EndGame: %s\n", string );
  26834. @@ -233,10 +234,10 @@ void Host_Exec_f( void )
  26835. return;
  26836. }
  26837.  
  26838. - // HACKHACK: don't execute listenserver.cfg in singleplayer
  26839. - if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 )))
  26840. + // don't execute listenserver.cfg in singleplayer
  26841. + if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 )))
  26842. {
  26843. - if( Cvar_VariableValue( "maxplayers" ) == 1.0f )
  26844. + if( Cvar_VariableInteger( "maxplayers" ) == 1 )
  26845. return;
  26846. }
  26847.  
  26848. @@ -309,12 +310,12 @@ qboolean Host_IsLocalClient( void )
  26849. Host_RegisterDecal
  26850. =================
  26851. */
  26852. -qboolean Host_RegisterDecal( const char *name )
  26853. +qboolean Host_RegisterDecal( const char *name, int *count )
  26854. {
  26855. char shortname[CS_SIZE];
  26856. int i;
  26857.  
  26858. - if( !name || !name[0] )
  26859. + if( !name || !*name )
  26860. return 0;
  26861.  
  26862. FS_FileBase( name, shortname );
  26863. @@ -333,7 +334,7 @@ qboolean Host_RegisterDecal( const char *name )
  26864.  
  26865. // register new decal
  26866. Q_strncpy( host.draw_decals[i], shortname, sizeof( host.draw_decals[i] ));
  26867. - num_decals++;
  26868. + *count += 1;
  26869.  
  26870. return true;
  26871. }
  26872. @@ -346,17 +347,16 @@ Host_InitDecals
  26873. void Host_InitDecals( void )
  26874. {
  26875. search_t *t;
  26876. - int i;
  26877. + int i, num_decals = 0;
  26878.  
  26879. memset( host.draw_decals, 0, sizeof( host.draw_decals ));
  26880. - num_decals = 0;
  26881.  
  26882. // lookup all decals in decals.wad
  26883. t = FS_Search( "decals.wad/*.*", true, false );
  26884.  
  26885. for( i = 0; t && i < t->numfilenames; i++ )
  26886. {
  26887. - if( !Host_RegisterDecal( t->filenames[i] ))
  26888. + if( !Host_RegisterDecal( t->filenames[i], &num_decals ))
  26889. break;
  26890. }
  26891.  
  26892. @@ -373,27 +373,25 @@ Write ambient sounds into demo
  26893. */
  26894. void Host_RestartAmbientSounds( void )
  26895. {
  26896. - soundlist_t soundInfo[64];
  26897. + soundlist_t soundInfo[128];
  26898. string curtrack, looptrack;
  26899. int i, nSounds;
  26900. - fs_offset_t position;
  26901. + long position;
  26902.  
  26903. - if( !SV_Active( ))
  26904. - {
  26905. - return;
  26906. - }
  26907. + if( !SV_Active( )) return;
  26908.  
  26909. - nSounds = S_GetCurrentStaticSounds( soundInfo, 64 );
  26910. + nSounds = S_GetCurrentStaticSounds( soundInfo, 128 );
  26911.  
  26912. for( i = 0; i < nSounds; i++ )
  26913. {
  26914. - if( !soundInfo[i].looping || soundInfo[i].entnum == -1 )
  26915. + soundlist_t *si = &soundInfo[i];
  26916. +
  26917. + if( !si->looping || si->entnum == -1 )
  26918. continue;
  26919.  
  26920. MsgDev( D_NOTE, "Restarting sound %s...\n", soundInfo[i].name );
  26921. - S_StopSound( soundInfo[i].entnum, soundInfo[i].channel, soundInfo[i].name );
  26922. - SV_StartSound( pfnPEntityOfEntIndex( soundInfo[i].entnum ), CHAN_STATIC, soundInfo[i].name,
  26923. - soundInfo[i].volume, soundInfo[i].attenuation, 0, soundInfo[i].pitch );
  26924. + S_StopSound( si->entnum, si->channel, si->name );
  26925. + SV_StartSound( pfnPEntityOfEntIndex( si->entnum ), CHAN_STATIC, si->name, si->volume, si->attenuation, 0, si->pitch );
  26926. }
  26927.  
  26928. // restart soundtrack
  26929. @@ -418,10 +416,7 @@ void Host_RestartDecals( void )
  26930. sizebuf_t *msg;
  26931. int i;
  26932.  
  26933. - if( !SV_Active( ))
  26934. - {
  26935. - return;
  26936. - }
  26937. + if( !SV_Active( )) return;
  26938.  
  26939. // g-cont. add space for studiodecals if present
  26940. host.decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
  26941. @@ -465,20 +460,103 @@ void Host_RestartDecals( void )
  26942.  
  26943. /*
  26944. ===================
  26945. -Host_GetConsoleCommands
  26946. +Host_GetCommands
  26947.  
  26948. Add them exactly as if they had been typed at the console
  26949. ===================
  26950. */
  26951. -void Host_GetConsoleCommands( void )
  26952. +void Host_GetCommands( void )
  26953. {
  26954. char *cmd;
  26955.  
  26956. - if( host.type == HOST_DEDICATED )
  26957. + if( host.type != HOST_DEDICATED )
  26958. + return;
  26959. +
  26960. + cmd = Con_Input();
  26961. + if( cmd ) Cbuf_AddText( cmd );
  26962. +}
  26963. +
  26964. +/*
  26965. +===================
  26966. +Host_FrameTime
  26967. +
  26968. +Returns false if the time is too short to run a frame
  26969. +===================
  26970. +*/
  26971. +qboolean Host_FrameTime( float time )
  26972. +{
  26973. + static double oldtime;
  26974. + double minframetime;
  26975. + double fps;
  26976. +
  26977. + host.realtime += time;
  26978. +
  26979. + // limit fps to withing tolerable range
  26980. + fps = bound( HOST_MINFPS, HOST_FPS, HOST_MAXFPS );
  26981. + minframetime = ( 1.0 / fps );
  26982. +
  26983. + if(( host.realtime - oldtime ) < minframetime )
  26984. + {
  26985. + // framerate is too high
  26986. + return false;
  26987. + }
  26988. +
  26989. + host.frametime = host.realtime - oldtime;
  26990. + host.realframetime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
  26991. + oldtime = host.realtime;
  26992. +
  26993. + if( host_framerate->value > 0 && ( Host_IsLocalGame( )))
  26994. + {
  26995. + float fps = host_framerate->value;
  26996. + if( fps > 1 ) fps = 1.0f / fps;
  26997. + host.frametime = fps;
  26998. + }
  26999. + else
  27000. + { // don't allow really long or short frames
  27001. + host.frametime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
  27002. + }
  27003. +
  27004. + return true;
  27005. +}
  27006. +
  27007. +/*
  27008. +===================
  27009. +Host_RenderTime
  27010. +
  27011. +Returns false if the time is too short to render a frame
  27012. +===================
  27013. +*/
  27014. +qboolean Host_RenderTime( float time )
  27015. +{
  27016. + static double oldtime;
  27017. + static double newtime;
  27018. + double fps;
  27019. +
  27020. + newtime += time;
  27021. +
  27022. + // dedicated's tic_rate regulates server frame rate. Don't apply fps filter here.
  27023. + fps = host_maxfps->value;
  27024. +
  27025. + // clamp the fps in multiplayer games
  27026. + if( fps != 0 )
  27027. {
  27028. - cmd = Con_Input();
  27029. - if( cmd ) Cbuf_AddText( cmd );
  27030. + double minframetime;
  27031. +
  27032. + // limit fps to withing tolerable range
  27033. + fps = bound( MIN_FPS, fps, MAX_FPS );
  27034. +
  27035. + minframetime = 1.0 / fps;
  27036. +
  27037. + if(( newtime - oldtime ) < minframetime )
  27038. + {
  27039. + // framerate is too high
  27040. + return false;
  27041. + }
  27042. }
  27043. +
  27044. + oldtime = newtime;
  27045. +
  27046. + return true;
  27047. }
  27048.  
  27049. /*
  27050. @@ -498,6 +576,7 @@ qboolean Host_FilterTime( float time )
  27051. // dedicated's tic_rate regulates server frame rate. Don't apply fps filter here.
  27052. fps = host_maxfps->value;
  27053.  
  27054. + // clamp the fps in multiplayer games
  27055. if( fps != 0 )
  27056. {
  27057. float minframetime;
  27058. @@ -542,18 +621,39 @@ void Host_Frame( float time )
  27059. if( setjmp( host.abortframe ))
  27060. return;
  27061.  
  27062. - Host_InputFrame (); // input frame
  27063. + // new-style game loop
  27064. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  27065. + {
  27066. + // decide the simulation time
  27067. + if( Host_FrameTime( time ))
  27068. + {
  27069. + Host_InputFrame (); // input frame
  27070. + Host_GetCommands(); // dedicated
  27071. + Host_ServerFrame(); // server frame
  27072. + Host_ClientFrame(); // client frame
  27073. + host.framecount++;
  27074. + }
  27075.  
  27076. - // decide the simulation time
  27077. - if( !Host_FilterTime( time ))
  27078. - return;
  27079. + // clamp the renderer time
  27080. + if( !Host_RenderTime( time ))
  27081. + return;
  27082. +
  27083. + Host_RenderFrame (); // render frame
  27084. + }
  27085. + else // classic game loop
  27086. + {
  27087. + Host_InputFrame (); // input frame
  27088.  
  27089. - Host_GetConsoleCommands ();
  27090. + // decide the simulation time
  27091. + if( !Host_FilterTime( time ))
  27092. + return;
  27093.  
  27094. - Host_ServerFrame (); // server frame
  27095. - Host_ClientFrame (); // client frame
  27096. + Host_GetCommands ();
  27097. + Host_ServerFrame (); // server frame
  27098. + Host_ClientFrame (); // client frame
  27099.  
  27100. - host.framecount++;
  27101. + host.framecount++;
  27102. + }
  27103. }
  27104.  
  27105. /*
  27106. @@ -707,7 +807,7 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
  27107. GlobalMemoryStatus( &lpBuffer );
  27108.  
  27109. if( !GetCurrentDirectory( sizeof( host.rootdir ), host.rootdir ))
  27110. - Sys_Error( "couldn't determine current directory" );
  27111. + Sys_Error( "couldn't determine current directory\n" );
  27112.  
  27113. if( host.rootdir[Q_strlen( host.rootdir ) - 1] == '/' )
  27114. host.rootdir[Q_strlen( host.rootdir ) - 1] = 0;
  27115. @@ -718,7 +818,7 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
  27116. host.state = HOST_INIT; // initialzation started
  27117. host.developer = host.old_developer = 0;
  27118.  
  27119. - CRT_Init(); // init some CRT functions
  27120. + Memory_Init(); // init memory subsystem
  27121.  
  27122. // some commands may turn engine into infinity loop,
  27123. // e.g. xash.exe +game xash -game xash
  27124. @@ -728,7 +828,9 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
  27125.  
  27126. host.mempool = Mem_AllocPool( "Zone Engine" );
  27127.  
  27128. - if( Sys_CheckParm( "-console" )) host.developer = 1;
  27129. + if( Sys_CheckParm( "-console" ))
  27130. + host.developer = 1;
  27131. +
  27132. if( Sys_CheckParm( "-dev" ))
  27133. {
  27134. if( Sys_GetParmFromCmdLine( "-dev", dev_level ))
  27135. @@ -943,9 +1045,9 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
  27136. Cmd_RemoveCommand( "setgl" );
  27137.  
  27138. // we need to execute it again here
  27139. - Cmd_ExecuteString( "exec config.cfg\n", src_command );
  27140. - oldtime = Sys_DoubleTime();
  27141. - SCR_CheckStartupVids(); // must be last
  27142. + Cmd_ExecuteString( "exec config.cfg\n" );
  27143. + oldtime = Sys_DoubleTime() - 0.1;
  27144. + SCR_CheckStartupVids(); // must be last
  27145.  
  27146. // main window message loop
  27147. while( !host.crashed )
  27148. diff --git b/engine/common/imagelib/img_bmp.c a/engine/common/imagelib/img_bmp.c
  27149. index e57f5ae..c7d6f31 100644
  27150. --- b/engine/common/imagelib/img_bmp.c
  27151. +++ a/engine/common/imagelib/img_bmp.c
  27152. @@ -14,6 +14,7 @@ GNU General Public License for more details.
  27153. */
  27154.  
  27155. #include "imagelib.h"
  27156. +#include "mathlib.h"
  27157.  
  27158. /*
  27159. =============
  27160. @@ -26,6 +27,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
  27161. byte palette[256][4];
  27162. int i, columns, column, rows, row, bpp = 1;
  27163. int cbPalBytes = 0, padSize = 0, bps = 0;
  27164. + int reflectivity[3] = { 0, 0, 0 };
  27165. qboolean load_qfont = false;
  27166. bmp_t bhdr;
  27167.  
  27168. @@ -53,7 +55,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
  27169. if( bhdr.reserved0 != 0 ) return false;
  27170. if( bhdr.planes != 1 ) return false;
  27171.  
  27172. - if( Q_memcmp( bhdr.id, "BM", 2 ))
  27173. + if( memcmp( bhdr.id, "BM", 2 ))
  27174. {
  27175. MsgDev( D_ERROR, "Image_LoadBMP: only Windows-style BMP files supported (%s)\n", name );
  27176. return false;
  27177. @@ -108,7 +110,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
  27178. else cbPalBytes = bhdr.colors * sizeof( RGBQUAD );
  27179. }
  27180.  
  27181. - Q_memcpy( palette, buf_p, cbPalBytes );
  27182. + memcpy( palette, buf_p, cbPalBytes );
  27183.  
  27184. if( host.overview_loading && bhdr.bitsPerPixel == 8 )
  27185. {
  27186. @@ -280,13 +282,20 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
  27187. Mem_Free( image.rgba );
  27188. return false;
  27189. }
  27190. +
  27191. if( !Image_CheckFlag( IL_KEEP_8BIT ) && ( red != green || green != blue ))
  27192. image.flags |= IMAGE_HAS_COLOR;
  27193. +
  27194. + reflectivity[0] += red;
  27195. + reflectivity[1] += green;
  27196. + reflectivity[2] += blue;
  27197. }
  27198. buf_p += padSize; // actual only for 4-bit bmps
  27199. }
  27200.  
  27201. + VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
  27202. if( image.palette ) Image_GetPaletteBMP( image.palette );
  27203. + image.depth = 1;
  27204.  
  27205. return true;
  27206. }
  27207. @@ -378,7 +387,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
  27208.  
  27209. if( host.write_to_clipboard )
  27210. {
  27211. - Q_memcpy( clipbuf + cur_size, &bmih, sizeof( bmih ));
  27212. + memcpy( clipbuf + cur_size, &bmih, sizeof( bmih ));
  27213. cur_size += sizeof( bmih );
  27214. }
  27215. else
  27216. @@ -409,7 +418,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
  27217.  
  27218. if( host.write_to_clipboard )
  27219. {
  27220. - Q_memcpy( clipbuf + cur_size, rgrgbPalette, cbPalBytes );
  27221. + memcpy( clipbuf + cur_size, rgrgbPalette, cbPalBytes );
  27222. cur_size += cbPalBytes;
  27223. }
  27224. else
  27225. @@ -450,7 +459,7 @@ qboolean Image_SaveBMP( const char *name, rgbdata_t *pix )
  27226.  
  27227. if( host.write_to_clipboard )
  27228. {
  27229. - Q_memcpy( clipbuf + cur_size, pbBmpBits, cbBmpBits );
  27230. + memcpy( clipbuf + cur_size, pbBmpBits, cbBmpBits );
  27231. cur_size += cbBmpBits;
  27232. Sys_SetClipboardData( clipbuf, total_size );
  27233. Z_Free( clipbuf );
  27234. diff --git b/engine/common/imagelib/img_dds.c a/engine/common/imagelib/img_dds.c
  27235. index 837ade9..c6f36f8 100644
  27236. --- b/engine/common/imagelib/img_dds.c
  27237. +++ a/engine/common/imagelib/img_dds.c
  27238. @@ -14,6 +14,7 @@ GNU General Public License for more details.
  27239. */
  27240.  
  27241. #include "imagelib.h"
  27242. +#include "mathlib.h"
  27243.  
  27244. qboolean Image_CheckDXT3Alpha( dds_t *hdr, byte *fin )
  27245. {
  27246. @@ -175,10 +176,10 @@ size_t Image_DXTCalcMipmapSize( dds_t *hdr )
  27247. int i, width, height;
  27248.  
  27249. // now correct buffer size
  27250. - for( i = 0; i < hdr->dwMipMapCount; i++ )
  27251. + for( i = 0; i < Q_max( 1, ( hdr->dwMipMapCount )); i++ )
  27252. {
  27253. - width = max( 1, ( hdr->dwWidth >> i ));
  27254. - height = max( 1, ( hdr->dwHeight >> i ));
  27255. + width = Q_max( 1, ( hdr->dwWidth >> i ));
  27256. + height = Q_max( 1, ( hdr->dwHeight >> i ));
  27257. buffsize += Image_DXTGetLinearSize( image.type, width, height, image.depth );
  27258. }
  27259.  
  27260. @@ -247,7 +248,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, size_t filesize )
  27261. return false;
  27262. }
  27263.  
  27264. - Q_memcpy( &header, buffer, sizeof( dds_t ));
  27265. + memcpy( &header, buffer, sizeof( dds_t ));
  27266.  
  27267. if( header.dwIdent != DDSHEADER )
  27268. return false; // it's not a dds file, just skip it
  27269. @@ -295,27 +296,37 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, size_t filesize )
  27270. switch( image.encode )
  27271. {
  27272. case DXT_ENCODE_COLOR_YCoCg:
  27273. - image.flags |= IMAGE_HAS_COLOR;
  27274. + SetBits( image.flags, IMAGE_HAS_COLOR );
  27275. break;
  27276. case DXT_ENCODE_NORMAL_AG_ORTHO:
  27277. case DXT_ENCODE_NORMAL_AG_STEREO:
  27278. case DXT_ENCODE_NORMAL_AG_PARABOLOID:
  27279. case DXT_ENCODE_NORMAL_AG_QUARTIC:
  27280. case DXT_ENCODE_NORMAL_AG_AZIMUTHAL:
  27281. - image.flags |= IMAGE_HAS_COLOR;
  27282. + SetBits( image.flags, IMAGE_HAS_COLOR );
  27283. break;
  27284. default: // check for real alpha-pixels
  27285. if( image.type == PF_DXT3 && Image_CheckDXT3Alpha( &header, fin ))
  27286. - image.flags |= IMAGE_HAS_ALPHA;
  27287. + SetBits( image.flags, IMAGE_HAS_ALPHA );
  27288. else if( image.type == PF_DXT5 && Image_CheckDXT5Alpha( &header, fin ))
  27289. - image.flags |= IMAGE_HAS_ALPHA;
  27290. - image.flags |= IMAGE_HAS_COLOR;
  27291. + SetBits( image.flags, IMAGE_HAS_ALPHA );
  27292. + if( !FBitSet( header.dsPixelFormat.dwFlags, DDS_LUMINANCE ))
  27293. + SetBits( image.flags, IMAGE_HAS_COLOR ); // FIXME: analyze colors
  27294. break;
  27295. }
  27296.  
  27297. + if( header.dwReserved1[1] != 0 )
  27298. + {
  27299. + // store texture reflectivity
  27300. + image.fogParams[0] = ((header.dwReserved1[1] & 0x000000FF) >> 0 );
  27301. + image.fogParams[1] = ((header.dwReserved1[1] & 0x0000FF00) >> 8 );
  27302. + image.fogParams[2] = ((header.dwReserved1[1] & 0x00FF0000) >> 16);
  27303. + image.fogParams[3] = ((header.dwReserved1[1] & 0xFF000000) >> 24);
  27304. + }
  27305. +
  27306. // dds files will be uncompressed on a render. requires minimal of info for set this
  27307. image.rgba = Mem_Alloc( host.imagepool, image.size );
  27308. - Q_memcpy( image.rgba, fin, image.size );
  27309. + memcpy( image.rgba, fin, image.size );
  27310. image.flags |= IMAGE_DDS_FORMAT;
  27311.  
  27312. return true;
  27313. diff --git b/engine/common/imagelib/img_main.c a/engine/common/imagelib/img_main.c
  27314. index 8ed68f0..0b86257 100644
  27315. --- b/engine/common/imagelib/img_main.c
  27316. +++ a/engine/common/imagelib/img_main.c
  27317. @@ -102,12 +102,12 @@ void Image_Reset( void )
  27318. image.source_width = image.source_height = 0;
  27319. image.source_type = image.num_mips = 0;
  27320. image.num_sides = image.flags = 0;
  27321. + image.encode = DXT_ENCODE_DEFAULT;
  27322. image.type = PF_UNKNOWN;
  27323. image.fogParams[0] = 0;
  27324. image.fogParams[1] = 0;
  27325. image.fogParams[2] = 0;
  27326. image.fogParams[3] = 0;
  27327. - image.encode = 0;
  27328.  
  27329. // pointers will be saved with prevoius picture struct
  27330. // don't care about it
  27331. @@ -203,7 +203,7 @@ qboolean FS_AddSideToPack( const char *name, int adjust_flags )
  27332. if( resampled ) image.rgba = Image_Copy( image.size );
  27333.  
  27334. image.cubemap = Mem_Realloc( host.imagepool, image.cubemap, image.ptr + image.size );
  27335. - Q_memcpy( image.cubemap + image.ptr, image.rgba, image.size ); // add new side
  27336. + memcpy( image.cubemap + image.ptr, image.rgba, image.size ); // add new side
  27337.  
  27338. Mem_Free( image.rgba ); // release source buffer
  27339. image.ptr += image.size; // move to next
  27340. @@ -494,13 +494,13 @@ rgbdata_t *FS_CopyImage( rgbdata_t *in )
  27341. if( palSize )
  27342. {
  27343. out->palette = Mem_Alloc( host.imagepool, palSize );
  27344. - Q_memcpy( out->palette, in->palette, palSize );
  27345. + memcpy( out->palette, in->palette, palSize );
  27346. }
  27347.  
  27348. if( in->size )
  27349. {
  27350. out->buffer = Mem_Alloc( host.imagepool, in->size );
  27351. - Q_memcpy( out->buffer, in->buffer, in->size );
  27352. + memcpy( out->buffer, in->buffer, in->size );
  27353. }
  27354.  
  27355. return out;
  27356. diff --git b/engine/common/imagelib/img_quant.c a/engine/common/imagelib/img_quant.c
  27357. index 4ea8250..2ad8f7d 100644
  27358. --- b/engine/common/imagelib/img_quant.c
  27359. +++ a/engine/common/imagelib/img_quant.c
  27360. @@ -375,31 +375,25 @@ void learn( void )
  27361. if( rad <= 1 ) rad = 0;
  27362.  
  27363. for( i = 0; i < rad; i++ )
  27364. - {
  27365. - radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
  27366. - }
  27367. + radpower[i] = alpha * ((( rad * rad - i * i ) * radbias ) / ( rad * rad ));
  27368. +
  27369. + if( delta <= 0 ) return;
  27370.  
  27371. if(( lengthcount % prime1 ) != 0 )
  27372. {
  27373. - step = image.bpp * prime1;
  27374. + step = prime1 * image.bpp;
  27375. + }
  27376. + else if(( lengthcount % prime2 ) != 0 )
  27377. + {
  27378. + step = prime2 * image.bpp;
  27379. + }
  27380. + else if(( lengthcount % prime3 ) != 0 )
  27381. + {
  27382. + step = prime3 * image.bpp;
  27383. }
  27384. else
  27385. {
  27386. - if(( lengthcount % prime2 ) != 0 )
  27387. - {
  27388. - step = image.bpp * prime2;
  27389. - }
  27390. - else
  27391. - {
  27392. - if(( lengthcount % prime3 ) != 0 )
  27393. - {
  27394. - step = image.bpp * prime3;
  27395. - }
  27396. - else
  27397. - {
  27398. - step = image.bpp * prime4;
  27399. - }
  27400. - }
  27401. + step = prime4 * image.bpp;
  27402. }
  27403.  
  27404. i = 0;
  27405. @@ -427,7 +421,7 @@ void learn( void )
  27406. if( rad <= 1 ) rad = 0;
  27407.  
  27408. for( j = 0; j < rad; j++ )
  27409. - radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
  27410. + radpower[j] = alpha * ((( rad * rad - j * j ) * radbias ) / ( rad * rad ));
  27411. }
  27412. }
  27413. }
  27414. @@ -470,7 +464,7 @@ rgbdata_t *Image_Quantize( rgbdata_t *pic )
  27415. }
  27416.  
  27417. pic->buffer = Mem_Realloc( host.imagepool, pic->buffer, image.size );
  27418. - Q_memcpy( pic->buffer, image.tempbuffer, image.size );
  27419. + memcpy( pic->buffer, image.tempbuffer, image.size );
  27420. pic->type = PF_INDEXED_24;
  27421. pic->size = image.size;
  27422.  
  27423. diff --git b/engine/common/imagelib/img_tga.c a/engine/common/imagelib/img_tga.c
  27424. index 8c771b1..9fa019d 100644
  27425. --- b/engine/common/imagelib/img_tga.c
  27426. +++ a/engine/common/imagelib/img_tga.c
  27427. @@ -14,6 +14,7 @@ GNU General Public License for more details.
  27428. */
  27429.  
  27430. #include "imagelib.h"
  27431. +#include "mathlib.h"
  27432.  
  27433. /*
  27434. =============
  27435. @@ -26,6 +27,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
  27436. byte *buf_p, *pixbuf, *targa_rgba;
  27437. byte palette[256][4], red = 0, green = 0, blue = 0, alpha = 0;
  27438. int readpixelcount, pixelcount;
  27439. + int reflectivity[3] = { 0, 0, 0 };
  27440. qboolean compressed;
  27441. tga_t targa_header;
  27442.  
  27443. @@ -193,6 +195,10 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
  27444. if( red != green || green != blue )
  27445. image.flags |= IMAGE_HAS_COLOR;
  27446.  
  27447. + reflectivity[0] += red;
  27448. + reflectivity[1] += green;
  27449. + reflectivity[2] += blue;
  27450. +
  27451. *pixbuf++ = red;
  27452. *pixbuf++ = green;
  27453. *pixbuf++ = blue;
  27454. @@ -206,6 +212,10 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
  27455. }
  27456. }
  27457. }
  27458. +
  27459. + VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
  27460. + image.depth = 1;
  27461. +
  27462. return true;
  27463. }
  27464.  
  27465. @@ -229,7 +239,6 @@ qboolean Image_SaveTGA( const char *name, rgbdata_t *pix )
  27466. else outsize = pix->width * pix->height * 3 + 18 + Q_strlen( comment );
  27467.  
  27468. buffer = (byte *)Mem_Alloc( host.imagepool, outsize );
  27469. - Q_memset( buffer, 0, 18 );
  27470.  
  27471. // prepare header
  27472. buffer[0] = Q_strlen( comment ); // tga comment length
  27473. diff --git b/engine/common/imagelib/img_utils.c a/engine/common/imagelib/img_utils.c
  27474. index 651d270..23c5c0b 100644
  27475. --- b/engine/common/imagelib/img_utils.c
  27476. +++ a/engine/common/imagelib/img_utils.c
  27477. @@ -177,6 +177,11 @@ void Image_Init( void )
  27478. image.loadformats = load_game;
  27479. image.saveformats = save_game;
  27480. break;
  27481. + case HOST_DEDICATED:
  27482. + image.cmd_flags = 0;
  27483. + image.loadformats = load_game;
  27484. + image.saveformats = save_null;
  27485. + break;
  27486. default: // all other instances not using imagelib or will be reinstalling later
  27487. image.loadformats = load_null;
  27488. image.saveformats = save_null;
  27489. @@ -197,7 +202,7 @@ byte *Image_Copy( size_t size )
  27490. byte *out;
  27491.  
  27492. out = Mem_Alloc( host.imagepool, size );
  27493. - Q_memcpy( out, image.tempbuffer, size );
  27494. + memcpy( out, image.tempbuffer, size );
  27495.  
  27496. return out;
  27497. }
  27498. @@ -279,9 +284,9 @@ int Image_ComparePalette( const byte *pal )
  27499. {
  27500. if( pal == NULL )
  27501. return PAL_INVALID;
  27502. - else if( !Q_memcmp( palette_q1, pal, 768 ))
  27503. + else if( !memcmp( palette_q1, pal, 768 ))
  27504. return PAL_QUAKE1;
  27505. - else if( !Q_memcmp( palette_hl, pal, 768 ))
  27506. + else if( !memcmp( palette_hl, pal, 768 ))
  27507. return PAL_HALFLIFE;
  27508. return PAL_CUSTOM;
  27509. }
  27510. @@ -442,7 +447,7 @@ void Image_CopyPalette32bit( void )
  27511. {
  27512. if( image.palette ) return; // already created ?
  27513. image.palette = Mem_Alloc( host.imagepool, 1024 );
  27514. - Q_memcpy( image.palette, image.d_currentpal, 1024 );
  27515. + memcpy( image.palette, image.d_currentpal, 1024 );
  27516. }
  27517.  
  27518. void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
  27519. @@ -462,6 +467,8 @@ void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
  27520.  
  27521. maxcol = max( max( r, g ), b ) / 255.0f;
  27522. mincol = min( min( r, g ), b ) / 255.0f;
  27523. +
  27524. + if( maxcol == 0 ) continue;
  27525.  
  27526. val = maxcol;
  27527. sat = (maxcol - mincol) / maxcol;
  27528. @@ -528,7 +535,7 @@ void Image_CopyParms( rgbdata_t *src )
  27529. image.size = src->size;
  27530. image.palette = src->palette; // may be NULL
  27531.  
  27532. - Q_memcpy( image.fogParams, src->fogParams, sizeof( image.fogParams ));
  27533. + memcpy( image.fogParams, src->fogParams, sizeof( image.fogParams ));
  27534. }
  27535.  
  27536. /*
  27537. @@ -567,7 +574,7 @@ qboolean Image_Copy8bitRGBA( const byte *in, byte *out, int pixels )
  27538. // check for color
  27539. for( i = 0; i < 256; i++ )
  27540. {
  27541. - col = (rgba_t *)image.d_currentpal[i];
  27542. + col = (rgba_t *)&image.d_currentpal[i];
  27543. if( col[0] != col[1] || col[1] != col[2] )
  27544. {
  27545. image.flags |= IMAGE_HAS_COLOR;
  27546. @@ -713,7 +720,7 @@ void Image_Resample32Lerp( const void *indata, int inwidth, int inheight, void *
  27547. if( yi != oldy )
  27548. {
  27549. inrow = (byte *)indata + inwidth4 * yi;
  27550. - if (yi == oldy+1) Q_memcpy( resamplerow1, resamplerow2, outwidth4 );
  27551. + if (yi == oldy+1) memcpy( resamplerow1, resamplerow2, outwidth4 );
  27552. else Image_Resample32LerpLine( inrow, resamplerow1, inwidth, outwidth );
  27553. Image_Resample32LerpLine( inrow + inwidth4, resamplerow2, inwidth, outwidth );
  27554. oldy = yi;
  27555. @@ -779,12 +786,12 @@ void Image_Resample32Lerp( const void *indata, int inwidth, int inheight, void *
  27556. if( yi != oldy )
  27557. {
  27558. inrow = (byte *)indata + inwidth4*yi;
  27559. - if( yi == oldy + 1 ) Q_memcpy( resamplerow1, resamplerow2, outwidth4 );
  27560. + if( yi == oldy + 1 ) memcpy( resamplerow1, resamplerow2, outwidth4 );
  27561. else Image_Resample32LerpLine( inrow, resamplerow1, inwidth, outwidth);
  27562. oldy = yi;
  27563. }
  27564.  
  27565. - Q_memcpy( out, resamplerow1, outwidth4 );
  27566. + memcpy( out, resamplerow1, outwidth4 );
  27567. }
  27568. }
  27569.  
  27570. @@ -860,7 +867,7 @@ void Image_Resample24Lerp( const void *indata, int inwidth, int inheight, void *
  27571. if( yi != oldy )
  27572. {
  27573. inrow = (byte *)indata + inwidth3 * yi;
  27574. - if( yi == oldy + 1) Q_memcpy( resamplerow1, resamplerow2, outwidth3 );
  27575. + if( yi == oldy + 1) memcpy( resamplerow1, resamplerow2, outwidth3 );
  27576. else Image_Resample24LerpLine( inrow, resamplerow1, inwidth, outwidth );
  27577. Image_Resample24LerpLine( inrow + inwidth3, resamplerow2, inwidth, outwidth );
  27578. oldy = yi;
  27579. @@ -919,12 +926,12 @@ void Image_Resample24Lerp( const void *indata, int inwidth, int inheight, void *
  27580. if( yi != oldy )
  27581. {
  27582. inrow = (byte *)indata + inwidth3*yi;
  27583. - if( yi == oldy + 1) Q_memcpy( resamplerow1, resamplerow2, outwidth3 );
  27584. + if( yi == oldy + 1) memcpy( resamplerow1, resamplerow2, outwidth3 );
  27585. else Image_Resample24LerpLine( inrow, resamplerow1, inwidth, outwidth );
  27586. oldy = yi;
  27587. }
  27588.  
  27589. - Q_memcpy( out, resamplerow1, outwidth3 );
  27590. + memcpy( out, resamplerow1, outwidth3 );
  27591. }
  27592. }
  27593.  
  27594. @@ -1103,8 +1110,8 @@ byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int ou
  27595. return (byte *)indata;
  27596. }
  27597.  
  27598. - if( samples == 1 ) Q_memset( out, 0xFF, newsize ); // last palette color
  27599. - else Q_memset( out, 0x00808080, newsize ); // gray (alpha leaved 0x00)
  27600. + if( samples == 1 ) memset( out, 0xFF, newsize ); // last palette color
  27601. + else memset( out, 0x00808080, newsize ); // gray (alpha leaved 0x00)
  27602.  
  27603. for( y = 0; y < outheight; y++ )
  27604. {
  27605. @@ -1114,7 +1121,7 @@ byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int ou
  27606. {
  27607. if( x < inwidth )
  27608. *out++ = *in++;
  27609. - else *out++;
  27610. + else out++;
  27611. }
  27612. }
  27613. }
  27614. @@ -1260,7 +1267,7 @@ qboolean Image_AddIndexedImageToPack( const byte *in, int width, int height )
  27615.  
  27616. // reallocate image buffer
  27617. image.rgba = Mem_Alloc( host.imagepool, image.size );
  27618. - if( !expand_to_rgba ) Q_memcpy( image.rgba, in, image.size );
  27619. + if( !expand_to_rgba ) memcpy( image.rgba, in, image.size );
  27620. else if( !Image_Copy8bitRGBA( in, image.rgba, mipsize ))
  27621. return false; // probably pallette not installed
  27622.  
  27623. @@ -1331,7 +1338,7 @@ qboolean Image_Decompress( const byte *data )
  27624. break;
  27625. case PF_RGBA_32:
  27626. // fast default case
  27627. - Q_memcpy( fout, fin, size );
  27628. + memcpy( fout, fin, size );
  27629. break;
  27630. default: return false;
  27631. }
  27632. @@ -1357,7 +1364,7 @@ rgbdata_t *Image_DecompressInternal( rgbdata_t *pic )
  27633. pic->type = PF_RGBA_32;
  27634.  
  27635. pic->buffer = Mem_Realloc( host.imagepool, pic->buffer, image.size );
  27636. - Q_memcpy( pic->buffer, image.tempbuffer, image.size );
  27637. + memcpy( pic->buffer, image.tempbuffer, image.size );
  27638. if( pic->palette ) Mem_Free( pic->palette );
  27639. pic->flags = image.flags;
  27640. pic->palette = NULL;
  27641. @@ -1538,7 +1545,7 @@ qboolean Image_ApplyFilter( rgbdata_t *pic, int filter, float factor, float bias
  27642. }
  27643.  
  27644. // copy result back
  27645. - Q_memcpy( fin, fout, size );
  27646. + memcpy( fin, fout, size );
  27647.  
  27648. return true;
  27649. }
  27650. @@ -1567,7 +1574,7 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
  27651. if( flags & IMAGE_MAKE_LUMA )
  27652. {
  27653. out = Image_CreateLumaInternal( pic->buffer, pic->width, pic->height, pic->type, pic->flags );
  27654. - if( pic->buffer != out ) Q_memcpy( pic->buffer, image.tempbuffer, pic->size );
  27655. + if( pic->buffer != out ) memcpy( pic->buffer, image.tempbuffer, pic->size );
  27656. pic->flags &= ~IMAGE_HAS_LUMA;
  27657. }
  27658.  
  27659. @@ -1585,7 +1592,7 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, float gamma, uin
  27660. if( filter ) Image_ApplyFilter( pic, filter->filter, filter->factor, filter->bias, filter->flags, filter->blendFunc );
  27661.  
  27662. out = Image_FlipInternal( pic->buffer, &pic->width, &pic->height, pic->type, flags );
  27663. - if( pic->buffer != out ) Q_memcpy( pic->buffer, image.tempbuffer, pic->size );
  27664. + if( pic->buffer != out ) memcpy( pic->buffer, image.tempbuffer, pic->size );
  27665.  
  27666. if(( flags & IMAGE_RESAMPLE && width > 0 && height > 0 ) || ( flags & IMAGE_ROUND ) || ( flags & IMAGE_ROUNDFILLER ))
  27667. {
  27668. diff --git b/engine/common/imagelib/img_wad.c a/engine/common/imagelib/img_wad.c
  27669. index 3c0f490..4f90112 100644
  27670. --- b/engine/common/imagelib/img_wad.c
  27671. +++ a/engine/common/imagelib/img_wad.c
  27672. @@ -58,6 +58,7 @@ qboolean Image_LoadPAL( const char *name, const byte *buffer, size_t filesize )
  27673. image.rgba = NULL; // only palette, not real image
  27674. image.size = 1024; // expanded palette
  27675. image.width = image.height = 0;
  27676. + image.depth = 1;
  27677.  
  27678. return true;
  27679. }
  27680. @@ -80,7 +81,7 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
  27681. if( filesize < sizeof( font ))
  27682. return false;
  27683.  
  27684. - Q_memcpy( &font, buffer, sizeof( font ));
  27685. + memcpy( &font, buffer, sizeof( font ));
  27686.  
  27687. // last sixty four bytes - what the hell ????
  27688. size = sizeof( qfont_t ) - 4 + ( font.height * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
  27689. @@ -119,6 +120,7 @@ qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
  27690. }
  27691.  
  27692. image.type = PF_INDEXED_32; // 32-bit palette
  27693. + image.depth = 1;
  27694.  
  27695. return Image_AddIndexedImageToPack( fin, image.width, image.height );
  27696. }
  27697. @@ -170,6 +172,7 @@ qboolean Image_LoadMDL( const char *name, const byte *buffer, size_t filesize )
  27698. }
  27699.  
  27700. image.type = PF_INDEXED_32; // 32-bit palete
  27701. + image.depth = 1;
  27702.  
  27703. return Image_AddIndexedImageToPack( fin, image.width, image.height );
  27704. }
  27705. @@ -214,6 +217,7 @@ qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize )
  27706. // sorry, can't validate palette rendermode
  27707. if( !Image_LumpValidSize( name )) return false;
  27708. image.type = PF_INDEXED_32; // 32-bit palete
  27709. + image.depth = 1;
  27710.  
  27711. // detect alpha-channel by palette type
  27712. switch( image.d_rendermode )
  27713. @@ -253,24 +257,12 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize )
  27714. if( Q_stristr( name, "palette.lmp" ))
  27715. return Image_LoadPAL( name, buffer, filesize );
  27716.  
  27717. - // greatest hack from id software
  27718. - if( image.hint != IL_HINT_HL && Q_stristr( name, "conchars" ))
  27719. - {
  27720. - image.width = image.height = 128;
  27721. - image.flags |= IMAGE_HAS_ALPHA;
  27722. - rendermode = LUMP_QFONT;
  27723. - filesize += sizeof(lmp);
  27724. - fin = (byte *)buffer;
  27725. - }
  27726. - else
  27727. - {
  27728. - fin = (byte *)buffer;
  27729. - Q_memcpy( &lmp, fin, sizeof( lmp ));
  27730. - image.width = lmp.width;
  27731. - image.height = lmp.height;
  27732. - rendermode = LUMP_NORMAL;
  27733. - fin += sizeof(lmp);
  27734. - }
  27735. + fin = (byte *)buffer;
  27736. + memcpy( &lmp, fin, sizeof( lmp ));
  27737. + image.width = lmp.width;
  27738. + image.height = lmp.height;
  27739. + rendermode = LUMP_NORMAL;
  27740. + fin += sizeof( lmp );
  27741.  
  27742. pixels = image.width * image.height;
  27743.  
  27744. @@ -305,6 +297,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize )
  27745. if( fin[0] == 255 ) image.flags |= IMAGE_HAS_ALPHA;
  27746. Image_GetPaletteLMP( pal, rendermode );
  27747. image.type = PF_INDEXED_32; // 32-bit palete
  27748. + image.depth = 1;
  27749.  
  27750. return Image_AddIndexedImageToPack( fin, image.width, image.height );
  27751. }
  27752. @@ -321,6 +314,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
  27753. byte *fin, *pal;
  27754. int ofs[4], rendermode;
  27755. int i, pixels, numcolors;
  27756. + int reflectivity[3] = { 0, 0, 0 };
  27757.  
  27758. if( filesize < sizeof( mip ))
  27759. {
  27760. @@ -328,14 +322,14 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
  27761. return false;
  27762. }
  27763.  
  27764. - Q_memcpy( &mip, buffer, sizeof( mip ));
  27765. + memcpy( &mip, buffer, sizeof( mip ));
  27766. image.width = mip.width;
  27767. image.height = mip.height;
  27768.  
  27769. if( !Image_ValidSize( name ))
  27770. return false;
  27771.  
  27772. - Q_memcpy( ofs, mip.offsets, sizeof( ofs ));
  27773. + memcpy( ofs, mip.offsets, sizeof( ofs ));
  27774. pixels = image.width * image.height;
  27775.  
  27776. if( image.hint != IL_HINT_Q1 && filesize >= (int)sizeof(mip) + ((pixels * 85)>>6) + sizeof(short) + 768)
  27777. @@ -462,7 +456,20 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
  27778. // calc the decal reflectivity
  27779. image.fogParams[3] = VectorAvg( image.fogParams );
  27780. }
  27781. + else if( pal != NULL )// calc texture reflectivity
  27782. + {
  27783. + for( i = 0; i < 256; i++ )
  27784. + {
  27785. + reflectivity[0] += pal[i*3+0];
  27786. + reflectivity[1] += pal[i*3+1];
  27787. + reflectivity[2] += pal[i*3+2];
  27788. + }
  27789. +
  27790. + VectorDivide( reflectivity, 256, image.fogParams );
  27791. + }
  27792.  
  27793. image.type = PF_INDEXED_32; // 32-bit palete
  27794. + image.depth = 1;
  27795. +
  27796. return Image_AddIndexedImageToPack( fin, image.width, image.height );
  27797. }
  27798. \ No newline at end of file
  27799. diff --git b/engine/common/input.c a/engine/common/input.c
  27800. index 046f082..8a0f684 100644
  27801. --- b/engine/common/input.c
  27802. +++ a/engine/common/input.c
  27803. @@ -105,8 +105,8 @@ static int Host_MapKey( int key )
  27804. case 0x0D: return K_KP_ENTER;
  27805. case 0x2F: return K_KP_SLASH;
  27806. case 0xAF: return K_KP_PLUS;
  27807. + default: return result;
  27808. }
  27809. - return result;
  27810. }
  27811. }
  27812.  
  27813. @@ -290,7 +290,7 @@ void IN_DeactivateMouse( void )
  27814.  
  27815. /*
  27816. ================
  27817. -IN_Mouse
  27818. +IN_MouseMove
  27819. ================
  27820. */
  27821. void IN_MouseMove( void )
  27822. @@ -331,12 +331,12 @@ void IN_MouseEvent( int mstate )
  27823. // perform button actions
  27824. for( i = 0; i < in_mouse_buttons; i++ )
  27825. {
  27826. - if(( mstate & ( 1<<i )) && !( in_mouse_oldbuttonstate & ( 1<<i )))
  27827. + if( FBitSet( mstate, BIT( i )) && !FBitSet( in_mouse_oldbuttonstate, BIT( i )))
  27828. {
  27829. Key_Event( K_MOUSE1 + i, true );
  27830. }
  27831.  
  27832. - if(!( mstate & ( 1<<i )) && ( in_mouse_oldbuttonstate & ( 1<<i )))
  27833. + if( !FBitSet( mstate, BIT( i )) && FBitSet( in_mouse_oldbuttonstate, BIT( i )))
  27834. {
  27835. Key_Event( K_MOUSE1 + i, false );
  27836. }
  27837. @@ -383,13 +383,13 @@ void Host_InputFrame( void )
  27838.  
  27839. Cbuf_Execute ();
  27840.  
  27841. - if( host.state == HOST_RESTART )
  27842. - host.state = HOST_FRAME; // restart is finished
  27843. -
  27844. if( host.type == HOST_DEDICATED )
  27845. {
  27846. - // let the dedicated server some sleep
  27847. - Sys_Sleep( 1 );
  27848. + if( !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  27849. + {
  27850. + // let the dedicated server some sleep
  27851. + Sys_Sleep( 1 );
  27852. + }
  27853. }
  27854. else
  27855. {
  27856. @@ -435,7 +435,7 @@ IN_WndProc
  27857. main window procedure
  27858. ====================
  27859. */
  27860. -long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
  27861. +LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam )
  27862. {
  27863. int i, temp = 0;
  27864. qboolean fActivate;
  27865. @@ -455,7 +455,8 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
  27866. IN_ActivateCursor();
  27867. break;
  27868. case WM_MOUSEWHEEL:
  27869. - if( !in_mouseactive ) break;
  27870. + if( !in_mouseactive )
  27871. + break;
  27872. if(( short )HIWORD( wParam ) > 0 )
  27873. {
  27874. Key_Event( K_MWHEELUP, true );
  27875. @@ -478,17 +479,12 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
  27876. case WM_ACTIVATE:
  27877. if( host.state == HOST_SHUTDOWN )
  27878. break; // no need to activate
  27879. - if( host.state != HOST_RESTART )
  27880. - {
  27881. - if( HIWORD( wParam ))
  27882. - host.state = HOST_SLEEP;
  27883. - else if( LOWORD( wParam ) == WA_INACTIVE )
  27884. - host.state = HOST_NOFOCUS;
  27885. - else host.state = HOST_FRAME;
  27886. - fActivate = (host.state == HOST_FRAME) ? true : false;
  27887. - }
  27888. - else fActivate = true; // video sucessfully restarted
  27889. -
  27890. + if( HIWORD( wParam ))
  27891. + host.state = HOST_SLEEP;
  27892. + else if( LOWORD( wParam ) == WA_INACTIVE )
  27893. + host.state = HOST_NOFOCUS;
  27894. + else host.state = HOST_FRAME;
  27895. + fActivate = (host.state == HOST_FRAME) ? true : false;
  27896. wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER;
  27897.  
  27898. S_Activate( fActivate, host.hWnd );
  27899. @@ -500,7 +496,7 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
  27900. SetForegroundWindow( hWnd );
  27901. ShowWindow( hWnd, SW_RESTORE );
  27902. }
  27903. - else if( Cvar_VariableInteger( "fullscreen" ) && host.state != HOST_RESTART )
  27904. + else if( Cvar_VariableInteger( "fullscreen" ))
  27905. {
  27906. ShowWindow( hWnd, SW_MINIMIZE );
  27907. }
  27908. diff --git b/engine/common/input.h a/engine/common/input.h
  27909. index 284cfa2..9bff4fc 100644
  27910. --- b/engine/common/input.h
  27911. +++ a/engine/common/input.h
  27912. @@ -45,7 +45,7 @@ void IN_MouseEvent( int mstate );
  27913. void IN_ActivateMouse( qboolean force );
  27914. void IN_DeactivateMouse( void );
  27915. void IN_ToggleClientMouse( int newstate, int oldstate );
  27916. -long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam );
  27917. +LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam );
  27918. void IN_SetCursor( HICON hCursor );
  27919.  
  27920. #endif//INPUT_H
  27921. \ No newline at end of file
  27922. diff --git b/engine/common/keys.c a/engine/common/keys.c
  27923. index 4674409..aa9e2ab 100644
  27924. --- b/engine/common/keys.c
  27925. +++ a/engine/common/keys.c
  27926. @@ -46,18 +46,18 @@ keyname_t keynames[] =
  27927. {"RIGHTARROW", K_RIGHTARROW, "+right" },
  27928. {"ALT", K_ALT, "+strafe" },
  27929. {"CTRL", K_CTRL, "+attack" },
  27930. -{"SHIFT", K_SHIFT, "+speed" }, // replace with +attack2 ?
  27931. +{"SHIFT", K_SHIFT, "+speed" },
  27932. {"CAPSLOCK", K_CAPSLOCK, "" },
  27933. {"F1", K_F1, "cmd help" },
  27934. {"F2", K_F2, "menu_savegame" },
  27935. {"F3", K_F3, "menu_loadgame" },
  27936. -{"F4", K_F4, "menu_keys" },
  27937. -{"F5", K_F5, "menu_startserver" },
  27938. +{"F4", K_F4, "menu_controls" },
  27939. +{"F5", K_F5, "menu_creategame" },
  27940. {"F6", K_F6, "savequick" },
  27941. {"F7", K_F7, "loadquick" },
  27942. {"F8", K_F8, "stop" },
  27943. {"F9", K_F9, "" },
  27944. -{"F10", K_F10, "menu_quit" },
  27945. +{"F10", K_F10, "menu_main" },
  27946. {"F11", K_F11, "" },
  27947. {"F12", K_F12, "screenshot" },
  27948. {"INS", K_INS, "" },
  27949. @@ -106,7 +106,7 @@ Key_IsDown
  27950. */
  27951. qboolean Key_IsDown( int keynum )
  27952. {
  27953. - if ( keynum == -1 )
  27954. + if( keynum == -1 )
  27955. return false;
  27956. return keys[keynum].down;
  27957. }
  27958. @@ -179,6 +179,7 @@ int Key_StringToKeynum( const char *str )
  27959. if( !Q_stricmp( str, kn->name ))
  27960. return kn->keynum;
  27961. }
  27962. +
  27963. return -1;
  27964. }
  27965.  
  27966. @@ -275,6 +276,7 @@ int Key_GetKey( const char *binding )
  27967. if( keys[i].binding && !Q_stricmp( binding, keys[i].binding ))
  27968. return i;
  27969. }
  27970. +
  27971. return -1;
  27972. }
  27973.  
  27974. @@ -294,11 +296,13 @@ void Key_Unbind_f( void )
  27975. }
  27976.  
  27977. b = Key_StringToKeynum( Cmd_Argv( 1 ));
  27978. +
  27979. if( b == -1 )
  27980. {
  27981. Msg( "\"%s\" isn't a valid key\n", Cmd_Argv( 1 ));
  27982. return;
  27983. }
  27984. +
  27985. Key_SetBinding( b, "" );
  27986. }
  27987.  
  27988. @@ -325,8 +329,8 @@ Key_Reset_f
  27989. */
  27990. void Key_Reset_f( void )
  27991. {
  27992. - int i;
  27993. keyname_t *kn;
  27994. + int i;
  27995.  
  27996. // clear all keys first
  27997. for( i = 0; i < 256; i++ )
  27998. @@ -347,8 +351,8 @@ Key_Bind_f
  27999. */
  28000. void Key_Bind_f( void )
  28001. {
  28002. - int i, c, b;
  28003. char cmd[1024];
  28004. + int i, c, b;
  28005.  
  28006. c = Cmd_Argc();
  28007.  
  28008. @@ -398,12 +402,13 @@ void Key_WriteBindings( file_t *f )
  28009. int i;
  28010.  
  28011. if( !f ) return;
  28012. +
  28013. FS_Printf( f, "unbindall\n" );
  28014.  
  28015. for( i = 0; i < 256; i++ )
  28016. {
  28017. if( keys[i].binding && keys[i].binding[0] )
  28018. - FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
  28019. + FS_Printf( f, "bind %s \"%s\"\n", Key_KeynumToString( i ), keys[i].binding );
  28020. }
  28021. }
  28022.  
  28023. @@ -551,11 +556,15 @@ void Key_Event( int key, qboolean down )
  28024. // escape is always handled special
  28025. if( key == K_ESCAPE && down )
  28026. {
  28027. - kb = keys[key].binding;
  28028. -
  28029. switch( cls.key_dest )
  28030. {
  28031. case key_game:
  28032. + if( gl_showtextures->integer )
  28033. + {
  28034. + // close texture atlas
  28035. + Cvar_SetFloat( "r_showtextures", 0.0f );
  28036. + return;
  28037. + }
  28038. if( host.mouse_visible && cls.state != ca_cinematic )
  28039. {
  28040. clgame.dllFuncs.pfnKey_Event( down, key, keys[key].binding );
  28041. @@ -717,9 +726,7 @@ void Key_ClearStates( void )
  28042. }
  28043.  
  28044. if( clgame.hInstance )
  28045. - {
  28046. clgame.dllFuncs.IN_ClearStates();
  28047. - }
  28048. }
  28049.  
  28050. /*
  28051. diff --git b/engine/common/library.c a/engine/common/library.c
  28052. index f2688e3..efd3cfc 100644
  28053. --- b/engine/common/library.c
  28054. +++ a/engine/common/library.c
  28055. @@ -53,10 +53,10 @@ typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
  28056.  
  28057. static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
  28058. {
  28059. - int i, size;
  28060. - byte *dest;
  28061. - byte *codeBase = module->codeBase;
  28062. - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
  28063. + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers );
  28064. + byte *codeBase = module->codeBase;
  28065. + int i, size;
  28066. + byte *dest;
  28067.  
  28068. for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
  28069. {
  28070. @@ -85,9 +85,9 @@ static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMO
  28071.  
  28072. static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
  28073. {
  28074. - int i, size;
  28075. - byte *codeBase = module->codeBase;
  28076. - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
  28077. + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
  28078. + byte *codeBase = module->codeBase;
  28079. + int i, size;
  28080.  
  28081. for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ )
  28082. {
  28083. @@ -96,13 +96,13 @@ static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module )
  28084. size = old_headers->OptionalHeader.SectionAlignment;
  28085. if( size > 0 )
  28086. {
  28087. - VirtualFree( codeBase + section->VirtualAddress, size, MEM_DECOMMIT );
  28088. + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), size, MEM_DECOMMIT );
  28089. section->Misc.PhysicalAddress = 0;
  28090. }
  28091. continue;
  28092. }
  28093.  
  28094. - VirtualFree( codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_DECOMMIT );
  28095. + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), section->SizeOfRawData, MEM_DECOMMIT );
  28096. section->Misc.PhysicalAddress = 0;
  28097. }
  28098. }
  28099. @@ -147,16 +147,16 @@ static void FinalizeSections( MEMORYMODULE *module )
  28100. {
  28101. // change memory access flags
  28102. if( !VirtualProtect((LPVOID)section->Misc.PhysicalAddress, size, protect, &oldProtect ))
  28103. - Sys_Error( "Com_FinalizeSections: error protecting memory page\n" );
  28104. + Sys_Error( "FinalizeSections: error protecting memory page\n" );
  28105. }
  28106. }
  28107. }
  28108.  
  28109. static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
  28110. {
  28111. - DWORD i;
  28112. - byte *codeBase = module->codeBase;
  28113. - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
  28114. + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC );
  28115. + byte *codeBase = module->codeBase;
  28116. + DWORD i;
  28117.  
  28118. if( directory->Size > 0 )
  28119. {
  28120. @@ -200,12 +200,12 @@ static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta )
  28121.  
  28122. static FARPROC MemoryGetProcAddress( void *module, const char *name )
  28123. {
  28124. - int idx = -1;
  28125. - DWORD i, *nameRef;
  28126. - WORD *ordinal;
  28127. - PIMAGE_EXPORT_DIRECTORY exports;
  28128. - byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
  28129. - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
  28130. + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT );
  28131. + byte *codeBase = ((PMEMORYMODULE)module)->codeBase;
  28132. + PIMAGE_EXPORT_DIRECTORY exports;
  28133. + int idx = -1;
  28134. + DWORD i, *nameRef;
  28135. + WORD *ordinal;
  28136.  
  28137. if( directory->Size == 0 )
  28138. {
  28139. @@ -253,9 +253,9 @@ static FARPROC MemoryGetProcAddress( void *module, const char *name )
  28140.  
  28141. static int BuildImportTable( MEMORYMODULE *module )
  28142. {
  28143. - int result=1;
  28144. - byte *codeBase = module->codeBase;
  28145. - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
  28146. + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT );
  28147. + byte *codeBase = module->codeBase;
  28148. + int result = 1;
  28149.  
  28150. if( directory->Size > 0 )
  28151. {
  28152. diff --git b/engine/common/mathlib.c a/engine/common/mathlib.c
  28153. index 9d31d24..0811f85 100644
  28154. --- b/engine/common/mathlib.c
  28155. +++ a/engine/common/mathlib.c
  28156. @@ -430,17 +430,22 @@ AngleQuaternion
  28157.  
  28158. ====================
  28159. */
  28160. -void AngleQuaternion( const vec3_t angles, vec4_t q )
  28161. +void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio )
  28162. {
  28163. - float angle;
  28164. float sr, sp, sy, cr, cp, cy;
  28165.  
  28166. - angle = angles[2] * 0.5f;
  28167. - SinCos( angle, &sy, &cy );
  28168. - angle = angles[1] * 0.5f;
  28169. - SinCos( angle, &sp, &cp );
  28170. - angle = angles[0] * 0.5f;
  28171. - SinCos( angle, &sr, &cr );
  28172. + if( studio )
  28173. + {
  28174. + SinCos( angles[ROLL] * 0.5f, &sy, &cy );
  28175. + SinCos( angles[YAW] * 0.5f, &sp, &cp );
  28176. + SinCos( angles[PITCH] * 0.5f, &sr, &cr );
  28177. + }
  28178. + else
  28179. + {
  28180. + SinCos( DEG2RAD( angles[YAW] ) * 0.5f, &sy, &cy );
  28181. + SinCos( DEG2RAD( angles[PITCH] ) * 0.5f, &sp, &cp );
  28182. + SinCos( DEG2RAD( angles[ROLL] ) * 0.5f, &sr, &cr );
  28183. + }
  28184.  
  28185. q[0] = sr * cp * cy - cr * sp * sy; // X
  28186. q[1] = cr * sp * cy + sr * cp * sy; // Y
  28187. @@ -450,6 +455,19 @@ void AngleQuaternion( const vec3_t angles, vec4_t q )
  28188.  
  28189. /*
  28190. ====================
  28191. +QuaternionAngle
  28192. +
  28193. +====================
  28194. +*/
  28195. +void QuaternionAngle( const vec4_t q, vec3_t angles )
  28196. +{
  28197. + matrix3x4 mat;
  28198. + Matrix3x4_FromOriginQuat( mat, q, vec3_origin );
  28199. + Matrix3x4_AnglesFromMatrix( mat, angles );
  28200. +}
  28201. +
  28202. +/*
  28203. +====================
  28204. QuaternionSlerp
  28205.  
  28206. ====================
  28207. diff --git b/engine/common/mathlib.h a/engine/common/mathlib.h
  28208. index f44e3ff..c88c8e6 100644
  28209. --- b/engine/common/mathlib.h
  28210. +++ a/engine/common/mathlib.h
  28211. @@ -55,10 +55,21 @@ GNU General Public License for more details.
  28212.  
  28213. #define RAD_TO_STUDIO (32768.0 / M_PI)
  28214. #define STUDIO_TO_RAD (M_PI / 32768.0)
  28215. -#define nanmask (255<<23)
  28216. +
  28217. +#define INV127F ( 1.0f / 127.0f )
  28218. +#define INV255F ( 1.0f / 255.0f )
  28219. +#define MAKE_SIGNED( x ) ((( x ) * INV127F ) - 1.0f )
  28220. +
  28221. +#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
  28222. +#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
  28223. +#define Q_recip( a ) ((float)(1.0f / (float)(a)))
  28224. +#define Q_floor( a ) ((float)(long)(a))
  28225. +#define Q_ceil( a ) ((float)(long)((a) + 1))
  28226.  
  28227. #define Q_rint(x) ((x) < 0 ? ((int)((x)-0.5f)) : ((int)((x)+0.5f)))
  28228. -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
  28229. +#define IS_NAN(x) (((*(int *)&x) & (255<<23)) == (255<<23))
  28230. +
  28231. +#define ALIGN( x, a ) ((( x ) + (( size_t )( a ) - 1 )) & ~(( size_t )( a ) - 1 ))
  28232.  
  28233. #define VectorIsNAN(v) (IS_NAN(v[0]) || IS_NAN(v[1]) || IS_NAN(v[2]))
  28234. #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
  28235. @@ -123,7 +134,8 @@ qboolean BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t m
  28236. qboolean BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t origin, float radius );
  28237. float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
  28238.  
  28239. -void AngleQuaternion( const vec3_t angles, vec4_t q );
  28240. +void AngleQuaternion( const vec3_t angles, vec4_t q, qboolean studio );
  28241. +void QuaternionAngle( const vec4_t q, vec3_t angles );
  28242. void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt );
  28243. float RemapVal( float val, float A, float B, float C, float D );
  28244. float ApproachVal( float target, float value, float speed );
  28245. @@ -132,7 +144,7 @@ float ApproachVal( float target, float value, float speed );
  28246. // matrixlib.c
  28247. //
  28248. #define Matrix3x4_LoadIdentity( mat ) Matrix3x4_Copy( mat, matrix3x4_identity )
  28249. -#define Matrix3x4_Copy( out, in ) Q_memcpy( out, in, sizeof( matrix3x4 ))
  28250. +#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
  28251.  
  28252. void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] );
  28253. void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] );
  28254. @@ -145,9 +157,10 @@ void Matrix3x4_TransformPositivePlane( const matrix3x4 in, const vec3_t normal,
  28255. void Matrix3x4_SetOrigin( matrix3x4 out, float x, float y, float z );
  28256. void Matrix3x4_Invert_Simple( matrix3x4 out, const matrix3x4 in1 );
  28257. void Matrix3x4_OriginFromMatrix( const matrix3x4 in, float *out );
  28258. +void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
  28259.  
  28260. #define Matrix4x4_LoadIdentity( mat ) Matrix4x4_Copy( mat, matrix4x4_identity )
  28261. -#define Matrix4x4_Copy( out, in ) Q_memcpy( out, in, sizeof( matrix4x4 ))
  28262. +#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
  28263.  
  28264. void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] );
  28265. void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] );
  28266. diff --git b/engine/common/matrixlib.c a/engine/common/matrixlib.c
  28267. index af992d2..fdeea66 100644
  28268. --- b/engine/common/matrixlib.c
  28269. +++ a/engine/common/matrixlib.c
  28270. @@ -94,6 +94,26 @@ void Matrix3x4_OriginFromMatrix( const matrix3x4 in, float *out )
  28271. out[2] = in[2][3];
  28272. }
  28273.  
  28274. +void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out )
  28275. +{
  28276. + float xyDist = sqrt( in[0][0] * in[0][0] + in[1][0] * in[1][0] );
  28277. +
  28278. + if( xyDist > 0.001f )
  28279. + {
  28280. + // enough here to get angles?
  28281. + out[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
  28282. + out[1] = RAD2DEG( atan2( in[1][0], in[0][0] ));
  28283. + out[2] = RAD2DEG( atan2( in[2][1], in[2][2] ));
  28284. + }
  28285. + else
  28286. + {
  28287. + // forward is mostly Z, gimbal lock
  28288. + out[0] = RAD2DEG( atan2( -in[2][0], xyDist ));
  28289. + out[1] = RAD2DEG( atan2( -in[0][1], in[1][1] ));
  28290. + out[2] = 0.0f;
  28291. + }
  28292. +}
  28293. +
  28294. void Matrix3x4_FromOriginQuat( matrix3x4 out, const vec4_t quaternion, const vec3_t origin )
  28295. {
  28296. out[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2];
  28297. diff --git b/engine/common/mod_local.h a/engine/common/mod_local.h
  28298. index 896c944..0f61ce5 100644
  28299. --- b/engine/common/mod_local.h
  28300. +++ a/engine/common/mod_local.h
  28301. @@ -42,6 +42,14 @@ GNU General Public License for more details.
  28302. #define SURF_INFO( surf, mod ) ((mextrasurf_t *)mod->cache.data + (surf - mod->surfaces))
  28303. #define INFO_SURF( surf, mod ) (mod->surfaces + (surf - (mextrasurf_t *)mod->cache.data))
  28304.  
  28305. +#define CHECKVISBIT( vis, b ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] & (1 << ((b) & 7))) : (byte)false )
  28306. +#define SETVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] |= (1 << ((b) & 7))) : (byte)false )
  28307. +#define CLEARVISBIT( vis, b )( void ) ((b) >= 0 ? (byte)((vis)[(b) >> 3] &= ~(1 << ((b) & 7))) : (byte)false )
  28308. +
  28309. +#define REFPVS_RADIUS 2.0f // radius for rendering
  28310. +#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
  28311. +#define FATPHS_RADIUS 16.0f
  28312. +
  28313. // model flags (stored in model_t->flags)
  28314. #define MODEL_CONVEYOR BIT( 0 )
  28315. #define MODEL_HAS_ORIGIN BIT( 1 )
  28316. @@ -72,19 +80,30 @@ typedef struct
  28317. vec3_t hull_sizes[MAX_MAP_HULLS]; // actual hull sizes
  28318. msurface_t **draw_surfaces; // used for sorting translucent surfaces
  28319. int max_surfaces; // max surfaces per submodel (for all models)
  28320. - size_t visdatasize; // actual size of the visdata
  28321. - size_t litdatasize; // actual size of the lightdata
  28322. - size_t vecdatasize; // actual size of the deluxdata
  28323. - size_t entdatasize; // actual size of the entity string
  28324. - size_t texdatasize; // actual size of the textures lump
  28325. +
  28326. qboolean loading; // true if worldmodel is loading
  28327. qboolean sky_sphere; // true when quake sky-sphere is used
  28328. qboolean has_mirrors; // one or more brush models contain reflective textures
  28329. + qboolean custom_skybox; // if sky_sphere is active and custom skybox set
  28330. + qboolean water_alpha; // allow translucency water
  28331. int lm_sample_size; // defaulting to 16 (BSP31 uses 8)
  28332. int block_size; // lightmap blocksize
  28333. color24 *deluxedata; // deluxemap data pointer
  28334. char message[2048]; // just for debug
  28335.  
  28336. + // visibility info
  28337. + byte *visdata; // uncompressed visdata
  28338. + size_t visbytes; // cluster size
  28339. + size_t fatbytes; // fatpvs size
  28340. + int visclusters; // num visclusters
  28341. +
  28342. + // world stats
  28343. + size_t visdatasize; // actual size of the visdata
  28344. + size_t litdatasize; // actual size of the lightdata
  28345. + size_t vecdatasize; // actual size of the deluxdata
  28346. + size_t entdatasize; // actual size of the entity string
  28347. + size_t texdatasize; // actual size of the textures lump
  28348. +
  28349. vec3_t mins; // real accuracy world bounds
  28350. vec3_t maxs;
  28351. vec3_t size;
  28352. @@ -117,20 +136,21 @@ model_t *Mod_FindName( const char *name, qboolean create );
  28353. model_t *Mod_LoadModel( model_t *mod, qboolean world );
  28354. model_t *Mod_ForName( const char *name, qboolean world );
  28355. qboolean Mod_RegisterModel( const char *name, int index );
  28356. -int Mod_PointLeafnum( const vec3_t p );
  28357. -byte *Mod_LeafPVS( mleaf_t *leaf, model_t *model );
  28358. -byte *Mod_LeafPHS( mleaf_t *leaf, model_t *model );
  28359. mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
  28360. +qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, short *lastleaf );
  28361. void Mod_TesselatePolygon( msurface_t *surf, model_t *mod, float tessSize );
  28362. int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *lastleaf );
  28363. +int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
  28364. qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
  28365. +int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
  28366. +int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
  28367. +int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
  28368. void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info );
  28369. void Mod_AmbientLevels( const vec3_t p, byte *pvolumes );
  28370. -byte *Mod_CompressVis( const byte *in, size_t *size );
  28371. -byte *Mod_DecompressVis( const byte *in );
  28372. +int Mod_SampleSizeForFace( msurface_t *surf );
  28373. +byte *Mod_GetPVSForPoint( const vec3_t p );
  28374. modtype_t Mod_GetType( int handle );
  28375. model_t *Mod_Handle( int handle );
  28376. -struct wadlist_s *Mod_WadList( void );
  28377.  
  28378. //
  28379. // mod_studio.c
  28380. diff --git b/engine/common/mod_studio.c a/engine/common/mod_studio.c
  28381. index a64d856..264a55b 100644
  28382. --- b/engine/common/mod_studio.c
  28383. +++ a/engine/common/mod_studio.c
  28384. @@ -208,8 +208,6 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
  28385. mstudiobbox_t *phitbox;
  28386. int i, j;
  28387.  
  28388. - ASSERT( numhitboxes );
  28389. -
  28390. *numhitboxes = 0; // assume error
  28391.  
  28392. if( mod_studiocache->integer )
  28393. @@ -230,8 +228,6 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
  28394. mod_studiohdr = Mod_Extradata( model );
  28395. if( !mod_studiohdr ) return NULL; // probably not a studiomodel
  28396.  
  28397. - ASSERT( pBlendAPI != NULL );
  28398. -
  28399. VectorCopy( angles, angles2 );
  28400.  
  28401. if( !( host.features & ENGINE_COMPENSATE_QUAKE_BUG ))
  28402. @@ -406,13 +402,13 @@ static void Mod_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbon
  28403.  
  28404. if( !VectorCompare( angle1, angle2 ))
  28405. {
  28406. - AngleQuaternion( angle1, q1 );
  28407. - AngleQuaternion( angle2, q2 );
  28408. + AngleQuaternion( angle1, q1, true );
  28409. + AngleQuaternion( angle2, q2, true );
  28410. QuaternionSlerp( q1, q2, s, q );
  28411. }
  28412. else
  28413. {
  28414. - AngleQuaternion( angle1, q );
  28415. + AngleQuaternion( angle1, q, true );
  28416. }
  28417. }
  28418.  
  28419. @@ -745,8 +741,6 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAttachment, float *origin,
  28420. if( mod_studiohdr->numattachments <= 0 )
  28421. return;
  28422.  
  28423. - ASSERT( pBlendAPI != NULL );
  28424. -
  28425. if( mod_studiohdr->numattachments > MAXSTUDIOATTACHMENTS )
  28426. {
  28427. mod_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it
  28428. @@ -794,8 +788,6 @@ void Mod_GetBonePosition( const edict_t *e, int iBone, float *origin, float *ang
  28429. mod_studiohdr = (studiohdr_t *)Mod_Extradata( mod );
  28430. if( !mod_studiohdr ) return;
  28431.  
  28432. - ASSERT( pBlendAPI != NULL );
  28433. -
  28434. pBlendAPI->SV_StudioSetupBones( mod, e->v.frame, e->v.sequence, e->v.angles, e->v.origin,
  28435. e->v.controller, e->v.blending, iBone, e );
  28436.  
  28437. @@ -987,7 +979,7 @@ void Mod_InitStudioAPI( void )
  28438. pBlendIface = (STUDIOAPI)Com_GetProcAddress( svgame.hInstance, "Server_GetBlendingInterface" );
  28439. if( pBlendIface && pBlendIface( SV_BLENDING_INTERFACE_VERSION, &pBlendAPI, &gStudioAPI, &studio_transform, &studio_bones ))
  28440. {
  28441. - MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized Server Blending interface ^7ver. %i\n", SV_BLENDING_INTERFACE_VERSION );
  28442. + MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized Server Blending interface ^7ver. %i\n", SV_BLENDING_INTERFACE_VERSION );
  28443. return;
  28444. }
  28445.  
  28446. diff --git b/engine/common/model.c a/engine/common/model.c
  28447. index e0c9c24..678ec15 100644
  28448. --- b/engine/common/model.c
  28449. +++ a/engine/common/model.c
  28450. @@ -22,6 +22,7 @@ GNU General Public License for more details.
  28451. #include "gl_local.h"
  28452. #include "features.h"
  28453. #include "client.h"
  28454. +#include "server.h" // LUMP_ error codes
  28455.  
  28456. #define MAX_SIDE_VERTS 512 // per one polygon
  28457.  
  28458. @@ -160,6 +161,7 @@ void Mod_PrintBSPFileSizes_f( void )
  28459.  
  28460. Msg( "=== Total BSP file data space used: %s ===\n", Q_memprint( totalmemory ));
  28461. Msg( "World size ( %g %g %g ) units\n", world.size[0], world.size[1], world.size[2] );
  28462. + Msg( "Supports transparency world water: %s\n", world.water_alpha ? "Yes" : "No" );
  28463. Msg( "original name: ^1%s\n", worldmodel->name );
  28464. Msg( "internal name: %s\n", (world.message[0]) ? va( "^2%s", world.message ) : "none" );
  28465. }
  28466. @@ -204,94 +206,50 @@ void Mod_SetupHulls( vec3_t mins[MAX_MAP_HULLS], vec3_t maxs[MAX_MAP_HULLS] )
  28467.  
  28468. /*
  28469. ===================
  28470. -Mod_CompressVis
  28471. +Mod_DecompressVis
  28472. ===================
  28473. */
  28474. -byte *Mod_CompressVis( const byte *in, size_t *size )
  28475. +static void Mod_DecompressVis( const byte *in, const byte *inend, byte *out, byte *outend )
  28476. {
  28477. - int j, rep;
  28478. - int visrow;
  28479. - byte *dest_p;
  28480. + byte *outstart = out;
  28481. + int c;
  28482.  
  28483. - if( !worldmodel )
  28484. + while( out < outend )
  28485. {
  28486. - Host_Error( "Mod_CompressVis: no worldmodel\n" );
  28487. - return NULL;
  28488. - }
  28489. -
  28490. - dest_p = visdata;
  28491. - visrow = (worldmodel->numleafs + 7) >> 3;
  28492. -
  28493. - for( j = 0; j < visrow; j++ )
  28494. - {
  28495. - *dest_p++ = in[j];
  28496. - if( in[j] ) continue;
  28497. -
  28498. - rep = 1;
  28499. - for( j++; j < visrow; j++ )
  28500. + if( in == inend )
  28501. {
  28502. - if( in[j] || rep == 255 )
  28503. - break;
  28504. - else rep++;
  28505. + MsgDev( D_WARN, "Mod_DecompressVis: input underrun (decompressed %i of %i output bytes)\n",
  28506. + (int)(out - outstart), (int)(outend - outstart));
  28507. + return;
  28508. }
  28509. - *dest_p++ = rep;
  28510. - j--;
  28511. - }
  28512. -
  28513. - if( size ) *size = dest_p - visdata;
  28514. -
  28515. - return visdata;
  28516. -}
  28517.  
  28518. -/*
  28519. -===================
  28520. -Mod_DecompressVis
  28521. -===================
  28522. -*/
  28523. -byte *Mod_DecompressVis( const byte *in )
  28524. -{
  28525. - int c, row;
  28526. - byte *out;
  28527. + c = *in++;
  28528.  
  28529. - if( !worldmodel )
  28530. - {
  28531. - Host_Error( "Mod_DecompressVis: no worldmodel\n" );
  28532. - return NULL;
  28533. - }
  28534. -
  28535. - row = (worldmodel->numleafs + 7) >> 3;
  28536. - out = visdata;
  28537. -
  28538. - if( !in )
  28539. - {
  28540. - // no vis info, so make all visible
  28541. - while( row )
  28542. + if( c )
  28543. {
  28544. - *out++ = 0xff;
  28545. - row--;
  28546. + *out++ = c;
  28547. }
  28548. - return visdata;
  28549. - }
  28550. -
  28551. - do
  28552. - {
  28553. - if( *in )
  28554. + else
  28555. {
  28556. - *out++ = *in++;
  28557. - continue;
  28558. - }
  28559. -
  28560. - c = in[1];
  28561. - in += 2;
  28562. + if( in == inend )
  28563. + {
  28564. + MsgDev( D_REPORT, "Mod_DecompressVis: input underrun (during zero-run) (decompressed %i of %i output bytes)\n",
  28565. + (int)(out - outstart), (int)(outend - outstart));
  28566. + return;
  28567. + }
  28568.  
  28569. - while( c )
  28570. - {
  28571. - *out++ = 0;
  28572. - c--;
  28573. + for( c = *in++; c > 0; c-- )
  28574. + {
  28575. + if( out == outend )
  28576. + {
  28577. + MsgDev( D_REPORT, "Mod_DecompressVis: output overrun (decompressed %i of %i output bytes)\n",
  28578. + (int)(out - outstart), (int)(outend - outstart));
  28579. + return;
  28580. + }
  28581. + *out++ = 0;
  28582. + }
  28583. }
  28584. - } while( out - visdata < row );
  28585. -
  28586. - return visdata;
  28587. + }
  28588. }
  28589.  
  28590. /*
  28591. @@ -317,41 +275,99 @@ mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
  28592.  
  28593. /*
  28594. ==================
  28595. -Mod_LeafPVS
  28596. +Mod_GetPVSForPoint
  28597.  
  28598. +Returns PVS data for a given point
  28599. +NOTE: can return NULL
  28600. ==================
  28601. */
  28602. -byte *Mod_LeafPVS( mleaf_t *leaf, model_t *model )
  28603. +byte *Mod_GetPVSForPoint( const vec3_t p )
  28604. {
  28605. - if( !model || !leaf || leaf == model->leafs || !model->visdata )
  28606. - return Mod_DecompressVis( NULL );
  28607. - return Mod_DecompressVis( leaf->compressed_vis );
  28608. + mnode_t *node;
  28609. + mleaf_t *leaf = NULL;
  28610. +
  28611. + ASSERT( worldmodel != NULL );
  28612. +
  28613. + node = worldmodel->nodes;
  28614. +
  28615. + while( 1 )
  28616. + {
  28617. + if( node->contents < 0 )
  28618. + {
  28619. + leaf = (mleaf_t *)node;
  28620. + break; // we found a leaf
  28621. + }
  28622. + node = node->children[PlaneDiff( p, node->plane ) < 0];
  28623. + }
  28624. +
  28625. + if( leaf && leaf->cluster >= 0 )
  28626. + return world.visdata + leaf->cluster * world.visbytes;
  28627. + return NULL;
  28628. }
  28629.  
  28630. /*
  28631. ==================
  28632. -Mod_LeafPHS
  28633. +Mod_FatPVS_RecursiveBSPNode
  28634.  
  28635. ==================
  28636. */
  28637. -byte *Mod_LeafPHS( mleaf_t *leaf, model_t *model )
  28638. +static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node )
  28639. {
  28640. - if( !model || !leaf || leaf == model->leafs || !model->visdata )
  28641. - return Mod_DecompressVis( NULL );
  28642. - return Mod_DecompressVis( leaf->compressed_pas );
  28643. + int i;
  28644. +
  28645. + while( node->contents >= 0 )
  28646. + {
  28647. + float d = PlaneDiff( org, node->plane );
  28648. +
  28649. + if( d > radius )
  28650. + node = node->children[0];
  28651. + else if( d < -radius )
  28652. + node = node->children[1];
  28653. + else
  28654. + {
  28655. + // go down both sides
  28656. + Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0] );
  28657. + node = node->children[1];
  28658. + }
  28659. + }
  28660. +
  28661. + // if this leaf is in a cluster, accumulate the vis bits
  28662. + if(((mleaf_t *)node)->cluster >= 0 )
  28663. + {
  28664. + byte *vis = world.visdata + ((mleaf_t *)node)->cluster * world.visbytes;
  28665. +
  28666. + for( i = 0; i < visbytes; i++ )
  28667. + visbuffer[i] |= vis[i];
  28668. + }
  28669. }
  28670.  
  28671. /*
  28672. ==================
  28673. -Mod_PointLeafnum
  28674. +Mod_FatPVS_RecursiveBSPNode
  28675.  
  28676. +Calculates a PVS that is the inclusive or of all leafs
  28677. +within radius pixels of the given point.
  28678. ==================
  28679. */
  28680. -int Mod_PointLeafnum( const vec3_t p )
  28681. +int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
  28682. {
  28683. - // map not loaded
  28684. - if ( !worldmodel ) return 0;
  28685. - return Mod_PointInLeaf( p, worldmodel->nodes ) - worldmodel->leafs;
  28686. + mleaf_t *leaf = Mod_PointInLeaf( org, worldmodel->nodes );
  28687. + int bytes = world.visbytes;
  28688. +
  28689. + bytes = Q_min( bytes, visbytes );
  28690. +
  28691. + // enable full visibility for some reasons
  28692. + if( fullvis || !world.visclusters || !leaf || leaf->cluster < 0 )
  28693. + {
  28694. + memset( visbuffer, 0xFF, bytes );
  28695. + return bytes;
  28696. + }
  28697. +
  28698. + if( !merge ) memset( visbuffer, 0x00, bytes );
  28699. +
  28700. + Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes );
  28701. +
  28702. + return bytes;
  28703. }
  28704.  
  28705. /*
  28706. @@ -363,8 +379,7 @@ LEAF LISTING
  28707. */
  28708. static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
  28709. {
  28710. - mplane_t *plane;
  28711. - int s;
  28712. + int sides;
  28713.  
  28714. while( 1 )
  28715. {
  28716. @@ -382,18 +397,17 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
  28717. return;
  28718. }
  28719.  
  28720. - ll->list[ll->count++] = leaf - worldmodel->leafs - 1;
  28721. + ll->list[ll->count++] = leaf->cluster;
  28722. return;
  28723. }
  28724.  
  28725. - plane = node->plane;
  28726. - s = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, plane );
  28727. + sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
  28728.  
  28729. - if( s == 1 )
  28730. + if( sides == 1 )
  28731. {
  28732. node = node->children[0];
  28733. }
  28734. - else if( s == 2 )
  28735. + else if( sides == 2 )
  28736. {
  28737. node = node->children[1];
  28738. }
  28739. @@ -421,11 +435,12 @@ int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int list
  28740.  
  28741. VectorCopy( mins, ll.mins );
  28742. VectorCopy( maxs, ll.maxs );
  28743. - ll.count = 0;
  28744. +
  28745. ll.maxcount = listsize;
  28746. - ll.list = list;
  28747. - ll.topnode = -1;
  28748. ll.overflowed = false;
  28749. + ll.topnode = -1;
  28750. + ll.list = list;
  28751. + ll.count = 0;
  28752.  
  28753. Mod_BoxLeafnums_r( &ll, worldmodel->nodes );
  28754.  
  28755. @@ -453,15 +468,42 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi
  28756.  
  28757. for( i = 0; i < count; i++ )
  28758. {
  28759. - int leafnum = leafList[i];
  28760. -
  28761. - if( leafnum != -1 && visbits[leafnum>>3] & (1<<( leafnum & 7 )))
  28762. + if( CHECKVISBIT( visbits, leafList[i] ))
  28763. return true;
  28764. }
  28765. return false;
  28766. }
  28767.  
  28768. /*
  28769. +=============
  28770. +Mod_HeadnodeVisible
  28771. +=============
  28772. +*/
  28773. +qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, short *lastleaf )
  28774. +{
  28775. + if( !node || node->contents == CONTENTS_SOLID )
  28776. + return false;
  28777. +
  28778. + if( node->contents < 0 )
  28779. + {
  28780. + if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
  28781. + return false;
  28782. +
  28783. + if( lastleaf )
  28784. + *lastleaf = ((mleaf_t *)node)->cluster;
  28785. + return true;
  28786. + }
  28787. +
  28788. + if( Mod_HeadnodeVisible( node->children[0], visbits, lastleaf ))
  28789. + return true;
  28790. +
  28791. + if( Mod_HeadnodeVisible( node->children[1], visbits, lastleaf ))
  28792. + return true;
  28793. +
  28794. + return false;
  28795. +}
  28796. +
  28797. +/*
  28798. ==================
  28799. Mod_AmbientLevels
  28800.  
  28801. @@ -480,6 +522,56 @@ void Mod_AmbientLevels( const vec3_t p, byte *pvolumes )
  28802. }
  28803.  
  28804. /*
  28805. +==================
  28806. +Mod_SampleSizeForFace
  28807. +
  28808. +return the current lightmap resolution per face
  28809. +==================
  28810. +*/
  28811. +int Mod_SampleSizeForFace( msurface_t *surf )
  28812. +{
  28813. + if( !surf || !surf->texinfo || !surf->texinfo->faceinfo )
  28814. + return LM_SAMPLE_SIZE;
  28815. +
  28816. + return surf->texinfo->faceinfo->texture_step;
  28817. +}
  28818. +
  28819. +/*
  28820. +==================
  28821. +Mod_CheckWaterAlphaSupport
  28822. +
  28823. +converted maps potential may don't
  28824. +support water transparency
  28825. +==================
  28826. +*/
  28827. +static qboolean Mod_CheckWaterAlphaSupport( void )
  28828. +{
  28829. + mleaf_t *leaf;
  28830. + int i, j;
  28831. + const byte *pvs;
  28832. +
  28833. + if( world.visdatasize <= 0 ) return true;
  28834. +
  28835. + // check all liquid leafs to see if they can see into empty leafs, if any
  28836. + // can we can assume this map supports r_wateralpha
  28837. + for( i = 0, leaf = loadmodel->leafs; i < loadmodel->numleafs; i++, leaf++ )
  28838. + {
  28839. + if(( leaf->contents == CONTENTS_WATER || leaf->contents == CONTENTS_SLIME ) && leaf->cluster >= 0 )
  28840. + {
  28841. + pvs = world.visdata + leaf->cluster * world.visbytes;
  28842. +
  28843. + for( j = 0; j < loadmodel->numleafs; j++ )
  28844. + {
  28845. + if( CHECKVISBIT( pvs, loadmodel->leafs[j].cluster ) && loadmodel->leafs[j].contents == CONTENTS_EMPTY )
  28846. + return true;
  28847. + }
  28848. + }
  28849. + }
  28850. +
  28851. + return false;
  28852. +}
  28853. +
  28854. +/*
  28855. ================
  28856. Mod_FreeUserData
  28857. ================
  28858. @@ -490,10 +582,21 @@ static void Mod_FreeUserData( model_t *mod )
  28859. if( !mod || !mod->name[0] )
  28860. return;
  28861.  
  28862. - if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
  28863. + if( host.type == HOST_DEDICATED )
  28864. {
  28865. - // let the client.dll free custom data
  28866. - clgame.drawFuncs.Mod_ProcessUserData( mod, false, NULL );
  28867. + if( svgame.physFuncs.Mod_ProcessUserData != NULL )
  28868. + {
  28869. + // let the server.dll free custom data
  28870. + svgame.physFuncs.Mod_ProcessUserData( mod, false, NULL );
  28871. + }
  28872. + }
  28873. + else
  28874. + {
  28875. + if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
  28876. + {
  28877. + // let the client.dll free custom data
  28878. + clgame.drawFuncs.Mod_ProcessUserData( mod, false, NULL );
  28879. + }
  28880. }
  28881. }
  28882.  
  28883. @@ -618,7 +721,7 @@ static void Mod_LoadSubmodels( const dlump_t *l )
  28884. {
  28885. for( j = 0; j < 3; j++ )
  28886. {
  28887. - // spread the mins / maxs by a pixel
  28888. + // spread the mins / maxs by a unit
  28889. out->mins[j] = in->mins[j] - 1.0f;
  28890. out->maxs[j] = in->maxs[j] + 1.0f;
  28891. out->origin[j] = in->origin[j];
  28892. @@ -640,7 +743,7 @@ static void Mod_LoadSubmodels( const dlump_t *l )
  28893. VectorAverage( out->mins, out->maxs, out->origin );
  28894. }
  28895.  
  28896. - world.max_surfaces = max( world.max_surfaces, out->numfaces );
  28897. + world.max_surfaces = Q_max( world.max_surfaces, out->numfaces );
  28898. }
  28899.  
  28900. if( world.loading )
  28901. @@ -671,6 +774,7 @@ static void Mod_LoadTextures( const dlump_t *l )
  28902. GL_FreeTexture( tr.alphaskyTexture );
  28903. tr.solidskyTexture = tr.alphaskyTexture = 0;
  28904. world.texdatasize = l->filelen;
  28905. + world.custom_skybox = false;
  28906. world.has_mirrors = false;
  28907. world.sky_sphere = false;
  28908. }
  28909. @@ -744,7 +848,6 @@ static void Mod_LoadTextures( const dlump_t *l )
  28910. if( load_external )
  28911. {
  28912. tr.solidskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP, NULL );
  28913. - GL_SetTextureType( tr.solidskyTexture, TEX_BRUSH );
  28914. load_external = false;
  28915. }
  28916.  
  28917. @@ -766,7 +869,6 @@ static void Mod_LoadTextures( const dlump_t *l )
  28918. if( load_external )
  28919. {
  28920. tr.alphaskyTexture = GL_LoadTexture( texname, NULL, 0, TF_UNCOMPRESSED|TF_NOMIPMAP, NULL );
  28921. - GL_SetTextureType( tr.alphaskyTexture, TEX_BRUSH );
  28922. load_external = false;
  28923. }
  28924. }
  28925. @@ -918,13 +1020,6 @@ static void Mod_LoadTextures( const dlump_t *l )
  28926. }
  28927. }
  28928. }
  28929. -
  28930. - if( tx->gl_texturenum != tr.defaultTexture )
  28931. - {
  28932. - // apply texture type (just for debug)
  28933. - GL_SetTextureType( tx->gl_texturenum, TEX_BRUSH );
  28934. - GL_SetTextureType( tx->fb_texturenum, TEX_BRUSH );
  28935. - }
  28936. }
  28937.  
  28938. // sequence the animations
  28939. @@ -932,11 +1027,11 @@ static void Mod_LoadTextures( const dlump_t *l )
  28940. {
  28941. tx = loadmodel->textures[i];
  28942.  
  28943. - if( !tx || tx->name[0] != '+' )
  28944. + if( tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0 )
  28945. continue;
  28946.  
  28947. if( tx->anim_next )
  28948. - continue; // allready sequenced
  28949. + continue; // already sequenced
  28950.  
  28951. // find the number of frames in the animation
  28952. memset( anims, 0, sizeof( anims ));
  28953. @@ -959,23 +1054,22 @@ static void Mod_LoadTextures( const dlump_t *l )
  28954. altanims[altmax] = tx;
  28955. altmax++;
  28956. }
  28957. - else Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
  28958. + else MsgDev( D_ERROR, "Mod_LoadTextures: bad animating texture %s\n", tx->name );
  28959.  
  28960. for( j = i + 1; j < loadmodel->numtextures; j++ )
  28961. {
  28962. tx2 = loadmodel->textures[j];
  28963. - if( !tx2 || tx2->name[0] != '+' )
  28964. - continue;
  28965.  
  28966. - if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
  28967. + if( tx2->name[0] != '+' || Q_strcmp( tx2->name + 2, tx->name + 2 ))
  28968. continue;
  28969.  
  28970. num = tx2->name[1];
  28971. +
  28972. if( num >= '0' && num <= '9' )
  28973. {
  28974. num -= '0';
  28975. anims[num] = tx2;
  28976. - if (num+1 > max)
  28977. + if( num + 1 > max )
  28978. max = num + 1;
  28979. }
  28980. else if( num >= 'a' && num <= 'j' )
  28981. @@ -985,14 +1079,21 @@ static void Mod_LoadTextures( const dlump_t *l )
  28982. if( num + 1 > altmax )
  28983. altmax = num + 1;
  28984. }
  28985. - else Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
  28986. + else MsgDev( D_ERROR, "Mod_LoadTextures: bad animating texture %s\n", tx->name );
  28987. }
  28988.  
  28989. // link them all together
  28990. for( j = 0; j < max; j++ )
  28991. {
  28992. tx2 = anims[j];
  28993. - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  28994. +
  28995. + if( !tx2 )
  28996. + {
  28997. + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  28998. + tx->anim_total = 0;
  28999. + break;
  29000. + }
  29001. +
  29002. tx2->anim_total = max * ANIM_CYCLE;
  29003. tx2->anim_min = j * ANIM_CYCLE;
  29004. tx2->anim_max = (j + 1) * ANIM_CYCLE;
  29005. @@ -1003,7 +1104,14 @@ static void Mod_LoadTextures( const dlump_t *l )
  29006. for( j = 0; j < altmax; j++ )
  29007. {
  29008. tx2 = altanims[j];
  29009. - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  29010. +
  29011. + if( !tx2 )
  29012. + {
  29013. + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  29014. + tx->anim_total = 0;
  29015. + break;
  29016. + }
  29017. +
  29018. tx2->anim_total = altmax * ANIM_CYCLE;
  29019. tx2->anim_min = j * ANIM_CYCLE;
  29020. tx2->anim_max = (j+1) * ANIM_CYCLE;
  29021. @@ -1017,11 +1125,11 @@ static void Mod_LoadTextures( const dlump_t *l )
  29022. {
  29023. tx = loadmodel->textures[i];
  29024.  
  29025. - if( !tx || tx->name[0] != '-' )
  29026. + if( tx->name[0] != '-' || tx->name[1] == 0 || tx->name[2] == 0 )
  29027. continue;
  29028.  
  29029. if( tx->anim_next )
  29030. - continue; // allready sequenced
  29031. + continue; // already sequenced
  29032.  
  29033. // find the number of frames in the sequence
  29034. memset( anims, 0, sizeof( anims ));
  29035. @@ -1034,33 +1142,39 @@ static void Mod_LoadTextures( const dlump_t *l )
  29036. anims[max] = tx;
  29037. max++;
  29038. }
  29039. - else Host_Error( "Mod_LoadTextures: bad detail texture %s\n", tx->name );
  29040. + else MsgDev( D_ERROR, "Mod_LoadTextures: bad detail texture %s\n", tx->name );
  29041.  
  29042. for( j = i + 1; j < loadmodel->numtextures; j++ )
  29043. {
  29044. tx2 = loadmodel->textures[j];
  29045. - if( !tx2 || tx2->name[0] != '-' )
  29046. - continue;
  29047.  
  29048. - if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
  29049. + if( tx2->name[0] != '-' || Q_strcmp( tx2->name + 2, tx->name + 2 ))
  29050. continue;
  29051.  
  29052. num = tx2->name[1];
  29053. +
  29054. if( num >= '0' && num <= '9' )
  29055. {
  29056. num -= '0';
  29057. anims[num] = tx2;
  29058. - if( num+1 > max )
  29059. + if( num + 1 > max )
  29060. max = num + 1;
  29061. }
  29062. - else Host_Error( "Mod_LoadTextures: bad detail texture %s\n", tx->name );
  29063. + else MsgDev( D_ERROR, "Mod_LoadTextures: bad detail texture %s\n", tx->name );
  29064. }
  29065.  
  29066. // link them all together
  29067. for( j = 0; j < max; j++ )
  29068. {
  29069. tx2 = anims[j];
  29070. - if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  29071. +
  29072. + if( !tx2 )
  29073. + {
  29074. + MsgDev( D_ERROR, "Mod_LoadTextures: missing frame %i of %s\n", j, tx->name );
  29075. + tx->anim_total = 0;
  29076. + break;
  29077. + }
  29078. +
  29079. tx2->anim_total = -( max * ANIM_CYCLE ); // to differentiate from animations
  29080. tx2->anim_min = j * ANIM_CYCLE;
  29081. tx2->anim_max = (j + 1) * ANIM_CYCLE;
  29082. @@ -1074,14 +1188,49 @@ static void Mod_LoadTextures( const dlump_t *l )
  29083. Mod_LoadTexInfo
  29084. =================
  29085. */
  29086. -static void Mod_LoadTexInfo( const dlump_t *l )
  29087. +static mfaceinfo_t *Mod_LoadFaceInfo( const dlump_t *l, int *numfaceinfo )
  29088. +{
  29089. + dfaceinfo_t *in;
  29090. + mfaceinfo_t *out, *faceinfo;
  29091. + int i, count;
  29092. +
  29093. + in = (void *)(mod_base + l->fileofs);
  29094. + if( l->filelen % sizeof( *in ))
  29095. + Host_Error( "Mod_LoadFaceInfo: funny lump size in %s\n", loadmodel->name );
  29096. +
  29097. + count = l->filelen / sizeof( *in );
  29098. + faceinfo = out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
  29099. +
  29100. + for( i = 0; i < count; i++, in++, out++ )
  29101. + {
  29102. + Q_strncpy( out->landname, in->landname, sizeof( out->landname ));
  29103. + out->texture_step = in->texture_step;
  29104. + out->max_extent = in->max_extent;
  29105. + out->groupid = in->groupid;
  29106. + }
  29107. +
  29108. + *numfaceinfo = count;
  29109. +
  29110. + return faceinfo;
  29111. +}
  29112. +
  29113. +/*
  29114. +=================
  29115. +Mod_LoadTexInfo
  29116. +=================
  29117. +*/
  29118. +static void Mod_LoadTexInfo( const dlump_t *l, dextrahdr_t *extrahdr )
  29119. {
  29120. dtexinfo_t *in;
  29121. mtexinfo_t *out;
  29122. int miptex;
  29123. + mfaceinfo_t *fi = NULL;
  29124. + int fi_count;
  29125. int i, j, count;
  29126. - float len1, len2;
  29127. -
  29128. +
  29129. + if( extrahdr != NULL )
  29130. + fi = Mod_LoadFaceInfo( &extrahdr->lumps[LUMP_FACEINFO], &fi_count );
  29131. +
  29132. in = (void *)(mod_base + l->fileofs);
  29133. if( l->filelen % sizeof( *in ))
  29134. Host_Error( "Mod_LoadTexInfo: funny lump size in %s\n", loadmodel->name );
  29135. @@ -1097,22 +1246,16 @@ static void Mod_LoadTexInfo( const dlump_t *l )
  29136. for( j = 0; j < 8; j++ )
  29137. out->vecs[0][j] = in->vecs[0][j];
  29138.  
  29139. - len1 = VectorLength( out->vecs[0] );
  29140. - len2 = VectorLength( out->vecs[1] );
  29141. - len1 = ( len1 + len2 ) / 2;
  29142. -
  29143. - // g-cont: can use this info for GL_TEXTURE_LOAD_BIAS_EXT ?
  29144. - if( len1 < 0.32f ) out->mipadjust = 4;
  29145. - else if( len1 < 0.49f ) out->mipadjust = 3;
  29146. - else if( len1 < 0.99f ) out->mipadjust = 2;
  29147. - else out->mipadjust = 1;
  29148. -
  29149. miptex = in->miptex;
  29150. if( miptex < 0 || miptex > loadmodel->numtextures )
  29151. Host_Error( "Mod_LoadTexInfo: bad miptex number in '%s'\n", loadmodel->name );
  29152.  
  29153. out->texture = loadmodel->textures[miptex];
  29154. out->flags = in->flags;
  29155. +
  29156. + // make sure what faceinfo is really exist
  29157. + if( extrahdr != NULL && in->faceinfo != -1 && in->faceinfo < fi_count )
  29158. + out->faceinfo = &fi[in->faceinfo];
  29159. }
  29160. }
  29161.  
  29162. @@ -1182,10 +1325,35 @@ static void Mod_LoadDeluxemap( void )
  29163.  
  29164. /*
  29165. =================
  29166. +Mod_LoadLightVecs
  29167. +=================
  29168. +*/
  29169. +static void Mod_LoadLightVecs( const dlump_t *l )
  29170. +{
  29171. + byte *in;
  29172. +
  29173. + in = (void *)(mod_base + l->fileofs);
  29174. + world.vecdatasize = l->filelen;
  29175. +
  29176. + if( world.vecdatasize != world.litdatasize )
  29177. + {
  29178. + MsgDev( D_ERROR, "Mod_LoadLightVecs: has mismatched size (%i should be %i)\n", world.vecdatasize, world.litdatasize );
  29179. + world.deluxedata = NULL;
  29180. + world.vecdatasize = 0;
  29181. + return;
  29182. + }
  29183. +
  29184. + world.deluxedata = Mem_Alloc( loadmodel->mempool, world.vecdatasize );
  29185. + memcpy( world.deluxedata, in, world.vecdatasize );
  29186. + MsgDev( D_INFO, "Mod_LoadLightVecs: loaded\n" );
  29187. +}
  29188. +
  29189. +/*
  29190. +=================
  29191. Mod_LoadLighting
  29192. =================
  29193. */
  29194. -static void Mod_LoadLighting( const dlump_t *l )
  29195. +static void Mod_LoadLighting( const dlump_t *l, dextrahdr_t *extrahdr )
  29196. {
  29197. byte d, *in;
  29198. color24 *out;
  29199. @@ -1229,8 +1397,20 @@ static void Mod_LoadLighting( const dlump_t *l )
  29200. break;
  29201. }
  29202.  
  29203. + if( !world.loading ) return; // only world can have deluxedata (FIXME: what about quake models?)
  29204. +
  29205. + // not supposed to be load ?
  29206. + if( !FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
  29207. + {
  29208. + world.deluxedata = NULL;
  29209. + world.vecdatasize = 0;
  29210. + return;
  29211. + }
  29212. +
  29213. // try to loading deluxemap too
  29214. - Mod_LoadDeluxemap ();
  29215. + if( extrahdr != NULL )
  29216. + Mod_LoadLightVecs( &extrahdr->lumps[LUMP_LIGHTVECS] );
  29217. + else Mod_LoadDeluxemap (); // old method
  29218. }
  29219.  
  29220. /*
  29221. @@ -1244,10 +1424,11 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
  29222. {
  29223. float mins[2], maxs[2], val;
  29224. int bmins[2], bmaxs[2];
  29225. - int i, j, e;
  29226. + int i, j, e, sample_size;
  29227. mtexinfo_t *tex;
  29228. mvertex_t *v;
  29229.  
  29230. + sample_size = Mod_SampleSizeForFace( surf );
  29231. tex = surf->texinfo;
  29232.  
  29233. mins[0] = mins[1] = 999999;
  29234. @@ -1273,13 +1454,13 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
  29235.  
  29236. for( i = 0; i < 2; i++ )
  29237. {
  29238. - bmins[i] = floor( mins[i] / LM_SAMPLE_SIZE );
  29239. - bmaxs[i] = ceil( maxs[i] / LM_SAMPLE_SIZE );
  29240. + bmins[i] = floor( mins[i] / sample_size );
  29241. + bmaxs[i] = ceil( maxs[i] / sample_size );
  29242.  
  29243. - surf->texturemins[i] = bmins[i] * LM_SAMPLE_SIZE;
  29244. - surf->extents[i] = (bmaxs[i] - bmins[i]) * LM_SAMPLE_SIZE;
  29245. + surf->texturemins[i] = bmins[i] * sample_size;
  29246. + surf->extents[i] = (bmaxs[i] - bmins[i]) * sample_size;
  29247.  
  29248. - if(!( tex->flags & TEX_SPECIAL ) && surf->extents[i] > 4096 )
  29249. + if( !FBitSet( tex->flags, TEX_SPECIAL ) && surf->extents[i] > 4096 )
  29250. MsgDev( D_ERROR, "Bad surface extents %i\n", surf->extents[i] );
  29251. }
  29252. }
  29253. @@ -1324,7 +1505,7 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
  29254. uint bufSize;
  29255. vec3_t normal, tangent, binormal;
  29256. mtexinfo_t *texinfo = surf->texinfo;
  29257. - int i, numElems;
  29258. + int i, numElems, sample_size;
  29259. byte *buffer;
  29260. msurfmesh_t *mesh;
  29261.  
  29262. @@ -1334,6 +1515,7 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
  29263. bufSize = sizeof( msurfmesh_t ) + numVerts * sizeof( glvert_t ) + numElems * sizeof( word );
  29264. buffer = Mem_Alloc( loadmodel->mempool, bufSize );
  29265.  
  29266. + sample_size = Mod_SampleSizeForFace( surf );
  29267. mesh = (msurfmesh_t *)buffer;
  29268. buffer += sizeof( msurfmesh_t );
  29269. mesh->numVerts = numVerts;
  29270. @@ -1390,14 +1572,14 @@ static void Mod_BuildPolygon( mextrasurf_t *info, msurface_t *surf, int numVerts
  29271.  
  29272. // lightmap texture coordinates
  29273. s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
  29274. - s += surf->light_s * LM_SAMPLE_SIZE;
  29275. - s += LM_SAMPLE_SIZE >> 1;
  29276. - s /= BLOCK_SIZE * LM_SAMPLE_SIZE;
  29277. + s += surf->light_s * sample_size;
  29278. + s += sample_size >> 1;
  29279. + s /= BLOCK_SIZE * sample_size;
  29280.  
  29281. t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
  29282. - t += surf->light_t * LM_SAMPLE_SIZE;
  29283. - t += LM_SAMPLE_SIZE >> 1;
  29284. - t /= BLOCK_SIZE * LM_SAMPLE_SIZE;
  29285. + t += surf->light_t * sample_size;
  29286. + t += sample_size >> 1;
  29287. + t /= BLOCK_SIZE * sample_size;
  29288.  
  29289. out->lmcoord[0] = s;
  29290. out->lmcoord[1] = t;
  29291. @@ -1421,6 +1603,7 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
  29292. vec3_t normal, tangent, binormal, mins, maxs;
  29293. mtexinfo_t *texinfo = surf->texinfo;
  29294. vec2_t totalST, totalLM;
  29295. + int sample_size;
  29296. float s, t, scale;
  29297. int i, j, f, b;
  29298. uint bufSize;
  29299. @@ -1432,6 +1615,8 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
  29300. for( i = 0, v = verts; i < numVerts; i++, v += 3 )
  29301. AddPointToBounds( v, mins, maxs );
  29302.  
  29303. + sample_size = Mod_SampleSizeForFace( surf );
  29304. +
  29305. for( i = 0; i < 3; i++ )
  29306. {
  29307. m = tessSize * (float)floor((( mins[i] + maxs[i] ) * 0.5f ) / tessSize + 0.5f );
  29308. @@ -1558,14 +1743,14 @@ static void Mod_SubdividePolygon( mextrasurf_t *info, msurface_t *surf, int numV
  29309. {
  29310. // lightmap texture coordinates
  29311. s = DotProduct( verts, texinfo->vecs[0] ) + texinfo->vecs[0][3] - surf->texturemins[0];
  29312. - s += surf->light_s * LM_SAMPLE_SIZE;
  29313. - s += LM_SAMPLE_SIZE >> 1;
  29314. - s /= BLOCK_SIZE * LM_SAMPLE_SIZE;
  29315. + s += surf->light_s * sample_size;
  29316. + s += sample_size >> 1;
  29317. + s /= BLOCK_SIZE * sample_size;
  29318.  
  29319. t = DotProduct( verts, texinfo->vecs[1] ) + texinfo->vecs[1][3] - surf->texturemins[1];
  29320. - t += surf->light_t * LM_SAMPLE_SIZE;
  29321. - t += LM_SAMPLE_SIZE >> 1;
  29322. - t /= BLOCK_SIZE * LM_SAMPLE_SIZE;
  29323. + t += surf->light_t * sample_size;
  29324. + t += sample_size >> 1;
  29325. + t /= BLOCK_SIZE * sample_size;
  29326. }
  29327. else
  29328. {
  29329. @@ -1726,7 +1911,7 @@ void Mod_BuildSurfacePolygons( msurface_t *surf, mextrasurf_t *info )
  29330. }
  29331.  
  29332. // subdivide water or sky sphere for Quake1 maps
  29333. - if(( surf->flags & SURF_DRAWTURB && !( surf->flags & SURF_REFLECT )) || ( surf->flags & SURF_DRAWSKY && world.loading && world.sky_sphere ))
  29334. + if( surf->flags & SURF_DRAWTURB && !( surf->flags & SURF_REFLECT ))
  29335. {
  29336. Mod_SubdividePolygon( info, surf, surf->numedges, verts[0], 64.0f );
  29337. Mod_ConvertSurface( info, surf );
  29338. @@ -1905,9 +2090,6 @@ static void Mod_LoadSurfaces( const dlump_t *l )
  29339. if( host.features & ENGINE_BUILD_SURFMESHES && (( out->flags & SURF_DRAWTILED ) || !out->samples ))
  29340. Mod_BuildSurfacePolygons( out, info );
  29341.  
  29342. - if( out->flags & SURF_DRAWSKY && world.loading && world.sky_sphere )
  29343. - GL_SubdivideSurface( out ); // cut up polygon for warps
  29344. -
  29345. if( out->flags & SURF_DRAWTURB )
  29346. GL_SubdivideSurface( out ); // cut up polygon for warps
  29347. }
  29348. @@ -2105,6 +2287,17 @@ static void Mod_LoadLeafs( const dlump_t *l )
  29349. loadmodel->leafs = out;
  29350. loadmodel->numleafs = count;
  29351.  
  29352. + if( world.loading )
  29353. + {
  29354. + // get visleafs from the submodel data
  29355. + world.visclusters = loadmodel->submodels[0].visleafs;
  29356. + world.visbytes = (world.visclusters + 7) >> 3;
  29357. + world.visdata = (byte *)Mem_Alloc( loadmodel->mempool, world.visclusters * world.visbytes );
  29358. +
  29359. + // enable full visibility as default
  29360. + memset( world.visdata, 0xFF, world.visclusters * world.visbytes );
  29361. + }
  29362. +
  29363. for( i = 0; i < count; i++, in++, out++ )
  29364. {
  29365. for( j = 0; j < 3; j++ )
  29366. @@ -2117,6 +2310,29 @@ static void Mod_LoadLeafs( const dlump_t *l )
  29367.  
  29368. p = in->visofs;
  29369.  
  29370. + if( world.loading )
  29371. + {
  29372. + out->cluster = ( i - 1 ); // solid leaf 0 has no visdata
  29373. + if( out->cluster >= world.visclusters )
  29374. + out->cluster = -1;
  29375. +
  29376. + // ignore visofs errors on leaf 0 (solid)
  29377. + if( p >= 0 && out->cluster >= 0 && loadmodel->visdata )
  29378. + {
  29379. + if( p < world.visdatasize )
  29380. + {
  29381. + byte *inrow = loadmodel->visdata + p;
  29382. + byte *inrowend = loadmodel->visdata + world.visdatasize;
  29383. + byte *outrow = world.visdata + out->cluster * world.visbytes;
  29384. + byte *outrowend = world.visdata + (out->cluster + 1) * world.visbytes;
  29385. +
  29386. + Mod_DecompressVis( inrow, inrowend, outrow, outrowend );
  29387. + }
  29388. + else MsgDev( D_WARN, "Mod_LoadLeafs: invalid visofs for leaf #%i\n", i );
  29389. + }
  29390. + }
  29391. + else out->cluster = -1; // no visclusters on bmodels
  29392. +
  29393. if( p == -1 ) out->compressed_vis = NULL;
  29394. else out->compressed_vis = loadmodel->visdata + p;
  29395.  
  29396. @@ -2140,6 +2356,14 @@ static void Mod_LoadLeafs( const dlump_t *l )
  29397.  
  29398. if( loadmodel->leafs[0].contents != CONTENTS_SOLID )
  29399. Host_Error( "Mod_LoadLeafs: Map %s has leaf 0 is not CONTENTS_SOLID\n", loadmodel->name );
  29400. +
  29401. + // do some final things for world
  29402. + if( world.loading )
  29403. + {
  29404. + // store size of fat pvs
  29405. + world.fatbytes = (world.visclusters + 31) >> 3;
  29406. + world.water_alpha = Mod_CheckWaterAlphaSupport();
  29407. + }
  29408. }
  29409.  
  29410. /*
  29411. @@ -2172,6 +2396,9 @@ static void Mod_LoadPlanes( const dlump_t *l )
  29412. out->signbits |= 1<<j;
  29413. }
  29414.  
  29415. + if( VectorIsNull( out->normal ))
  29416. + Host_Error( "Mod_LoadPlanes: bad normal for plane #%i\n", i );
  29417. +
  29418. out->dist = in->dist;
  29419. out->type = in->type;
  29420. }
  29421. @@ -2210,6 +2437,7 @@ static void Mod_LoadEntities( const dlump_t *l )
  29422. char *pfile;
  29423. string keyname;
  29424. char token[2048];
  29425. + char wadstring[2048];
  29426.  
  29427. // make sure what we really has terminator
  29428. loadmodel->entities = Mem_Alloc( loadmodel->mempool, l->filelen + 1 );
  29429. @@ -2245,23 +2473,19 @@ static void Mod_LoadEntities( const dlump_t *l )
  29430.  
  29431. if( !Q_stricmp( keyname, "wad" ))
  29432. {
  29433. - char *path = token;
  29434. - string wadpath;
  29435. + char *pszWadFile;
  29436. +
  29437. + Q_strncpy( wadstring, token, 2046 );
  29438. + wadstring[2046] = 0;
  29439. +
  29440. + if( !Q_strchr( wadstring, ';' ))
  29441. + Q_strcat( wadstring, ";" );
  29442.  
  29443. // parse wad pathes
  29444. - while( path )
  29445. + for (pszWadFile = strtok( wadstring, ";" ); pszWadFile!= NULL; pszWadFile = strtok( NULL, ";" ))
  29446. {
  29447. - char *end = Q_strchr( path, ';' );
  29448. - if( !end )
  29449. - {
  29450. - // if specified only once wad
  29451. - if( !wadlist.count )
  29452. - FS_FileBase( path, wadlist.wadnames[wadlist.count++] );
  29453. - break;
  29454. - }
  29455. - Q_strncpy( wadpath, path, (end - path) + 1 );
  29456. - FS_FileBase( wadpath, wadlist.wadnames[wadlist.count++] );
  29457. - path += (end - path) + 1; // move pointer
  29458. + COM_FixSlashes( pszWadFile );
  29459. + FS_FileBase( pszWadFile, wadlist.wadnames[wadlist.count++] );
  29460. if( wadlist.count >= 256 ) break; // too many wads...
  29461. }
  29462. }
  29463. @@ -2510,135 +2734,6 @@ static void Mod_MakeHull0( void )
  29464.  
  29465. /*
  29466. =================
  29467. -Mod_CalcPHS
  29468. -=================
  29469. -*/
  29470. -void Mod_CalcPHS( void )
  29471. -{
  29472. - int hcount, vcount;
  29473. - int i, j, k, l, index, num;
  29474. - int rowbytes, rowwords;
  29475. - int bitbyte, rowsize;
  29476. - int *visofs, total_size = 0;
  29477. - byte *vismap, *vismap_p;
  29478. - byte *uncompressed_vis;
  29479. - byte *uncompressed_pas;
  29480. - byte *compressed_pas;
  29481. - byte *scan, *comp;
  29482. - uint *dest, *src;
  29483. - double timestart;
  29484. - size_t phsdatasize;
  29485. -
  29486. - // no worldmodel or no visdata
  29487. - if( !world.loading || !worldmodel || !worldmodel->visdata )
  29488. - return;
  29489. -
  29490. - MsgDev( D_NOTE, "Building PAS...\n" );
  29491. - timestart = Sys_DoubleTime();
  29492. -
  29493. - // NOTE: first leaf is skipped becuase is a outside leaf. Now all leafs have shift up by 1.
  29494. - // and last leaf (which equal worldmodel->numleafs) has no visdata! Add one extra leaf
  29495. - // to avoid this situation.
  29496. - num = worldmodel->numleafs;
  29497. - rowwords = (num + 31) >> 5;
  29498. - rowbytes = rowwords * 4;
  29499. -
  29500. - // typically PHS reqiured more room because RLE fails on multiple 1 not 0
  29501. - phsdatasize = world.visdatasize * 32; // empirically determined
  29502. -
  29503. - // allocate pvs and phs data single array
  29504. - visofs = Mem_Alloc( worldmodel->mempool, num * sizeof( int ));
  29505. - uncompressed_vis = Mem_Alloc( worldmodel->mempool, rowbytes * num * 2 );
  29506. - uncompressed_pas = uncompressed_vis + rowbytes * num;
  29507. - compressed_pas = Mem_Alloc( worldmodel->mempool, phsdatasize );
  29508. - vismap = vismap_p = compressed_pas; // compressed PHS buffer
  29509. - scan = uncompressed_vis;
  29510. - vcount = 0;
  29511. -
  29512. - // uncompress pvs first
  29513. - for( i = 0; i < num; i++, scan += rowbytes )
  29514. - {
  29515. - memcpy( scan, Mod_LeafPVS( worldmodel->leafs + i, worldmodel ), rowbytes );
  29516. - if( i == 0 ) continue;
  29517. -
  29518. - for( j = 0; j < num; j++ )
  29519. - {
  29520. - if( scan[j>>3] & (1<<( j & 7 )))
  29521. - vcount++;
  29522. - }
  29523. - }
  29524. -
  29525. - scan = uncompressed_vis;
  29526. - hcount = 0;
  29527. -
  29528. - dest = (uint *)uncompressed_pas;
  29529. -
  29530. - for( i = 0; i < num; i++, dest += rowwords, scan += rowbytes )
  29531. - {
  29532. - memcpy( dest, scan, rowbytes );
  29533. -
  29534. - for( j = 0; j < rowbytes; j++ )
  29535. - {
  29536. - bitbyte = scan[j];
  29537. - if( !bitbyte ) continue;
  29538. -
  29539. - for( k = 0; k < 8; k++ )
  29540. - {
  29541. - if(!( bitbyte & ( 1<<k )))
  29542. - continue;
  29543. - // or this pvs row into the phs
  29544. - // +1 because pvs is 1 based
  29545. - index = ((j<<3) + k + 1);
  29546. - if( index >= num ) continue;
  29547. -
  29548. - src = (uint *)uncompressed_vis + index * rowwords;
  29549. - for( l = 0; l < rowwords; l++ )
  29550. - dest[l] |= src[l];
  29551. - }
  29552. - }
  29553. -
  29554. - // compress PHS data back
  29555. - comp = Mod_CompressVis( (byte *)dest, &rowsize );
  29556. - visofs[i] = vismap_p - vismap; // leaf 0 is a common solid
  29557. - total_size += rowsize;
  29558. -
  29559. - if( total_size > phsdatasize )
  29560. - {
  29561. - Host_Error( "CalcPHS: vismap expansion overflow %s > %s\n", Q_memprint( total_size ), Q_memprint( phsdatasize ));
  29562. - }
  29563. -
  29564. - memcpy( vismap_p, comp, rowsize );
  29565. - vismap_p += rowsize; // move pointer
  29566. -
  29567. - if( i == 0 ) continue;
  29568. -
  29569. - for( j = 0; j < num; j++ )
  29570. - {
  29571. - if(((byte *)dest)[j>>3] & (1<<( j & 7 )))
  29572. - hcount++;
  29573. - }
  29574. - }
  29575. -
  29576. - // adjust compressed pas data to fit the size
  29577. - compressed_pas = Mem_Realloc( worldmodel->mempool, compressed_pas, total_size );
  29578. -
  29579. - // apply leaf pointers
  29580. - for( i = 0; i < worldmodel->numleafs; i++ )
  29581. - worldmodel->leafs[i].compressed_pas = compressed_pas + visofs[i];
  29582. -
  29583. - // release uncompressed data
  29584. - Mem_Free( uncompressed_vis );
  29585. - Mem_Free( visofs ); // release vis offsets
  29586. -
  29587. - // NOTE: we don't need to store off pointer to compressed pas-data
  29588. - // because this is will be automatiaclly frees by mempool internal pointer
  29589. - // and we never use this pointer after this point
  29590. - MsgDev( D_NOTE, "Average leaves visible / audible / total: %i / %i / %i\n", vcount / num, hcount / num, num );
  29591. - MsgDev( D_NOTE, "PAS building time: %g secs\n", Sys_DoubleTime() - timestart );
  29592. -}
  29593. -
  29594. -/*
  29595. -=================
  29596. Mod_UnloadBrushModel
  29597.  
  29598. Release all uploaded textures
  29599. @@ -2679,17 +2774,23 @@ Mod_LoadBrushModel
  29600. */
  29601. static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded )
  29602. {
  29603. - int i, j;
  29604. - int sample_size;
  29605. - char *ents;
  29606. - dheader_t *header;
  29607. - dmodel_t *bm;
  29608. + int i, j;
  29609. + int sample_size;
  29610. + char *ents;
  29611. + dheader_t *header;
  29612. + dextrahdr_t *extrahdr;
  29613. + dmodel_t *bm;
  29614.  
  29615. if( loaded ) *loaded = false;
  29616. header = (dheader_t *)buffer;
  29617. loadmodel->type = mod_brush;
  29618. i = header->version;
  29619.  
  29620. + // BSP31 and BSP30 have different offsets
  29621. + if( i == XTBSP_VERSION )
  29622. + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
  29623. + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
  29624. +
  29625. switch( i )
  29626. {
  29627. case 28: // get support for quake1 beta
  29628. @@ -2720,12 +2821,18 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
  29629. MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)", loadmodel->name, i, world.version );
  29630. return;
  29631. }
  29632. +
  29633. + loadmodel->numframes = sample_size; // NOTE: world store sample size into model_t->numframes
  29634. bmodel_version = i; // share it
  29635.  
  29636. // swap all the lumps
  29637. mod_base = (byte *)header;
  29638. loadmodel->mempool = Mem_AllocPool( va( "^2%s^7", loadmodel->name ));
  29639.  
  29640. + // make sure what extrahdr is valid
  29641. + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
  29642. + extrahdr = NULL; // no extra header
  29643. +
  29644. // load into heap
  29645. if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 && (header->lumps[LUMP_ENTITIES].filelen % sizeof( dplane_t )) == 0 )
  29646. {
  29647. @@ -2744,13 +2851,14 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
  29648. if( world.version <= 29 && world.mapversion == 220 && (header->lumps[LUMP_LIGHTING].filelen % 3) == 0 )
  29649. world.version = bmodel_version = HLBSP_VERSION;
  29650.  
  29651. + Mod_LoadSubmodels( &header->lumps[LUMP_MODELS] );
  29652. Mod_LoadVertexes( &header->lumps[LUMP_VERTEXES] );
  29653. Mod_LoadEdges( &header->lumps[LUMP_EDGES] );
  29654. Mod_LoadSurfEdges( &header->lumps[LUMP_SURFEDGES] );
  29655. Mod_LoadTextures( &header->lumps[LUMP_TEXTURES] );
  29656. - Mod_LoadLighting( &header->lumps[LUMP_LIGHTING] );
  29657. + Mod_LoadLighting( &header->lumps[LUMP_LIGHTING], extrahdr );
  29658. Mod_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
  29659. - Mod_LoadTexInfo( &header->lumps[LUMP_TEXINFO] );
  29660. + Mod_LoadTexInfo( &header->lumps[LUMP_TEXINFO], extrahdr );
  29661. Mod_LoadSurfaces( &header->lumps[LUMP_FACES] );
  29662. Mod_LoadMarkSurfaces( &header->lumps[LUMP_MARKSURFACES] );
  29663. Mod_LoadLeafs( &header->lumps[LUMP_LEAFS] );
  29664. @@ -2759,11 +2867,9 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
  29665. if( bmodel_version == XTBSP_VERSION )
  29666. Mod_LoadClipnodes31( &header->lumps[LUMP_CLIPNODES], &header->lumps[LUMP_CLIPNODES2], &header->lumps[LUMP_CLIPNODES3] );
  29667. else Mod_LoadClipnodes( &header->lumps[LUMP_CLIPNODES] );
  29668. - Mod_LoadSubmodels( &header->lumps[LUMP_MODELS] );
  29669.  
  29670. Mod_MakeHull0 ();
  29671. -
  29672. - loadmodel->numframes = 2; // regular and alternate animation
  29673. +
  29674. ents = loadmodel->entities;
  29675.  
  29676. // set up the submodels
  29677. @@ -2791,12 +2897,14 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
  29678. if( i != 0 )
  29679. {
  29680. // HACKHACK: c2a1 issues
  29681. - if( !bm->origin[0] && !bm->origin[1] ) mod->flags |= MODEL_HAS_ORIGIN;
  29682. + if( !bm->origin[0] && !bm->origin[1] )
  29683. + SetBits( mod->flags, MODEL_HAS_ORIGIN );
  29684.  
  29685. Mod_FindModelOrigin( ents, va( "*%i", i ), bm->origin );
  29686.  
  29687. // flag 2 is indicated model with origin brush!
  29688. - if( !VectorIsNull( bm->origin )) mod->flags |= MODEL_HAS_ORIGIN;
  29689. + if( !VectorIsNull( bm->origin ))
  29690. + SetBits( mod->flags, MODEL_HAS_ORIGIN );
  29691. }
  29692.  
  29693. for( j = 0; i != 0 && j < mod->nummodelsurfaces; j++ )
  29694. @@ -2815,7 +2923,7 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
  29695. if( surf->plane->type == PLANE_Z )
  29696. {
  29697. // kill bottom plane too
  29698. - if( info->mins[2] == bm->mins[2] + 1 )
  29699. + if( info->mins[2] == bm->mins[2] + 1.0f )
  29700. surf->flags |= SURF_WATERCSG;
  29701. }
  29702. else
  29703. @@ -2971,10 +3079,24 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
  29704.  
  29705. return NULL;
  29706. }
  29707. - else if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
  29708. + else
  29709. {
  29710. - // let the client.dll load custom data
  29711. - clgame.drawFuncs.Mod_ProcessUserData( mod, true, buf );
  29712. + if( host.type == HOST_DEDICATED )
  29713. + {
  29714. + if( svgame.physFuncs.Mod_ProcessUserData != NULL )
  29715. + {
  29716. + // let the server.dll load custom data
  29717. + svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
  29718. + }
  29719. + }
  29720. + else
  29721. + {
  29722. + if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
  29723. + {
  29724. + // let the client.dll load custom data
  29725. + clgame.drawFuncs.Mod_ProcessUserData( mod, true, buf );
  29726. + }
  29727. + }
  29728. }
  29729.  
  29730. Mem_Free( buf );
  29731. @@ -3010,7 +3132,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
  29732.  
  29733. // now replacement table is invalidate
  29734. memset( com_models, 0, sizeof( com_models ));
  29735. -
  29736. com_models[1] = cm_models; // make link to world
  29737.  
  29738. // update the lightmap blocksize
  29739. @@ -3031,7 +3152,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
  29740. }
  29741.  
  29742. // clear all studio submodels on restart
  29743. - // HACKHACK: throw all external BSP-models to refresh their lightmaps properly
  29744. for( i = 1; i < cm_nummodels; i++ )
  29745. {
  29746. if( cm_models[i].type == mod_studio )
  29747. @@ -3052,9 +3172,6 @@ void Mod_LoadWorld( const char *name, uint *checksum, qboolean multiplayer )
  29748. world.loading = false;
  29749.  
  29750. if( checksum ) *checksum = world.checksum;
  29751. -
  29752. - // calc Potentially Hearable Set and compress it
  29753. - Mod_CalcPHS();
  29754. }
  29755.  
  29756. /*
  29757. @@ -3106,7 +3223,9 @@ void Mod_GetFrames( int handle, int *numFrames )
  29758. return;
  29759. }
  29760.  
  29761. - *numFrames = mod->numframes;
  29762. + if( mod->type == mod_brush )
  29763. + *numFrames = 2; // regular and alternate animation
  29764. + else *numFrames = mod->numframes;
  29765. if( *numFrames < 1 ) *numFrames = 1;
  29766. }
  29767.  
  29768. @@ -3246,7 +3365,233 @@ model_t *Mod_Handle( int handle )
  29769. return com_models[handle];
  29770. }
  29771.  
  29772. -wadlist_t *Mod_WadList( void )
  29773. +/*
  29774. +==================
  29775. +Mod_CheckLump
  29776. +
  29777. +check lump for existing
  29778. +==================
  29779. +*/
  29780. +int Mod_CheckLump( const char *filename, const int lump, int *lumpsize )
  29781. +{
  29782. + file_t *f = FS_Open( filename, "rb", true );
  29783. + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
  29784. + size_t prefetch_size = sizeof( buffer );
  29785. + dextrahdr_t *extrahdr;
  29786. + dheader_t *header;
  29787. +
  29788. + if( !f ) return LUMP_LOAD_COULDNT_OPEN;
  29789. +
  29790. + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
  29791. + {
  29792. + FS_Close( f );
  29793. + return LUMP_LOAD_BAD_HEADER;
  29794. + }
  29795. +
  29796. + header = (dheader_t *)buffer;
  29797. +
  29798. + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
  29799. + {
  29800. + FS_Close( f );
  29801. + return LUMP_LOAD_BAD_VERSION;
  29802. + }
  29803. +
  29804. + // BSP31 and BSP30 have different offsets
  29805. + if( header->version == XTBSP_VERSION )
  29806. + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
  29807. + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
  29808. +
  29809. + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
  29810. + {
  29811. + FS_Close( f );
  29812. + return LUMP_LOAD_NO_EXTRADATA;
  29813. + }
  29814. +
  29815. + if( lump < 0 || lump >= EXTRA_LUMPS )
  29816. + {
  29817. + FS_Close( f );
  29818. + return LUMP_LOAD_INVALID_NUM;
  29819. + }
  29820. +
  29821. + if( extrahdr->lumps[lump].filelen <= 0 )
  29822. + {
  29823. + FS_Close( f );
  29824. + return LUMP_LOAD_NOT_EXIST;
  29825. + }
  29826. +
  29827. + if( lumpsize )
  29828. + *lumpsize = extrahdr->lumps[lump].filelen;
  29829. +
  29830. + FS_Close( f );
  29831. +
  29832. + return LUMP_LOAD_OK;
  29833. +}
  29834. +
  29835. +/*
  29836. +==================
  29837. +Mod_ReadLump
  29838. +
  29839. +reading random lump by user request
  29840. +==================
  29841. +*/
  29842. +int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize )
  29843. +{
  29844. + file_t *f = FS_Open( filename, "rb", true );
  29845. + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
  29846. + size_t prefetch_size = sizeof( buffer );
  29847. + dextrahdr_t *extrahdr;
  29848. + dheader_t *header;
  29849. + byte *data;
  29850. + int length;
  29851. +
  29852. + if( !f ) return LUMP_LOAD_COULDNT_OPEN;
  29853. +
  29854. + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
  29855. + {
  29856. + FS_Close( f );
  29857. + return LUMP_LOAD_BAD_HEADER;
  29858. + }
  29859. +
  29860. + header = (dheader_t *)buffer;
  29861. +
  29862. + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
  29863. + {
  29864. + FS_Close( f );
  29865. + return LUMP_LOAD_BAD_VERSION;
  29866. + }
  29867. +
  29868. + // BSP31 and BSP30 have different offsets
  29869. + if( header->version == XTBSP_VERSION )
  29870. + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
  29871. + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
  29872. +
  29873. + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
  29874. + {
  29875. + FS_Close( f );
  29876. + return LUMP_LOAD_NO_EXTRADATA;
  29877. + }
  29878. +
  29879. + if( lump < 0 || lump >= EXTRA_LUMPS )
  29880. + {
  29881. + FS_Close( f );
  29882. + return LUMP_LOAD_INVALID_NUM;
  29883. + }
  29884. +
  29885. + if( extrahdr->lumps[lump].filelen <= 0 )
  29886. + {
  29887. + FS_Close( f );
  29888. + return LUMP_LOAD_NOT_EXIST;
  29889. + }
  29890. +
  29891. + data = malloc( extrahdr->lumps[lump].filelen + 1 );
  29892. + length = extrahdr->lumps[lump].filelen;
  29893. +
  29894. + if( !data )
  29895. + {
  29896. + FS_Close( f );
  29897. + return LUMP_LOAD_MEM_FAILED;
  29898. + }
  29899. +
  29900. + FS_Seek( f, extrahdr->lumps[lump].fileofs, SEEK_SET );
  29901. +
  29902. + if( FS_Read( f, data, length ) != length )
  29903. + {
  29904. + Mem_Free( data );
  29905. + FS_Close( f );
  29906. + return LUMP_LOAD_CORRUPTED;
  29907. + }
  29908. +
  29909. + data[length] = 0; // write term
  29910. + FS_Close( f );
  29911. +
  29912. + if( lumpsize )
  29913. + *lumpsize = length;
  29914. + *lumpdata = data;
  29915. +
  29916. + return LUMP_LOAD_OK;
  29917. +}
  29918. +
  29919. +/*
  29920. +==================
  29921. +Mod_SaveLump
  29922. +
  29923. +writing lump by user request
  29924. +only empty lumps is allows
  29925. +==================
  29926. +*/
  29927. +int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize )
  29928. {
  29929. - return &wadlist;
  29930. + file_t *f = FS_Open( filename, "e+b", true );
  29931. + byte buffer[sizeof( dheader31_t ) + sizeof( dextrahdr_t )];
  29932. + size_t prefetch_size = sizeof( buffer );
  29933. + dextrahdr_t *extrahdr;
  29934. + dheader_t *header;
  29935. +
  29936. + if( !f ) return LUMP_SAVE_COULDNT_OPEN;
  29937. +
  29938. + if( !lumpdata || lumpsize <= 0 )
  29939. + return LUMP_SAVE_NO_DATA;
  29940. +
  29941. + if( FS_Read( f, buffer, prefetch_size ) != prefetch_size )
  29942. + {
  29943. + FS_Close( f );
  29944. + return LUMP_SAVE_BAD_HEADER;
  29945. + }
  29946. +
  29947. + header = (dheader_t *)buffer;
  29948. +
  29949. + if( header->version != HLBSP_VERSION && header->version != XTBSP_VERSION )
  29950. + {
  29951. + FS_Close( f );
  29952. + return LUMP_SAVE_BAD_VERSION;
  29953. + }
  29954. +
  29955. + // BSP31 and BSP30 have different offsets
  29956. + if( header->version == XTBSP_VERSION )
  29957. + extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader31_t ));
  29958. + else extrahdr = (dextrahdr_t *)((byte *)buffer + sizeof( dheader_t ));
  29959. +
  29960. + if( extrahdr->id != IDEXTRAHEADER || extrahdr->version != EXTRA_VERSION )
  29961. + {
  29962. + FS_Close( f );
  29963. + return LUMP_SAVE_NO_EXTRADATA;
  29964. + }
  29965. +
  29966. + if( lump < 0 || lump >= EXTRA_LUMPS )
  29967. + {
  29968. + FS_Close( f );
  29969. + return LUMP_SAVE_INVALID_NUM;
  29970. + }
  29971. +
  29972. + if( extrahdr->lumps[lump].filelen != 0 )
  29973. + {
  29974. + FS_Close( f );
  29975. + return LUMP_SAVE_ALREADY_EXIST;
  29976. + }
  29977. +
  29978. + FS_Seek( f, 0, SEEK_END );
  29979. +
  29980. + // will be saved later
  29981. + extrahdr->lumps[lump].fileofs = FS_Tell( f );
  29982. + extrahdr->lumps[lump].filelen = lumpsize;
  29983. +
  29984. + if( FS_Write( f, lumpdata, lumpsize ) != lumpsize )
  29985. + {
  29986. + FS_Close( f );
  29987. + return LUMP_SAVE_CORRUPTED;
  29988. + }
  29989. +
  29990. + // update the header
  29991. + if( header->version == XTBSP_VERSION )
  29992. + FS_Seek( f, sizeof( dheader31_t ), SEEK_SET );
  29993. + else FS_Seek( f, sizeof( dheader_t ), SEEK_SET );
  29994. +
  29995. + if( FS_Write( f, extrahdr, sizeof( dextrahdr_t )) != sizeof( dextrahdr_t ))
  29996. + {
  29997. + FS_Close( f );
  29998. + return LUMP_SAVE_CORRUPTED;
  29999. + }
  30000. +
  30001. + FS_Close( f );
  30002. + return LUMP_SAVE_OK;
  30003. }
  30004. \ No newline at end of file
  30005. diff --git b/engine/common/net_buffer.c a/engine/common/net_buffer.c
  30006. index 2c645e3..96c693a 100644
  30007. --- b/engine/common/net_buffer.c
  30008. +++ a/engine/common/net_buffer.c
  30009. @@ -26,15 +26,7 @@ static dword ExtraMasks[32];
  30010.  
  30011. short MSG_BigShort( short swap )
  30012. {
  30013. - short *s = &swap;
  30014. -
  30015. - __asm {
  30016. - mov ebx, s
  30017. - mov al, [ebx+1]
  30018. - mov ah, [ebx ]
  30019. - mov [ebx], ax
  30020. - }
  30021. - return *s;
  30022. + return (swap >> 8)|(swap << 8);
  30023. }
  30024.  
  30025. void MSG_InitMasks( void )
  30026. @@ -57,32 +49,32 @@ void MSG_InitMasks( void )
  30027. ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
  30028. }
  30029.  
  30030. -void MSG_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
  30031. +void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
  30032. {
  30033. - bf->pDebugName = pDebugName;
  30034. + sb->pDebugName = pDebugName;
  30035.  
  30036. - MSG_StartWriting( bf, pData, nBytes, 0, nMaxBits );
  30037. + MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
  30038. }
  30039.  
  30040. -void MSG_StartWriting( sizebuf_t *bf, void *pData, int nBytes, int iStartBit, int nBits )
  30041. +void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
  30042. {
  30043. // make sure it's dword aligned and padded.
  30044. Assert(((dword)pData & 3 ) == 0 );
  30045.  
  30046. - bf->pData = (byte *)pData;
  30047. + sb->pData = (byte *)pData;
  30048.  
  30049. if( nBits == -1 )
  30050. {
  30051. - bf->nDataBits = nBytes << 3;
  30052. + sb->nDataBits = nBytes << 3;
  30053. }
  30054. else
  30055. {
  30056. Assert( nBits <= nBytes * 8 );
  30057. - bf->nDataBits = nBits;
  30058. + sb->nDataBits = nBits;
  30059. }
  30060.  
  30061. - bf->iCurBit = iStartBit;
  30062. - bf->bOverflow = false;
  30063. + sb->iCurBit = iStartBit;
  30064. + sb->bOverflow = false;
  30065. }
  30066.  
  30067. /*
  30068. @@ -92,70 +84,68 @@ MSG_Clear
  30069. for clearing overflowed buffer
  30070. =======================
  30071. */
  30072. -void MSG_Clear( sizebuf_t *bf )
  30073. +void MSG_Clear( sizebuf_t *sb )
  30074. {
  30075. - bf->iCurBit = 0;
  30076. - bf->bOverflow = false;
  30077. + sb->iCurBit = 0;
  30078. + sb->bOverflow = false;
  30079. }
  30080.  
  30081. -static qboolean MSG_Overflow( sizebuf_t *bf, int nBits )
  30082. +static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
  30083. {
  30084. - if( bf->iCurBit + nBits > bf->nDataBits )
  30085. - bf->bOverflow = true;
  30086. - return bf->bOverflow;
  30087. + if( sb->iCurBit + nBits > sb->nDataBits )
  30088. + sb->bOverflow = true;
  30089. + return sb->bOverflow;
  30090. }
  30091.  
  30092. -qboolean MSG_CheckOverflow( sizebuf_t *bf )
  30093. +qboolean MSG_CheckOverflow( sizebuf_t *sb )
  30094. {
  30095. - ASSERT( bf );
  30096. -
  30097. - return MSG_Overflow( bf, 0 );
  30098. + return MSG_Overflow( sb, 0 );
  30099. }
  30100.  
  30101. -void MSG_SeekToBit( sizebuf_t *bf, int bitPos )
  30102. +void MSG_SeekToBit( sizebuf_t *sb, int bitPos )
  30103. {
  30104. - bf->iCurBit = bitPos;
  30105. + sb->iCurBit = bitPos;
  30106. }
  30107.  
  30108. -void MSG_SeekToByte( sizebuf_t *bf, int bytePos )
  30109. +void MSG_SeekToByte( sizebuf_t *sb, int bytePos )
  30110. {
  30111. - bf->iCurBit = bytePos << 3;
  30112. + sb->iCurBit = bytePos << 3;
  30113. }
  30114.  
  30115. -void MSG_WriteOneBit( sizebuf_t *bf, int nValue )
  30116. +void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
  30117. {
  30118. - if( !MSG_Overflow( bf, 1 ))
  30119. + if( !MSG_Overflow( sb, 1 ))
  30120. {
  30121. - if( nValue ) bf->pData[bf->iCurBit>>3] |= BIT( bf->iCurBit & 7 );
  30122. - else bf->pData[bf->iCurBit>>3] &= ~BIT( bf->iCurBit & 7 );
  30123. + if( nValue ) sb->pData[sb->iCurBit>>3] |= BIT( sb->iCurBit & 7 );
  30124. + else sb->pData[sb->iCurBit>>3] &= ~BIT( sb->iCurBit & 7 );
  30125.  
  30126. - bf->iCurBit++;
  30127. + sb->iCurBit++;
  30128. }
  30129. }
  30130.  
  30131. -void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bCheckRange )
  30132. +void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
  30133. {
  30134. Assert( numbits >= 0 && numbits <= 32 );
  30135.  
  30136. // bounds checking..
  30137. - if(( bf->iCurBit + numbits ) > bf->nDataBits )
  30138. + if(( sb->iCurBit + numbits ) > sb->nDataBits )
  30139. {
  30140. - bf->bOverflow = true;
  30141. - bf->iCurBit = bf->nDataBits;
  30142. + sb->bOverflow = true;
  30143. + sb->iCurBit = sb->nDataBits;
  30144. }
  30145. else
  30146. {
  30147. int nBitsLeft = numbits;
  30148. - int iCurBit = bf->iCurBit;
  30149. + int iCurBit = sb->iCurBit;
  30150. uint iDWord = iCurBit >> 5; // Mask in a dword.
  30151. dword iCurBitMasked;
  30152. int nBitsWritten;
  30153.  
  30154. - Assert(( iDWord * 4 + sizeof( long )) <= (uint)MSG_GetMaxBytes( bf ));
  30155. + Assert(( iDWord * 4 + sizeof( long )) <= (uint)MSG_GetMaxBytes( sb ));
  30156.  
  30157. iCurBitMasked = iCurBit & 31;
  30158. - ((dword *)bf->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
  30159. - ((dword *)bf->pData)[iDWord] |= curData << iCurBitMasked;
  30160. + ((dword *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
  30161. + ((dword *)sb->pData)[iDWord] |= curData << iCurBitMasked;
  30162.  
  30163. // did it span a dword?
  30164. nBitsWritten = 32 - iCurBitMasked;
  30165. @@ -167,10 +157,10 @@ void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bC
  30166. curData >>= nBitsWritten;
  30167.  
  30168. iCurBitMasked = iCurBit & 31;
  30169. - ((dword *)bf->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
  30170. - ((dword *)bf->pData)[iDWord+1] |= curData << iCurBitMasked;
  30171. + ((dword *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
  30172. + ((dword *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
  30173. }
  30174. - bf->iCurBit += numbits;
  30175. + sb->iCurBit += numbits;
  30176. }
  30177. }
  30178.  
  30179. @@ -181,33 +171,33 @@ MSG_WriteSBitLong
  30180. sign bit comes first
  30181. =======================
  30182. */
  30183. -void MSG_WriteSBitLong( sizebuf_t *bf, int data, int numbits )
  30184. +void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits )
  30185. {
  30186. // do we have a valid # of bits to encode with?
  30187. - Assert( numbits >= 1 );
  30188. + Assert( numbits >= 1 && numbits <= 32 );
  30189.  
  30190. // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
  30191. // (Some old code writes direct integers right into the buffer).
  30192. if( data < 0 )
  30193. {
  30194. - MSG_WriteUBitLongExt( bf, (uint)( 0x80000000 + data ), numbits - 1, false );
  30195. - MSG_WriteOneBit( bf, 1 );
  30196. + MSG_WriteUBitLong( sb, (uint)( 0x80000000 + data ), numbits - 1 );
  30197. + MSG_WriteOneBit( sb, 1 );
  30198. }
  30199. else
  30200. {
  30201. - MSG_WriteUBitLong( bf, (uint)data, numbits - 1 );
  30202. - MSG_WriteOneBit( bf, 0 );
  30203. + MSG_WriteUBitLong( sb, (uint)data, numbits - 1 );
  30204. + MSG_WriteOneBit( sb, 0 );
  30205. }
  30206. }
  30207.  
  30208. -void MSG_WriteBitLong( sizebuf_t *bf, uint data, int numbits, qboolean bSigned )
  30209. +void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned )
  30210. {
  30211. if( bSigned )
  30212. - MSG_WriteSBitLong( bf, (int)data, numbits );
  30213. - else MSG_WriteUBitLong( bf, data, numbits );
  30214. + MSG_WriteSBitLong( sb, (int)data, numbits );
  30215. + else MSG_WriteUBitLong( sb, data, numbits );
  30216. }
  30217.  
  30218. -qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
  30219. +qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
  30220. {
  30221. byte *pOut = (byte *)pData;
  30222. int nBitsLeft = nBits;
  30223. @@ -215,7 +205,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
  30224. // get output dword-aligned.
  30225. while((( dword )pOut & 3 ) != 0 && nBitsLeft >= 8 )
  30226. {
  30227. - MSG_WriteUBitLongExt( bf, *pOut, 8, false );
  30228. + MSG_WriteUBitLong( sb, *pOut, 8 );
  30229.  
  30230. nBitsLeft -= 8;
  30231. ++pOut;
  30232. @@ -224,7 +214,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
  30233. // read dwords.
  30234. while( nBitsLeft >= 32 )
  30235. {
  30236. - MSG_WriteUBitLongExt( bf, *(( dword *)pOut ), 32, false );
  30237. + MSG_WriteUBitLong( sb, *(( dword *)pOut ), 32 );
  30238.  
  30239. pOut += sizeof( dword );
  30240. nBitsLeft -= 32;
  30241. @@ -233,7 +223,7 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
  30242. // read the remaining bytes.
  30243. while( nBitsLeft >= 8 )
  30244. {
  30245. - MSG_WriteUBitLongExt( bf, *pOut, 8, false );
  30246. + MSG_WriteUBitLong( sb, *pOut, 8 );
  30247.  
  30248. nBitsLeft -= 8;
  30249. ++pOut;
  30250. @@ -242,13 +232,13 @@ qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits )
  30251. // Read the remaining bits.
  30252. if( nBitsLeft )
  30253. {
  30254. - MSG_WriteUBitLongExt( bf, *pOut, nBitsLeft, false );
  30255. + MSG_WriteUBitLong( sb, *pOut, nBitsLeft );
  30256. }
  30257.  
  30258. - return !bf->bOverflow;
  30259. + return !sb->bOverflow;
  30260. }
  30261.  
  30262. -void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits )
  30263. +void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits )
  30264. {
  30265. uint mask, shift;
  30266. int d;
  30267. @@ -263,136 +253,141 @@ void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits )
  30268. d = (int)(( fAngle * shift ) / 360.0f );
  30269. d &= mask;
  30270.  
  30271. - MSG_WriteUBitLong( bf, (uint)d, numbits );
  30272. + MSG_WriteUBitLong( sb, (uint)d, numbits );
  30273. }
  30274.  
  30275. -void MSG_WriteCoord( sizebuf_t *bf, float val )
  30276. +void MSG_WriteCoord( sizebuf_t *sb, float val )
  30277. {
  30278. // g-cont. we loose precision here but keep old size of coord variable!
  30279. - if( host.features & ENGINE_WRITE_LARGE_COORD )
  30280. - MSG_WriteShort( bf, (int)( val * 2.0f ));
  30281. - else MSG_WriteShort( bf, (int)( val * 8.0f ));
  30282. + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
  30283. + MSG_WriteShort( sb, (int)( val * 2.0f ));
  30284. + else MSG_WriteShort( sb, (int)( val * 8.0f ));
  30285. }
  30286.  
  30287. -void MSG_WriteVec3Coord( sizebuf_t *bf, const float *fa )
  30288. +void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa )
  30289. {
  30290. - MSG_WriteCoord( bf, fa[0] );
  30291. - MSG_WriteCoord( bf, fa[1] );
  30292. - MSG_WriteCoord( bf, fa[2] );
  30293. + MSG_WriteCoord( sb, fa[0] );
  30294. + MSG_WriteCoord( sb, fa[1] );
  30295. + MSG_WriteCoord( sb, fa[2] );
  30296. }
  30297.  
  30298. -void MSG_WriteBitFloat( sizebuf_t *bf, float val )
  30299. +void MSG_WriteBitFloat( sizebuf_t *sb, float val )
  30300. {
  30301. long intVal;
  30302.  
  30303. - ASSERT( sizeof( long ) == sizeof( float ));
  30304. - ASSERT( sizeof( float ) == 4 );
  30305. + Assert( sizeof( long ) == sizeof( float ));
  30306. + Assert( sizeof( float ) == 4 );
  30307.  
  30308. intVal = *((long *)&val );
  30309. - MSG_WriteUBitLong( bf, intVal, 32 );
  30310. + MSG_WriteUBitLong( sb, intVal, 32 );
  30311. +}
  30312. +
  30313. +void MSG_WriteChar( sizebuf_t *sb, int val )
  30314. +{
  30315. + MSG_WriteSBitLong( sb, val, sizeof( char ) << 3 );
  30316. }
  30317.  
  30318. -void MSG_WriteChar( sizebuf_t *bf, int val )
  30319. +void MSG_WriteByte( sizebuf_t *sb, int val )
  30320. {
  30321. - MSG_WriteSBitLong( bf, val, sizeof( char ) << 3 );
  30322. + MSG_WriteUBitLong( sb, val, sizeof( byte ) << 3 );
  30323. }
  30324.  
  30325. -void MSG_WriteByte( sizebuf_t *bf, int val )
  30326. +void MSG_WriteShort( sizebuf_t *sb, int val )
  30327. {
  30328. - MSG_WriteUBitLong( bf, val, sizeof( byte ) << 3 );
  30329. + MSG_WriteSBitLong( sb, val, sizeof(short ) << 3 );
  30330. }
  30331.  
  30332. -void MSG_WriteShort( sizebuf_t *bf, int val )
  30333. +void MSG_WriteWord( sizebuf_t *sb, int val )
  30334. {
  30335. - MSG_WriteSBitLong( bf, val, sizeof(short ) << 3 );
  30336. + MSG_WriteUBitLong( sb, val, sizeof( word ) << 3 );
  30337. }
  30338.  
  30339. -void MSG_WriteWord( sizebuf_t *bf, int val )
  30340. +void MSG_WriteLong( sizebuf_t *sb, long val )
  30341. {
  30342. - MSG_WriteUBitLong( bf, val, sizeof( word ) << 3 );
  30343. + MSG_WriteSBitLong( sb, val, sizeof( long ) << 3 );
  30344. }
  30345.  
  30346. -void MSG_WriteLong( sizebuf_t *bf, long val )
  30347. +void MSG_WriteDword( sizebuf_t *sb, dword val )
  30348. {
  30349. - MSG_WriteSBitLong( bf, val, sizeof( long ) << 3 );
  30350. + MSG_WriteUBitLong( sb, val, sizeof( dword ) << 3 );
  30351. }
  30352.  
  30353. -void MSG_WriteFloat( sizebuf_t *bf, float val )
  30354. +void MSG_WriteFloat( sizebuf_t *sb, float val )
  30355. {
  30356. - MSG_WriteBits( bf, &val, sizeof( val ) << 3 );
  30357. + MSG_WriteBits( sb, &val, sizeof( val ) << 3 );
  30358. }
  30359.  
  30360. -qboolean MSG_WriteBytes( sizebuf_t *bf, const void *pBuf, int nBytes )
  30361. +qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes )
  30362. {
  30363. - return MSG_WriteBits( bf, pBuf, nBytes << 3 );
  30364. + return MSG_WriteBits( sb, pBuf, nBytes << 3 );
  30365. }
  30366.  
  30367. -qboolean MSG_WriteString( sizebuf_t *bf, const char *pStr )
  30368. +qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr )
  30369. {
  30370. if( pStr )
  30371. {
  30372. do
  30373. {
  30374. - MSG_WriteChar( bf, *pStr );
  30375. + MSG_WriteChar( sb, *pStr );
  30376. pStr++;
  30377. } while( *( pStr - 1 ));
  30378. }
  30379. - else MSG_WriteChar( bf, 0 );
  30380. + else MSG_WriteChar( sb, 0 );
  30381.  
  30382. - return !bf->bOverflow;
  30383. + return !sb->bOverflow;
  30384. }
  30385.  
  30386. -int MSG_ReadOneBit( sizebuf_t *bf )
  30387. +int MSG_ReadOneBit( sizebuf_t *sb )
  30388. {
  30389. - if( !MSG_Overflow( bf, 1 ))
  30390. + if( !MSG_Overflow( sb, 1 ))
  30391. {
  30392. - int value = bf->pData[bf->iCurBit >> 3] & (1 << ( bf->iCurBit & 7 ));
  30393. - bf->iCurBit++;
  30394. + int value = sb->pData[sb->iCurBit >> 3] & (1 << ( sb->iCurBit & 7 ));
  30395. + sb->iCurBit++;
  30396. return !!value;
  30397. }
  30398. return 0;
  30399. }
  30400.  
  30401. -uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits )
  30402. +uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
  30403. {
  30404. int idword1;
  30405. uint dword1, ret;
  30406.  
  30407. if( numbits == 8 )
  30408. {
  30409. - int leftBits = MSG_GetNumBitsLeft( bf );
  30410. + int leftBits = MSG_GetNumBitsLeft( sb );
  30411.  
  30412. if( leftBits >= 0 && leftBits < 8 )
  30413. return 0; // end of message
  30414. }
  30415.  
  30416. - if(( bf->iCurBit + numbits ) > bf->nDataBits )
  30417. + if(( sb->iCurBit + numbits ) > sb->nDataBits )
  30418. {
  30419. - bf->bOverflow = true;
  30420. - bf->iCurBit = bf->nDataBits;
  30421. + sb->bOverflow = true;
  30422. + sb->iCurBit = sb->nDataBits;
  30423. return 0;
  30424. }
  30425.  
  30426. - ASSERT( numbits > 0 && numbits <= 32 );
  30427. + Assert( numbits > 0 && numbits <= 32 );
  30428.  
  30429. // Read the current dword.
  30430. - idword1 = bf->iCurBit >> 5;
  30431. - dword1 = ((uint *)bf->pData)[idword1];
  30432. - dword1 >>= ( bf->iCurBit & 31 ); // get the bits we're interested in.
  30433. + idword1 = sb->iCurBit >> 5;
  30434. + dword1 = ((uint *)sb->pData)[idword1];
  30435. + dword1 >>= ( sb->iCurBit & 31 ); // get the bits we're interested in.
  30436.  
  30437. - bf->iCurBit += numbits;
  30438. + sb->iCurBit += numbits;
  30439. ret = dword1;
  30440.  
  30441. // Does it span this dword?
  30442. - if(( bf->iCurBit - 1 ) >> 5 == idword1 )
  30443. + if(( sb->iCurBit - 1 ) >> 5 == idword1 )
  30444. {
  30445. if( numbits != 32 )
  30446. ret &= ExtraMasks[numbits];
  30447. }
  30448. else
  30449. {
  30450. - int nExtraBits = bf->iCurBit & 31;
  30451. - uint dword2 = ((uint *)bf->pData)[idword1+1] & ExtraMasks[nExtraBits];
  30452. + int nExtraBits = sb->iCurBit & 31;
  30453. + uint dword2 = ((uint *)sb->pData)[idword1+1] & ExtraMasks[nExtraBits];
  30454.  
  30455. // no need to mask since we hit the end of the dword.
  30456. // shift the second dword's part into the high bits.
  30457. @@ -401,33 +396,33 @@ uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits )
  30458. return ret;
  30459. }
  30460.  
  30461. -float MSG_ReadBitFloat( sizebuf_t *bf )
  30462. +float MSG_ReadBitFloat( sizebuf_t *sb )
  30463. {
  30464. long val;
  30465. int bit, byte;
  30466.  
  30467. - ASSERT( sizeof( float ) == sizeof( long ));
  30468. - ASSERT( sizeof( float ) == 4 );
  30469. + Assert( sizeof( float ) == sizeof( long ));
  30470. + Assert( sizeof( float ) == 4 );
  30471.  
  30472. - if( MSG_Overflow( bf, 32 ))
  30473. + if( MSG_Overflow( sb, 32 ))
  30474. return 0.0f;
  30475.  
  30476. - bit = bf->iCurBit & 0x7;
  30477. - byte = bf->iCurBit >> 3;
  30478. + bit = sb->iCurBit & 0x7;
  30479. + byte = sb->iCurBit >> 3;
  30480.  
  30481. - val = bf->pData[byte] >> bit;
  30482. - val |= ((int)bf->pData[byte + 1]) << ( 8 - bit );
  30483. - val |= ((int)bf->pData[byte + 2]) << ( 16 - bit );
  30484. - val |= ((int)bf->pData[byte + 3]) << ( 24 - bit );
  30485. + val = sb->pData[byte] >> bit;
  30486. + val |= ((int)sb->pData[byte + 1]) << ( 8 - bit );
  30487. + val |= ((int)sb->pData[byte + 2]) << ( 16 - bit );
  30488. + val |= ((int)sb->pData[byte + 3]) << ( 24 - bit );
  30489.  
  30490. if( bit != 0 )
  30491. - val |= ((int)bf->pData[byte + 4]) << ( 32 - bit );
  30492. - bf->iCurBit += 32;
  30493. + val |= ((int)sb->pData[byte + 4]) << ( 32 - bit );
  30494. + sb->iCurBit += 32;
  30495.  
  30496. return *((float *)&val);
  30497. }
  30498.  
  30499. -qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
  30500. +qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
  30501. {
  30502. byte *pOut = (byte *)pOutData;
  30503. int nBitsLeft = nBits;
  30504. @@ -435,7 +430,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
  30505. // get output dword-aligned.
  30506. while((( dword )pOut & 3) != 0 && nBitsLeft >= 8 )
  30507. {
  30508. - *pOut = (byte)MSG_ReadUBitLong( bf, 8 );
  30509. + *pOut = (byte)MSG_ReadUBitLong( sb, 8 );
  30510. ++pOut;
  30511. nBitsLeft -= 8;
  30512. }
  30513. @@ -443,7 +438,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
  30514. // read dwords.
  30515. while( nBitsLeft >= 32 )
  30516. {
  30517. - *((dword *)pOut) = MSG_ReadUBitLong( bf, 32 );
  30518. + *((dword *)pOut) = MSG_ReadUBitLong( sb, 32 );
  30519. pOut += sizeof( dword );
  30520. nBitsLeft -= 32;
  30521. }
  30522. @@ -451,7 +446,7 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
  30523. // read the remaining bytes.
  30524. while( nBitsLeft >= 8 )
  30525. {
  30526. - *pOut = MSG_ReadUBitLong( bf, 8 );
  30527. + *pOut = MSG_ReadUBitLong( sb, 8 );
  30528. ++pOut;
  30529. nBitsLeft -= 8;
  30530. }
  30531. @@ -459,20 +454,20 @@ qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits )
  30532. // read the remaining bits.
  30533. if( nBitsLeft )
  30534. {
  30535. - *pOut = MSG_ReadUBitLong( bf, nBitsLeft );
  30536. + *pOut = MSG_ReadUBitLong( sb, nBitsLeft );
  30537. }
  30538.  
  30539. - return !bf->bOverflow;
  30540. + return !sb->bOverflow;
  30541. }
  30542.  
  30543. -float MSG_ReadBitAngle( sizebuf_t *bf, int numbits )
  30544. +float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
  30545. {
  30546. float fReturn, shift;
  30547. int i;
  30548.  
  30549. shift = (float)( 1 << numbits );
  30550.  
  30551. - i = MSG_ReadUBitLong( bf, numbits );
  30552. + i = MSG_ReadUBitLong( sb, numbits );
  30553. fReturn = (float)i * ( 360.0f / shift );
  30554.  
  30555. // clamp the finale angle
  30556. @@ -483,83 +478,89 @@ float MSG_ReadBitAngle( sizebuf_t *bf, int numbits )
  30557. }
  30558.  
  30559. // Append numbits least significant bits from data to the current bit stream
  30560. -int MSG_ReadSBitLong( sizebuf_t *bf, int numbits )
  30561. +int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
  30562. {
  30563. int r, sign;
  30564.  
  30565. - r = MSG_ReadUBitLong( bf, numbits - 1 );
  30566. + r = MSG_ReadUBitLong( sb, numbits - 1 );
  30567.  
  30568. // NOTE: it does this wierdness here so it's bit-compatible with regular integer data in the buffer.
  30569. // (Some old code writes direct integers right into the buffer).
  30570. - sign = MSG_ReadOneBit( bf );
  30571. + sign = MSG_ReadOneBit( sb );
  30572. if( sign ) r = -( BIT( numbits - 1 ) - r );
  30573.  
  30574. return r;
  30575. }
  30576.  
  30577. -uint MSG_ReadBitLong( sizebuf_t *bf, int numbits, qboolean bSigned )
  30578. +uint MSG_ReadBitLong( sizebuf_t *sb, int numbits, qboolean bSigned )
  30579. {
  30580. if( bSigned )
  30581. - return (uint)MSG_ReadSBitLong( bf, numbits );
  30582. - return MSG_ReadUBitLong( bf, numbits );
  30583. + return (uint)MSG_ReadSBitLong( sb, numbits );
  30584. + return MSG_ReadUBitLong( sb, numbits );
  30585. }
  30586.  
  30587. -int MSG_ReadChar( sizebuf_t *bf )
  30588. +int MSG_ReadChar( sizebuf_t *sb )
  30589. {
  30590. - return MSG_ReadSBitLong( bf, sizeof( char ) << 3 );
  30591. + return MSG_ReadSBitLong( sb, sizeof( char ) << 3 );
  30592. }
  30593.  
  30594. -int MSG_ReadByte( sizebuf_t *bf )
  30595. +int MSG_ReadByte( sizebuf_t *sb )
  30596. {
  30597. - return MSG_ReadUBitLong( bf, sizeof( byte ) << 3 );
  30598. + return MSG_ReadUBitLong( sb, sizeof( byte ) << 3 );
  30599. }
  30600.  
  30601. -int MSG_ReadShort( sizebuf_t *bf )
  30602. +int MSG_ReadShort( sizebuf_t *sb )
  30603. {
  30604. - return MSG_ReadSBitLong( bf, sizeof( short ) << 3 );
  30605. + return MSG_ReadSBitLong( sb, sizeof( short ) << 3 );
  30606. }
  30607.  
  30608. -int MSG_ReadWord( sizebuf_t *bf )
  30609. +int MSG_ReadWord( sizebuf_t *sb )
  30610. {
  30611. - return MSG_ReadUBitLong( bf, sizeof( word ) << 3 );
  30612. + return MSG_ReadUBitLong( sb, sizeof( word ) << 3 );
  30613. }
  30614.  
  30615. -float MSG_ReadCoord( sizebuf_t *bf )
  30616. +float MSG_ReadCoord( sizebuf_t *sb )
  30617. {
  30618. // g-cont. we loose precision here but keep old size of coord variable!
  30619. - if( host.features & ENGINE_WRITE_LARGE_COORD )
  30620. - return (float)(MSG_ReadShort( bf ) * ( 1.0f / 2.0f ));
  30621. - return (float)(MSG_ReadShort( bf ) * ( 1.0f / 8.0f ));
  30622. + if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
  30623. + return (float)(MSG_ReadShort( sb ) * ( 1.0f / 2.0f ));
  30624. + return (float)(MSG_ReadShort( sb ) * ( 1.0f / 8.0f ));
  30625. }
  30626.  
  30627. -void MSG_ReadVec3Coord( sizebuf_t *bf, vec3_t fa )
  30628. +void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa )
  30629. {
  30630. - fa[0] = MSG_ReadCoord( bf );
  30631. - fa[1] = MSG_ReadCoord( bf );
  30632. - fa[2] = MSG_ReadCoord( bf );
  30633. + fa[0] = MSG_ReadCoord( sb );
  30634. + fa[1] = MSG_ReadCoord( sb );
  30635. + fa[2] = MSG_ReadCoord( sb );
  30636. }
  30637.  
  30638. -long MSG_ReadLong( sizebuf_t *bf )
  30639. +long MSG_ReadLong( sizebuf_t *sb )
  30640. {
  30641. - return MSG_ReadSBitLong( bf, sizeof( long ) << 3 );
  30642. + return MSG_ReadSBitLong( sb, sizeof( long ) << 3 );
  30643. }
  30644.  
  30645. -float MSG_ReadFloat( sizebuf_t *bf )
  30646. +dword MSG_ReadDword( sizebuf_t *sb )
  30647. +{
  30648. + return MSG_ReadUBitLong( sb, sizeof( dword ) << 3 );
  30649. +}
  30650. +
  30651. +float MSG_ReadFloat( sizebuf_t *sb )
  30652. {
  30653. float ret;
  30654. - ASSERT( sizeof( ret ) == 4 );
  30655.  
  30656. - MSG_ReadBits( bf, &ret, 32 );
  30657. + Assert( sizeof( ret ) == 4 );
  30658. +
  30659. + MSG_ReadBits( sb, &ret, 32 );
  30660.  
  30661. return ret;
  30662. }
  30663.  
  30664. -qboolean MSG_ReadBytes( sizebuf_t *bf, void *pOut, int nBytes )
  30665. +qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
  30666. {
  30667. - return MSG_ReadBits( bf, pOut, nBytes << 3 );
  30668. + return MSG_ReadBits( sb, pOut, nBytes << 3 );
  30669. }
  30670.  
  30671. -char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
  30672. +char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
  30673. {
  30674. static char string[MAX_SYSPATH];
  30675. int l = 0, c;
  30676. @@ -567,7 +568,7 @@ char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
  30677. do
  30678. {
  30679. // use MSG_ReadByte so -1 is out of bounds
  30680. - c = MSG_ReadByte( bf );
  30681. + c = MSG_ReadByte( sb );
  30682.  
  30683. if( c == 0 ) break;
  30684. else if( bLine && c == '\n' )
  30685. @@ -585,20 +586,20 @@ char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine )
  30686. return string;
  30687. }
  30688.  
  30689. -void MSG_ExciseBits( sizebuf_t *bf, int startbit, int bitstoremove )
  30690. +void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
  30691. {
  30692. int i, endbit = startbit + bitstoremove;
  30693. - int remaining_to_end = bf->nDataBits - endbit;
  30694. + int remaining_to_end = sb->nDataBits - endbit;
  30695. sizebuf_t temp;
  30696.  
  30697. - MSG_StartWriting( &temp, bf->pData, bf->nDataBits << 3, startbit, -1 );
  30698. - MSG_SeekToBit( bf, endbit );
  30699. + MSG_StartWriting( &temp, sb->pData, sb->nDataBits << 3, startbit, -1 );
  30700. + MSG_SeekToBit( sb, endbit );
  30701.  
  30702. for( i = 0; i < remaining_to_end; i++ )
  30703. {
  30704. - MSG_WriteOneBit( &temp, MSG_ReadOneBit( bf ));
  30705. + MSG_WriteOneBit( &temp, MSG_ReadOneBit( sb ));
  30706. }
  30707.  
  30708. - MSG_SeekToBit( bf, startbit );
  30709. - bf->nDataBits -= bitstoremove;
  30710. + MSG_SeekToBit( sb, startbit );
  30711. + sb->nDataBits -= bitstoremove;
  30712. }
  30713. \ No newline at end of file
  30714. diff --git b/engine/common/net_buffer.h a/engine/common/net_buffer.h
  30715. index 674ad65..c8c6fd1 100644
  30716. --- b/engine/common/net_buffer.h
  30717. +++ a/engine/common/net_buffer.h
  30718. @@ -45,80 +45,81 @@ typedef struct sizebuf_s
  30719. int nDataBits;
  30720. } sizebuf_t;
  30721.  
  30722. -#define MSG_WriteUBitLong( bf, data, bits ) MSG_WriteUBitLongExt( bf, data, bits, true );
  30723. #define MSG_StartReading MSG_StartWriting
  30724. #define MSG_GetNumBytesRead MSG_GetNumBytesWritten
  30725. #define MSG_GetRealBytesRead MSG_GetRealBytesWritten
  30726. #define MSG_GetNumBitsRead MSG_GetNumBitsWritten
  30727. #define MSG_ReadBitAngles MSG_ReadBitVec3Coord
  30728. -#define MSG_ReadString( bf ) MSG_ReadStringExt( bf, false )
  30729. -#define MSG_ReadStringLine( bf ) MSG_ReadStringExt( bf, true )
  30730. -#define MSG_ReadAngle( bf ) (float)(MSG_ReadChar( bf ) * ( 360.0f / 256.0f ))
  30731. -#define MSG_Init( bf, name, data, bytes ) MSG_InitExt( bf, name, data, bytes, -1 )
  30732. +#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
  30733. +#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
  30734. +#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
  30735. +#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
  30736.  
  30737. // common functions
  30738. -void MSG_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
  30739. +void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
  30740. void MSG_InitMasks( void ); // called once at startup engine
  30741. -void MSG_SeekToBit( sizebuf_t *bf, int bitPos );
  30742. -void MSG_SeekToByte( sizebuf_t *bf, int bytePos );
  30743. -void MSG_ExciseBits( sizebuf_t *bf, int startbit, int bitstoremove );
  30744. -qboolean MSG_CheckOverflow( sizebuf_t *bf );
  30745. +void MSG_SeekToBit( sizebuf_t *sb, int bitPos );
  30746. +void MSG_SeekToByte( sizebuf_t *sb, int bytePos );
  30747. +void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
  30748. +qboolean MSG_CheckOverflow( sizebuf_t *sb );
  30749. short MSG_BigShort( short swap );
  30750.  
  30751. // init writing
  30752. -void MSG_StartWriting( sizebuf_t *bf, void *pData, int nBytes, int iStartBit, int nBits );
  30753. -void MSG_Clear( sizebuf_t *bf );
  30754. +void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
  30755. +void MSG_Clear( sizebuf_t *sb );
  30756.  
  30757. // Bit-write functions
  30758. -void MSG_WriteOneBit( sizebuf_t *bf, int nValue );
  30759. -void MSG_WriteUBitLongExt( sizebuf_t *bf, uint curData, int numbits, qboolean bCheckRange );
  30760. -void MSG_WriteSBitLong( sizebuf_t *bf, int data, int numbits );
  30761. -void MSG_WriteBitLong( sizebuf_t *bf, uint data, int numbits, qboolean bSigned );
  30762. -qboolean MSG_WriteBits( sizebuf_t *bf, const void *pData, int nBits );
  30763. -void MSG_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits );
  30764. -void MSG_WriteBitFloat( sizebuf_t *bf, float val );
  30765. +void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
  30766. +void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
  30767. +void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
  30768. +void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
  30769. +qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
  30770. +void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits );
  30771. +void MSG_WriteBitFloat( sizebuf_t *sb, float val );
  30772.  
  30773. // Byte-write functions
  30774. -void MSG_WriteChar( sizebuf_t *bf, int val );
  30775. -void MSG_WriteByte( sizebuf_t *bf, int val );
  30776. -void MSG_WriteShort( sizebuf_t *bf, int val );
  30777. -void MSG_WriteWord( sizebuf_t *bf, int val );
  30778. -void MSG_WriteLong( sizebuf_t *bf, long val );
  30779. -void MSG_WriteCoord( sizebuf_t *bf, float val );
  30780. -void MSG_WriteFloat( sizebuf_t *bf, float val );
  30781. -void MSG_WriteVec3Coord( sizebuf_t *bf, const float *fa );
  30782. -qboolean MSG_WriteBytes( sizebuf_t *bf, const void *pBuf, int nBytes ); // same as MSG_WriteData
  30783. -qboolean MSG_WriteString( sizebuf_t *bf, const char *pStr ); // returns false if it overflows the buffer.
  30784. +void MSG_WriteChar( sizebuf_t *sb, int val );
  30785. +void MSG_WriteByte( sizebuf_t *sb, int val );
  30786. +void MSG_WriteShort( sizebuf_t *sb, int val );
  30787. +void MSG_WriteWord( sizebuf_t *sb, int val );
  30788. +void MSG_WriteLong( sizebuf_t *sb, long val );
  30789. +void MSG_WriteDword( sizebuf_t *sb, dword val );
  30790. +void MSG_WriteCoord( sizebuf_t *sb, float val );
  30791. +void MSG_WriteFloat( sizebuf_t *sb, float val );
  30792. +void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
  30793. +qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
  30794. +qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
  30795.  
  30796. // helper functions
  30797. -_inline int MSG_GetNumBytesWritten( sizebuf_t *bf ) { return BitByte( bf->iCurBit ); }
  30798. -_inline int MSG_GetRealBytesWritten( sizebuf_t *bf ) { return bf->iCurBit >> 3; } // unpadded
  30799. -_inline int MSG_GetNumBitsWritten( sizebuf_t *bf ) { return bf->iCurBit; }
  30800. -_inline int MSG_GetMaxBits( sizebuf_t *bf ) { return bf->nDataBits; }
  30801. -_inline int MSG_GetMaxBytes( sizebuf_t *bf ) { return bf->nDataBits >> 3; }
  30802. -_inline int MSG_GetNumBitsLeft( sizebuf_t *bf ) { return bf->nDataBits - bf->iCurBit; }
  30803. -_inline int MSG_GetNumBytesLeft( sizebuf_t *bf ) { return MSG_GetNumBitsLeft( bf ) >> 3; }
  30804. -_inline byte *MSG_GetData( sizebuf_t *bf ) { return bf->pData; }
  30805. +_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
  30806. +_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
  30807. +_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
  30808. +_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
  30809. +_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
  30810. +_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
  30811. +_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
  30812. +_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
  30813.  
  30814. // Bit-read functions
  30815. -int MSG_ReadOneBit( sizebuf_t *bf );
  30816. -float MSG_ReadBitFloat( sizebuf_t *bf );
  30817. -qboolean MSG_ReadBits( sizebuf_t *bf, void *pOutData, int nBits );
  30818. -float MSG_ReadBitAngle( sizebuf_t *bf, int numbits );
  30819. -int MSG_ReadSBitLong( sizebuf_t *bf, int numbits );
  30820. -uint MSG_ReadUBitLong( sizebuf_t *bf, int numbits );
  30821. -uint MSG_ReadBitLong( sizebuf_t *bf, int numbits, qboolean bSigned );
  30822. +int MSG_ReadOneBit( sizebuf_t *sb );
  30823. +float MSG_ReadBitFloat( sizebuf_t *sb );
  30824. +qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits );
  30825. +float MSG_ReadBitAngle( sizebuf_t *sb, int numbits );
  30826. +int MSG_ReadSBitLong( sizebuf_t *sb, int numbits );
  30827. +uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits );
  30828. +uint MSG_ReadBitLong( sizebuf_t *sb, int numbits, qboolean bSigned );
  30829.  
  30830. // Byte-read functions
  30831. -int MSG_ReadChar( sizebuf_t *bf );
  30832. -int MSG_ReadByte( sizebuf_t *bf );
  30833. -int MSG_ReadShort( sizebuf_t *bf );
  30834. -int MSG_ReadWord( sizebuf_t *bf );
  30835. -long MSG_ReadLong( sizebuf_t *bf );
  30836. -float MSG_ReadCoord( sizebuf_t *bf );
  30837. -float MSG_ReadFloat( sizebuf_t *bf );
  30838. -void MSG_ReadVec3Coord( sizebuf_t *bf, vec3_t fa );
  30839. -qboolean MSG_ReadBytes( sizebuf_t *bf, void *pOut, int nBytes );
  30840. -char *MSG_ReadStringExt( sizebuf_t *bf, qboolean bLine );
  30841. +int MSG_ReadChar( sizebuf_t *sb );
  30842. +int MSG_ReadByte( sizebuf_t *sb );
  30843. +int MSG_ReadShort( sizebuf_t *sb );
  30844. +int MSG_ReadWord( sizebuf_t *sb );
  30845. +long MSG_ReadLong( sizebuf_t *sb );
  30846. +dword MSG_ReadDword( sizebuf_t *sb );
  30847. +float MSG_ReadCoord( sizebuf_t *sb );
  30848. +float MSG_ReadFloat( sizebuf_t *sb );
  30849. +void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
  30850. +qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
  30851. +char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
  30852.  
  30853. #endif//NET_BUFFER_H
  30854. \ No newline at end of file
  30855. diff --git b/engine/common/net_chan.c a/engine/common/net_chan.c
  30856. index cafa55e..08ea6e7 100644
  30857. --- b/engine/common/net_chan.c
  30858. +++ a/engine/common/net_chan.c
  30859. @@ -17,6 +17,7 @@ GNU General Public License for more details.
  30860. #include "netchan.h"
  30861. #include "mathlib.h"
  30862. #include "net_encode.h"
  30863. +#include "protocol.h"
  30864.  
  30865. #define MAKE_FRAGID( id, count ) ((( id & 0xffff ) << 16 ) | ( count & 0xffff ))
  30866. #define FRAG_GETID( fragid ) (( fragid >> 16 ) & 0xffff )
  30867. @@ -121,7 +122,6 @@ void Netchan_Init( void )
  30868.  
  30869. net_mempool = Mem_AllocPool( "Network Pool" );
  30870.  
  30871. - Huff_Init (); // initialize huffman compression
  30872. MSG_InitMasks (); // initialize bit-masks
  30873. }
  30874.  
  30875. @@ -163,7 +163,6 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport )
  30876. chan->incoming_sequence = 0;
  30877. chan->outgoing_sequence = 1;
  30878. chan->rate = DEFAULT_RATE;
  30879. - chan->compress = false; // work but low efficiency
  30880. chan->qport = qport;
  30881.  
  30882. MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
  30883. @@ -1166,8 +1165,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30884. qboolean send_reliable_fragment;
  30885. qboolean send_resending = false;
  30886. qboolean send_reliable;
  30887. - size_t size1, size2;
  30888. - uint w1, w2, hdr_size;
  30889. + uint w1, w2;
  30890. int i, j;
  30891. float fRate;
  30892.  
  30893. @@ -1351,9 +1349,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30894. }
  30895.  
  30896. if( send_reliable && send_reliable_fragment )
  30897. - {
  30898. - w1 |= ( 1 << 30 );
  30899. - }
  30900. + SetBits( w1, BIT( 30 ));
  30901.  
  30902. chan->outgoing_sequence++;
  30903. chan->last_sent = host.realtime;
  30904. @@ -1385,8 +1381,6 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30905. }
  30906. }
  30907.  
  30908. - hdr_size = MSG_GetNumBytesWritten( &send );
  30909. -
  30910. // copy the reliable message to the packet first
  30911. if( send_reliable )
  30912. {
  30913. @@ -1396,16 +1390,11 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30914.  
  30915. // is there room for the unreliable payload?
  30916. if( MSG_GetNumBitsLeft( &send ) >= length )
  30917. - {
  30918. MSG_WriteBits( &send, data, length );
  30919. - }
  30920. - else
  30921. - {
  30922. - MsgDev( D_WARN, "Netchan_Transmit: unreliable message overflow\n" );
  30923. - }
  30924. + else MsgDev( D_WARN, "Netchan_Transmit: unreliable message overflow\n" );
  30925.  
  30926. // deal with packets that are too small for some networks
  30927. - if( MSG_GetNumBytesWritten( &send ) < 16 ) // packet too small for some networks
  30928. + if( MSG_GetNumBytesWritten( &send ) < 16 && !NET_IsLocalAddress( chan->remote_address )) // packet too small for some networks
  30929. {
  30930. int i;
  30931.  
  30932. @@ -1413,7 +1402,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30933. for( i = MSG_GetNumBytesWritten( &send ); i < 16; i++ )
  30934. {
  30935. // NOTE: that the server can parse svc_nop, too.
  30936. - MSG_WriteByte( &send, 1 );
  30937. + MSG_WriteByte( &send, svc_nop );
  30938. }
  30939. }
  30940.  
  30941. @@ -1424,12 +1413,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
  30942.  
  30943. Netchan_UpdateFlow( chan );
  30944.  
  30945. - size1 = MSG_GetNumBytesWritten( &send );
  30946. - if( chan->compress ) Huff_CompressPacket( &send, hdr_size );
  30947. - size2 = MSG_GetNumBytesWritten( &send );
  30948. -
  30949. - chan->total_sended += size2;
  30950. - chan->total_sended_uncompressed += size1;
  30951. + chan->total_sended += MSG_GetNumBytesWritten( &send );
  30952.  
  30953. // send the datagram
  30954. if( !CL_IsPlaybackDemo( ))
  30955. @@ -1488,21 +1472,18 @@ modifies net_message so that it points to the packet payload
  30956. */
  30957. qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
  30958. {
  30959. - uint sequence, sequence_ack, hdr_size;
  30960. + uint sequence, sequence_ack;
  30961. uint reliable_ack, reliable_message;
  30962. uint fragid[MAX_STREAMS] = { 0, 0 };
  30963. qboolean frag_message[MAX_STREAMS] = { false, false };
  30964. int frag_offset[MAX_STREAMS] = { 0, 0 };
  30965. int frag_length[MAX_STREAMS] = { 0, 0 };
  30966. qboolean message_contains_fragments;
  30967. - size_t size1, size2;
  30968. int i, qport;
  30969.  
  30970. if( !CL_IsPlaybackDemo() && !NET_CompareAdr( net_from, chan->remote_address ))
  30971. - {
  30972. return false;
  30973. - }
  30974. -
  30975. +
  30976. // get sequence numbers
  30977. MSG_Clear( msg );
  30978. sequence = MSG_ReadLong( msg );
  30979. @@ -1517,7 +1498,7 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
  30980. reliable_message = sequence >> 31;
  30981. reliable_ack = sequence_ack >> 31;
  30982.  
  30983. - message_contains_fragments = sequence & ( 1 << 30 ) ? true : false;
  30984. + message_contains_fragments = FBitSet( sequence, BIT( 30 )) ? true : false;
  30985.  
  30986. if( message_contains_fragments )
  30987. {
  30988. @@ -1533,9 +1514,9 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
  30989. }
  30990. }
  30991.  
  30992. - sequence &= ~(1<<31);
  30993. - sequence &= ~(1<<30);
  30994. - sequence_ack &= ~(1<<31);
  30995. + sequence &= ~BIT( 31 );
  30996. + sequence &= ~BIT( 30 );
  30997. + sequence_ack &= ~BIT( 31 );
  30998.  
  30999. if( net_showpackets->integer == 2 )
  31000. {
  31001. @@ -1619,14 +1600,8 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
  31002. chan->flow[FLOW_INCOMING].current++;
  31003.  
  31004. Netchan_UpdateFlow( chan );
  31005. - hdr_size = MSG_GetNumBytesRead( msg );
  31006. -
  31007. - size1 = MSG_GetMaxBytes( msg );
  31008. - if( chan->compress ) Huff_DecompressPacket( msg, hdr_size );
  31009. - size2 = MSG_GetMaxBytes( msg );
  31010.  
  31011. - chan->total_received += size1;
  31012. - chan->total_received_uncompressed += size2;
  31013. + chan->total_received += MSG_GetMaxBytes( msg );
  31014. chan->good_count += 1;
  31015.  
  31016. if( message_contains_fragments )
  31017. diff --git b/engine/common/net_encode.c a/engine/common/net_encode.c
  31018. index 7e9c52c..b7a2df9 100644
  31019. --- b/engine/common/net_encode.c
  31020. +++ a/engine/common/net_encode.c
  31021. @@ -375,7 +375,7 @@ void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
  31022. {
  31023. int i;
  31024.  
  31025. - ASSERT( dt != NULL );
  31026. + Assert( dt != NULL );
  31027.  
  31028. // set all fields is active by default
  31029. for( i = 0; i < dt->numFields; i++ )
  31030. @@ -424,7 +424,7 @@ qboolean Delta_AddField( const char *pStructName, const char *pName, int flags,
  31031.  
  31032. // get the delta struct
  31033. dt = Delta_FindStruct( pStructName );
  31034. - ASSERT( dt != NULL );
  31035. + Assert( dt != NULL );
  31036.  
  31037. // check for coexisting field
  31038. for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
  31039. @@ -472,16 +472,16 @@ void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pFiel
  31040. int nameIndex;
  31041. delta_info_t *dt;
  31042.  
  31043. - ASSERT( pField );
  31044. + Assert( pField );
  31045.  
  31046. if( !pField->name || !*pField->name )
  31047. return; // not initialized ?
  31048.  
  31049. dt = Delta_FindStructByIndex( tableIndex );
  31050. - ASSERT( dt && dt->bInitialized );
  31051. + Assert( dt && dt->bInitialized );
  31052.  
  31053. nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
  31054. - ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
  31055. + Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
  31056.  
  31057. MSG_WriteByte( msg, svc_deltatable );
  31058. MSG_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables
  31059. @@ -516,10 +516,10 @@ void Delta_ParseTableField( sizebuf_t *msg )
  31060. tableIndex = MSG_ReadUBitLong( msg, 4 );
  31061. dt = Delta_FindStructByIndex( tableIndex );
  31062.  
  31063. - ASSERT( dt != NULL );
  31064. + Assert( dt != NULL );
  31065.  
  31066. nameIndex = MSG_ReadUBitLong( msg, 8 ); // read field name index
  31067. - ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
  31068. + Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
  31069. pName = dt->pInfo[nameIndex].name;
  31070. flags = MSG_ReadUBitLong( msg, 10 );
  31071. bits = MSG_ReadUBitLong( msg, 5 ) + 1;
  31072. @@ -695,7 +695,7 @@ void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encode
  31073. // assume we have handled '{'
  31074. while(( *delta_script = COM_ParseFile( *delta_script, token )) != NULL )
  31075. {
  31076. - ASSERT( dt->numFields <= dt->maxFields );
  31077. + Assert( dt->numFields <= dt->maxFields );
  31078.  
  31079. if( !Q_strcmp( token, "DEFINE_DELTA" ))
  31080. {
  31081. @@ -747,9 +747,10 @@ void Delta_InitFields( void )
  31082. while(( pfile = COM_ParseFile( pfile, token )) != NULL )
  31083. {
  31084. dt = Delta_FindStruct( token );
  31085. +
  31086. if( dt == NULL )
  31087. {
  31088. - Sys_Error( "delta.lst: unknown struct %s\n", token );
  31089. + Sys_Error( "%s: unknown struct %s\n", DELTA_PATH, token );
  31090. }
  31091.  
  31092. pfile = COM_ParseFile( pfile, encodeDll );
  31093. @@ -760,10 +761,11 @@ void Delta_InitFields( void )
  31094.  
  31095. // jump to '{'
  31096. pfile = COM_ParseFile( pfile, token );
  31097. +
  31098. if( token[0] != '{' )
  31099. {
  31100. - Sys_Error( "delta.lst: missing '{' in section %s\n", dt->pName );
  31101. - }
  31102. + Sys_Error( "%s: missing '{' in section %s\n", DELTA_PATH, dt->pName );
  31103. + }
  31104.  
  31105. Delta_ParseTable( &pfile, dt, encodeDll, encodeFunc );
  31106. }
  31107. @@ -787,7 +789,7 @@ void Delta_Init( void )
  31108.  
  31109. dt = Delta_FindStruct( "movevars_t" );
  31110.  
  31111. - ASSERT( dt != NULL );
  31112. + Assert( dt != NULL );
  31113. if( dt->bInitialized ) return; // "movevars_t" already specified by user
  31114.  
  31115. // create movevars_t delta internal
  31116. @@ -804,15 +806,19 @@ void Delta_Init( void )
  31117. Delta_AddField( "movevars_t", "bounce", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
  31118. Delta_AddField( "movevars_t", "stepsize", DT_FLOAT|DT_SIGNED, 16, 16.0f, 1.0f );
  31119. Delta_AddField( "movevars_t", "maxvelocity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
  31120. - Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 18, 1.0f, 1.0f ); // no fractional part
  31121. +
  31122. + if( host.features & ENGINE_WRITE_LARGE_COORD )
  31123. + Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 18, 1.0f, 1.0f );
  31124. + else Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
  31125. +
  31126. Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 16.0f, 8.0f );
  31127. Delta_AddField( "movevars_t", "skyName", DT_STRING, 1, 1.0f, 1.0f );
  31128. Delta_AddField( "movevars_t", "footsteps", DT_INTEGER, 1, 1.0f, 1.0f );
  31129. Delta_AddField( "movevars_t", "rollangle", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
  31130. Delta_AddField( "movevars_t", "rollspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
  31131. - Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f ); // 0 - 264
  31132. - Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f );
  31133. - Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 12, 1.0f, 1.0f );
  31134. + Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f ); // 0 - 264
  31135. + Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
  31136. + Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f );
  31137. Delta_AddField( "movevars_t", "skyvec_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1
  31138. Delta_AddField( "movevars_t", "skyvec_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
  31139. Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
  31140. @@ -822,6 +828,7 @@ void Delta_Init( void )
  31141. Delta_AddField( "movevars_t", "skyangle", DT_ANGLE, 16, 1.0f, 1.0f ); // 0 - 360
  31142. Delta_AddField( "movevars_t", "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
  31143. Delta_AddField( "movevars_t", "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f );
  31144. +
  31145. // now done
  31146. dt->bInitialized = true;
  31147. }
  31148. @@ -964,9 +971,9 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba
  31149. float val_a, val_b;
  31150. int fromF, toF;
  31151.  
  31152. - ASSERT( pField );
  31153. - ASSERT( from );
  31154. - ASSERT( to );
  31155. + Assert( pField );
  31156. + Assert( from );
  31157. + Assert( to );
  31158.  
  31159. if( pField->bInactive )
  31160. return true;
  31161. @@ -1027,7 +1034,7 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba
  31162. if( pField->multiplier != 1.0f ) fromF *= pField->multiplier;
  31163. if( pField->multiplier != 1.0f ) toF *= pField->multiplier;
  31164. }
  31165. - else if( pField->flags & ( DT_FLOAT|DT_ANGLE ))
  31166. + else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
  31167. {
  31168. // don't convert floats to integers
  31169. fromF = *((int *)((byte *)from + pField->offset ));
  31170. @@ -1145,7 +1152,7 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to
  31171. else if( pField->flags & DT_TIMEWINDOW_BIG )
  31172. {
  31173. flValue = *(float *)((byte *)to + pField->offset );
  31174. - flTime = (timebase * pField->multiplier) - (flValue * pField->multiplier);
  31175. + flTime = Q_rint( timebase * pField->multiplier ) - Q_rint( flValue * pField->multiplier );
  31176. iValue = (uint)abs( flTime );
  31177.  
  31178. MSG_WriteBitLong( msg, iValue, pField->bits, bSigned );
  31179. @@ -1177,7 +1184,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to,
  31180.  
  31181. bChanged = MSG_ReadOneBit( msg );
  31182.  
  31183. - ASSERT( pField->multiplier != 0.0f );
  31184. + Assert( pField->multiplier != 0.0f );
  31185.  
  31186. if( pField->flags & DT_BYTE )
  31187. {
  31188. @@ -1308,10 +1315,10 @@ void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
  31189. int i;
  31190.  
  31191. dt = Delta_FindStruct( "usercmd_t" );
  31192. - ASSERT( dt && dt->bInitialized );
  31193. + Assert( dt && dt->bInitialized );
  31194.  
  31195. pField = dt->pFields;
  31196. - ASSERT( pField );
  31197. + Assert( pField );
  31198.  
  31199. // activate fields and call custom encode func
  31200. Delta_CustomEncode( dt, from, to );
  31201. @@ -1335,10 +1342,10 @@ void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
  31202. int i;
  31203.  
  31204. dt = Delta_FindStruct( "usercmd_t" );
  31205. - ASSERT( dt && dt->bInitialized );
  31206. + Assert( dt && dt->bInitialized );
  31207.  
  31208. pField = dt->pFields;
  31209. - ASSERT( pField );
  31210. + Assert( pField );
  31211.  
  31212. *to = *from;
  31213.  
  31214. @@ -1368,10 +1375,10 @@ void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
  31215. int i;
  31216.  
  31217. dt = Delta_FindStruct( "event_t" );
  31218. - ASSERT( dt && dt->bInitialized );
  31219. + Assert( dt && dt->bInitialized );
  31220.  
  31221. pField = dt->pFields;
  31222. - ASSERT( pField );
  31223. + Assert( pField );
  31224.  
  31225. // activate fields and call custom encode func
  31226. Delta_CustomEncode( dt, from, to );
  31227. @@ -1395,10 +1402,10 @@ void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
  31228. int i;
  31229.  
  31230. dt = Delta_FindStruct( "event_t" );
  31231. - ASSERT( dt && dt->bInitialized );
  31232. + Assert( dt && dt->bInitialized );
  31233.  
  31234. pField = dt->pFields;
  31235. - ASSERT( pField );
  31236. + Assert( pField );
  31237.  
  31238. *to = *from;
  31239.  
  31240. @@ -1424,10 +1431,10 @@ qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *t
  31241. int numChanges = 0;
  31242.  
  31243. dt = Delta_FindStruct( "movevars_t" );
  31244. - ASSERT( dt && dt->bInitialized );
  31245. + Assert( dt && dt->bInitialized );
  31246.  
  31247. pField = dt->pFields;
  31248. - ASSERT( pField );
  31249. + Assert( pField );
  31250.  
  31251. startBit = msg->iCurBit;
  31252.  
  31253. @@ -1459,10 +1466,10 @@ void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
  31254. int i;
  31255.  
  31256. dt = Delta_FindStruct( "movevars_t" );
  31257. - ASSERT( dt && dt->bInitialized );
  31258. + Assert( dt && dt->bInitialized );
  31259.  
  31260. pField = dt->pFields;
  31261. - ASSERT( pField );
  31262. + Assert( pField );
  31263.  
  31264. *to = *from;
  31265.  
  31266. @@ -1495,10 +1502,10 @@ void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to,
  31267. int i;
  31268.  
  31269. dt = Delta_FindStruct( "clientdata_t" );
  31270. - ASSERT( dt && dt->bInitialized );
  31271. + Assert( dt && dt->bInitialized );
  31272.  
  31273. pField = dt->pFields;
  31274. - ASSERT( pField );
  31275. + Assert( pField );
  31276.  
  31277. // activate fields and call custom encode func
  31278. Delta_CustomEncode( dt, from, to );
  31279. @@ -1524,10 +1531,10 @@ void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, f
  31280. int i;
  31281.  
  31282. dt = Delta_FindStruct( "clientdata_t" );
  31283. - ASSERT( dt && dt->bInitialized );
  31284. + Assert( dt && dt->bInitialized );
  31285.  
  31286. pField = dt->pFields;
  31287. - ASSERT( pField );
  31288. + Assert( pField );
  31289.  
  31290. *to = *from;
  31291.  
  31292. @@ -1561,10 +1568,10 @@ void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to
  31293. int numChanges = 0;
  31294.  
  31295. dt = Delta_FindStruct( "weapon_data_t" );
  31296. - ASSERT( dt && dt->bInitialized );
  31297. + Assert( dt && dt->bInitialized );
  31298.  
  31299. pField = dt->pFields;
  31300. - ASSERT( pField );
  31301. + Assert( pField );
  31302.  
  31303. // activate fields and call custom encode func
  31304. Delta_CustomEncode( dt, from, to );
  31305. @@ -1599,10 +1606,10 @@ void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to,
  31306. int i;
  31307.  
  31308. dt = Delta_FindStruct( "weapon_data_t" );
  31309. - ASSERT( dt && dt->bInitialized );
  31310. + Assert( dt && dt->bInitialized );
  31311.  
  31312. pField = dt->pFields;
  31313. - ASSERT( pField );
  31314. + Assert( pField );
  31315.  
  31316. *to = *from;
  31317.  
  31318. @@ -1666,10 +1673,11 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
  31319. MSG_WriteWord( msg, to->number );
  31320. MSG_WriteUBitLong( msg, 0, 2 ); // alive
  31321.  
  31322. - if( to->entityType != from->entityType )
  31323. + if( force || ( to->entityType != from->entityType ))
  31324. {
  31325. MSG_WriteOneBit( msg, 1 );
  31326. MSG_WriteUBitLong( msg, to->entityType, 2 );
  31327. + numChanges++;
  31328. }
  31329. else MSG_WriteOneBit( msg, 0 );
  31330.  
  31331. @@ -1689,10 +1697,10 @@ void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *
  31332. dt = Delta_FindStruct( "custom_entity_state_t" );
  31333. }
  31334.  
  31335. - ASSERT( dt && dt->bInitialized );
  31336. + Assert( dt && dt->bInitialized );
  31337.  
  31338. pField = dt->pFields;
  31339. - ASSERT( pField );
  31340. + Assert( pField );
  31341.  
  31342. // activate fields and call custom encode func
  31343. Delta_CustomEncode( dt, from, to );
  31344. @@ -1772,10 +1780,10 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
  31345. dt = Delta_FindStruct( "custom_entity_state_t" );
  31346. }
  31347.  
  31348. - ASSERT( dt && dt->bInitialized );
  31349. + Assert( dt && dt->bInitialized );
  31350.  
  31351. pField = dt->pFields;
  31352. - ASSERT( pField );
  31353. + Assert( pField );
  31354.  
  31355. // process fields
  31356. for( i = 0; i < dt->numFields; i++, pField++ )
  31357. diff --git b/engine/common/net_huff.c a/engine/common/net_huff.c
  31358. deleted file mode 100644
  31359. index a851d51..0000000
  31360. diff --git b/engine/common/netchan.h a/engine/common/netchan.h
  31361. index 8d59a9c..228f9f3 100644
  31362. --- b/engine/common/netchan.h
  31363. +++ a/engine/common/netchan.h
  31364. @@ -38,7 +38,7 @@ GNU General Public License for more details.
  31365. // NETWORKING INFO
  31366.  
  31367. // This is the packet payload without any header bytes (which are attached for actual sending)
  31368. -#define NET_MAX_PAYLOAD 80000
  31369. +#define NET_MAX_PAYLOAD 96000
  31370.  
  31371. // This is the payload plus any header info (excluding UDP header)
  31372.  
  31373. @@ -59,12 +59,13 @@ GNU General Public License for more details.
  31374. // bytes will be stripped by the networking channel layer
  31375. #define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
  31376.  
  31377. -#define MASTERSERVER_ADR "celest.in:27010"
  31378. +#define MASTERSERVER_ADR "ms.xash.su:27010"
  31379. #define PORT_MASTER 27010
  31380. #define PORT_CLIENT 27005
  31381. #define PORT_SERVER 27015
  31382. #define MULTIPLAYER_BACKUP 64 // how many data slots to use when in multiplayer (must be power of 2)
  31383. #define SINGLEPLAYER_BACKUP 16 // same for single player
  31384. +#define NUM_PACKET_ENTITIES 128
  31385.  
  31386. /*
  31387. ==============================================================
  31388. @@ -130,9 +131,7 @@ typedef struct netchan_s
  31389. netsrc_t sock; // NS_SERVER or NS_CLIENT, depending on channel.
  31390. netadr_t remote_address; // address this channel is talking to.
  31391. int qport; // qport value to write when transmitting
  31392. -
  31393. - qboolean compress; // enable huffman compression
  31394. -
  31395. +
  31396. double last_received; // for timeouts
  31397. double last_sent; // for retransmits
  31398.  
  31399. @@ -185,10 +184,7 @@ typedef struct netchan_s
  31400.  
  31401. // added for net_speeds
  31402. size_t total_sended;
  31403. - size_t total_sended_uncompressed;
  31404. -
  31405. size_t total_received;
  31406. - size_t total_received_uncompressed;
  31407. } netchan_t;
  31408.  
  31409. extern netadr_t net_from;
  31410. @@ -216,9 +212,4 @@ qboolean Netchan_CanPacket( netchan_t *chan );
  31411. void Netchan_FragSend( netchan_t *chan );
  31412. void Netchan_Clear( netchan_t *chan );
  31413.  
  31414. -// huffman compression
  31415. -void Huff_Init( void );
  31416. -void Huff_CompressPacket( sizebuf_t *msg, int offset );
  31417. -void Huff_DecompressPacket( sizebuf_t *msg, int offset );
  31418. -
  31419. #endif//NET_MSG_H
  31420. \ No newline at end of file
  31421. diff --git b/engine/common/pm_trace.c a/engine/common/pm_trace.c
  31422. index 49e7b51..af087cf 100644
  31423. --- b/engine/common/pm_trace.c
  31424. +++ a/engine/common/pm_trace.c
  31425. @@ -117,7 +117,8 @@ hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
  31426. {
  31427. hull_t *hull;
  31428.  
  31429. - ASSERT( pe && pe->model != NULL );
  31430. + Assert( pe != NULL );
  31431. + Assert( pe->model != NULL );
  31432.  
  31433. switch( pmove->usehull )
  31434. {
  31435. @@ -135,7 +136,7 @@ hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
  31436. break;
  31437. }
  31438.  
  31439. - ASSERT( hull != NULL );
  31440. + Assert( hull != NULL );
  31441.  
  31442. // force to use hull0 because other hulls doesn't exist for water
  31443. if( pe->model->flags & MODEL_LIQUID && pe->solid != SOLID_TRIGGER )
  31444. @@ -202,7 +203,7 @@ qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec
  31445. }
  31446.  
  31447. if( num < hull->firstclipnode || num > hull->lastclipnode )
  31448. - Sys_Error( "PM_RecursiveHullCheck: bad node number\n" );
  31449. + Host_Error( "PM_RecursiveHullCheck: bad node number %i\n", num );
  31450.  
  31451. // find the point distances
  31452. node = hull->clipnodes + num;
  31453. diff --git b/engine/common/protocol.h a/engine/common/protocol.h
  31454. index eac68b2..bb6b1df 100644
  31455. --- b/engine/common/protocol.h
  31456. +++ a/engine/common/protocol.h
  31457. @@ -65,6 +65,7 @@ GNU General Public License for more details.
  31458. #define svc_resourcelist 43 // [short][...]
  31459. #define svc_deltamovevars 44 // [movevars_t]
  31460. #define svc_customization 45 // <see code>
  31461. +
  31462. #define svc_crosshairangle 47 // [byte][byte]
  31463. #define svc_soundfade 48 // [float*4] sound fade parms
  31464.  
  31465. @@ -88,7 +89,7 @@ GNU General Public License for more details.
  31466. #define clc_requestcvarvalue 9
  31467. #define clc_requestcvarvalue2 10
  31468.  
  31469. -#define MAX_VISIBLE_PACKET 512 // 512 visible entities per frame (hl1 has 256)
  31470. +#define MAX_VISIBLE_PACKET 1024 // 1024 visible entities per frame (hl1 has 256)
  31471.  
  31472. // additional protocol data
  31473. #define MAX_CLIENT_BITS 5
  31474. diff --git b/engine/common/random.c a/engine/common/random.c
  31475. index ae84496..bbadde5 100644
  31476. --- b/engine/common/random.c
  31477. +++ a/engine/common/random.c
  31478. @@ -23,9 +23,9 @@ static long idum = 0;
  31479. #define IQ 127773
  31480. #define IR 2836
  31481. #define NTAB 32
  31482. -#define NDIV (1+(IM-1)/NTAB)
  31483. -#define AM (1.0/IM)
  31484. #define EPS 1.2e-7
  31485. +#define NDIV (1 + (IM - 1) / NTAB)
  31486. +#define AM (1.0 / IM)
  31487. #define RNMX (1.0 - EPS)
  31488.  
  31489. void COM_SetRandomSeed( long lSeed )
  31490. @@ -41,15 +41,14 @@ void COM_SetRandomSeed( long lSeed )
  31491.  
  31492. long lran1( void )
  31493. {
  31494. - int j;
  31495. - long k;
  31496. + static long iy = 0;
  31497. + static long iv[NTAB];
  31498. + int j;
  31499. + long k;
  31500.  
  31501. - static long iy = 0;
  31502. - static long iv[NTAB];
  31503. -
  31504. if( idum <= 0 || !iy )
  31505. {
  31506. - if(-(idum) < 1) idum=1;
  31507. + if( -(idum) < 1 ) idum = 1;
  31508. else idum = -(idum);
  31509.  
  31510. for( j = NTAB + 7; j >= 0; j-- )
  31511. @@ -59,10 +58,11 @@ long lran1( void )
  31512. if( idum < 0 ) idum += IM;
  31513. if( j < NTAB ) iv[j] = idum;
  31514. }
  31515. +
  31516. iy = iv[0];
  31517. }
  31518.  
  31519. - k = (idum)/IQ;
  31520. + k = (idum) / IQ;
  31521. idum = IA * (idum - k * IQ) - IR * k;
  31522. if( idum < 0 ) idum += IM;
  31523. j = iy / NDIV;
  31524. @@ -72,7 +72,7 @@ long lran1( void )
  31525. return iy;
  31526. }
  31527.  
  31528. -// fran1 -- return a random floating-point number on the interval [0,1)
  31529. +// fran1 -- return a random floating-point number on the interval [0,1]
  31530. float fran1( void )
  31531. {
  31532. float temp = (float)AM * lran1();
  31533. @@ -85,20 +85,20 @@ float Com_RandomFloat( float flLow, float flHigh )
  31534. {
  31535. float fl;
  31536.  
  31537. - if( idum == 0 ) COM_SetRandomSeed(0);
  31538. + if( idum == 0 ) COM_SetRandomSeed( 0 );
  31539.  
  31540. - fl = fran1(); // float in [0, 1)
  31541. + fl = fran1(); // float in [0,1]
  31542. return (fl * (flHigh - flLow)) + flLow; // float in [low, high)
  31543. }
  31544.  
  31545. long Com_RandomLong( long lLow, long lHigh )
  31546. {
  31547. dword maxAcceptable;
  31548. - dword n, x = lHigh-lLow + 1;
  31549. + dword n, x = lHigh - lLow + 1;
  31550.  
  31551. - if( idum == 0 ) COM_SetRandomSeed(0);
  31552. + if( idum == 0 ) COM_SetRandomSeed( 0 );
  31553.  
  31554. - if( x <= 0 || MAX_RANDOM_RANGE < x-1 )
  31555. + if( x <= 0 || MAX_RANDOM_RANGE < x - 1 )
  31556. return lLow;
  31557.  
  31558. // The following maps a uniform distribution on the interval [0, MAX_RANDOM_RANGE]
  31559. @@ -108,7 +108,7 @@ long Com_RandomLong( long lLow, long lHigh )
  31560. // the average number of times through the loop is 2. For cases where x is
  31561. // much smaller than MAX_RANDOM_RANGE, the average number of times through the
  31562. // loop is very close to 1.
  31563. - maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE+1) % x );
  31564. + maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x );
  31565. do
  31566. {
  31567. n = lran1();
  31568. diff --git b/engine/common/soundlib/snd_mp3.c a/engine/common/soundlib/snd_mp3.c
  31569. index 1b901d3..e697cec 100644
  31570. --- b/engine/common/soundlib/snd_mp3.c
  31571. +++ a/engine/common/soundlib/snd_mp3.c
  31572. @@ -119,7 +119,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, size_t filesize )
  31573. outsize = ( sound.size - bytesWrite );
  31574. else outsize = mpeg.outsize;
  31575.  
  31576. - Q_memcpy( &sound.wav[bytesWrite], mpeg.out, outsize );
  31577. + memcpy( &sound.wav[bytesWrite], mpeg.out, outsize );
  31578. bytesWrite += outsize;
  31579. }
  31580.  
  31581. @@ -218,7 +218,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
  31582. mpeg_t *mpg;
  31583.  
  31584. mpg = (mpeg_t *)stream->ptr;
  31585. - ASSERT( mpg != NULL );
  31586. + Assert( mpg != NULL );
  31587.  
  31588. while( 1 )
  31589. {
  31590. @@ -262,7 +262,7 @@ long Stream_ReadMPG( stream_t *stream, long needBytes, void *buffer )
  31591.  
  31592. // copy raw sample to output buffer
  31593. data = (byte *)buffer + bytesWritten;
  31594. - Q_memcpy( data, &mpg->out[stream->buffsize], outsize );
  31595. + memcpy( data, &mpg->out[stream->buffsize], outsize );
  31596. bytesWritten += outsize;
  31597. mpg->outsize -= outsize;
  31598. stream->buffsize += outsize;
  31599. diff --git b/engine/common/soundlib/snd_utils.c a/engine/common/soundlib/snd_utils.c
  31600. index 43670b8..45f50cc 100644
  31601. --- b/engine/common/soundlib/snd_utils.c
  31602. +++ a/engine/common/soundlib/snd_utils.c
  31603. @@ -88,7 +88,7 @@ byte *Sound_Copy( size_t size )
  31604. byte *out;
  31605.  
  31606. out = Mem_Alloc( host.soundpool, size );
  31607. - Q_memcpy( out, sound.tempbuffer, size );
  31608. + memcpy( out, sound.tempbuffer, size );
  31609.  
  31610. return out;
  31611. }
  31612. diff --git b/engine/common/soundlib/snd_wav.c a/engine/common/soundlib/snd_wav.c
  31613. index 8b2e212..da934d0 100644
  31614. --- b/engine/common/soundlib/snd_wav.c
  31615. +++ a/engine/common/soundlib/snd_wav.c
  31616. @@ -270,7 +270,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize )
  31617. if(( filesize - hdr_size ) < 16384 )
  31618. {
  31619. sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, 16384 );
  31620. - Q_memcpy( sound.tempbuffer, buffer + (iff_dataPtr - buffer), filesize - hdr_size );
  31621. + memcpy( sound.tempbuffer, buffer + (iff_dataPtr - buffer), filesize - hdr_size );
  31622. return Sound_LoadMPG( name, sound.tempbuffer, 16384 );
  31623. }
  31624.  
  31625. @@ -281,7 +281,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, size_t filesize )
  31626. sound.size = sound.samples * sound.width * sound.channels;
  31627. sound.wav = Mem_Alloc( host.soundpool, sound.size );
  31628.  
  31629. - Q_memcpy( sound.wav, buffer + (iff_dataPtr - buffer), sound.size );
  31630. + memcpy( sound.wav, buffer + (iff_dataPtr - buffer), sound.size );
  31631.  
  31632. // now convert 8-bit sounds to signed
  31633. if( sound.width == 1 )
  31634. diff --git b/engine/common/sys_win.c a/engine/common/sys_win.c
  31635. index 038e8db..68a2e7e 100644
  31636. --- b/engine/common/sys_win.c
  31637. +++ a/engine/common/sys_win.c
  31638. @@ -48,8 +48,15 @@ create buffer, that contain clipboard
  31639. */
  31640. char *Sys_GetClipboardData( void )
  31641. {
  31642. - char *data = NULL;
  31643. - char *cliptext;
  31644. + static char *data = NULL;
  31645. + char *cliptext;
  31646. +
  31647. + if( data )
  31648. + {
  31649. + // release previous cbd
  31650. + Z_Free( data );
  31651. + data = NULL;
  31652. + }
  31653.  
  31654. if( OpenClipboard( NULL ) != 0 )
  31655. {
  31656. @@ -66,6 +73,7 @@ char *Sys_GetClipboardData( void )
  31657. }
  31658. CloseClipboard();
  31659. }
  31660. +
  31661. return data;
  31662. }
  31663.  
  31664. @@ -259,9 +267,9 @@ qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size )
  31665. {
  31666. int argc = Sys_CheckParm( parm );
  31667.  
  31668. - if( !argc ) return false;
  31669. - if( !out ) return false;
  31670. - if( !host.argv[argc + 1] ) return false;
  31671. + if( !argc || !out || !host.argv[argc + 1] )
  31672. + return false;
  31673. +
  31674. Q_strncpy( out, host.argv[argc+1], size );
  31675.  
  31676. return true;
  31677. @@ -534,8 +542,8 @@ print into window console
  31678. void Sys_Print( const char *pMsg )
  31679. {
  31680. const char *msg;
  31681. - char buffer[32768];
  31682. - char logbuf[32768];
  31683. + char buffer[MAX_PRINT_MSG];
  31684. + char logbuf[MAX_PRINT_MSG];
  31685. char *b = buffer;
  31686. char *c = logbuf;
  31687. int i = 0;
  31688. @@ -554,22 +562,20 @@ void Sys_Print( const char *pMsg )
  31689. if( msg[i] == '\n' && msg[i+1] == '\r' )
  31690. {
  31691. b[0] = '\r';
  31692. - b[1] = '\n';
  31693. - c[0] = '\n';
  31694. + b[1] = c[0] = '\n';
  31695. b += 2, c++;
  31696. i++;
  31697. }
  31698. else if( msg[i] == '\r' )
  31699. {
  31700. - b[0] = '\r';
  31701. + b[0] = c[0] = '\r';
  31702. b[1] = '\n';
  31703. - b += 2;
  31704. + b += 2, c++;
  31705. }
  31706. else if( msg[i] == '\n' )
  31707. {
  31708. b[0] = '\r';
  31709. - b[1] = '\n';
  31710. - c[0] = '\n';
  31711. + b[1] = c[0] = '\n';
  31712. b += 2, c++;
  31713. }
  31714. else if( msg[i] == '\35' || msg[i] == '\36' || msg[i] == '\37' )
  31715. @@ -588,7 +594,7 @@ void Sys_Print( const char *pMsg )
  31716. i++;
  31717. }
  31718.  
  31719. - *b = *c = 0; // cutoff garbage
  31720. + *b = *c = 0; // terminator
  31721.  
  31722. Sys_PrintLog( logbuf );
  31723. Con_WinPrint( buffer );
  31724. @@ -604,7 +610,7 @@ formatted message
  31725. void Msg( const char *pMsg, ... )
  31726. {
  31727. va_list argptr;
  31728. - char text[8192];
  31729. + char text[MAX_PRINT_MSG];
  31730.  
  31731. va_start( argptr, pMsg );
  31732. Q_vsnprintf( text, sizeof( text ), pMsg, argptr );
  31733. @@ -623,7 +629,7 @@ formatted developer message
  31734. void MsgDev( int level, const char *pMsg, ... )
  31735. {
  31736. va_list argptr;
  31737. - char text[8192];
  31738. + char text[MAX_PRINT_MSG];
  31739.  
  31740. if( host.developer < level ) return;
  31741.  
  31742. @@ -641,7 +647,7 @@ void MsgDev( int level, const char *pMsg, ... )
  31743. break;
  31744. case D_INFO:
  31745. case D_NOTE:
  31746. - case D_AICONSOLE:
  31747. + case D_REPORT:
  31748. Sys_Print( text );
  31749. break;
  31750. }
  31751. diff --git b/engine/common/system.h a/engine/common/system.h
  31752. index 96f4776..2be0c58 100644
  31753. --- b/engine/common/system.h
  31754. +++ a/engine/common/system.h
  31755. @@ -86,8 +86,6 @@ void Sys_SetClipboardData( const byte *buffer, size_t size );
  31756. qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size );
  31757. void Sys_ShellExecute( const char *path, const char *parms, qboolean exit );
  31758. void Sys_SendKeyEvents( void );
  31759. -qboolean Sys_CheckMMX( void );
  31760. -qboolean Sys_CheckSSE( void );
  31761. void Sys_Print( const char *pMsg );
  31762. void Sys_PrintLog( const char *pMsg );
  31763. void Sys_InitLog( void );
  31764. diff --git b/engine/common/titles.c a/engine/common/titles.c
  31765. index e5a6a8a..0a318d6 100644
  31766. --- b/engine/common/titles.c
  31767. +++ a/engine/common/titles.c
  31768. @@ -121,32 +121,6 @@ static int ParseFloats( const char *pText, float *pFloat, int count )
  31769. return 0;
  31770. }
  31771.  
  31772. -// trims all whitespace from the front and end of a string
  31773. -void TrimSpace( const char *source, char *dest )
  31774. -{
  31775. - int start, end, length;
  31776. -
  31777. - start = 0;
  31778. - end = Q_strlen( source );
  31779. -
  31780. - while( source[start] && IsWhiteSpace( source[start] ))
  31781. - start++;
  31782. -
  31783. - end--;
  31784. - while( end > 0 && IsWhiteSpace( source[end] ))
  31785. - end--;
  31786. -
  31787. - end++;
  31788. -
  31789. - length = end - start;
  31790. - if( length > 0 )
  31791. - memcpy( dest, source + start, length );
  31792. - else length = 0;
  31793. -
  31794. - // terminate the dest string
  31795. - dest[length] = 0;
  31796. -}
  31797. -
  31798. static int IsToken( const char *pText, const char *pTokenName )
  31799. {
  31800. if( !pText || !pTokenName )
  31801. @@ -253,7 +227,7 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize )
  31802.  
  31803. while( COM_MemFgets( pMemFile, fileSize, &filePos, buf, 512 ) != NULL )
  31804. {
  31805. - TrimSpace( buf, trim );
  31806. + COM_TrimSpace( buf, trim );
  31807.  
  31808. switch( mode )
  31809. {
  31810. diff --git b/engine/common/zone.c a/engine/common/zone.c
  31811. index 10f9d2a..9df8dc4 100644
  31812. --- b/engine/common/zone.c
  31813. +++ a/engine/common/zone.c
  31814. @@ -15,8 +15,8 @@ GNU General Public License for more details.
  31815.  
  31816. #include "common.h"
  31817.  
  31818. -#define MEMCLUMPSIZE (65536 - 1536) // give malloc padding so we can't waste most of a page at the end
  31819. #define MEMUNIT 8 // smallest unit we care about is this many bytes
  31820. +#define MEMCLUMPSIZE (65536 - 1536) // give malloc padding so we can't waste most of a page at the end
  31821. #define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
  31822. #define MEMBITINTS (MEMBITS / 32)
  31823.  
  31824. @@ -71,7 +71,7 @@ void *_Mem_Alloc( byte *poolptr, size_t size, const char *filename, int fileline
  31825. int i, j, k, needed, endbit, largest;
  31826. memclump_t *clump, **clumpchainpointer;
  31827. memheader_t *mem;
  31828. - mempool_t *pool = (mempool_t *)((byte *)poolptr);
  31829. + mempool_t *pool = (mempool_t *)poolptr;
  31830.  
  31831. if( size <= 0 ) return NULL;
  31832. if( poolptr == NULL ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
  31833. @@ -115,7 +115,7 @@ loopcontinue:;
  31834. pool->realsize += sizeof( memclump_t );
  31835. clump = malloc( sizeof( memclump_t ));
  31836. if( clump == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
  31837. - _memset( clump, 0, sizeof( memclump_t ), filename, fileline );
  31838. + memset( clump, 0, sizeof( memclump_t ));
  31839. *clumpchainpointer = clump;
  31840. clump->sentinel1 = MEMCLUMP_SENTINEL;
  31841. clump->sentinel2 = MEMCLUMP_SENTINEL;
  31842. @@ -153,7 +153,7 @@ choseclump:
  31843. mem->prev = NULL;
  31844. pool->chain = mem;
  31845. if( mem->next ) mem->next->prev = mem;
  31846. - _memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size, filename, fileline );
  31847. + memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
  31848.  
  31849. return (void *)((byte *)mem + sizeof( memheader_t ));
  31850. }
  31851. @@ -232,7 +232,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
  31852. }
  31853.  
  31854. pool->realsize -= sizeof( memclump_t );
  31855. - _memset( clump, 0xBF, sizeof( memclump_t ), filename, fileline );
  31856. + memset( clump, 0xBF, sizeof( memclump_t ));
  31857. free( clump );
  31858. }
  31859. else
  31860. @@ -257,8 +257,8 @@ void _Mem_Free( void *data, const char *filename, int fileline )
  31861.  
  31862. void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, const char *filename, int fileline )
  31863. {
  31864. - char *nb;
  31865. memheader_t *memhdr = NULL;
  31866. + char *nb;
  31867.  
  31868. if( size <= 0 ) return memptr; // no need to reallocate
  31869.  
  31870. @@ -272,11 +272,8 @@ void *_Mem_Realloc( byte *poolptr, void *memptr, size_t size, const char *filena
  31871.  
  31872. if( memptr ) // first allocate?
  31873. {
  31874. - size_t newsize;
  31875. -
  31876. - // get size of old block
  31877. - newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
  31878. - _memcpy( nb, memptr, newsize, filename, fileline );
  31879. + size_t newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
  31880. + memcpy( nb, memptr, newsize );
  31881. _Mem_Free( memptr, filename, fileline ); // free unused old block
  31882. }
  31883.  
  31884. @@ -289,7 +286,7 @@ byte *_Mem_AllocPool( const char *name, const char *filename, int fileline )
  31885.  
  31886. pool = (mempool_t *)malloc( sizeof( mempool_t ));
  31887. if( pool == NULL ) Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
  31888. - _memset( pool, 0, sizeof( mempool_t ), filename, fileline );
  31889. + memset( pool, 0, sizeof( mempool_t ));
  31890.  
  31891. // fill header
  31892. pool->sentinel1 = MEMHEADER_SENTINEL1;
  31893. @@ -303,27 +300,27 @@ byte *_Mem_AllocPool( const char *name, const char *filename, int fileline )
  31894. pool->next = poolchain;
  31895. poolchain = pool;
  31896.  
  31897. - return (byte *)((mempool_t *)pool);
  31898. + return (byte *)pool;
  31899. }
  31900.  
  31901. void _Mem_FreePool( byte **poolptr, const char *filename, int fileline )
  31902. {
  31903. - mempool_t *pool = (mempool_t *)((byte *)*poolptr );
  31904. + mempool_t *pool = (mempool_t *)*poolptr;
  31905. mempool_t **chainaddress;
  31906.  
  31907. if( pool )
  31908. {
  31909. // unlink pool from chain
  31910. for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
  31911. - if( *chainaddress != pool) Sys_Error("Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
  31912. - 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 );
  31913. - 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 );
  31914. + if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
  31915. + 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 );
  31916. + 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 );
  31917. *chainaddress = pool->next;
  31918.  
  31919. // free memory owned by the pool
  31920. while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
  31921. // free the pool itself
  31922. - _memset( pool, 0xBF, sizeof( mempool_t ), filename, fileline );
  31923. + memset( pool, 0xBF, sizeof( mempool_t ));
  31924. free( pool );
  31925. *poolptr = NULL;
  31926. }
  31927. @@ -331,7 +328,7 @@ void _Mem_FreePool( byte **poolptr, const char *filename, int fileline )
  31928.  
  31929. void _Mem_EmptyPool( byte *poolptr, const char *filename, int fileline )
  31930. {
  31931. - mempool_t *pool = (mempool_t *)((byte *)poolptr);
  31932. + mempool_t *pool = (mempool_t *)poolptr;
  31933. if( poolptr == NULL ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
  31934.  
  31935. 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 );
  31936. @@ -370,7 +367,7 @@ Check pointer for memory
  31937. qboolean Mem_IsAllocatedExt( byte *poolptr, void *data )
  31938. {
  31939. mempool_t *pool = NULL;
  31940. - if( poolptr ) pool = (mempool_t *)((byte *)poolptr);
  31941. + if( poolptr ) pool = (mempool_t *)poolptr;
  31942.  
  31943. return Mem_CheckAlloc( pool, data );
  31944. }
  31945. @@ -379,13 +376,17 @@ void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
  31946. {
  31947. memheader_t *mem;
  31948.  
  31949. - if (data == NULL) Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
  31950. + if( data == NULL )
  31951. + Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
  31952. +
  31953. mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
  31954. +
  31955. if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
  31956. {
  31957. mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
  31958. 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 );
  31959. }
  31960. +
  31961. if( *((byte *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 )
  31962. {
  31963. mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
  31964. diff --git b/engine/engine.dsp a/engine/engine.dsp
  31965. index 4f91fe0..6e6a201 100644
  31966. --- b/engine/engine.dsp
  31967. +++ a/engine/engine.dsp
  31968. @@ -61,9 +61,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!release
  31969. InputPath=\Xash3D\src_main\temp\engine\!release\xash.dll
  31970. SOURCE="$(InputPath)"
  31971.  
  31972. +BuildCmds= \
  31973. + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \
  31974. + copy $(TargetDir)\xash.dll "D:\Paranoia2\xash.dll" \
  31975. +
  31976. +
  31977. "D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
  31978. - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll"
  31979. + $(BuildCmds)
  31980.  
  31981. +"D:\Paranoia2\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
  31982. + $(BuildCmds)
  31983. # End Custom Build
  31984.  
  31985. !ELSEIF "$(CFG)" == "engine - Win32 Debug"
  31986. @@ -98,9 +105,16 @@ TargetDir=\Xash3D\src_main\temp\engine\!debug
  31987. InputPath=\Xash3D\src_main\temp\engine\!debug\xash.dll
  31988. SOURCE="$(InputPath)"
  31989.  
  31990. +BuildCmds= \
  31991. + copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll" \
  31992. + copy $(TargetDir)\xash.dll "D:\Paranoia2\xash.dll" \
  31993. +
  31994. +
  31995. "D:\Xash3D\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
  31996. - copy $(TargetDir)\xash.dll "D:\Xash3D\xash.dll"
  31997. + $(BuildCmds)
  31998.  
  31999. +"D:\Paranoia2\xash.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
  32000. + $(BuildCmds)
  32001. # End Custom Build
  32002.  
  32003. !ENDIF
  32004. @@ -142,11 +156,15 @@ SOURCE=.\client\cl_game.c
  32005. # End Source File
  32006. # Begin Source File
  32007.  
  32008. +SOURCE=.\client\cl_gameui.c
  32009. +# End Source File
  32010. +# Begin Source File
  32011. +
  32012. SOURCE=.\client\cl_main.c
  32013. # End Source File
  32014. # Begin Source File
  32015.  
  32016. -SOURCE=.\client\cl_menu.c
  32017. +SOURCE=.\client\cl_netgraph.c
  32018. # End Source File
  32019. # Begin Source File
  32020.  
  32021. @@ -366,10 +384,6 @@ SOURCE=.\common\net_encode.c
  32022. # End Source File
  32023. # Begin Source File
  32024.  
  32025. -SOURCE=.\common\net_huff.c
  32026. -# End Source File
  32027. -# Begin Source File
  32028. -
  32029. SOURCE=.\common\network.c
  32030. # End Source File
  32031. # Begin Source File
  32032. diff --git b/engine/physint.h a/engine/physint.h
  32033. index af923a0..d6f2223 100644
  32034. --- b/engine/physint.h
  32035. +++ a/engine/physint.h
  32036. @@ -26,6 +26,28 @@ GNU General Public License for more details.
  32037. #define SERVER_LOADING 1
  32038. #define SERVER_ACTIVE 2
  32039.  
  32040. +// LUMP reading errors
  32041. +#define LUMP_LOAD_OK 0
  32042. +#define LUMP_LOAD_COULDNT_OPEN 1
  32043. +#define LUMP_LOAD_BAD_HEADER 2
  32044. +#define LUMP_LOAD_BAD_VERSION 3
  32045. +#define LUMP_LOAD_NO_EXTRADATA 4
  32046. +#define LUMP_LOAD_INVALID_NUM 5
  32047. +#define LUMP_LOAD_NOT_EXIST 6
  32048. +#define LUMP_LOAD_MEM_FAILED 7
  32049. +#define LUMP_LOAD_CORRUPTED 8
  32050. +
  32051. +// LUMP saving errors
  32052. +#define LUMP_SAVE_OK 0
  32053. +#define LUMP_SAVE_COULDNT_OPEN 1
  32054. +#define LUMP_SAVE_BAD_HEADER 2
  32055. +#define LUMP_SAVE_BAD_VERSION 3
  32056. +#define LUMP_SAVE_NO_EXTRADATA 4
  32057. +#define LUMP_SAVE_INVALID_NUM 5
  32058. +#define LUMP_SAVE_ALREADY_EXIST 6
  32059. +#define LUMP_SAVE_NO_DATA 7
  32060. +#define LUMP_SAVE_CORRUPTED 8
  32061. +
  32062. typedef struct areanode_s
  32063. {
  32064. int axis; // -1 = leaf node
  32065. @@ -64,6 +86,24 @@ typedef struct server_physics_api_s
  32066. // static allocations
  32067. void *(*pfnMemAlloc)( size_t cb, const char *filename, const int fileline );
  32068. void (*pfnMemFree)( void *mem, const char *filename, const int fileline );
  32069. +
  32070. + // trace & contents
  32071. + int (*pfnMaskPointContents)( const float *pos, int groupmask );
  32072. + trace_t (*pfnTrace)( const float *p0, float *mins, float *maxs, const float *p1, int type, edict_t *e );
  32073. + trace_t (*pfnTraceNoEnts)( const float *p0, float *mins, float *maxs, const float *p1, int type, edict_t *e );
  32074. + int (*pfnBoxInPVS)( const float *org, const float *boxmins, const float *boxmaxs );
  32075. +
  32076. + // message handler (missed function to write raw bytes)
  32077. + void (*pfnWriteBytes)( byte *bytes, int count );
  32078. +
  32079. + // BSP lump management
  32080. + int (*pfnCheckLump)( const char *filename, const int lump, int *lumpsize );
  32081. + int (*pfnReadLump)( const char *filename, const int lump, void **lumpdata, int *lumpsize );
  32082. + int (*pfnSaveLump)( const char *filename, const int lump, void *lumpdata, int lumpsize );
  32083. +
  32084. + // FS tools
  32085. + int (*pfnSaveFile)( const char *filename, const void *data, long len );
  32086. + const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height );
  32087. } server_physics_api_t;
  32088.  
  32089. // physic callbacks
  32090. @@ -109,6 +149,10 @@ typedef struct physics_interface_s
  32091. const char* (*pfnGetString)( string_t iString );
  32092. // helper for restore custom decals that have custom message (e.g. Paranoia)
  32093. int (*pfnRestoreDecal)( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
  32094. + // handle custom trigger touching for player
  32095. + void (*PM_PlayerTouch)( struct playermove_s *ppmove, edict_t *client );
  32096. + // alloc or destroy model custom data (called only for dedicated servers, otherwise using an client version)
  32097. + void (*Mod_ProcessUserData)( struct model_s *mod, qboolean create, const byte *buffer );
  32098. } physics_interface_t;
  32099.  
  32100. #endif//PHYSINT_H
  32101. \ No newline at end of file
  32102. diff --git b/engine/server/server.h a/engine/server/server.h
  32103. index a877ccf..38ef3cd 100644
  32104. --- b/engine/server/server.h
  32105. +++ a/engine/server/server.h
  32106. @@ -37,7 +37,7 @@ extern int SV_UPDATE_BACKUP;
  32107. // hostflags
  32108. #define SVF_SKIPLOCALHOST BIT( 0 )
  32109. #define SVF_PLAYERSONLY BIT( 1 )
  32110. -#define SVF_PORTALPASS BIT( 2 ) // we are do portal pass
  32111. +#define SVF_MERGE_VISIBILITY BIT( 2 ) // we are do portal pass
  32112.  
  32113. // mapvalid flags
  32114. #define MAP_IS_EXIST BIT( 0 )
  32115. @@ -53,10 +53,18 @@ extern int SV_UPDATE_BACKUP;
  32116. #define MAKE_STRING(str) SV_MakeString( str )
  32117.  
  32118. #define MAX_PUSHED_ENTS 256
  32119. -#define MAX_CAMERAS 32
  32120. +#define MAX_VIEWENTS 128
  32121. +
  32122. +#define FCL_RESEND_USERINFO BIT( 0 )
  32123. +#define FCL_RESEND_MOVEVARS BIT( 1 )
  32124. +#define FCL_SKIP_NET_MESSAGE BIT( 2 )
  32125. +#define FCL_SEND_NET_MESSAGE BIT( 3 )
  32126. +#define FCL_PREDICT_MOVEMENT BIT( 4 ) // movement prediction is enabled
  32127. +#define FCL_LOCAL_WEAPONS BIT( 5 ) // weapon prediction is enabled
  32128. +#define FCL_LAG_COMPENSATION BIT( 6 ) // lag compensation is enabled
  32129. +#define FCL_FAKECLIENT BIT( 7 ) // this client is a fake player controlled by the game DLL
  32130. +#define FCL_HLTV_PROXY BIT( 8 ) // this is a proxy for a HLTV client (spectator)
  32131.  
  32132. -#define DVIS_PVS 0
  32133. -#define DVIS_PHS 1
  32134.  
  32135. typedef enum
  32136. {
  32137. @@ -114,7 +122,9 @@ typedef struct server_s
  32138. int viewentity; // applied on client restore. this is temporare place
  32139. // until client connected
  32140.  
  32141. - double time; // sv.time += host.frametime
  32142. + double time; // sv.time += sv.frametime
  32143. + double time_residual; // unclamped
  32144. + float frametime; // 1.0 / sv_fps->value
  32145. int net_framenum; // to avoid send edicts twice through portals
  32146.  
  32147. int hostflags; // misc server flags: predicting etc
  32148. @@ -143,10 +153,6 @@ typedef struct server_s
  32149.  
  32150. sv_baselines_t instanced; // instanced baselines
  32151.  
  32152. - // unreliable data to send to clients.
  32153. - sizebuf_t datagram;
  32154. - byte datagram_buf[NET_MAX_PAYLOAD];
  32155. -
  32156. // reliable data to send to clients.
  32157. sizebuf_t reliable_datagram; // copied to all clients at end of frame
  32158. byte reliable_datagram_buf[NET_MAX_PAYLOAD];
  32159. @@ -165,6 +171,7 @@ typedef struct server_s
  32160. uint checksum; // for catching cheater maps
  32161.  
  32162. qboolean write_bad_message; // just for debug
  32163. + qboolean simulating; // physics is running
  32164. qboolean paused;
  32165. } server_t;
  32166.  
  32167. @@ -175,7 +182,7 @@ typedef struct
  32168. float latency;
  32169.  
  32170. clientdata_t clientdata;
  32171. - weapon_data_t weapondata[64];
  32172. + weapon_data_t weapondata[MAX_LOCAL_WEAPONS];
  32173.  
  32174. int num_entities;
  32175. int first_entity; // into the circular sv_packet_entities[]
  32176. @@ -185,35 +192,24 @@ typedef struct sv_client_s
  32177. {
  32178. cl_state_t state;
  32179. char name[32]; // extracted from userinfo, color string allowed
  32180. + int flags; // client flags, some info
  32181.  
  32182. char userinfo[MAX_INFO_STRING]; // name, etc (received from client)
  32183. char physinfo[MAX_INFO_STRING]; // set on server (transmit to client)
  32184.  
  32185. - qboolean send_message;
  32186. - qboolean skip_message;
  32187. -
  32188. - qboolean local_weapons; // enable weapon predicting
  32189. - qboolean lag_compensation; // enable lag compensation
  32190. - qboolean hltv_proxy; // this is spectator proxy (hltv)
  32191. -
  32192. netchan_t netchan;
  32193. int chokecount; // number of messages rate supressed
  32194. int delta_sequence; // -1 = no compression.
  32195.  
  32196. double next_messagetime; // time when we should send next world state update
  32197. - double cl_updaterate; // default time to wait for next message
  32198. double next_checkpingtime; // time to send all players pings to client
  32199. + double cl_updaterate; // client requested updaterate
  32200. double timebase; // client timebase
  32201.  
  32202. customization_t customization; // player customization linked list
  32203. resource_t resource1;
  32204. resource_t resource2; // <mapname.res> from client (server downloading)
  32205.  
  32206. - qboolean sendmovevars;
  32207. - qboolean sendinfo;
  32208. -
  32209. - qboolean fakeclient; // This client is a fake player controlled by the game DLL
  32210. -
  32211. usercmd_t lastcmd; // for filling in big drops
  32212.  
  32213. double last_cmdtime;
  32214. @@ -231,8 +227,8 @@ typedef struct sv_client_s
  32215. edict_t *pViewEntity; // svc_setview member
  32216. int messagelevel; // for filtering printed messages
  32217.  
  32218. - edict_t *cameras[MAX_CAMERAS]; // list of portal cameras in player PVS
  32219. - int num_cameras; // num of portal cameras that can merge PVS
  32220. + edict_t *viewentity[MAX_VIEWENTS]; // list of portal cameras in player PVS
  32221. + int num_viewents; // num of portal cameras that can merge PVS
  32222.  
  32223. // the datagram is written to by sound calls, prints, temp ents, etc.
  32224. // it can be harmlessly overflowed.
  32225. @@ -269,8 +265,8 @@ typedef struct sv_client_s
  32226. typedef struct
  32227. {
  32228. netadr_t adr;
  32229. - int challenge;
  32230. double time;
  32231. + int challenge;
  32232. qboolean connected;
  32233. } challenge_t;
  32234.  
  32235. @@ -443,9 +439,12 @@ void SV_ExecuteUserCommand (char *s);
  32236. void SV_InitOperatorCommands( void );
  32237. void SV_KillOperatorCommands( void );
  32238. void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo );
  32239. +void SV_RemoteCommand( netadr_t from, sizebuf_t *msg );
  32240. void SV_PrepWorldFrame( void );
  32241. void SV_ProcessFile( sv_client_t *cl, char *filename );
  32242. void SV_SendResourceList( sv_client_t *cl );
  32243. +void SV_AddToMaster( netadr_t from, sizebuf_t *msg );
  32244. +qboolean SV_IsSimulating( void );
  32245. void Master_Add( void );
  32246. void Master_Heartbeat( void );
  32247. void Master_Packet( void );
  32248. @@ -489,7 +488,7 @@ void SV_WaterMove( edict_t *ent );
  32249. //
  32250. void SV_SendClientMessages( void );
  32251. void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... );
  32252. -void SV_BroadcastPrintf( int level, char *fmt, ... );
  32253. +void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... );
  32254. void SV_BroadcastCommand( char *fmt, ... );
  32255.  
  32256. //
  32257. @@ -500,7 +499,6 @@ void SV_RefreshUserinfo( void );
  32258. void SV_GetChallenge( netadr_t from );
  32259. void SV_DirectConnect( netadr_t from );
  32260. void SV_TogglePause( const char *msg );
  32261. -void SV_PutClientInServer( edict_t *ent );
  32262. qboolean SV_ShouldUpdatePing( sv_client_t *cl );
  32263. const char *SV_GetClientIDString( sv_client_t *cl );
  32264. void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg );
  32265. @@ -550,12 +548,14 @@ void SV_FreeEdict( edict_t *pEdict );
  32266. void SV_InitEdict( edict_t *pEdict );
  32267. const char *SV_ClassName( const edict_t *e );
  32268. void SV_SetModel( edict_t *ent, const char *name );
  32269. +void SV_FreePrivateData( edict_t *pEdict );
  32270. void SV_CopyTraceToGlobal( trace_t *trace );
  32271. void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max );
  32272. edict_t* SV_FindEntityByString( edict_t *pStartEdict, const char *pszField, const char *pszValue );
  32273. void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
  32274. float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
  32275. void SV_PlaybackReliableEvent( sizebuf_t *msg, word eventindex, float delay, event_args_t *args );
  32276. +qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax );
  32277. void SV_BaselineForEntity( edict_t *pEdict );
  32278. void SV_WriteEntityPatch( const char *filename );
  32279. char *SV_ReadEntityScript( const char *filename, int *flags );
  32280. @@ -572,6 +572,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  32281. void SV_CreateStaticEntity( struct sizebuf_s *msg, sv_static_entity_t *ent );
  32282. edict_t* pfnPEntityOfEntIndex( int iEntIndex );
  32283. int pfnIndexOfEdict( const edict_t *pEdict );
  32284. +void pfnWriteBytes( const byte *bytes, int count );
  32285. void SV_UpdateBaseVelocity( edict_t *ent );
  32286. byte *pfnSetFatPVS( const float *org );
  32287. byte *pfnSetFatPAS( const float *org );
  32288. @@ -610,7 +611,6 @@ void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs )
  32289. //
  32290. void SV_ClearWorld( void );
  32291. void SV_UnlinkEdict( edict_t *ent );
  32292. -qboolean SV_HeadnodeVisible( mnode_t *node, byte *visbits, int *lastleaf );
  32293. void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace );
  32294. void SV_CustomClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace );
  32295. trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end );
  32296. diff --git b/engine/server/sv_client.c a/engine/server/sv_client.c
  32297. index 75784e5..d1a96ed 100644
  32298. --- b/engine/server/sv_client.c
  32299. +++ a/engine/server/sv_client.c
  32300. @@ -97,10 +97,10 @@ A connection request that did not come from the master
  32301. void SV_DirectConnect( netadr_t from )
  32302. {
  32303. char userinfo[MAX_INFO_STRING];
  32304. + char physinfo[MAX_PHYSINFO_STRING];
  32305. sv_client_t temp, *cl, *newcl;
  32306. - char physinfo[512];
  32307. - int i, edictnum;
  32308. int qport, version;
  32309. + int i, edictnum;
  32310. int count = 0;
  32311. int challenge;
  32312. edict_t *ent;
  32313. @@ -245,13 +245,14 @@ gotnewcl:
  32314. Netchan_OutOfBandPrint( NS_SERVER, from, "client_connect" );
  32315.  
  32316. newcl->state = cs_connected;
  32317. - newcl->cl_updaterate = 0.05; // 20 fps as default
  32318. newcl->lastmessage = host.realtime;
  32319. newcl->lastconnect = host.realtime;
  32320. + newcl->cl_updaterate = 0.05; // 20 fps as default
  32321. newcl->delta_sequence = -1;
  32322.  
  32323. // parse some info from the info strings (this can override cl_updaterate)
  32324. - SV_UserinfoChanged( newcl, userinfo );
  32325. + Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
  32326. + SV_UserinfoChanged( newcl, newcl->userinfo );
  32327.  
  32328. newcl->next_messagetime = host.realtime + newcl->cl_updaterate;
  32329.  
  32330. @@ -280,16 +281,7 @@ void SV_DisconnectClient( edict_t *pClient )
  32331. // don't send to other clients
  32332. pClient->v.modelindex = 0;
  32333.  
  32334. - if( pClient->pvPrivateData != NULL )
  32335. - {
  32336. - // NOTE: new interface can be missing
  32337. - if( svgame.dllFuncs2.pfnOnFreeEntPrivateData != NULL )
  32338. - svgame.dllFuncs2.pfnOnFreeEntPrivateData( pClient );
  32339. -
  32340. - // clear any dlls data but keep engine data
  32341. - Mem_Free( pClient->pvPrivateData );
  32342. - pClient->pvPrivateData = NULL;
  32343. - }
  32344. + SV_FreePrivateData( pClient );
  32345.  
  32346. // invalidate serial number
  32347. pClient->serialnumber++;
  32348. @@ -355,9 +347,9 @@ edict_t *SV_FakeConnect( const char *netname )
  32349. ent = EDICT_NUM( edictnum );
  32350. newcl->edict = ent;
  32351. newcl->challenge = -1; // fake challenge
  32352. - newcl->fakeclient = true;
  32353. newcl->delta_sequence = -1;
  32354. newcl->userid = g_userid++; // create unique userid
  32355. + SetBits( newcl->flags, FCL_FAKECLIENT );
  32356.  
  32357. // get the game a chance to reject this connection or modify the userinfo
  32358. if( !SV_ClientConnect( ent, userinfo ))
  32359. @@ -367,15 +359,16 @@ edict_t *SV_FakeConnect( const char *netname )
  32360. }
  32361.  
  32362. // parse some info from the info strings
  32363. - SV_UserinfoChanged( newcl, userinfo );
  32364. + Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
  32365. + SV_UserinfoChanged( newcl, newcl->userinfo );
  32366. + SetBits( cl->flags, FCL_RESEND_USERINFO );
  32367.  
  32368. MsgDev( D_NOTE, "Bot %i connecting with challenge %p\n", i, -1 );
  32369.  
  32370. - ent->v.flags |= FL_FAKECLIENT; // mark it as fakeclient
  32371. + SetBits( ent->v.flags, FL_FAKECLIENT ); // mark it as fakeclient
  32372. newcl->state = cs_spawned;
  32373. newcl->lastmessage = host.realtime; // don't timeout
  32374. newcl->lastconnect = host.realtime;
  32375. - newcl->sendinfo = true;
  32376.  
  32377. return ent;
  32378. }
  32379. @@ -425,21 +418,19 @@ void SV_DropClient( sv_client_t *drop )
  32380. return; // already dropped
  32381.  
  32382. // add the disconnect
  32383. - if( !drop->fakeclient )
  32384. - {
  32385. + if( !FBitSet( drop->flags, FCL_FAKECLIENT ))
  32386. MSG_WriteByte( &drop->netchan.message, svc_disconnect );
  32387. - }
  32388.  
  32389. // let the game known about client state
  32390. SV_DisconnectClient( drop->edict );
  32391.  
  32392. - drop->fakeclient = false;
  32393. - drop->hltv_proxy = false;
  32394. + ClearBits( drop->flags, FCL_FAKECLIENT );
  32395. + ClearBits( drop->flags, FCL_HLTV_PROXY );
  32396. drop->state = cs_zombie; // become free in a few seconds
  32397. drop->name[0] = 0;
  32398.  
  32399. if( drop->frames )
  32400. - Mem_Free( drop->frames ); // fakeclients doesn't have frames
  32401. + Mem_Free( drop->frames ); // release delta
  32402. drop->frames = NULL;
  32403.  
  32404. if( NET_CompareBaseAdr( drop->netchan.remote_address, host.rd.address ) )
  32405. @@ -492,7 +483,7 @@ void SV_BeginRedirect( netadr_t adr, int target, char *buffer, int buffersize, v
  32406.  
  32407. void SV_FlushRedirect( netadr_t adr, int dest, char *buf )
  32408. {
  32409. - if( svs.currentPlayer && svs.currentPlayer->fakeclient )
  32410. + if( svs.currentPlayer && FBitSet( svs.currentPlayer->flags, FCL_FAKECLIENT ))
  32411. return;
  32412.  
  32413. switch( dest )
  32414. @@ -548,7 +539,7 @@ char *SV_StatusString( void )
  32415. cl = &svs.clients[i];
  32416. if( cl->state == cs_connected || cl->state == cs_spawned )
  32417. {
  32418. - Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, cl->ping, cl->name );
  32419. + Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, (int)cl->ping, cl->name );
  32420. playerLength = Q_strlen( player );
  32421. if( statusLength + playerLength >= sizeof( status ))
  32422. break; // can't hold any more
  32423. @@ -642,7 +633,7 @@ void SV_Info( netadr_t from )
  32424. int version;
  32425.  
  32426. // ignore in single player
  32427. - if( sv_maxclients->integer == 1 )
  32428. + if( sv_maxclients->integer == 1 || !svs.initialized )
  32429. return;
  32430.  
  32431. version = Q_atoi( Cmd_Argv( 1 ));
  32432. @@ -660,9 +651,9 @@ void SV_Info( netadr_t from )
  32433.  
  32434. Info_SetValueForKey( string, "host", hostname->string );
  32435. Info_SetValueForKey( string, "map", sv.name );
  32436. - Info_SetValueForKey( string, "dm", va( "%i", svgame.globals->deathmatch ));
  32437. - Info_SetValueForKey( string, "team", va( "%i", svgame.globals->teamplay ));
  32438. - Info_SetValueForKey( string, "coop", va( "%i", svgame.globals->coop ));
  32439. + Info_SetValueForKey( string, "dm", va( "%i", (int)svgame.globals->deathmatch ));
  32440. + Info_SetValueForKey( string, "team", va( "%i", (int)svgame.globals->teamplay ));
  32441. + Info_SetValueForKey( string, "coop", va( "%i", (int)svgame.globals->coop ));
  32442. Info_SetValueForKey( string, "numcl", va( "%i", count ));
  32443. Info_SetValueForKey( string, "maxcl", va( "%i", sv_maxclients->integer ));
  32444. Info_SetValueForKey( string, "gamedir", GI->gamefolder );
  32445. @@ -685,7 +676,7 @@ void SV_BuildNetAnswer( netadr_t from )
  32446. int i, count = 0;
  32447.  
  32448. // ignore in single player
  32449. - if( sv_maxclients->integer == 1 )
  32450. + if( sv_maxclients->integer == 1 || !svs.initialized )
  32451. return;
  32452.  
  32453. version = Q_atoi( Cmd_Argv( 1 ));
  32454. @@ -693,18 +684,27 @@ void SV_BuildNetAnswer( netadr_t from )
  32455. type = Q_atoi( Cmd_Argv( 3 ));
  32456.  
  32457. if( version != PROTOCOL_VERSION )
  32458. + {
  32459. + // handle the unsupported protocol
  32460. + string[0] = '\0';
  32461. + Info_SetValueForKey( string, "neterror", "protocol" );
  32462. +
  32463. + // send error unsupported protocol
  32464. + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
  32465. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32466. return;
  32467. + }
  32468.  
  32469. if( type == NETAPI_REQUEST_PING )
  32470. {
  32471. - Q_snprintf( answer, sizeof( answer ), "netinfo %i %i\n", context, type );
  32472. - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
  32473. + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, "" );
  32474. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32475. }
  32476. else if( type == NETAPI_REQUEST_RULES )
  32477. {
  32478. // send serverinfo
  32479. Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, Cvar_Serverinfo( ));
  32480. - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
  32481. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32482. }
  32483. else if( type == NETAPI_REQUEST_PLAYERS )
  32484. {
  32485. @@ -716,14 +716,14 @@ void SV_BuildNetAnswer( netadr_t from )
  32486. {
  32487. edict_t *ed = svs.clients[i].edict;
  32488. float time = host.realtime - svs.clients[i].lastconnect;
  32489. - Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, ed->v.frags, time ), sizeof( string ));
  32490. + Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, (int)ed->v.frags, time ), sizeof( string ));
  32491. count++;
  32492. }
  32493. }
  32494.  
  32495. // send playernames
  32496. Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
  32497. - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
  32498. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32499. }
  32500. else if( type == NETAPI_REQUEST_DETAILS )
  32501. {
  32502. @@ -740,7 +740,16 @@ void SV_BuildNetAnswer( netadr_t from )
  32503.  
  32504. // send serverinfo
  32505. Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
  32506. - Netchan_OutOfBandPrint( NS_SERVER, from, answer ); // no info string
  32507. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32508. + }
  32509. + else
  32510. + {
  32511. + string[0] = '\0';
  32512. + Info_SetValueForKey( string, "neterror", "undefined" );
  32513. +
  32514. + // send error undefined request type
  32515. + Q_snprintf( answer, sizeof( answer ), "netinfo %i %i %s\n", context, type, string );
  32516. + Netchan_OutOfBandPrint( NS_SERVER, from, answer );
  32517. }
  32518. }
  32519.  
  32520. @@ -781,8 +790,8 @@ Redirect all printfs
  32521. */
  32522. void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
  32523. {
  32524. - char remaining[1024];
  32525. static char outputbuf[2048];
  32526. + char remaining[1024];
  32527. int i;
  32528.  
  32529. MsgDev( D_INFO, "Rcon from %s:\n%s\n", NET_AdrToString( from ), MSG_GetData( msg ) + 4 );
  32530. @@ -796,7 +805,7 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
  32531. Q_strcat( remaining, Cmd_Argv( i ));
  32532. Q_strcat( remaining, " " );
  32533. }
  32534. - Cmd_ExecuteString( remaining, src_command );
  32535. + Cmd_ExecuteString( remaining );
  32536. }
  32537. else MsgDev( D_ERROR, "Bad rcon_password.\n" );
  32538.  
  32539. @@ -817,7 +826,7 @@ int SV_CalcPing( sv_client_t *cl )
  32540. client_frame_t *frame;
  32541.  
  32542. // bots don't have a real ping
  32543. - if( cl->fakeclient || !cl->frames )
  32544. + if( FBitSet( cl->flags, FCL_FAKECLIENT ) || !cl->frames )
  32545. return 5;
  32546.  
  32547. count = 0;
  32548. @@ -872,7 +881,7 @@ void SV_EstablishTimeBase( sv_client_t *cl, usercmd_t *cmds, int dropped, int nu
  32549. for( ; numcmds > 0; numcmds-- )
  32550. runcmd_time += cmds[numcmds - 1].msec / 1000.0;
  32551.  
  32552. - cl->timebase = sv.time + cl->cl_updaterate - runcmd_time;
  32553. + cl->timebase = sv.frametime + svgame.globals->time - runcmd_time;
  32554. }
  32555.  
  32556. /*
  32557. @@ -945,6 +954,9 @@ void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg )
  32558. char info[MAX_INFO_STRING];
  32559. int i;
  32560.  
  32561. + // process userinfo before updating
  32562. + SV_UserinfoChanged( cl, cl->userinfo );
  32563. +
  32564. i = cl - svs.clients;
  32565.  
  32566. MSG_WriteByte( msg, svc_updateuserinfo );
  32567. @@ -971,11 +983,14 @@ SV_RefreshUserinfo
  32568. */
  32569. void SV_RefreshUserinfo( void )
  32570. {
  32571. - int i;
  32572. sv_client_t *cl;
  32573. + int i;
  32574.  
  32575. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  32576. - if( cl->state >= cs_connected ) cl->sendinfo = true;
  32577. + {
  32578. + if( cl->state >= cs_connected )
  32579. + SetBits( cl->flags, FCL_RESEND_USERINFO );
  32580. + }
  32581. }
  32582.  
  32583. /*
  32584. @@ -1004,10 +1019,10 @@ if this person needs ping data.
  32585. */
  32586. qboolean SV_ShouldUpdatePing( sv_client_t *cl )
  32587. {
  32588. - if( !cl->hltv_proxy )
  32589. + if( !FBitSet( cl->flags, FCL_HLTV_PROXY ))
  32590. {
  32591. SV_CalcPing( cl );
  32592. - return cl->lastcmd.buttons & IN_SCORE; // they are viewing the scoreboard. Send them pings.
  32593. + return FBitSet( cl->lastcmd.buttons, IN_SCORE ); // they are viewing the scoreboard. Send them pings.
  32594. }
  32595.  
  32596. if( host.realtime > cl->next_checkpingtime )
  32597. @@ -1068,85 +1083,101 @@ Called when a player connects to a server or respawns in
  32598. a deathmatch.
  32599. ============
  32600. */
  32601. -void SV_PutClientInServer( edict_t *ent )
  32602. +void SV_PutClientInServer( sv_client_t *cl )
  32603. {
  32604. - sv_client_t *client;
  32605. + edict_t *ent = cl->edict;
  32606.  
  32607. - client = SV_ClientFromEdict( ent, true );
  32608. - ASSERT( client != NULL );
  32609. + // now client is spawned
  32610. + cl->state = cs_spawned;
  32611.  
  32612. if( !sv.loadgame )
  32613. {
  32614. - client->hltv_proxy = Q_atoi( Info_ValueForKey( client->userinfo, "hltv" )) ? true : false;
  32615. + if( Q_atoi( Info_ValueForKey( cl->userinfo, "hltv" )))
  32616. + SetBits( cl->flags, FCL_HLTV_PROXY );
  32617.  
  32618. - if( client->hltv_proxy )
  32619. - ent->v.flags |= FL_PROXY;
  32620. + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
  32621. + SetBits( ent->v.flags, FL_PROXY );
  32622. else ent->v.flags = 0;
  32623.  
  32624. - ent->v.netname = MAKE_STRING( client->name );
  32625. + ent->v.netname = MAKE_STRING( cl->name );
  32626.  
  32627. // fisrt entering
  32628. svgame.globals->time = sv.time;
  32629. svgame.dllFuncs.pfnClientPutInServer( ent );
  32630.  
  32631. if( sv.background ) // don't attack player in background mode
  32632. - ent->v.flags |= (FL_GODMODE|FL_NOTARGET);
  32633. + SetBits( ent->v.flags, FL_GODMODE|FL_NOTARGET );
  32634.  
  32635. - client->pViewEntity = NULL; // reset pViewEntity
  32636. + cl->pViewEntity = NULL; // reset pViewEntity
  32637.  
  32638. if( svgame.globals->cdAudioTrack )
  32639. {
  32640. - MSG_WriteByte( &client->netchan.message, svc_stufftext );
  32641. - MSG_WriteString( &client->netchan.message, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
  32642. + MSG_WriteByte( &cl->netchan.message, svc_stufftext );
  32643. + MSG_WriteString( &cl->netchan.message, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
  32644. svgame.globals->cdAudioTrack = 0;
  32645. }
  32646. }
  32647. else
  32648. {
  32649. // enable dev-mode to prevent crash cheat-protecting from Invasion mod
  32650. - if( ent->v.flags & (FL_GODMODE|FL_NOTARGET) && !Q_stricmp( GI->gamefolder, "invasion" ))
  32651. - SV_ExecuteClientCommand( client, "test\n" );
  32652. + if( FBitSet( ent->v.flags, FL_GODMODE|FL_NOTARGET ) && !Q_stricmp( GI->gamefolder, "invasion" ))
  32653. + SV_ExecuteClientCommand( cl, "test\n" );
  32654.  
  32655. // NOTE: we needs to setup angles on restore here
  32656. if( ent->v.fixangle == 1 )
  32657. {
  32658. - MSG_WriteByte( &client->netchan.message, svc_setangle );
  32659. - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[0], 16 );
  32660. - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[1], 16 );
  32661. - MSG_WriteBitAngle( &client->netchan.message, ent->v.angles[2], 16 );
  32662. + MSG_WriteByte( &cl->netchan.message, svc_setangle );
  32663. + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[0], 16 );
  32664. + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[1], 16 );
  32665. + MSG_WriteBitAngle( &cl->netchan.message, ent->v.angles[2], 16 );
  32666. ent->v.fixangle = 0;
  32667. }
  32668. - ent->v.effects |= EF_NOINTERP;
  32669. + SetBits( ent->v.effects, EF_NOINTERP );
  32670.  
  32671. // reset weaponanim
  32672. - MSG_WriteByte( &client->netchan.message, svc_weaponanim );
  32673. - MSG_WriteByte( &client->netchan.message, 0 );
  32674. - MSG_WriteByte( &client->netchan.message, 0 );
  32675. + MSG_WriteByte( &cl->netchan.message, svc_weaponanim );
  32676. + MSG_WriteByte( &cl->netchan.message, 0 );
  32677. + MSG_WriteByte( &cl->netchan.message, 0 );
  32678.  
  32679. // trigger_camera restored here
  32680. if( sv.viewentity > 0 && sv.viewentity < GI->max_edicts )
  32681. - client->pViewEntity = EDICT_NUM( sv.viewentity );
  32682. - else client->pViewEntity = NULL;
  32683. + cl->pViewEntity = EDICT_NUM( sv.viewentity );
  32684. + else cl->pViewEntity = NULL;
  32685. }
  32686.  
  32687. + // refresh the userinfo and movevars
  32688. + // NOTE: because movevars can be changed during the connection process
  32689. + SetBits( cl->flags, FCL_RESEND_USERINFO|FCL_RESEND_MOVEVARS );
  32690. +
  32691. // reset client times
  32692. - client->last_cmdtime = 0.0;
  32693. - client->last_movetime = 0.0;
  32694. - client->next_movetime = 0.0;
  32695. + cl->last_cmdtime = 0.0;
  32696. + cl->last_movetime = 0.0;
  32697. + cl->next_movetime = 0.0;
  32698.  
  32699. - if( !client->fakeclient )
  32700. + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
  32701. {
  32702. - int viewEnt;
  32703. + sv_client_t *cur;
  32704. + int i, viewEnt;
  32705.  
  32706. - // resend the signon
  32707. - MSG_WriteBits( &client->netchan.message, MSG_GetData( &sv.signon ), MSG_GetNumBitsWritten( &sv.signon ));
  32708. + MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.signon ), MSG_GetNumBitsWritten( &sv.signon ));
  32709.  
  32710. - if( client->pViewEntity )
  32711. - viewEnt = NUM_FOR_EDICT( client->pViewEntity );
  32712. - else viewEnt = NUM_FOR_EDICT( client->edict );
  32713. + if( cl->pViewEntity )
  32714. + viewEnt = NUM_FOR_EDICT( cl->pViewEntity );
  32715. + else viewEnt = NUM_FOR_EDICT( cl->edict );
  32716.  
  32717. - MSG_WriteByte( &client->netchan.message, svc_setview );
  32718. - MSG_WriteWord( &client->netchan.message, viewEnt );
  32719. + MSG_WriteByte( &cl->netchan.message, svc_setview );
  32720. + MSG_WriteWord( &cl->netchan.message, viewEnt );
  32721. +
  32722. + // collect the info about all the players and send to me
  32723. + for( i = 0, cur = svs.clients; i < sv_maxclients->integer; i++, cur++ )
  32724. + {
  32725. + if( !cur->edict ) continue; // not in game yet
  32726. +
  32727. + if( cur == cl || cur->state != cs_spawned )
  32728. + continue;
  32729. +
  32730. + SV_FullClientUpdate( cur, &cl->netchan.message );
  32731. + }
  32732. }
  32733.  
  32734. // clear any temp states
  32735. @@ -1169,7 +1200,7 @@ void SV_TogglePause( const char *msg )
  32736.  
  32737. sv.paused ^= 1;
  32738.  
  32739. - if( msg ) SV_BroadcastPrintf( PRINT_HIGH, "%s", msg );
  32740. + if( msg ) SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", msg );
  32741.  
  32742. // send notification to all clients
  32743. MSG_WriteByte( &sv.reliable_datagram, svc_setpause );
  32744. @@ -1194,11 +1225,10 @@ This will be sent on the initial connection and upon each server load.
  32745. void SV_New_f( sv_client_t *cl )
  32746. {
  32747. int playernum;
  32748. - edict_t *ent;
  32749.  
  32750. if( cl->state != cs_connected )
  32751. {
  32752. - MsgDev( D_INFO, "new is not valid from the console\n" );
  32753. + MsgDev( D_INFO, "'new' is not valid from the console\n" );
  32754. return;
  32755. }
  32756.  
  32757. @@ -1218,15 +1248,11 @@ void SV_New_f( sv_client_t *cl )
  32758. MSG_WriteString( &cl->netchan.message, GI->gamefolder );
  32759. MSG_WriteLong( &cl->netchan.message, host.features );
  32760.  
  32761. - // refresh userinfo on spawn
  32762. - SV_RefreshUserinfo();
  32763. -
  32764. // game server
  32765. if( sv.state == ss_active )
  32766. {
  32767. // set up the entity for the client
  32768. - ent = EDICT_NUM( playernum + 1 );
  32769. - cl->edict = ent;
  32770. + cl->edict = EDICT_NUM( playernum + 1 );
  32771.  
  32772. // NOTE: custom resources download is disabled until is done
  32773. if( /*sv_maxclients->integer ==*/ 1 )
  32774. @@ -1255,7 +1281,7 @@ void SV_ContinueLoading_f( sv_client_t *cl )
  32775. {
  32776. if( cl->state != cs_connected )
  32777. {
  32778. - MsgDev( D_INFO, "continueloading is not valid from the console\n" );
  32779. + MsgDev( D_INFO, "'continueloading' is not valid from the console\n" );
  32780. return;
  32781. }
  32782.  
  32783. @@ -1345,14 +1371,14 @@ void SV_WriteModels_f( sv_client_t *cl )
  32784.  
  32785. if( cl->state != cs_connected )
  32786. {
  32787. - MsgDev( D_INFO, "modellist is not valid from the console\n" );
  32788. + MsgDev( D_INFO, "'modellist' is not valid from the console\n" );
  32789. return;
  32790. }
  32791.  
  32792. // handle the case of a level changing while a client was connecting
  32793. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32794. {
  32795. - MsgDev( D_INFO, "modellist from different level\n" );
  32796. + MsgDev( D_INFO, "'modellist' from different level\n" );
  32797. SV_New_f( cl );
  32798. return;
  32799. }
  32800. @@ -1391,14 +1417,14 @@ void SV_WriteSounds_f( sv_client_t *cl )
  32801.  
  32802. if( cl->state != cs_connected )
  32803. {
  32804. - MsgDev( D_INFO, "soundlist is not valid from the console\n" );
  32805. + MsgDev( D_INFO, "'soundlist' is not valid from the console\n" );
  32806. return;
  32807. }
  32808.  
  32809. // handle the case of a level changing while a client was connecting
  32810. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32811. {
  32812. - MsgDev( D_INFO, "soundlist from different level\n" );
  32813. + MsgDev( D_INFO, "'soundlist' from different level\n" );
  32814. SV_New_f( cl );
  32815. return;
  32816. }
  32817. @@ -1437,14 +1463,14 @@ void SV_WriteEvents_f( sv_client_t *cl )
  32818.  
  32819. if( cl->state != cs_connected )
  32820. {
  32821. - MsgDev( D_INFO, "eventlist is not valid from the console\n" );
  32822. + MsgDev( D_INFO, "'eventlist' is not valid from the console\n" );
  32823. return;
  32824. }
  32825.  
  32826. // handle the case of a level changing while a client was connecting
  32827. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32828. {
  32829. - MsgDev( D_INFO, "eventlist from different level\n" );
  32830. + MsgDev( D_INFO, "'eventlist' from different level\n" );
  32831. SV_New_f( cl );
  32832. return;
  32833. }
  32834. @@ -1483,14 +1509,14 @@ void SV_WriteLightstyles_f( sv_client_t *cl )
  32835.  
  32836. if( cl->state != cs_connected )
  32837. {
  32838. - MsgDev( D_INFO, "lightstyles is not valid from the console\n" );
  32839. + MsgDev( D_INFO, "'lightstyles' is not valid from the console\n" );
  32840. return;
  32841. }
  32842.  
  32843. // handle the case of a level changing while a client was connecting
  32844. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32845. {
  32846. - MsgDev( D_INFO, "lightstyles from different level\n" );
  32847. + MsgDev( D_INFO, "'lightstyles' from different level\n" );
  32848. SV_New_f( cl );
  32849. return;
  32850. }
  32851. @@ -1531,14 +1557,14 @@ void SV_UserMessages_f( sv_client_t *cl )
  32852.  
  32853. if( cl->state != cs_connected )
  32854. {
  32855. - MsgDev( D_INFO, "usermessages is not valid from the console\n" );
  32856. + MsgDev( D_INFO, "'usermsgs' is not valid from the console\n" );
  32857. return;
  32858. }
  32859.  
  32860. // handle the case of a level changing while a client was connecting
  32861. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32862. {
  32863. - MsgDev( D_INFO, "usermessages from different level\n" );
  32864. + MsgDev( D_INFO, "'usermsgs' from different level\n" );
  32865. SV_New_f( cl );
  32866. return;
  32867. }
  32868. @@ -1581,14 +1607,14 @@ void SV_DeltaInfo_f( sv_client_t *cl )
  32869.  
  32870. if( cl->state != cs_connected )
  32871. {
  32872. - MsgDev( D_INFO, "deltainfo is not valid from the console\n" );
  32873. + MsgDev( D_INFO, "'deltainfo' is not valid from the console\n" );
  32874. return;
  32875. }
  32876.  
  32877. // handle the case of a level changing while a client was connecting
  32878. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32879. {
  32880. - MsgDev( D_INFO, "deltainfo from different level\n" );
  32881. + MsgDev( D_INFO, "'deltainfo' from different level\n" );
  32882. SV_New_f( cl );
  32883. return;
  32884. }
  32885. @@ -1644,14 +1670,14 @@ void SV_Baselines_f( sv_client_t *cl )
  32886.  
  32887. if( cl->state != cs_connected )
  32888. {
  32889. - MsgDev( D_INFO, "baselines is not valid from the console\n" );
  32890. + MsgDev( D_INFO, "'baselines' is not valid from the console\n" );
  32891. return;
  32892. }
  32893.  
  32894. // handle the case of a level changing while a client was connecting
  32895. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32896. {
  32897. - MsgDev( D_INFO, "baselines from different level\n" );
  32898. + MsgDev( D_INFO, "'baselines' from different level\n" );
  32899. SV_New_f( cl );
  32900. return;
  32901. }
  32902. @@ -1664,7 +1690,7 @@ void SV_Baselines_f( sv_client_t *cl )
  32903. while( MSG_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < svgame.numEntities )
  32904. {
  32905. base = &svs.baselines[start];
  32906. - if( base->number && ( base->modelindex || base->effects != EF_NODRAW ))
  32907. + if(( !start || base->number ) && ( base->modelindex || base->effects != EF_NODRAW ))
  32908. {
  32909. MSG_WriteByte( &cl->netchan.message, svc_spawnbaseline );
  32910. MSG_WriteDeltaEntity( &nullstate, base, &cl->netchan.message, true, SV_IsPlayerIndex( base->number ), sv.time );
  32911. @@ -1689,20 +1715,19 @@ void SV_Begin_f( sv_client_t *cl )
  32912. {
  32913. if( cl->state != cs_connected )
  32914. {
  32915. - MsgDev( D_INFO, "begin is not valid from the console\n" );
  32916. + MsgDev( D_INFO, "'begin' is not valid from the console\n" );
  32917. return;
  32918. }
  32919.  
  32920. // handle the case of a level changing while a client was connecting
  32921. if( Q_atoi( Cmd_Argv( 1 )) != svs.spawncount )
  32922. {
  32923. - Msg( "begin from different level\n" );
  32924. + Msg( "'begin' from different level\n" );
  32925. SV_New_f( cl );
  32926. return;
  32927. }
  32928.  
  32929. - cl->state = cs_spawned;
  32930. - SV_PutClientInServer( cl->edict );
  32931. + SV_PutClientInServer( cl );
  32932.  
  32933. // if we are paused, tell the client
  32934. if( sv.paused )
  32935. @@ -1754,7 +1779,7 @@ void SV_Pause_f( sv_client_t *cl )
  32936. return;
  32937. }
  32938.  
  32939. - if( cl->hltv_proxy )
  32940. + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
  32941. {
  32942. SV_ClientPrintf( cl, PRINT_HIGH, "Spectators can not pause.\n" );
  32943. return;
  32944. @@ -1779,27 +1804,33 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
  32945. {
  32946. int i, dupc = 1;
  32947. edict_t *ent = cl->edict;
  32948. - string temp1, temp2;
  32949. + string name1, name2;
  32950. sv_client_t *current;
  32951. char *val;
  32952.  
  32953. if( !userinfo || !userinfo[0] ) return; // ignored
  32954.  
  32955. - Q_strncpy( cl->userinfo, userinfo, sizeof( cl->userinfo ));
  32956. -
  32957. val = Info_ValueForKey( cl->userinfo, "name" );
  32958. - Q_strncpy( temp2, val, sizeof( temp2 ));
  32959. - TrimSpace( temp2, temp1 );
  32960. + Q_strncpy( name2, val, sizeof( name2 ));
  32961. + COM_TrimSpace( name2, name1 );
  32962.  
  32963. - if( !Q_stricmp( temp1, "console" )) // keyword came from OSHLDS
  32964. + if( !Q_stricmp( name1, "console" ))
  32965. {
  32966. Info_SetValueForKey( cl->userinfo, "name", "unnamed" );
  32967. val = Info_ValueForKey( cl->userinfo, "name" );
  32968. }
  32969. - else if( Q_strcmp( temp1, val ))
  32970. + else if( Q_strcmp( name1, val ))
  32971. {
  32972. - Info_SetValueForKey( cl->userinfo, "name", temp1 );
  32973. + Info_SetValueForKey( cl->userinfo, "name", name1 );
  32974. + val = Info_ValueForKey( cl->userinfo, "name" );
  32975. + }
  32976. +
  32977. + if( !Q_strlen( name1 ))
  32978. + {
  32979. + Info_SetValueForKey( cl->userinfo, "name", "unnamed" );
  32980. val = Info_ValueForKey( cl->userinfo, "name" );
  32981. + Q_strncpy( name2, "unnamed", sizeof( name2 ));
  32982. + Q_strncpy( name1, "unnamed", sizeof( name1 ));
  32983. }
  32984.  
  32985. // check to see if another user by the same name exists
  32986. @@ -1817,15 +1848,15 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
  32987. if( i != sv_maxclients->integer )
  32988. {
  32989. // dup name
  32990. - Q_snprintf( temp2, sizeof( temp2 ), "%s (%u)", temp1, dupc++ );
  32991. - Info_SetValueForKey( cl->userinfo, "name", temp2 );
  32992. + Q_snprintf( name2, sizeof( name2 ), "%s (%u)", name1, dupc++ );
  32993. + Info_SetValueForKey( cl->userinfo, "name", name2 );
  32994. val = Info_ValueForKey( cl->userinfo, "name" );
  32995. - Q_strncpy( cl->name, temp2, sizeof( cl->name ));
  32996. + Q_strncpy( cl->name, name2, sizeof( cl->name ));
  32997. }
  32998. else
  32999. {
  33000. if( dupc == 1 ) // unchanged
  33001. - Q_strncpy( cl->name, temp1, sizeof( cl->name ));
  33002. + Q_strncpy( cl->name, name1, sizeof( cl->name ));
  33003. break;
  33004. }
  33005. }
  33006. @@ -1837,18 +1868,31 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
  33007. else cl->netchan.rate = DEFAULT_RATE;
  33008.  
  33009. // msg command
  33010. - val = Info_ValueForKey( cl->userinfo, "msg" );
  33011. + val = Info_ValueForKey( cl->userinfo, "cl_msglevel" );
  33012. if( Q_strlen( val )) cl->messagelevel = Q_atoi( val );
  33013.  
  33014. - cl->local_weapons = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) ? true : false;
  33015. - cl->lag_compensation = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )) ? true : false;
  33016. + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_predict" )))
  33017. + SetBits( cl->flags, FCL_PREDICT_MOVEMENT );
  33018. + else ClearBits( cl->flags, FCL_PREDICT_MOVEMENT );
  33019. +
  33020. + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )))
  33021. + SetBits( cl->flags, FCL_LAG_COMPENSATION );
  33022. + else ClearBits( cl->flags, FCL_LAG_COMPENSATION );
  33023. +
  33024. + if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )))
  33025. + SetBits( cl->flags, FCL_LOCAL_WEAPONS );
  33026. + else ClearBits( cl->flags, FCL_LOCAL_WEAPONS );
  33027.  
  33028. val = Info_ValueForKey( cl->userinfo, "cl_updaterate" );
  33029.  
  33030. if( Q_strlen( val ))
  33031. {
  33032. - int i = bound( 10, Q_atoi( val ), 300 );
  33033. - cl->cl_updaterate = 1.0f / i;
  33034. + if( Q_atoi( val ) != 0 )
  33035. + {
  33036. + int i = bound( 10, Q_atoi( val ), 300 );
  33037. + cl->cl_updaterate = 1.0 / i;
  33038. + }
  33039. + else cl->cl_updaterate = 0.0;
  33040. }
  33041.  
  33042. if( sv_maxclients->integer > 1 )
  33043. @@ -1873,9 +1917,10 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
  33044.  
  33045. // call prog code to allow overrides
  33046. svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
  33047. - ent->v.netname = MAKE_STRING( cl->name );
  33048.  
  33049. - if( cl->state >= cs_connected ) cl->sendinfo = true; // needs for update client info
  33050. + val = Info_ValueForKey( userinfo, "name" );
  33051. + Q_strncpy( cl->name, val, sizeof( cl->name ));
  33052. + ent->v.netname = MAKE_STRING( cl->name );
  33053. }
  33054.  
  33055. /*
  33056. @@ -1885,7 +1930,10 @@ SV_UpdateUserinfo_f
  33057. */
  33058. static void SV_UpdateUserinfo_f( sv_client_t *cl )
  33059. {
  33060. - SV_UserinfoChanged( cl, Cmd_Argv( 1 ));
  33061. + Q_strncpy( cl->userinfo, Cmd_Argv( 1 ), sizeof( cl->userinfo ));
  33062. +
  33063. + if( cl->state >= cs_connected )
  33064. + SetBits( cl->flags, FCL_RESEND_USERINFO ); // needs for update client info
  33065. }
  33066.  
  33067. /*
  33068. @@ -1926,7 +1974,7 @@ static void SV_Godmode_f( sv_client_t *cl )
  33069.  
  33070. pEntity->v.flags = pEntity->v.flags ^ FL_GODMODE;
  33071.  
  33072. - if ( !( pEntity->v.flags & FL_GODMODE ))
  33073. + if( !FBitSet( pEntity->v.flags, FL_GODMODE ))
  33074. SV_ClientPrintf( cl, PRINT_HIGH, "godmode OFF\n" );
  33075. else SV_ClientPrintf( cl, PRINT_HIGH, "godmode ON\n" );
  33076. }
  33077. @@ -1945,7 +1993,7 @@ static void SV_Notarget_f( sv_client_t *cl )
  33078.  
  33079. pEntity->v.flags = pEntity->v.flags ^ FL_NOTARGET;
  33080.  
  33081. - if ( !( pEntity->v.flags & FL_NOTARGET ))
  33082. + if( !FBitSet( pEntity->v.flags, FL_NOTARGET ))
  33083. SV_ClientPrintf( cl, PRINT_HIGH, "notarget OFF\n" );
  33084. else SV_ClientPrintf( cl, PRINT_HIGH, "notarget ON\n" );
  33085. }
  33086. @@ -1957,12 +2005,12 @@ SV_SendRes_f
  33087. */
  33088. void SV_SendRes_f( sv_client_t *cl )
  33089. {
  33090. - sizebuf_t msg;
  33091. static byte buffer[65535];
  33092. + sizebuf_t msg;
  33093.  
  33094. if( cl->state != cs_connected )
  33095. {
  33096. - MsgDev( D_INFO, "sendres is not valid from the console\n" );
  33097. + MsgDev( D_INFO, "'sendres' is not valid from the console\n" );
  33098. return;
  33099. }
  33100.  
  33101. @@ -2039,6 +2087,71 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s )
  33102. }
  33103.  
  33104. /*
  33105. +==================
  33106. +SV_TSourceEngineQuery
  33107. +==================
  33108. +*/
  33109. +void SV_TSourceEngineQuery( netadr_t from )
  33110. +{
  33111. + // A2S_INFO
  33112. + char answer[1024] = "";
  33113. + int count = 0, bots = 0;
  33114. + int index;
  33115. + sizebuf_t buf;
  33116. +
  33117. + if( svs.clients )
  33118. + {
  33119. + for( index = 0; index < sv_maxclients->integer; index++ )
  33120. + {
  33121. + if( svs.clients[index].state >= cs_connected )
  33122. + {
  33123. + if( FBitSet( svs.clients[index].flags, FCL_FAKECLIENT ))
  33124. + bots++;
  33125. + else count++;
  33126. + }
  33127. + }
  33128. + }
  33129. +
  33130. + MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
  33131. +
  33132. + MSG_WriteByte( &buf, 'm' );
  33133. + MSG_WriteString( &buf, NET_AdrToString( net_local ) );
  33134. + MSG_WriteString( &buf, hostname->string );
  33135. + MSG_WriteString( &buf, sv.name );
  33136. + MSG_WriteString( &buf, GI->gamefolder );
  33137. + MSG_WriteString( &buf, GI->title );
  33138. + MSG_WriteByte( &buf, count );
  33139. + MSG_WriteByte( &buf, sv_maxclients->integer );
  33140. + MSG_WriteByte( &buf, PROTOCOL_VERSION );
  33141. + MSG_WriteByte( &buf, host.type == HOST_DEDICATED ? 'D' : 'L');
  33142. + MSG_WriteByte( &buf, 'W' );
  33143. +
  33144. + if( Q_stricmp( GI->gamedir, "valve" ))
  33145. + {
  33146. + MSG_WriteByte( &buf, 1 ); // mod
  33147. + MSG_WriteString( &buf, GI->game_url );
  33148. + MSG_WriteString( &buf, GI->update_url );
  33149. + MSG_WriteByte( &buf, 0 );
  33150. + MSG_WriteLong( &buf, (long)GI->version );
  33151. + MSG_WriteLong( &buf, GI->size );
  33152. +
  33153. + if( GI->gamemode == 2 )
  33154. + MSG_WriteByte( &buf, 1 ); // multiplayer_only
  33155. + else MSG_WriteByte( &buf, 0 );
  33156. +
  33157. + if( Q_strstr( GI->game_dll, "hl." ))
  33158. + MSG_WriteByte( &buf, 0 ); // Half-Life DLL
  33159. + else MSG_WriteByte( &buf, 1 ); // Own DLL
  33160. + }
  33161. + else MSG_WriteByte( &buf, 0 ); // Half-Life
  33162. +
  33163. + MSG_WriteByte( &buf, GI->secure ); // unsecure
  33164. + MSG_WriteByte( &buf, bots );
  33165. +
  33166. + NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
  33167. +}
  33168. +
  33169. +/*
  33170. =================
  33171. SV_ConnectionlessPacket
  33172.  
  33173. @@ -2053,9 +2166,6 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
  33174. char *args;
  33175. char *c, buf[MAX_SYSPATH];
  33176. int len = sizeof( buf );
  33177. - uint challenge;
  33178. - int index, count = 0;
  33179. - char query[512], ostype = 'w';
  33180.  
  33181. MSG_Clear( msg );
  33182. MSG_ReadLong( msg );// skip the -1 marker
  33183. @@ -2074,46 +2184,9 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
  33184. else if( !Q_strcmp( c, "connect" )) SV_DirectConnect( from );
  33185. else if( !Q_strcmp( c, "rcon" )) SV_RemoteCommand( from, msg );
  33186. else if( !Q_strcmp( c, "netinfo" )) SV_BuildNetAnswer( from );
  33187. - 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 )
  33188. - {
  33189. - memcpy(&challenge, &msg->pData[6], sizeof(int));
  33190. -
  33191. - for( index = 0; index < sv_maxclients->integer; index++ )
  33192. - {
  33193. - if( svs.clients[index].state >= cs_connected )
  33194. - count++;
  33195. - }
  33196. -
  33197. - Q_snprintf( query, sizeof( query ),
  33198. - "0\n"
  33199. - "\\protocol\\%d" // protocol version
  33200. - "\\challenge\\%u" // challenge number that got after FF FF FF FF 73 0A
  33201. - "\\players\\%d" // current player number
  33202. - "\\max\\%d" // max_players
  33203. - "\\bots\\0" // bot number?
  33204. - "\\gamedir\\%s" // gamedir. _xash appended, because Xash3D is not compatible with GS in multiplayer
  33205. - "\\map\\%s" // current map
  33206. - "\\type\\d" // server type
  33207. - "\\password\\0" // is password set
  33208. - "\\os\\%c" // server OS?
  33209. - "\\secure\\0" // server anti-cheat? VAC?
  33210. - "\\lan\\0" // is LAN server?
  33211. - "\\version\\%f" // server version
  33212. - "\\region\\255" // server region
  33213. - "\\product\\%s\n", // product? Where is the difference with gamedir?
  33214. - PROTOCOL_VERSION,
  33215. - challenge,
  33216. - count,
  33217. - sv_maxclients->integer,
  33218. - GI->gamefolder,
  33219. - sv.name,
  33220. - ostype,
  33221. - XASH_VERSION,
  33222. - GI->gamefolder
  33223. - );
  33224. -
  33225. - NET_SendPacket( NS_SERVER, Q_strlen( query ), query, from );
  33226. - }
  33227. + else if( !Q_strcmp( c, "s")) SV_AddToMaster( from, msg );
  33228. + else if( !Q_strcmp( c, "T" "Source" )) SV_TSourceEngineQuery( from );
  33229. + else if( !Q_strcmp( c, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
  33230. else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
  33231. {
  33232. // user out of band message (must be handled in CL_ConnectionlessPacket)
  33233. @@ -2139,11 +2212,10 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
  33234. client_frame_t *frame;
  33235. int key, size, checksum1, checksum2;
  33236. int i, numbackup, newcmds, numcmds;
  33237. - usercmd_t nullcmd, *from;
  33238. - usercmd_t cmds[32], *to;
  33239. + usercmd_t nullcmd, *to, *from;
  33240. + usercmd_t cmds[32];
  33241. edict_t *player;
  33242.  
  33243. - numbackup = 2;
  33244. player = cl->edict;
  33245.  
  33246. frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
  33247. @@ -2167,7 +2239,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
  33248. return;
  33249. }
  33250.  
  33251. - from = &nullcmd; // first cmd are starting from null-comressed usercmd_t
  33252. + from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
  33253.  
  33254. for( i = numcmds - 1; i >= 0; i-- )
  33255. {
  33256. @@ -2248,10 +2320,10 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
  33257. // adjust latency time by 1/2 last client frame since
  33258. // the message probably arrived 1/2 through client's frame loop
  33259. frame->latency -= cl->lastcmd.msec * 0.5f / 1000.0f;
  33260. - frame->latency = max( 0.0f, frame->latency );
  33261. + frame->latency = Q_max( 0.0f, frame->latency );
  33262.  
  33263. - if( player->v.animtime > sv.time + host.frametime )
  33264. - player->v.animtime = sv.time + host.frametime;
  33265. + if( player->v.animtime > svgame.globals->time + host.frametime )
  33266. + player->v.animtime = svgame.globals->time + host.frametime;
  33267. }
  33268.  
  33269. /*
  33270. @@ -2280,7 +2352,7 @@ void SV_ParseCvarValue( sv_client_t *cl, sizebuf_t *msg )
  33271.  
  33272. if( svgame.dllFuncs2.pfnCvarValue != NULL )
  33273. svgame.dllFuncs2.pfnCvarValue( cl->edict, value );
  33274. - MsgDev( D_AICONSOLE, "Cvar query response: name:%s, value:%s\n", cl->name, value );
  33275. + MsgDev( D_REPORT, "Cvar query response: name:%s, value:%s\n", cl->name, value );
  33276. }
  33277.  
  33278. /*
  33279. @@ -2299,7 +2371,7 @@ void SV_ParseCvarValue2( sv_client_t *cl, sizebuf_t *msg )
  33280.  
  33281. if( svgame.dllFuncs2.pfnCvarValue2 != NULL )
  33282. svgame.dllFuncs2.pfnCvarValue2( cl->edict, requestID, name, value );
  33283. - MsgDev( D_AICONSOLE, "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
  33284. + MsgDev( D_REPORT, "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
  33285. }
  33286.  
  33287. /*
  33288. @@ -2319,7 +2391,7 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
  33289. // calc ping time
  33290. frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
  33291.  
  33292. - // raw ping doesn't factor in message interval, either
  33293. + // ping time doesn't factor in message interval, either
  33294. frame->ping_time = host.realtime - frame->senttime - cl->cl_updaterate;
  33295.  
  33296. // on first frame ( no senttime ) don't skew ping
  33297. @@ -2364,7 +2436,9 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
  33298. case clc_nop:
  33299. break;
  33300. case clc_userinfo:
  33301. - SV_UserinfoChanged( cl, MSG_ReadString( msg ));
  33302. + Q_strncpy( cl->userinfo, MSG_ReadString( msg ), sizeof( cl->userinfo ));
  33303. + if( cl->state >= cs_connected )
  33304. + SetBits( cl->flags, FCL_RESEND_USERINFO ); // needs for update client info
  33305. break;
  33306. case clc_delta:
  33307. cl->delta_sequence = MSG_ReadByte( msg );
  33308. diff --git b/engine/server/sv_cmds.c a/engine/server/sv_cmds.c
  33309. index 88f039e..7ba96db 100644
  33310. --- b/engine/server/sv_cmds.c
  33311. +++ a/engine/server/sv_cmds.c
  33312. @@ -25,10 +25,10 @@ Sends text across to be displayed if the level passes
  33313. */
  33314. void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... )
  33315. {
  33316. - va_list argptr;
  33317. char string[MAX_SYSPATH];
  33318. + va_list argptr;
  33319.  
  33320. - if( level < cl->messagelevel || cl->fakeclient )
  33321. + if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
  33322. return;
  33323.  
  33324. va_start( argptr, fmt );
  33325. @@ -47,14 +47,15 @@ SV_BroadcastPrintf
  33326. Sends text to all active clients
  33327. =================
  33328. */
  33329. -void SV_BroadcastPrintf( int level, char *fmt, ... )
  33330. +void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... )
  33331. {
  33332. char string[MAX_SYSPATH];
  33333. va_list argptr;
  33334. sv_client_t *cl;
  33335. int i;
  33336.  
  33337. - if( !sv.state ) return;
  33338. + if( sv.state == ss_dead )
  33339. + return;
  33340.  
  33341. va_start( argptr, fmt );
  33342. Q_vsprintf( string, fmt, argptr );
  33343. @@ -65,9 +66,11 @@ void SV_BroadcastPrintf( int level, char *fmt, ... )
  33344.  
  33345. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  33346. {
  33347. - if( level < cl->messagelevel ) continue;
  33348. - if( cl->state != cs_spawned ) continue;
  33349. - if( cl->fakeclient ) continue;
  33350. + if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
  33351. + continue;
  33352. +
  33353. + if( cl == ignore || cl->state != cs_spawned )
  33354. + continue;
  33355.  
  33356. MSG_WriteByte( &cl->netchan.message, svc_print );
  33357. MSG_WriteByte( &cl->netchan.message, level );
  33358. @@ -84,10 +87,12 @@ Sends text to all active clients
  33359. */
  33360. void SV_BroadcastCommand( char *fmt, ... )
  33361. {
  33362. - va_list argptr;
  33363. char string[MAX_SYSPATH];
  33364. -
  33365. - if( !sv.state ) return;
  33366. + va_list argptr;
  33367. +
  33368. + if( sv.state == ss_dead )
  33369. + return;
  33370. +
  33371. va_start( argptr, fmt );
  33372. Q_vsprintf( string, fmt, argptr );
  33373. va_end( argptr );
  33374. @@ -187,6 +192,7 @@ void SV_Map_f( void )
  33375.  
  33376. // hold mapname to other place
  33377. Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
  33378. + FS_StripExtension( mapname );
  33379.  
  33380. // determine spawn entity classname
  33381. if( sv_maxclients->integer == 1 )
  33382. @@ -195,19 +201,19 @@ void SV_Map_f( void )
  33383.  
  33384. flags = SV_MapIsValid( mapname, spawn_entity, NULL );
  33385.  
  33386. - if( flags & MAP_INVALID_VERSION )
  33387. + if( FBitSet( flags, MAP_INVALID_VERSION ))
  33388. {
  33389. Msg( "SV_NewMap: map %s is invalid or not supported\n", mapname );
  33390. return;
  33391. }
  33392.  
  33393. - if(!( flags & MAP_IS_EXIST ))
  33394. + if( !FBitSet( flags, MAP_IS_EXIST ))
  33395. {
  33396. Msg( "SV_NewMap: map %s doesn't exist\n", mapname );
  33397. return;
  33398. }
  33399.  
  33400. - if(!( flags & MAP_HAS_SPAWNPOINT ))
  33401. + if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
  33402. {
  33403. Msg( "SV_NewMap: map %s doesn't have a valid spawnpoint\n", mapname );
  33404. return;
  33405. @@ -259,16 +265,24 @@ void SV_MapBackground_f( void )
  33406.  
  33407. // hold mapname to other place
  33408. Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
  33409. + FS_StripExtension( mapname );
  33410. +
  33411. flags = SV_MapIsValid( mapname, GI->sp_entity, NULL );
  33412.  
  33413. - if(!( flags & MAP_IS_EXIST ))
  33414. + if( FBitSet( flags, MAP_INVALID_VERSION ))
  33415. + {
  33416. + Msg( "SV_NewMap: map %s is invalid or not supported\n", mapname );
  33417. + return;
  33418. + }
  33419. +
  33420. + if( !FBitSet( flags, MAP_IS_EXIST ))
  33421. {
  33422. Msg( "SV_NewMap: map %s doesn't exist\n", mapname );
  33423. return;
  33424. }
  33425.  
  33426. // background maps allow without spawnpoints (just throw warning)
  33427. - if(!( flags & MAP_HAS_SPAWNPOINT ))
  33428. + if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
  33429. MsgDev( D_WARN, "SV_NewMap: map %s doesn't have a valid spawnpoint\n", mapname );
  33430.  
  33431. Q_strncpy( host.finalmsg, "", MAX_STRING );
  33432. @@ -453,7 +467,8 @@ Saves the state of the map just being exited and goes to a new map.
  33433. */
  33434. void SV_ChangeLevel_f( void )
  33435. {
  33436. - char *spawn_entity, *mapname;
  33437. + string mapname;
  33438. + char *spawn_entity;
  33439. int flags, c = Cmd_Argc();
  33440.  
  33441. if( c < 2 )
  33442. @@ -462,7 +477,9 @@ void SV_ChangeLevel_f( void )
  33443. return;
  33444. }
  33445.  
  33446. - mapname = Cmd_Argv( 1 );
  33447. + // hold mapname to other place
  33448. + Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
  33449. + FS_StripExtension( mapname );
  33450.  
  33451. // determine spawn entity classname
  33452. if( sv_maxclients->integer == 1 )
  33453. @@ -471,19 +488,19 @@ void SV_ChangeLevel_f( void )
  33454.  
  33455. flags = SV_MapIsValid( mapname, spawn_entity, Cmd_Argv( 2 ));
  33456.  
  33457. - if( flags & MAP_INVALID_VERSION )
  33458. + if( FBitSet( flags, MAP_INVALID_VERSION ))
  33459. {
  33460. Msg( "SV_ChangeLevel: map %s is invalid or not supported\n", mapname );
  33461. return;
  33462. }
  33463.  
  33464. - if(!( flags & MAP_IS_EXIST ))
  33465. + if( !FBitSet( flags, MAP_IS_EXIST ))
  33466. {
  33467. Msg( "SV_ChangeLevel: map %s doesn't exist\n", mapname );
  33468. return;
  33469. }
  33470.  
  33471. - if( c >= 3 && !( flags & MAP_HAS_LANDMARK ))
  33472. + if( c >= 3 && !FBitSet( flags, MAP_HAS_LANDMARK ))
  33473. {
  33474. if( sv_validate_changelevel->integer )
  33475. {
  33476. @@ -501,7 +518,7 @@ void SV_ChangeLevel_f( void )
  33477. return;
  33478. }
  33479.  
  33480. - if( c == 2 && !( flags & MAP_HAS_SPAWNPOINT ))
  33481. + if( c == 2 && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
  33482. {
  33483. if( sv_validate_changelevel->integer )
  33484. {
  33485. @@ -510,7 +527,7 @@ void SV_ChangeLevel_f( void )
  33486. }
  33487. }
  33488.  
  33489. - // bad changelevel position invoke enables in one-way transtion
  33490. + // bad changelevel position invoke enables in one-way transition
  33491. if( sv.net_framenum < 15 )
  33492. {
  33493. if( sv_validate_changelevel->integer )
  33494. @@ -611,7 +628,7 @@ void SV_Kick_f( void )
  33495. return;
  33496. }
  33497.  
  33498. - SV_BroadcastPrintf( PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name );
  33499. + SV_BroadcastPrintf( svs.currentPlayer, PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name );
  33500. SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "You were kicked from the game\n" );
  33501. SV_DropClient( svs.currentPlayer );
  33502.  
  33503. @@ -633,7 +650,7 @@ void SV_Kill_f( void )
  33504.  
  33505. if( svs.currentPlayer->edict->v.health <= 0.0f )
  33506. {
  33507. - SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "Can't suicide -- allready dead!\n");
  33508. + SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "Can't suicide - already dead!\n");
  33509. return;
  33510. }
  33511.  
  33512. @@ -673,8 +690,8 @@ SV_Status_f
  33513. */
  33514. void SV_Status_f( void )
  33515. {
  33516. - int i;
  33517. sv_client_t *cl;
  33518. + int i;
  33519.  
  33520. if( !svs.clients || sv.background )
  33521. {
  33522. @@ -698,7 +715,7 @@ void SV_Status_f( void )
  33523.  
  33524. if( cl->state == cs_connected ) Msg( "Connect" );
  33525. else if( cl->state == cs_zombie ) Msg( "Zombie " );
  33526. - else if( cl->fakeclient ) Msg( "Bot " );
  33527. + else if( FBitSet( cl->flags, FCL_FAKECLIENT )) Msg( "Bot " );
  33528. else
  33529. {
  33530. ping = cl->ping < 9999 ? cl->ping : 9999;
  33531. @@ -812,7 +829,9 @@ Kick everyone off, possibly in preparation for a new game
  33532. */
  33533. void SV_KillServer_f( void )
  33534. {
  33535. - if( !svs.initialized ) return;
  33536. + if( !svs.initialized )
  33537. + return;
  33538. +
  33539. Q_strncpy( host.finalmsg, "Server was killed", MAX_STRING );
  33540. SV_Shutdown( false );
  33541. NET_Config ( false ); // close network sockets
  33542. @@ -830,18 +849,18 @@ void SV_PlayersOnly_f( void )
  33543. if( !Cvar_VariableInteger( "sv_cheats" )) return;
  33544. sv.hostflags = sv.hostflags ^ SVF_PLAYERSONLY;
  33545.  
  33546. - if(!( sv.hostflags & SVF_PLAYERSONLY ))
  33547. - SV_BroadcastPrintf( D_INFO, "Resume server physic\n" );
  33548. - else SV_BroadcastPrintf( D_INFO, "Freeze server physic\n" );
  33549. + if( !FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
  33550. + SV_BroadcastPrintf( NULL, PRINT_HIGH, "Resume server physic\n" );
  33551. + else SV_BroadcastPrintf( NULL, PRINT_HIGH, "Freeze server physic\n" );
  33552. }
  33553.  
  33554. /*
  33555. ===============
  33556. -SV_EdictsInfo_f
  33557. +SV_EdictUsage_f
  33558.  
  33559. ===============
  33560. */
  33561. -void SV_EdictsInfo_f( void )
  33562. +void SV_EdictUsage_f( void )
  33563. {
  33564. int active;
  33565.  
  33566. @@ -924,7 +943,7 @@ void SV_InitOperatorCommands( void )
  33567. Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );
  33568. Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
  33569. Cmd_AddCommand( "entpatch", SV_EntPatch_f, "write entity patch to allow external editing" );
  33570. - Cmd_AddCommand( "edicts_info", SV_EdictsInfo_f, "show info about edicts" );
  33571. + Cmd_AddCommand( "edict_usage", SV_EdictUsage_f, "show info about edicts usage" );
  33572. Cmd_AddCommand( "entity_info", SV_EntityInfo_f, "show more info about edicts" );
  33573.  
  33574. if( host.type == HOST_DEDICATED )
  33575. @@ -968,7 +987,7 @@ void SV_KillOperatorCommands( void )
  33576. Cmd_RemoveCommand( "restart" );
  33577. Cmd_RemoveCommand( "reload" );
  33578. Cmd_RemoveCommand( "entpatch" );
  33579. - Cmd_RemoveCommand( "edicts_info" );
  33580. + Cmd_RemoveCommand( "edict_usage" );
  33581. Cmd_RemoveCommand( "entity_info" );
  33582.  
  33583. if( host.type == HOST_DEDICATED )
  33584. diff --git b/engine/server/sv_custom.c a/engine/server/sv_custom.c
  33585. index 67f082e..2a63484 100644
  33586. --- b/engine/server/sv_custom.c
  33587. +++ a/engine/server/sv_custom.c
  33588. @@ -302,7 +302,7 @@ void SV_SendConsistencyList( sizebuf_t *msg )
  33589. int lastIndex;
  33590. int i;
  33591.  
  33592. - if( mp_consistency->integer && ( sv.num_consistency_resources > 0 ) && !svs.currentPlayer->hltv_proxy )
  33593. + if( mp_consistency->integer && ( sv.num_consistency_resources > 0 ) && !FBitSet( svs.currentPlayer->flags, FCL_HLTV_PROXY ))
  33594. {
  33595. lastIndex = 0;
  33596. MSG_WriteOneBit( msg, 1 );
  33597. diff --git b/engine/server/sv_frame.c a/engine/server/sv_frame.c
  33598. index edefd98..43b7dbe 100644
  33599. --- b/engine/server/sv_frame.c
  33600. +++ a/engine/server/sv_frame.c
  33601. @@ -24,9 +24,6 @@ typedef struct
  33602. entity_state_t entities[MAX_VISIBLE_PACKET];
  33603. } sv_ents_t;
  33604.  
  33605. -static byte *clientpvs; // FatPVS
  33606. -static byte *clientphs; // FatPHS
  33607. -
  33608. int c_fullsend; // just a debug counter
  33609.  
  33610. /*
  33611. @@ -55,77 +52,84 @@ SV_AddEntitiesToPacket
  33612.  
  33613. =============
  33614. */
  33615. -static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents )
  33616. +static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents, qboolean from_client )
  33617. {
  33618. edict_t *ent;
  33619. - byte *pset;
  33620. + byte *clientpvs;
  33621. + byte *clientphs;
  33622. qboolean fullvis = false;
  33623. sv_client_t *netclient;
  33624. sv_client_t *cl = NULL;
  33625. entity_state_t *state;
  33626. - int e, player;
  33627. + int e;
  33628.  
  33629. // during an error shutdown message we may need to transmit
  33630. // the shutdown message after the server has shutdown, so
  33631. // specifically check for it
  33632. - if( !sv.state ) return;
  33633. + if( sv.state == ss_dead )
  33634. + return;
  33635.  
  33636. cl = SV_ClientFromEdict( pClient, true );
  33637.  
  33638. ASSERT( cl != NULL );
  33639.  
  33640. - if( pClient && !( sv.hostflags & SVF_PORTALPASS ))
  33641. + // portals can't change hostflags
  33642. + if( pClient && from_client )
  33643. {
  33644. - // portals can't change hostflags
  33645. - sv.hostflags &= ~SVF_SKIPLOCALHOST;
  33646. -
  33647. // setup hostflags
  33648. - if( cl->local_weapons )
  33649. - {
  33650. - sv.hostflags |= SVF_SKIPLOCALHOST;
  33651. - }
  33652. + if( FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
  33653. + SetBits( sv.hostflags, SVF_SKIPLOCALHOST );
  33654. + else ClearBits( sv.hostflags, SVF_SKIPLOCALHOST );
  33655.  
  33656. - // reset cameras each frame
  33657. - cl->num_cameras = 0;
  33658. + // reset viewents each frame
  33659. + cl->num_viewents = 0;
  33660. }
  33661.  
  33662. svgame.dllFuncs.pfnSetupVisibility( pViewEnt, pClient, &clientpvs, &clientphs );
  33663. if( !clientpvs ) fullvis = true;
  33664.  
  33665. + // don't send the world
  33666. for( e = 1; e < svgame.numEntities; e++ )
  33667. {
  33668. + byte *pset;
  33669. +
  33670. ent = EDICT_NUM( e );
  33671. - if( ent->free ) continue;
  33672. +
  33673. + if( !SV_IsValidEdict( ent ))
  33674. + continue;
  33675.  
  33676. // don't double add an entity through portals (already added)
  33677. // HACHACK: use pushmsec to keep net_framenum
  33678. if( ent->v.pushmsec == sv.net_framenum )
  33679. continue;
  33680.  
  33681. - if( ent->v.effects & EF_REQUEST_PHS )
  33682. + if( FBitSet( ent->v.effects, EF_REQUEST_PHS ))
  33683. pset = clientphs;
  33684. else pset = clientpvs;
  33685.  
  33686. state = &ents->entities[ents->num_entities];
  33687. netclient = SV_ClientFromEdict( ent, true );
  33688. - player = ( netclient != NULL );
  33689.  
  33690. // add entity to the net packet
  33691. - if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, player, pset ))
  33692. + if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, ( netclient != NULL ), pset ))
  33693. {
  33694. // to prevent adds it twice through portals
  33695. ent->v.pushmsec = sv.net_framenum;
  33696.  
  33697. - if( netclient && netclient->modelindex ) // apply custom model if present
  33698. + if( netclient && netclient->modelindex )
  33699. + {
  33700. + // update playermodel if this was changed
  33701. state->modelindex = netclient->modelindex;
  33702. + }
  33703.  
  33704. - if( SV_IsValidEdict( ent->v.aiment ) && ( ent->v.aiment->v.effects & EF_MERGE_VISIBILITY ))
  33705. + if( SV_IsValidEdict( ent->v.aiment ) && FBitSet( ent->v.aiment->v.effects, EF_MERGE_VISIBILITY ))
  33706. {
  33707. - if( cl != NULL && cl->num_cameras < MAX_CAMERAS )
  33708. + if( cl != NULL && cl->num_viewents < MAX_VIEWENTS )
  33709. {
  33710. - cl->cameras[cl->num_cameras] = ent->v.aiment;
  33711. - cl->num_cameras++;
  33712. + cl->viewentity[cl->num_viewents] = ent->v.aiment;
  33713. + cl->num_viewents++;
  33714. }
  33715. + else MsgDev( D_ERROR, "SV_AddEntitiesToPacket: too many viewentities!\n" );
  33716. }
  33717.  
  33718. // if we are full, silently discard entities
  33719. @@ -146,11 +150,11 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
  33720. if( fullvis ) continue; // portal ents will be added anyway, ignore recursion
  33721.  
  33722. // if its a portal entity, add everything visible from its camera position
  33723. - if( !( sv.hostflags & SVF_PORTALPASS ) && ent->v.effects & EF_MERGE_VISIBILITY )
  33724. + if( from_client && FBitSet( ent->v.effects, EF_MERGE_VISIBILITY ))
  33725. {
  33726. - sv.hostflags |= SVF_PORTALPASS;
  33727. - SV_AddEntitiesToPacket( ent, pClient, frame, ents );
  33728. - sv.hostflags &= ~SVF_PORTALPASS;
  33729. + SetBits( sv.hostflags, SVF_MERGE_VISIBILITY );
  33730. + SV_AddEntitiesToPacket( ent, pClient, frame, ents, false );
  33731. + ClearBits( sv.hostflags, SVF_MERGE_VISIBILITY );
  33732. }
  33733. }
  33734. }
  33735. @@ -173,8 +177,8 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
  33736. {
  33737. entity_state_t *oldent, *newent;
  33738. int oldindex, newindex;
  33739. - int oldnum, newnum;
  33740. int from_num_entities;
  33741. + int oldnum, newnum;
  33742. client_frame_t *from;
  33743.  
  33744. // this is the frame that we are going to delta update from
  33745. @@ -184,7 +188,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
  33746. from_num_entities = from->num_entities;
  33747.  
  33748. // the snapshot's entities may still have rolled off the buffer, though
  33749. - if( from->first_entity <= svs.next_client_entities - svs.num_client_entities )
  33750. + if( from->first_entity <= ( svs.next_client_entities - svs.num_client_entities ))
  33751. {
  33752. MsgDev( D_WARN, "%s: delta request from out of date entities.\n", cl->name );
  33753.  
  33754. @@ -223,7 +227,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
  33755. }
  33756. else
  33757. {
  33758. - newent = &svs.packet_entities[(to->first_entity+newindex)%svs.num_client_entities];
  33759. + newent = &svs.packet_entities[(to->first_entity+newindex) % svs.num_client_entities];
  33760. newnum = newent->number;
  33761. }
  33762.  
  33763. @@ -233,7 +237,7 @@ void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg
  33764. }
  33765. else
  33766. {
  33767. - oldent = &svs.packet_entities[(from->first_entity+oldindex)%svs.num_client_entities];
  33768. + oldent = &svs.packet_entities[(from->first_entity+oldindex) % svs.num_client_entities];
  33769. oldnum = oldent->number;
  33770. }
  33771.  
  33772. @@ -315,7 +319,7 @@ static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
  33773.  
  33774. for( j = 0; j < to->num_entities; j++ )
  33775. {
  33776. - state = &svs.packet_entities[(to->first_entity+j)%svs.num_client_entities];
  33777. + state = &svs.packet_entities[(to->first_entity+j) % svs.num_client_entities];
  33778. if( state->number == ent_index )
  33779. break;
  33780. }
  33781. @@ -331,10 +335,10 @@ static void SV_EmitEvents( sv_client_t *cl, client_frame_t *to, sizebuf_t *msg )
  33782. info->packet_index = j;
  33783. info->args.ducking = 0;
  33784.  
  33785. - if(!( info->args.flags & FEVENT_ORIGIN ))
  33786. + if( !FBitSet( info->args.flags, FEVENT_ORIGIN ))
  33787. VectorClear( info->args.origin );
  33788.  
  33789. - if(!( info->args.flags & FEVENT_ANGLES ))
  33790. + if( !FBitSet( info->args.flags, FEVENT_ANGLES ))
  33791. VectorClear( info->args.angles );
  33792.  
  33793. VectorClear( info->args.velocity );
  33794. @@ -477,14 +481,15 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
  33795. }
  33796.  
  33797. clent->v.fixangle = 0; // reset fixangle
  33798. - clent->v.pushmsec = 0; // reset net framenum
  33799. +
  33800. memset( &frame->clientdata, 0, sizeof( frame->clientdata ));
  33801. + clent->v.pushmsec = 0; // reset net framenum
  33802.  
  33803. // update clientdata_t
  33804. - svgame.dllFuncs.pfnUpdateClientData( clent, cl->local_weapons, &frame->clientdata );
  33805. + svgame.dllFuncs.pfnUpdateClientData( clent, FBitSet( cl->flags, FCL_LOCAL_WEAPONS ), &frame->clientdata );
  33806.  
  33807. MSG_WriteByte( msg, svc_clientdata );
  33808. - if( cl->hltv_proxy ) return; // don't send more nothing
  33809. + if( FBitSet( cl->flags, FCL_HLTV_PROXY )) return; // don't send more nothing
  33810.  
  33811. if( cl->delta_sequence == -1 ) from_cd = &nullcd;
  33812. else from_cd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].clientdata;
  33813. @@ -503,11 +508,11 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
  33814. // write clientdata_t
  33815. MSG_WriteClientData( msg, from_cd, to_cd, sv.time );
  33816.  
  33817. - if( cl->local_weapons && svgame.dllFuncs.pfnGetWeaponData( clent, frame->weapondata ))
  33818. + if( FBitSet( cl->flags, FCL_LOCAL_WEAPONS ) && svgame.dllFuncs.pfnGetWeaponData( clent, frame->weapondata ))
  33819. {
  33820. memset( &nullwd, 0, sizeof( nullwd ));
  33821.  
  33822. - for( i = 0; i < 64; i++ )
  33823. + for( i = 0; i < MAX_LOCAL_WEAPONS; i++ )
  33824. {
  33825. if( cl->delta_sequence == -1 ) from_wd = &nullwd;
  33826. else from_wd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].weapondata[i];
  33827. @@ -536,22 +541,22 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
  33828. static sv_ents_t frame_ents;
  33829. int i, send_pings;
  33830.  
  33831. + frame = &cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK];
  33832. clent = cl->edict;
  33833. - viewent = cl->pViewEntity; // himself or trigger_camera
  33834.  
  33835. - frame = &cl->frames[cl->netchan.outgoing_sequence & SV_UPDATE_MASK];
  33836. + viewent = cl->pViewEntity; // himself or trigger_camera
  33837.  
  33838. send_pings = SV_ShouldUpdatePing( cl );
  33839.  
  33840. + ClearBits( sv.hostflags, SVF_MERGE_VISIBILITY );
  33841. sv.net_framenum++; // now all portal-through entities are invalidate
  33842. - sv.hostflags &= ~SVF_PORTALPASS;
  33843.  
  33844. // clear everything in this snapshot
  33845. frame_ents.num_entities = c_fullsend = 0;
  33846.  
  33847. // add all the entities directly visible to the eye, which
  33848. // may include portal entities that merge other viewpoints
  33849. - SV_AddEntitiesToPacket( viewent, clent, frame, &frame_ents );
  33850. + SV_AddEntitiesToPacket( viewent, clent, frame, &frame_ents, true );
  33851.  
  33852. // if there were portals visible, there may be out of order entities
  33853. // in the list which will need to be resorted for the delta compression
  33854. @@ -559,6 +564,15 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
  33855. // of an entity being included twice.
  33856. qsort( frame_ents.entities, frame_ents.num_entities, sizeof( frame_ents.entities[0] ), SV_EntityNumbers );
  33857.  
  33858. + // it will break all connected clients, but it takes more than one week to overflow it
  33859. + if(( (uint)svs.next_client_entities ) + frame_ents.num_entities >= 0x7FFFFFFE )
  33860. + {
  33861. + // just reset counter
  33862. + svs.next_client_entities = 0;
  33863. + // delta is broken now, cannot keep connected clients
  33864. + SV_FinalMessage( "Server is running to long, reconnecting!", true );
  33865. + }
  33866. +
  33867. // copy the entity states out
  33868. frame->num_entities = 0;
  33869. frame->first_entity = svs.next_client_entities;
  33870. @@ -569,10 +583,6 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
  33871. state = &svs.packet_entities[svs.next_client_entities % svs.num_client_entities];
  33872. *state = frame_ents.entities[i];
  33873. svs.next_client_entities++;
  33874. -
  33875. - // this should never hit, map should always be restarted first in SV_Frame
  33876. - if( svs.next_client_entities >= 0x7FFFFFFE )
  33877. - Host_Error( "svs.next_client_entities wrapped\n" );
  33878. frame->num_entities++;
  33879. }
  33880.  
  33881. @@ -595,11 +605,11 @@ SV_SendClientDatagram
  33882. */
  33883. void SV_SendClientDatagram( sv_client_t *cl )
  33884. {
  33885. - byte msg_buf[NET_MAX_PAYLOAD];
  33886. - sizebuf_t msg;
  33887. + static byte msg_buf[NET_MAX_PAYLOAD];
  33888. + sizebuf_t msg;
  33889.  
  33890. - svs.currentPlayer = cl;
  33891. svs.currentPlayerNum = (cl - svs.clients);
  33892. + svs.currentPlayer = cl;
  33893.  
  33894. MSG_Init( &msg, "Datagram", msg_buf, sizeof( msg_buf ));
  33895.  
  33896. @@ -634,8 +644,8 @@ SV_UpdateToReliableMessages
  33897. */
  33898. void SV_UpdateToReliableMessages( void )
  33899. {
  33900. - int i;
  33901. sv_client_t *cl;
  33902. + int i;
  33903.  
  33904. // check for changes to be sent over the reliable streams to all clients
  33905. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  33906. @@ -645,37 +655,30 @@ void SV_UpdateToReliableMessages( void )
  33907. if( cl->state != cs_spawned )
  33908. continue;
  33909.  
  33910. - if( cl->sendinfo )
  33911. + if( FBitSet( cl->flags, FCL_RESEND_USERINFO ))
  33912. {
  33913. - cl->sendinfo = false;
  33914. SV_FullClientUpdate( cl, &sv.reliable_datagram );
  33915. + ClearBits( cl->flags, FCL_RESEND_USERINFO );
  33916. }
  33917.  
  33918. - if( cl->sendmovevars )
  33919. + if( FBitSet( cl->flags, FCL_RESEND_MOVEVARS ))
  33920. {
  33921. - cl->sendmovevars = false;
  33922. SV_FullUpdateMovevars( cl, &cl->netchan.message );
  33923. - }
  33924. + ClearBits( cl->flags, FCL_RESEND_MOVEVARS );
  33925. + }
  33926. }
  33927.  
  33928. // 1% chanse for simulate random network bugs
  33929. if( sv.write_bad_message && Com_RandomLong( 0, 512 ) == 404 )
  33930. {
  33931. // just for network debugging (send only for local client)
  33932. - MSG_WriteByte( &sv.datagram, svc_bad );
  33933. - MSG_WriteLong( &sv.datagram, rand( )); // send some random data
  33934. - MSG_WriteString( &sv.datagram, host.finalmsg ); // send final message
  33935. + MSG_WriteByte( &sv.reliable_datagram, svc_bad );
  33936. + MSG_WriteLong( &sv.reliable_datagram, rand( )); // send some random data
  33937. + MSG_WriteString( &sv.reliable_datagram, host.finalmsg ); // send final message
  33938. sv.write_bad_message = false;
  33939. }
  33940.  
  33941. // clear the server datagram if it overflowed.
  33942. - if( MSG_CheckOverflow( &sv.datagram ))
  33943. - {
  33944. - MsgDev( D_ERROR, "sv.datagram overflowed!\n" );
  33945. - MSG_Clear( &sv.datagram );
  33946. - }
  33947. -
  33948. - // clear the server datagram if it overflowed.
  33949. if( MSG_CheckOverflow( &sv.spectator_datagram ))
  33950. {
  33951. MsgDev( D_ERROR, "sv.spectator_datagram overflowed!\n" );
  33952. @@ -685,22 +688,18 @@ void SV_UpdateToReliableMessages( void )
  33953. // now send the reliable and server datagrams to all clients.
  33954. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  33955. {
  33956. - if( cl->state < cs_connected || cl->fakeclient )
  33957. + if( cl->state < cs_connected || FBitSet( cl->flags, FCL_FAKECLIENT ))
  33958. continue; // reliables go to all connected or spawned
  33959.  
  33960. MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
  33961. - MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
  33962.  
  33963. - if( cl->hltv_proxy )
  33964. - {
  33965. + if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
  33966. MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spectator_datagram ), MSG_GetNumBitsWritten( &sv.spectator_datagram ));
  33967. - }
  33968. }
  33969.  
  33970. // now clear the reliable and datagram buffers.
  33971. MSG_Clear( &sv.spectator_datagram );
  33972. MSG_Clear( &sv.reliable_datagram );
  33973. - MSG_Clear( &sv.datagram );
  33974. }
  33975.  
  33976. /*
  33977. @@ -714,7 +713,7 @@ void SV_SendClientMessages( void )
  33978. int i;
  33979.  
  33980. svs.currentPlayer = NULL;
  33981. - svs.currentPlayerNum = 0;
  33982. + svs.currentPlayerNum = -1;
  33983.  
  33984. if( sv.state == ss_dead )
  33985. return;
  33986. @@ -724,32 +723,22 @@ void SV_SendClientMessages( void )
  33987. // send a message to each connected client
  33988. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  33989. {
  33990. - if( !cl->state || cl->fakeclient )
  33991. + if( !cl->state || FBitSet( cl->flags, FCL_FAKECLIENT ))
  33992. continue;
  33993.  
  33994. - if( cl->skip_message )
  33995. + if( FBitSet( cl->flags, FCL_SKIP_NET_MESSAGE ))
  33996. {
  33997. - cl->skip_message = false;
  33998. + ClearBits( cl->flags, FCL_SKIP_NET_MESSAGE );
  33999. continue;
  34000. }
  34001.  
  34002. if( !host_limitlocal->integer && NET_IsLocalAddress( cl->netchan.remote_address ))
  34003. - cl->send_message = true;
  34004. + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34005.  
  34006. if( cl->state == cs_spawned )
  34007. {
  34008. - // Try to send a message as soon as we can.
  34009. - // If the target time for sending is within the next frame interval ( based on last frame ),
  34010. - // trigger the send now. Note that in single player,
  34011. - // send_message is also set to true any time a packet arrives from the client.
  34012. - float time_unti_next_message = cl->next_messagetime - (host.realtime + host.frametime);
  34013. -
  34014. - if( time_unti_next_message <= 0.0f )
  34015. - cl->send_message = true;
  34016. -
  34017. - // something got hosed
  34018. - if( time_unti_next_message > 2.0f )
  34019. - cl->send_message = true;
  34020. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ) || ( host.realtime + host.frametime ) >= cl->next_messagetime )
  34021. + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34022. }
  34023.  
  34024. // if the reliable message overflowed, drop the client
  34025. @@ -757,51 +746,48 @@ void SV_SendClientMessages( void )
  34026. {
  34027. MSG_Clear( &cl->netchan.message );
  34028. MSG_Clear( &cl->datagram );
  34029. - SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name );
  34030. + SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s overflowed\n", cl->name );
  34031. MsgDev( D_WARN, "reliable overflow for %s\n", cl->name );
  34032. SV_DropClient( cl );
  34033. - cl->send_message = true;
  34034. - cl->netchan.cleartime = 0; // don't choke this message
  34035. + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34036. + cl->netchan.cleartime = 0.0; // don't choke this message
  34037. }
  34038. - else if( cl->send_message )
  34039. + else if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE ))
  34040. {
  34041. // If we haven't gotten a message in sv_failuretime seconds, then stop sending messages to this client
  34042. // until we get another packet in from the client. This prevents crash/drop and reconnect where they are
  34043. // being hosed with "sequenced packet without connection" packets.
  34044. if(( host.realtime - cl->netchan.last_received ) > sv_failuretime->value )
  34045. - cl->send_message = false;
  34046. + ClearBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34047. }
  34048.  
  34049. // only send messages if the client has sent one
  34050. // and the bandwidth is not choked
  34051. - if( !cl->send_message ) continue;
  34052. -
  34053. - // Bandwidth choke active?
  34054. - if( !Netchan_CanPacket( &cl->netchan ))
  34055. + if( FBitSet( cl->flags, FCL_SEND_NET_MESSAGE ))
  34056. {
  34057. - cl->chokecount++;
  34058. - continue;
  34059. - }
  34060. -
  34061. - cl->send_message = false;
  34062. + // bandwidth choke active?
  34063. + if( !Netchan_CanPacket( &cl->netchan ))
  34064. + {
  34065. + cl->chokecount++;
  34066. + continue;
  34067. + }
  34068.  
  34069. - // Now that we were able to send, reset timer to point to next possible send time.
  34070. - cl->next_messagetime = host.realtime + host.frametime + cl->cl_updaterate;
  34071. + // now that we were able to send, reset timer to point to next possible send time.
  34072. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  34073. + cl->next_messagetime = host.realtime + cl->cl_updaterate;
  34074. + else cl->next_messagetime = host.realtime + host.frametime + cl->cl_updaterate;
  34075. + ClearBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34076.  
  34077. - if( cl->state == cs_spawned )
  34078. - {
  34079. - SV_SendClientDatagram( cl );
  34080. - }
  34081. - else
  34082. - {
  34083. - // just update reliable
  34084. - Netchan_Transmit( &cl->netchan, 0, NULL );
  34085. + // NOTE: we should send frame even if server is not simulated to prevent overflow
  34086. + if( cl->state == cs_spawned )
  34087. + SV_SendClientDatagram( cl );
  34088. + else Netchan_Transmit( &cl->netchan, 0, NULL ); // just update reliable
  34089. }
  34090. }
  34091.  
  34092. // reset current client
  34093. svs.currentPlayer = NULL;
  34094. - svs.currentPlayerNum = 0;
  34095. + svs.currentPlayerNum = -1;
  34096. }
  34097.  
  34098. /*
  34099. @@ -813,8 +799,8 @@ e.g. before changing level
  34100. */
  34101. void SV_SendMessagesToAll( void )
  34102. {
  34103. - int i;
  34104. sv_client_t *cl;
  34105. + int i;
  34106.  
  34107. if( sv.state == ss_dead )
  34108. return;
  34109. @@ -822,8 +808,9 @@ void SV_SendMessagesToAll( void )
  34110. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  34111. {
  34112. if( cl->state >= cs_connected )
  34113. - cl->send_message = true;
  34114. + SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
  34115. }
  34116. +
  34117. SV_SendClientMessages();
  34118. }
  34119.  
  34120. @@ -836,17 +823,18 @@ used before changing level
  34121. */
  34122. void SV_SkipUpdates( void )
  34123. {
  34124. - int i;
  34125. sv_client_t *cl;
  34126. + int i;
  34127.  
  34128. if( sv.state == ss_dead )
  34129. return;
  34130.  
  34131. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  34132. {
  34133. - if( cl->state != cs_spawned || cl->fakeclient )
  34134. + if( cl->state != cs_spawned || FBitSet( cl->flags, FCL_FAKECLIENT ))
  34135. continue;
  34136. - cl->skip_message = true;
  34137. +
  34138. + SetBits( cl->flags, FCL_SKIP_NET_MESSAGE );
  34139. }
  34140. }
  34141.  
  34142. @@ -871,7 +859,7 @@ void SV_InactivateClients( void )
  34143. if( !cl->state || !cl->edict )
  34144. continue;
  34145.  
  34146. - if( !cl->edict || (cl->edict->v.flags & FL_FAKECLIENT))
  34147. + if( !cl->edict || FBitSet( cl->edict->v.flags, FL_FAKECLIENT ))
  34148. continue;
  34149.  
  34150. if( svs.clients[i].state > cs_connected )
  34151. diff --git b/engine/server/sv_game.c a/engine/server/sv_game.c
  34152. index 483a888..5a99b55 100644
  34153. --- b/engine/server/sv_game.c
  34154. +++ a/engine/server/sv_game.c
  34155. @@ -28,8 +28,6 @@ static byte fatpvs[MAX_MAP_LEAFS/8];
  34156. static byte fatphs[MAX_MAP_LEAFS/8];
  34157. static byte clientpvs[MAX_MAP_LEAFS/8]; // for find client in PVS
  34158. static vec3_t viewPoint[MAX_CLIENTS];
  34159. -static byte *bitvector;
  34160. -static int fatbytes;
  34161.  
  34162. // exports
  34163. typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
  34164. @@ -218,35 +216,37 @@ Check visibility through client camera, portal camera, etc
  34165. */
  34166. qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
  34167. {
  34168. - int i, leafnum, clientnum;
  34169. - float *viewOrg = NULL;
  34170. + int i, clientnum;
  34171. + vec3_t vieworg;
  34172. + mleaf_t *leaf;
  34173.  
  34174. if( !mask ) return true; // full visibility
  34175.  
  34176. clientnum = cl - svs.clients;
  34177. - viewOrg = viewPoint[clientnum];
  34178. + VectorCopy( viewPoint[clientnum], vieworg );
  34179.  
  34180. // Invasion issues: wrong camera position received in ENGINE_SET_PVS
  34181. - if( cl->pViewEntity && !VectorCompare( viewOrg, cl->pViewEntity->v.origin ))
  34182. - viewOrg = cl->pViewEntity->v.origin;
  34183. + if( cl->pViewEntity && !VectorCompare( vieworg, cl->pViewEntity->v.origin ))
  34184. + VectorCopy( cl->pViewEntity->v.origin, vieworg );
  34185.  
  34186. - // -1 is because pvs rows are 1 based, not 0 based like leafs
  34187. - leafnum = Mod_PointLeafnum( viewOrg ) - 1;
  34188. - if( leafnum == -1 || (mask[leafnum>>3] & (1<<( leafnum & 7 ))))
  34189. + leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
  34190. +
  34191. + if( CHECKVISBIT( mask, leaf->cluster ))
  34192. return true; // visible from player view or camera view
  34193.  
  34194. // now check all the portal cameras
  34195. - for( i = 0; i < cl->num_cameras; i++ )
  34196. + for( i = 0; i < cl->num_viewents; i++ )
  34197. {
  34198. - edict_t *cam = cl->cameras[i];
  34199. + edict_t *view = cl->viewentity[i];
  34200.  
  34201. - if( !SV_IsValidEdict( cam ))
  34202. + if( !SV_IsValidEdict( view ))
  34203. continue;
  34204.  
  34205. - leafnum = Mod_PointLeafnum( cam->v.origin ) - 1;
  34206. - // g-cont. probably camera in bad leaf... allow to send message here?
  34207. - if( leafnum == -1 || (mask[leafnum>>3] & (1<<( leafnum & 7 ))))
  34208. - return true;
  34209. + VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
  34210. + leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
  34211. +
  34212. + if( CHECKVISBIT( mask, leaf->cluster ))
  34213. + return true; // visible from portal camera view
  34214. }
  34215.  
  34216. // not visible from any viewpoint
  34217. @@ -263,10 +263,10 @@ then clears sv.multicast.
  34218. MSG_ONE send to one client (ent can't be NULL)
  34219. MSG_ALL same as broadcast (origin can be NULL)
  34220. MSG_PVS send to clients potentially visible from org
  34221. -MSG_PHS send to clients potentially hearable from org
  34222. +MSG_PHS send to clients potentially audible from org
  34223. =================
  34224. */
  34225. -qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
  34226. +qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent, qboolean usermessage, qboolean filter )
  34227. {
  34228. byte *mask = NULL;
  34229. int j, numclients = sv_maxclients->integer;
  34230. @@ -274,7 +274,6 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
  34231. qboolean reliable = false;
  34232. qboolean specproxy = false;
  34233. int numsends = 0;
  34234. - mleaf_t *leaf;
  34235.  
  34236. switch( dest )
  34237. {
  34238. @@ -298,16 +297,15 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
  34239. // intentional fallthrough
  34240. case MSG_PAS:
  34241. if( origin == NULL ) return false;
  34242. - leaf = Mod_PointInLeaf( origin, sv.worldmodel->nodes );
  34243. - mask = Mod_LeafPHS( leaf, sv.worldmodel );
  34244. + Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, false );
  34245. + mask = fatphs; // using the FatPVS like a PHS
  34246. break;
  34247. case MSG_PVS_R:
  34248. reliable = true;
  34249. // intentional fallthrough
  34250. case MSG_PVS:
  34251. if( origin == NULL ) return false;
  34252. - leaf = Mod_PointInLeaf( origin, sv.worldmodel->nodes );
  34253. - mask = Mod_LeafPVS( leaf, sv.worldmodel );
  34254. + mask = Mod_GetPVSForPoint( origin );
  34255. break;
  34256. case MSG_ONE:
  34257. reliable = true;
  34258. @@ -333,13 +331,18 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
  34259. if( cl->state == cs_free || cl->state == cs_zombie )
  34260. continue;
  34261.  
  34262. - if( cl->state != cs_spawned && !reliable )
  34263. + if( cl->state != cs_spawned && ( !reliable || usermessage ))
  34264. continue;
  34265.  
  34266. - if( specproxy && !cl->hltv_proxy )
  34267. + if( specproxy && !FBitSet( cl->flags, FCL_HLTV_PROXY ))
  34268. continue;
  34269.  
  34270. - if( !cl->edict || cl->fakeclient )
  34271. + if( !cl->edict || FBitSet( cl->flags, FCL_FAKECLIENT ))
  34272. + continue;
  34273. +
  34274. + // reject step sounds while predicting is enabled
  34275. + // FIXME: make sure what this code doesn't cutoff something important!!!
  34276. + if( filter && cl == svs.currentPlayer && FBitSet( svs.currentPlayer->flags, FCL_PREDICT_MOVEMENT ))
  34277. continue;
  34278.  
  34279. if( ent != NULL && ent->v.groupinfo && cl->edict->v.groupinfo )
  34280. @@ -359,7 +362,7 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
  34281.  
  34282. MSG_Clear( &sv.multicast );
  34283.  
  34284. - return numsends; // debug
  34285. + return numsends; // just for debug
  34286. }
  34287.  
  34288. /*
  34289. @@ -525,67 +528,15 @@ void SV_RestartStaticEnts( void )
  34290. }
  34291.  
  34292. /*
  34293. -=============================================================================
  34294. -
  34295. -The PVS must include a small area around the client to allow head bobbing
  34296. -or other small motion on the client side. Otherwise, a bob might cause an
  34297. -entity that should be visible to not show up, especially when the bob
  34298. -crosses a waterline.
  34299. -
  34300. -=============================================================================
  34301. -*/
  34302. -static void SV_AddToFatPVS( const vec3_t org, int type, mnode_t *node )
  34303. -{
  34304. - byte *vis;
  34305. - float d;
  34306. -
  34307. - while( 1 )
  34308. - {
  34309. - // if this is a leaf, accumulate the pvs bits
  34310. - if( node->contents < 0 )
  34311. - {
  34312. - if( node->contents != CONTENTS_SOLID )
  34313. - {
  34314. - mleaf_t *leaf;
  34315. - int i;
  34316. -
  34317. - leaf = (mleaf_t *)node;
  34318. -
  34319. - if( type == DVIS_PVS )
  34320. - vis = Mod_LeafPVS( leaf, sv.worldmodel );
  34321. - else if( type == DVIS_PHS )
  34322. - vis = Mod_LeafPHS( leaf, sv.worldmodel );
  34323. - else vis = Mod_DecompressVis( NULL ); // get full visibility
  34324. -
  34325. - for( i = 0; i < fatbytes; i++ )
  34326. - bitvector[i] |= vis[i];
  34327. - }
  34328. - return;
  34329. - }
  34330. -
  34331. - d = PlaneDiff( org, node->plane );
  34332. - if( d > 8.0f ) node = node->children[0];
  34333. - else if( d < -8.0f ) node = node->children[1];
  34334. - else
  34335. - {
  34336. - // go down both
  34337. - SV_AddToFatPVS( org, type, node->children[0] );
  34338. - node = node->children[1];
  34339. - }
  34340. - }
  34341. -}
  34342. -
  34343. -/*
  34344. ==============
  34345. SV_BoxInPVS
  34346.  
  34347. check brush boxes in fat pvs
  34348. ==============
  34349. */
  34350. -static qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
  34351. +qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
  34352. {
  34353. - mleaf_t *leaf = Mod_PointInLeaf( org, sv.worldmodel->nodes );
  34354. - byte *vis = Mod_LeafPVS( leaf, sv.worldmodel );
  34355. + byte *vis = Mod_GetPVSForPoint( org );
  34356.  
  34357. if( !Mod_BoxVisible( absmin, absmax, vis ))
  34358. return false;
  34359. @@ -834,7 +785,7 @@ void SV_InitEdict( edict_t *pEdict )
  34360.  
  34361. void SV_FreeEdict( edict_t *pEdict )
  34362. {
  34363. - ASSERT( pEdict );
  34364. + ASSERT( pEdict != NULL );
  34365. ASSERT( pEdict->free == false );
  34366.  
  34367. // unlink from world
  34368. @@ -1033,7 +984,10 @@ void SV_BaselineForEntity( edict_t *pEdict )
  34369. float *mins, *maxs;
  34370. sv_client_t *cl;
  34371.  
  34372. - if( pEdict->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( pEdict, false )))
  34373. + if( !SV_IsValidEdict( pEdict ))
  34374. + return;
  34375. +
  34376. + if( FBitSet( pEdict->v.flags, FL_CLIENT ) && ( cl = SV_ClientFromEdict( pEdict, false )))
  34377. {
  34378. usehull = ( pEdict->v.flags & FL_DUCKING ) ? true : false;
  34379. modelindex = cl->modelindex ? cl->modelindex : pEdict->v.modelindex;
  34380. @@ -1422,7 +1376,7 @@ edict_t *pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float fl
  34381. return ent;
  34382. }
  34383.  
  34384. - return NULL;
  34385. + return svgame.edicts;
  34386. }
  34387.  
  34388. /*
  34389. @@ -1435,31 +1389,27 @@ build the new client PVS
  34390. int SV_CheckClientPVS( int check, qboolean bMergePVS )
  34391. {
  34392. byte *pvs;
  34393. - edict_t *ent;
  34394. - mleaf_t *leaf;
  34395. - vec3_t view;
  34396. + vec3_t vieworg;
  34397. sv_client_t *cl;
  34398. int i, j, k;
  34399. - int pvsbytes;
  34400. + edict_t *ent = NULL;
  34401.  
  34402. // cycle to the next one
  34403. check = bound( 1, check, svgame.globals->maxClients );
  34404.  
  34405. if( check == svgame.globals->maxClients )
  34406. - i = 1;
  34407. + i = 1; // reset cycle
  34408. else i = check + 1;
  34409.  
  34410. for( ;; i++ )
  34411. {
  34412. - if( i == svgame.globals->maxClients + 1 )
  34413. + if( i == ( svgame.globals->maxClients + 1 ))
  34414. i = 1;
  34415.  
  34416. ent = EDICT_NUM( i );
  34417. + if( i == check ) break; // didn't find anything else
  34418.  
  34419. - if( i == check )
  34420. - break; // didn't find anything else
  34421. -
  34422. - if( ent->free || !ent->pvPrivateData || ( ent->v.flags & FL_NOTARGET ))
  34423. + if( ent->free || !ent->pvPrivateData || FBitSet( ent->v.flags, FL_NOTARGET ))
  34424. continue;
  34425.  
  34426. // anything that is a client, or has a client as an enemy
  34427. @@ -1467,31 +1417,28 @@ int SV_CheckClientPVS( int check, qboolean bMergePVS )
  34428. }
  34429.  
  34430. cl = SV_ClientFromEdict( ent, true );
  34431. - pvsbytes = (sv.worldmodel->numleafs + 7) >> 3;
  34432. + memset( clientpvs, 0xFF, world.visbytes );
  34433.  
  34434. // get the PVS for the entity
  34435. - VectorAdd( ent->v.origin, ent->v.view_ofs, view );
  34436. - leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
  34437. - pvs = Mod_LeafPVS( leaf, sv.worldmodel );
  34438. - memcpy( clientpvs, pvs, pvsbytes );
  34439. + VectorAdd( ent->v.origin, ent->v.view_ofs, vieworg );
  34440. + pvs = Mod_GetPVSForPoint( vieworg );
  34441. + if( pvs ) memcpy( clientpvs, pvs, world.visbytes );
  34442.  
  34443. // transition in progress
  34444. if( !cl ) return i;
  34445.  
  34446. - // now merge PVS with all portal cameras
  34447. - for( k = 0; k < cl->num_cameras && bMergePVS; k++ )
  34448. + // now merge PVS with all the portal cameras
  34449. + for( k = 0; k < cl->num_viewents && bMergePVS; k++ )
  34450. {
  34451. - edict_t *cam = cl->cameras[k];
  34452. + edict_t *view = cl->viewentity[k];
  34453.  
  34454. - if( !SV_IsValidEdict( cam ))
  34455. + if( !SV_IsValidEdict( view ))
  34456. continue;
  34457.  
  34458. - VectorAdd( cam->v.origin, cam->v.view_ofs, view );
  34459. - leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
  34460. - if( leaf == NULL ) continue; // skip outside cameras
  34461. - pvs = Mod_LeafPVS( leaf, sv.worldmodel );
  34462. + VectorAdd( view->v.origin, view->v.view_ofs, vieworg );
  34463. + pvs = Mod_GetPVSForPoint( vieworg );
  34464.  
  34465. - for( j = 0; j < pvsbytes; j++ )
  34466. + for( j = 0; j < world.visbytes && pvs; j++ )
  34467. clientpvs[j] |= pvs[j];
  34468. }
  34469.  
  34470. @@ -1511,7 +1458,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
  34471. float delta;
  34472. model_t *mod;
  34473. qboolean bMergePVS;
  34474. - int i;
  34475. + mleaf_t *leaf;
  34476.  
  34477. if( !SV_IsValidEdict( pEdict ))
  34478. return svgame.edicts;
  34479. @@ -1519,7 +1466,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
  34480. delta = ( sv.time - sv.lastchecktime );
  34481.  
  34482. // don't merge visibility for portal entity, only for monsters
  34483. - bMergePVS = (pEdict->v.flags & FL_MONSTER) ? true : false;
  34484. + bMergePVS = FBitSet( pEdict->v.flags, FL_MONSTER ) ? true : false;
  34485.  
  34486. // find a new check if on a new frame
  34487. if( delta < 0.0f || delta >= 0.1f )
  34488. @@ -1530,6 +1477,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
  34489.  
  34490. // return check if it might be visible
  34491. pClient = EDICT_NUM( sv.lastcheck );
  34492. +
  34493. if( !SV_ClientFromEdict( pClient, true ))
  34494. return svgame.edicts;
  34495.  
  34496. @@ -1537,7 +1485,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
  34497.  
  34498. // portals & monitors
  34499. // NOTE: this specific break "radiaton tick" in normal half-life. use only as feature
  34500. - if(( host.features & ENGINE_TRANSFORM_TRACE_AABB ) && mod && mod->type == mod_brush && !( mod->flags & MODEL_HAS_ORIGIN ))
  34501. + if( FBitSet( host.features, ENGINE_TRANSFORM_TRACE_AABB ) && mod && mod->type == mod_brush && !FBitSet( mod->flags, MODEL_HAS_ORIGIN ))
  34502. {
  34503. // handle PVS origin for bmodels
  34504. VectorAverage( pEdict->v.mins, pEdict->v.maxs, view );
  34505. @@ -1551,13 +1499,12 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
  34506. if( pEdict->v.effects & EF_INVLIGHT )
  34507. view[2] -= 1.0f; // HACKHACK for barnacle
  34508.  
  34509. - i = Mod_PointLeafnum( view ) - 1;
  34510. + leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
  34511.  
  34512. - if( i < 0 || !((clientpvs[i>>3]) & (1 << (i & 7))))
  34513. - return svgame.edicts;
  34514. + if( CHECKVISBIT( clientpvs, leaf->cluster ))
  34515. + return pClient; // client which currently in PVS
  34516.  
  34517. - // client which currently in PVS
  34518. - return pClient;
  34519. + return svgame.edicts;
  34520. }
  34521.  
  34522. /*
  34523. @@ -1920,6 +1867,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  34524. {
  34525. int sound_idx;
  34526. int entityIndex;
  34527. + qboolean filter = false;
  34528. int msg_dest;
  34529. vec3_t origin;
  34530.  
  34531. @@ -1950,7 +1898,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  34532. VectorAverage( ent->v.mins, ent->v.maxs, origin );
  34533. VectorAdd( origin, ent->v.origin, origin );
  34534.  
  34535. - if( flags & SND_SPAWNING )
  34536. + if( FBitSet( flags, SND_SPAWNING ))
  34537. msg_dest = MSG_INIT;
  34538. else if( chan == CHAN_STATIC )
  34539. msg_dest = MSG_ALL;
  34540. @@ -1958,6 +1906,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  34541.  
  34542. // always sending stop sound command
  34543. if( flags & SND_STOP ) msg_dest = MSG_ALL;
  34544. + if( flags & SND_FILTER_CLIENT ) filter = true;
  34545.  
  34546. if( sample[0] == '!' && Q_isdigit( sample + 1 ))
  34547. {
  34548. @@ -1983,6 +1932,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  34549. if( sound_idx > 255 ) flags |= SND_LARGE_INDEX;
  34550.  
  34551. // not sending (because this is out of range)
  34552. + flags &= ~SND_FILTER_CLIENT;
  34553. flags &= ~SND_SPAWNING;
  34554.  
  34555. MSG_WriteByte( &sv.multicast, svc_sound );
  34556. @@ -1999,7 +1949,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
  34557. MSG_WriteWord( &sv.multicast, entityIndex );
  34558. MSG_WriteVec3Coord( &sv.multicast, origin );
  34559.  
  34560. - SV_Send( msg_dest, origin, NULL );
  34561. + SV_Send( msg_dest, origin, NULL, false, filter );
  34562. }
  34563.  
  34564. /*
  34565. @@ -2079,7 +2029,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
  34566. MSG_WriteWord( &sv.multicast, number );
  34567. MSG_WriteVec3Coord( &sv.multicast, pos );
  34568.  
  34569. - SV_Send( msg_dest, pos, NULL );
  34570. + SV_Send( msg_dest, pos, NULL, false, false );
  34571. }
  34572.  
  34573. /*
  34574. @@ -2088,11 +2038,11 @@ SV_StartMusic
  34575.  
  34576. =================
  34577. */
  34578. -void SV_StartMusic( const char *curtrack, const char *looptrack, fs_offset_t position )
  34579. +void SV_StartMusic( const char *curtrack, const char *looptrack, long position )
  34580. {
  34581. MSG_WriteByte( &sv.multicast, svc_stufftext );
  34582. MSG_WriteString( &sv.multicast, va( "music \"%s\" \"%s\" %i\n", curtrack, looptrack, position ));
  34583. - SV_Send( MSG_ALL, NULL, NULL );
  34584. + SV_Send( MSG_ALL, NULL, NULL, false, false );
  34585. }
  34586.  
  34587. /*
  34588. @@ -2173,6 +2123,9 @@ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v
  34589. return 1;
  34590. }
  34591.  
  34592. + if( pEdict != pentToSkip )
  34593. + MsgDev( D_ERROR, "TRACE_MONSTER_HULL: pEdict != pentToSkip\n" );
  34594. +
  34595. trace = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip );
  34596. if( ptr ) SV_ConvertTrace( ptr, &trace );
  34597.  
  34598. @@ -2341,7 +2294,7 @@ pfnClientCommand
  34599. */
  34600. void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
  34601. {
  34602. - sv_client_t *client;
  34603. + sv_client_t *cl;
  34604. string buffer;
  34605. va_list args;
  34606.  
  34607. @@ -2351,13 +2304,13 @@ void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
  34608. return;
  34609. }
  34610.  
  34611. - if(( client = SV_ClientFromEdict( pEdict, true )) == NULL )
  34612. + if(( cl = SV_ClientFromEdict( pEdict, true )) == NULL )
  34613. {
  34614. MsgDev( D_ERROR, "SV_ClientCommand: client is not spawned!\n" );
  34615. return;
  34616. }
  34617.  
  34618. - if( client->fakeclient )
  34619. + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
  34620. return;
  34621.  
  34622. va_start( args, szFmt );
  34623. @@ -2366,8 +2319,8 @@ void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
  34624.  
  34625. if( SV_IsValidCmd( buffer ))
  34626. {
  34627. - MSG_WriteByte( &client->netchan.message, svc_stufftext );
  34628. - MSG_WriteString( &client->netchan.message, buffer );
  34629. + MSG_WriteByte( &cl->netchan.message, svc_stufftext );
  34630. + MSG_WriteString( &cl->netchan.message, buffer );
  34631. }
  34632. else MsgDev( D_ERROR, "Tried to stuff bad command %s\n", buffer );
  34633. }
  34634. @@ -2390,18 +2343,20 @@ void pfnParticleEffect( const float *org, const float *dir, float color, float c
  34635. return;
  34636. }
  34637.  
  34638. - MSG_WriteByte( &sv.datagram, svc_particle );
  34639. - MSG_WriteVec3Coord( &sv.datagram, org );
  34640. + MSG_WriteByte( &sv.multicast, svc_particle );
  34641. + MSG_WriteVec3Coord( &sv.multicast, org );
  34642.  
  34643. for( i = 0; i < 3; i++ )
  34644. {
  34645. v = bound( -128, dir[i] * 16.0f, 127 );
  34646. - MSG_WriteChar( &sv.datagram, v );
  34647. + MSG_WriteChar( &sv.multicast, v );
  34648. }
  34649.  
  34650. - MSG_WriteByte( &sv.datagram, count );
  34651. - MSG_WriteByte( &sv.datagram, color );
  34652. - MSG_WriteByte( &sv.datagram, 0 );
  34653. + MSG_WriteByte( &sv.multicast, count );
  34654. + MSG_WriteByte( &sv.multicast, color );
  34655. + MSG_WriteByte( &sv.multicast, 0 );
  34656. +
  34657. + SV_Send( MSG_PVS, org, NULL, false, false );
  34658. }
  34659.  
  34660. /*
  34661. @@ -2617,7 +2572,7 @@ void pfnMessageEnd( void )
  34662. if( !VectorIsNull( svgame.msg_org )) org = svgame.msg_org;
  34663. svgame.msg_dest = bound( MSG_BROADCAST, svgame.msg_dest, MSG_SPEC );
  34664.  
  34665. - SV_Send( svgame.msg_dest, org, svgame.msg_ent );
  34666. + SV_Send( svgame.msg_dest, org, svgame.msg_ent, true, false );
  34667. }
  34668.  
  34669. /*
  34670. @@ -2698,6 +2653,18 @@ void pfnWriteCoord( float flValue )
  34671.  
  34672. /*
  34673. =============
  34674. +pfnWriteBytes
  34675. +
  34676. +=============
  34677. +*/
  34678. +void pfnWriteBytes( const byte *bytes, int count )
  34679. +{
  34680. + MSG_WriteBytes( &sv.multicast, bytes, count );
  34681. + svgame.msg_realsize += count;
  34682. +}
  34683. +
  34684. +/*
  34685. +=============
  34686. pfnWriteString
  34687.  
  34688. =============
  34689. @@ -2786,7 +2753,7 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
  34690. return;
  34691. break;
  34692. case at_aiconsole:
  34693. - if( host.developer < D_AICONSOLE )
  34694. + if( host.developer < D_REPORT )
  34695. return;
  34696. break;
  34697. case at_warning:
  34698. @@ -2821,7 +2788,7 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
  34699. =============
  34700. pfnEngineFprintf
  34701.  
  34702. -legacy. probably was a part of early save\restore system
  34703. +legacy. probably was a part of early version of save\restore system
  34704. =============
  34705. */
  34706. static void pfnEngineFprintf( FILE *pfile, char *szFmt, ... )
  34707. @@ -3115,7 +3082,7 @@ int pfnRegUserMsg( const char *pszName, int iSize )
  34708. MSG_WriteByte( &sv.multicast, svgame.msg[i].number );
  34709. MSG_WriteByte( &sv.multicast, (byte)iSize );
  34710. MSG_WriteString( &sv.multicast, svgame.msg[i].name );
  34711. - SV_Send( MSG_ALL, NULL, NULL );
  34712. + SV_Send( MSG_ALL, NULL, NULL, false, false );
  34713. }
  34714.  
  34715. return svgame.msg[i].number;
  34716. @@ -3185,7 +3152,7 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
  34717. if( sv.state != ss_active )
  34718. {
  34719. // send message into console during loading
  34720. - MsgDev( D_INFO, szMsg );
  34721. + MsgDev( D_INFO, "%s\n", szMsg );
  34722. return;
  34723. }
  34724.  
  34725. @@ -3198,15 +3165,18 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
  34726. switch( ptype )
  34727. {
  34728. case print_console:
  34729. - if( client->fakeclient ) MsgDev( D_INFO, szMsg );
  34730. + if( FBitSet( client->flags, FCL_FAKECLIENT ))
  34731. + MsgDev( D_INFO, "%s", szMsg );
  34732. else SV_ClientPrintf( client, PRINT_HIGH, "%s", szMsg );
  34733. break;
  34734. case print_chat:
  34735. - if( client->fakeclient ) return;
  34736. + if( FBitSet( client->flags, FCL_FAKECLIENT ))
  34737. + return;
  34738. SV_ClientPrintf( client, PRINT_CHAT, "%s", szMsg );
  34739. break;
  34740. case print_center:
  34741. - if( client->fakeclient ) return;
  34742. + if( FBitSet( client->flags, FCL_FAKECLIENT ))
  34743. + return;
  34744. MSG_WriteByte( &client->netchan.message, svc_centerprint );
  34745. MSG_WriteString( &client->netchan.message, szMsg );
  34746. break;
  34747. @@ -3222,8 +3192,8 @@ pfnServerPrint
  34748. void pfnServerPrint( const char *szMsg )
  34749. {
  34750. // while loading in-progress we can sending message only for local client
  34751. - if( sv.state != ss_active ) MsgDev( D_INFO, szMsg );
  34752. - else SV_BroadcastPrintf( PRINT_HIGH, "%s", szMsg );
  34753. + if( sv.state != ss_active ) MsgDev( D_INFO, "%s", szMsg );
  34754. + else SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", szMsg );
  34755. }
  34756.  
  34757. /*
  34758. @@ -3273,7 +3243,8 @@ void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw )
  34759. }
  34760.  
  34761. // fakeclients ignores it silently
  34762. - if( client->fakeclient ) return;
  34763. + if( FBitSet( client->flags, FCL_FAKECLIENT ))
  34764. + return;
  34765.  
  34766. if( pitch > 180.0f ) pitch -= 360;
  34767. if( pitch < -180.0f ) pitch += 360;
  34768. @@ -3317,7 +3288,8 @@ void pfnSetView( const edict_t *pClient, const edict_t *pViewent )
  34769. else client->pViewEntity = (edict_t *)pViewent;
  34770.  
  34771. // fakeclients ignore to send client message (but can see into the trigger_camera through the PVS)
  34772. - if( client->fakeclient ) return;
  34773. + if( FBitSet( client->flags, FCL_FAKECLIENT ))
  34774. + return;
  34775.  
  34776. MSG_WriteByte( &client->netchan.message, svc_setview );
  34777. MSG_WriteWord( &client->netchan.message, NUM_FOR_EDICT( pViewent ));
  34778. @@ -3370,22 +3342,7 @@ pfnGetPlayerWONId
  34779. */
  34780. uint pfnGetPlayerWONId( edict_t *e )
  34781. {
  34782. - sv_client_t *cl;
  34783. - int i;
  34784. -
  34785. - if( sv.state != ss_active )
  34786. - return -1;
  34787. -
  34788. - if( !SV_ClientFromEdict( e, false ))
  34789. - return -1;
  34790. -
  34791. - for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  34792. - {
  34793. - if( cl->edict == e && cl->authentication_method == 0 )
  34794. - return cl->WonID;
  34795. - }
  34796. -
  34797. - return -1;
  34798. + return 0xFFFFFFFF;
  34799. }
  34800.  
  34801. /*
  34802. @@ -3428,7 +3385,8 @@ void pfnFadeClientVolume( const edict_t *pEdict, int fadePercent, int fadeOutSec
  34803. return;
  34804. }
  34805.  
  34806. - if( cl->fakeclient ) return;
  34807. + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
  34808. + return;
  34809.  
  34810. MSG_WriteByte( &cl->netchan.message, svc_soundfade );
  34811. MSG_WriteByte( &cl->netchan.message, fadePercent );
  34812. @@ -3478,14 +3436,14 @@ void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, floa
  34813. return;
  34814. }
  34815.  
  34816. - if( !cl->fakeclient )
  34817. - return; // only fakeclients allows
  34818. + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
  34819. + return; // only fakeclients allows
  34820.  
  34821. oldcl = svs.currentPlayer;
  34822.  
  34823. svs.currentPlayer = SV_ClientFromEdict( pClient, true );
  34824. svs.currentPlayerNum = (svs.currentPlayer - svs.clients);
  34825. - svs.currentPlayer->timebase = (sv.time + host.frametime) - (msec / 1000.0f);
  34826. + svs.currentPlayer->timebase = (sv.time + sv.frametime) - (msec / 1000.0f);
  34827.  
  34828. memset( &cmd, 0, sizeof( cmd ));
  34829. if( v_angle ) VectorCopy( v_angle, cmd.viewangles );
  34830. @@ -3559,16 +3517,20 @@ pfnSetClientKeyValue
  34831. */
  34832. void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value )
  34833. {
  34834. + sv_client_t *cl;
  34835. +
  34836. clientIndex -= 1;
  34837.  
  34838. - if( clientIndex < 0 || clientIndex >= sv_maxclients->integer )
  34839. + if( !svs.clients || clientIndex < 0 || clientIndex >= sv_maxclients->integer )
  34840. return;
  34841.  
  34842. - if( svs.clients[clientIndex].state < cs_spawned || infobuffer == NULL )
  34843. + cl = &svs.clients[clientIndex];
  34844. +
  34845. + if( cl->state < cs_spawned || infobuffer == NULL )
  34846. return;
  34847.  
  34848. Info_SetValueForKey( infobuffer, key, value );
  34849. - svs.clients[clientIndex].sendinfo = true;
  34850. + SetBits( cl->flags, FCL_RESEND_USERINFO );
  34851. }
  34852.  
  34853. /*
  34854. @@ -3662,7 +3624,7 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
  34855. byte *mask = NULL;
  34856. vec3_t pvspoint;
  34857.  
  34858. - if( flags & FEV_CLIENT )
  34859. + if( FBitSet( flags, FEV_CLIENT ))
  34860. return; // someone stupid joke
  34861.  
  34862. // first check event for out of bounds
  34863. @@ -3710,14 +3672,14 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
  34864. args.entindex = invokerIndex = NUM_FOR_EDICT( pInvoker );
  34865.  
  34866. // g-cont. allow 'ducking' param for all entities
  34867. - args.ducking = (pInvoker->v.flags & FL_DUCKING) ? true : false;
  34868. + args.ducking = FBitSet( pInvoker->v.flags, FL_DUCKING ) ? true : false;
  34869.  
  34870. // this will be send only for reliable event
  34871. - if(!( args.flags & FEVENT_ORIGIN ))
  34872. + if( !FBitSet( args.flags, FEVENT_ORIGIN ))
  34873. VectorCopy( pInvoker->v.origin, args.origin );
  34874.  
  34875. // this will be send only for reliable event
  34876. - if(!( args.flags & FEVENT_ANGLES ))
  34877. + if( !FBitSet( args.flags, FEVENT_ANGLES ))
  34878. VectorCopy( pInvoker->v.angles, args.angles );
  34879.  
  34880. if( sv_sendvelocity->integer )
  34881. @@ -3730,54 +3692,50 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
  34882. invokerIndex = -1;
  34883. }
  34884.  
  34885. - if(!( flags & FEV_GLOBAL ) && VectorIsNull( pvspoint ))
  34886. + if( !FBitSet( flags, FEV_GLOBAL ) && VectorIsNull( pvspoint ))
  34887. {
  34888. MsgDev( D_ERROR, "%s: not a FEV_GLOBAL event missing origin. Ignored.\n", sv.event_precache[eventindex] );
  34889. return;
  34890. }
  34891.  
  34892. // check event for some user errors
  34893. - if( flags & (FEV_NOTHOST|FEV_HOSTONLY))
  34894. + if( FBitSet( flags, FEV_NOTHOST|FEV_HOSTONLY ))
  34895. {
  34896. if( !SV_ClientFromEdict( pInvoker, true ))
  34897. {
  34898. const char *ev_name = sv.event_precache[eventindex];
  34899. - if( flags & FEV_NOTHOST )
  34900. +
  34901. + if( FBitSet( flags, FEV_NOTHOST ))
  34902. {
  34903. MsgDev( D_WARN, "%s: specified FEV_NOTHOST when invoker not a client\n", ev_name );
  34904. - flags &= ~FEV_NOTHOST;
  34905. + ClearBits( flags, FEV_NOTHOST );
  34906. }
  34907.  
  34908. - if( flags & FEV_HOSTONLY )
  34909. + if( FBitSet( flags, FEV_HOSTONLY ))
  34910. {
  34911. MsgDev( D_WARN, "%s: specified FEV_HOSTONLY when invoker not a client\n", ev_name );
  34912. - flags &= ~FEV_HOSTONLY;
  34913. + ClearBits( flags, FEV_HOSTONLY );
  34914. }
  34915. }
  34916. }
  34917.  
  34918. - flags |= FEV_SERVER; // it's a server event!
  34919. + SetBits( flags, FEV_SERVER ); // it's a server event!
  34920. if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
  34921.  
  34922. - if(!( flags & FEV_GLOBAL ))
  34923. - {
  34924. - mleaf_t *leaf;
  34925. -
  34926. - // setup pvs cluster for invoker
  34927. - leaf = Mod_PointInLeaf( pvspoint, sv.worldmodel->nodes );
  34928. - mask = Mod_LeafPVS( leaf, sv.worldmodel );
  34929. - }
  34930. + // setup pvs cluster for invoker
  34931. + if( !FBitSet( flags, FEV_GLOBAL ))
  34932. + mask = Mod_GetPVSForPoint( pvspoint );
  34933.  
  34934. // process all the clients
  34935. for( slot = 0, cl = svs.clients; slot < sv_maxclients->integer; slot++, cl++ )
  34936. {
  34937. - if( cl->state != cs_spawned || !cl->edict || cl->fakeclient )
  34938. + if( cl->state != cs_spawned || !cl->edict || FBitSet( cl->flags, FCL_FAKECLIENT ))
  34939. continue;
  34940.  
  34941. if( SV_IsValidEdict( pInvoker ) && pInvoker->v.groupinfo && cl->edict->v.groupinfo )
  34942. {
  34943. - if(( svs.groupop == 0 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 0 )
  34944. - || ( svs.groupop == 1 && (cl->edict->v.groupinfo & pInvoker->v.groupinfo) == 1 ))
  34945. + if(( svs.groupop == 0 && FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ) == 0 )
  34946. + || ( svs.groupop == 1 && FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ) == 1 ))
  34947. continue;
  34948. }
  34949.  
  34950. @@ -3787,16 +3745,16 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
  34951. continue;
  34952. }
  34953.  
  34954. - if( flags & FEV_NOTHOST && cl == svs.currentPlayer && cl->local_weapons )
  34955. + if( FBitSet( flags, FEV_NOTHOST ) && cl == svs.currentPlayer && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
  34956. continue; // will be played on client side
  34957.  
  34958. - if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
  34959. + if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker )
  34960. continue; // sending only to invoker
  34961.  
  34962. // all checks passed, send the event
  34963.  
  34964. // reliable event
  34965. - if( flags & FEV_RELIABLE )
  34966. + if( FBitSet( flags, FEV_RELIABLE ))
  34967. {
  34968. // skipping queue, write direct into reliable datagram
  34969. SV_PlaybackReliableEvent( &cl->netchan.message, eventindex, delay, &args );
  34970. @@ -3807,11 +3765,12 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
  34971. es = &cl->events;
  34972. bestslot = -1;
  34973.  
  34974. - if( flags & FEV_UPDATE )
  34975. + if( FBitSet( flags, FEV_UPDATE ))
  34976. {
  34977. for( j = 0; j < MAX_EVENT_QUEUE; j++ )
  34978. {
  34979. ei = &es->ei[j];
  34980. +
  34981. if( ei->index == eventindex && invokerIndex != -1 && invokerIndex == ei->entity_index )
  34982. {
  34983. bestslot = j;
  34984. @@ -3864,16 +3823,15 @@ so we can't use a single PVS point
  34985. */
  34986. byte *pfnSetFatPVS( const float *org )
  34987. {
  34988. + qboolean fullvis = false;
  34989. +
  34990. if( !sv.worldmodel->visdata || sv_novis->integer || !org || CL_DisableVisibility( ))
  34991. - return Mod_DecompressVis( NULL );
  34992. + fullvis = true;
  34993.  
  34994. ASSERT( svs.currentPlayerNum >= 0 && svs.currentPlayerNum < MAX_CLIENTS );
  34995.  
  34996. - fatbytes = (sv.worldmodel->numleafs+31)>>3;
  34997. - bitvector = fatpvs;
  34998. -
  34999. // portals can't change viewpoint!
  35000. - if(!( sv.hostflags & SVF_PORTALPASS ))
  35001. + if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
  35002. {
  35003. vec3_t viewPos, offset;
  35004.  
  35005. @@ -3885,7 +3843,7 @@ byte *pfnSetFatPVS( const float *org )
  35006. // }
  35007. // so we have unneeded duck calculations who have affect when player
  35008. // is ducked into water. Remove offset to restore right PVS position
  35009. - if( svs.currentPlayer->edict->v.flags & FL_DUCKING )
  35010. + if( FBitSet( svs.currentPlayer->edict->v.flags, FL_DUCKING ))
  35011. {
  35012. VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
  35013. VectorSubtract( org, offset, viewPos );
  35014. @@ -3893,17 +3851,16 @@ byte *pfnSetFatPVS( const float *org )
  35015. else VectorCopy( org, viewPos );
  35016.  
  35017. // build a new PVS frame
  35018. - memset( bitvector, 0, fatbytes );
  35019. -
  35020. - SV_AddToFatPVS( viewPos, DVIS_PVS, sv.worldmodel->nodes );
  35021. + Mod_FatPVS( viewPos, FATPVS_RADIUS, fatpvs, world.fatbytes, false, fullvis );
  35022. VectorCopy( viewPos, viewPoint[svs.currentPlayerNum] );
  35023. }
  35024. else
  35025. {
  35026. - SV_AddToFatPVS( org, DVIS_PVS, sv.worldmodel->nodes );
  35027. + // merge PVS
  35028. + Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, true, fullvis );
  35029. }
  35030.  
  35031. - return bitvector;
  35032. + return fatpvs;
  35033. }
  35034.  
  35035. /*
  35036. @@ -3916,16 +3873,15 @@ so we can't use a single PHS point
  35037. */
  35038. byte *pfnSetFatPAS( const float *org )
  35039. {
  35040. + qboolean fullvis = false;
  35041. +
  35042. if( !sv.worldmodel->visdata || sv_novis->integer || !org || CL_DisableVisibility( ))
  35043. - return Mod_DecompressVis( NULL );
  35044. + fullvis = true;
  35045.  
  35046. ASSERT( svs.currentPlayerNum >= 0 && svs.currentPlayerNum < MAX_CLIENTS );
  35047.  
  35048. - fatbytes = (sv.worldmodel->numleafs+31)>>3;
  35049. - bitvector = fatphs;
  35050. -
  35051. // portals can't change viewpoint!
  35052. - if(!( sv.hostflags & SVF_PORTALPASS ))
  35053. + if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
  35054. {
  35055. vec3_t viewPos, offset;
  35056.  
  35057. @@ -3937,7 +3893,7 @@ byte *pfnSetFatPAS( const float *org )
  35058. // }
  35059. // so we have unneeded duck calculations who have affect when player
  35060. // is ducked into water. Remove offset to restore right PVS position
  35061. - if( svs.currentPlayer->edict->v.flags & FL_DUCKING )
  35062. + if( FBitSet( svs.currentPlayer->edict->v.flags, FL_DUCKING ))
  35063. {
  35064. VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
  35065. VectorSubtract( org, offset, viewPos );
  35066. @@ -3945,17 +3901,15 @@ byte *pfnSetFatPAS( const float *org )
  35067. else VectorCopy( org, viewPos );
  35068.  
  35069. // build a new PHS frame
  35070. - memset( bitvector, 0, fatbytes );
  35071. -
  35072. - SV_AddToFatPVS( viewPos, DVIS_PHS, sv.worldmodel->nodes );
  35073. + Mod_FatPVS( viewPos, FATPHS_RADIUS, fatphs, world.fatbytes, false, fullvis );
  35074. }
  35075. else
  35076. {
  35077. - // merge PVS
  35078. - SV_AddToFatPVS( org, DVIS_PHS, sv.worldmodel->nodes );
  35079. + // merge PHS
  35080. + Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, true, fullvis );
  35081. }
  35082.  
  35083. - return bitvector;
  35084. + return fatphs;
  35085. }
  35086.  
  35087. /*
  35088. @@ -3977,7 +3931,7 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
  35089. // vis not set - fullvis enabled
  35090. if( !pset ) return 1;
  35091.  
  35092. - if( ent->v.flags & FL_CUSTOMENTITY && ent->v.owner && ent->v.owner->v.flags & FL_CLIENT )
  35093. + if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ) && ent->v.owner && FBitSet( ent->v.owner->v.flags, FL_CLIENT ))
  35094. ent = ent->v.owner; // upcast beams to my owner
  35095.  
  35096. if( ent->headnode < 0 )
  35097. @@ -3985,7 +3939,7 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
  35098. // check individual leafs
  35099. for( i = 0; i < ent->num_leafs; i++ )
  35100. {
  35101. - if( pset[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7 )))
  35102. + if( CHECKVISBIT( pset, ent->leafnums[i] ))
  35103. return 1; // visible passed by leaf
  35104. }
  35105.  
  35106. @@ -3993,18 +3947,19 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
  35107. }
  35108. else
  35109. {
  35110. - int leafnum;
  35111. + short leafnum;
  35112.  
  35113. for( i = 0; i < MAX_ENT_LEAFS; i++ )
  35114. {
  35115. leafnum = ent->leafnums[i];
  35116. if( leafnum == -1 ) break;
  35117. - if( pset[leafnum >> 3] & (1 << ( leafnum & 7 )))
  35118. +
  35119. + if( CHECKVISBIT( pset, leafnum ))
  35120. return 1; // visible passed by leaf
  35121. }
  35122.  
  35123. // too many leafs for individual check, go by headnode
  35124. - if( !SV_HeadnodeVisible( &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
  35125. + if( !Mod_HeadnodeVisible( &sv.worldmodel->nodes[ent->headnode], pset, &leafnum ))
  35126. return 0;
  35127.  
  35128. ((edict_t *)ent)->leafnums[ent->num_leafs] = leafnum;
  35129. @@ -4027,7 +3982,7 @@ int pfnCanSkipPlayer( const edict_t *player )
  35130. if(( cl = SV_ClientFromEdict( player, false )) == NULL )
  35131. return false;
  35132.  
  35133. - return cl->local_weapons;
  35134. + return FBitSet( cl->flags, FCL_LOCAL_WEAPONS );
  35135. }
  35136.  
  35137. /*
  35138. @@ -4038,9 +3993,7 @@ pfnGetCurrentPlayer
  35139. */
  35140. int pfnGetCurrentPlayer( void )
  35141. {
  35142. - if( svs.currentPlayer )
  35143. - return (svs.currentPlayer - svs.clients);
  35144. - return -1;
  35145. + return svs.currentPlayerNum;
  35146. }
  35147.  
  35148. /*
  35149. @@ -4256,7 +4209,7 @@ const char *pfnGetPlayerAuthId( edict_t *e )
  35150. {
  35151. if( cl->edict == e )
  35152. {
  35153. - if( cl->fakeclient )
  35154. + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
  35155. Q_strncat( result, "BOT", sizeof( result ));
  35156. else if( cl->authentication_method == 0 )
  35157. Q_snprintf( result, sizeof( result ), "%u", (uint)cl->WonID );
  35158. @@ -4362,15 +4315,16 @@ pfnCheckParm
  35159. */
  35160. static int pfnCheckParm( char *parm, char **ppnext )
  35161. {
  35162. - static char str[64];
  35163. + int i = Sys_CheckParm( parm );
  35164.  
  35165. - if( Sys_GetParmFromCmdLine( parm, str ))
  35166. + if( ppnext != NULL )
  35167. {
  35168. - // get the pointer on cmdline param
  35169. - if( ppnext ) *ppnext = str;
  35170. - return 1;
  35171. + if( i > 0 && i < host.argc - 1 )
  35172. + *ppnext = (char*)host.argv[i + 1];
  35173. + else *ppnext = NULL;
  35174. }
  35175. - return 0;
  35176. +
  35177. + return i;
  35178. }
  35179.  
  35180. // engine callbacks
  35181. @@ -4516,7 +4470,7 @@ static enginefuncs_t gEngfuncs =
  35182. Cvar_DirectSet,
  35183. pfnForceUnmodified,
  35184. pfnGetPlayerStats,
  35185. - Cmd_AddGameCommand,
  35186. + Cmd_AddServerCommand,
  35187. pfnVoice_GetClientListening,
  35188. pfnVoice_SetClientListening,
  35189. pfnGetPlayerAuthId,
  35190. @@ -4782,8 +4736,8 @@ void SV_UnloadProgs( void )
  35191.  
  35192. // must unlink all game cvars,
  35193. // before pointers on them will be lost...
  35194. - Cmd_ExecuteString( "@unlink\n", src_command );
  35195. - Cmd_Unlink( CMD_EXTDLL );
  35196. + Cvar_Unlink( CVAR_SERVERDLL );
  35197. + Cmd_Unlink( CMD_SERVERDLL );
  35198.  
  35199. Mod_ResetStudioAPI ();
  35200.  
  35201. @@ -4876,7 +4830,7 @@ qboolean SV_LoadProgs( const char *name )
  35202. return false;
  35203. }
  35204. }
  35205. - else MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
  35206. + else MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
  35207. }
  35208. else if( !GetEntityAPI( &svgame.dllFuncs, version ))
  35209. {
  35210. diff --git b/engine/server/sv_init.c a/engine/server/sv_init.c
  35211. index d4ebc43..77fd89d 100644
  35212. --- b/engine/server/sv_init.c
  35213. +++ a/engine/server/sv_init.c
  35214. @@ -18,10 +18,17 @@ GNU General Public License for more details.
  35215.  
  35216. int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
  35217.  
  35218. +server_t sv; // local server
  35219. server_static_t svs; // persistant server info
  35220. svgame_static_t svgame; // persistant game info
  35221. -server_t sv; // local server
  35222.  
  35223. +/*
  35224. +================
  35225. +SV_ModelIndex
  35226. +
  35227. +register unique model for a server and client
  35228. +================
  35229. +*/
  35230. int SV_ModelIndex( const char *filename )
  35231. {
  35232. char name[64];
  35233. @@ -60,6 +67,13 @@ int SV_ModelIndex( const char *filename )
  35234. return i;
  35235. }
  35236.  
  35237. +/*
  35238. +================
  35239. +SV_SoundIndex
  35240. +
  35241. +register unique sound for client
  35242. +================
  35243. +*/
  35244. int SV_SoundIndex( const char *filename )
  35245. {
  35246. char name[64];
  35247. @@ -98,6 +112,13 @@ int SV_SoundIndex( const char *filename )
  35248. return i;
  35249. }
  35250.  
  35251. +/*
  35252. +================
  35253. +SV_EventIndex
  35254. +
  35255. +register network event for a server and client
  35256. +================
  35257. +*/
  35258. int SV_EventIndex( const char *filename )
  35259. {
  35260. char name[64];
  35261. @@ -135,6 +156,13 @@ int SV_EventIndex( const char *filename )
  35262. return i;
  35263. }
  35264.  
  35265. +/*
  35266. +================
  35267. +SV_GenericIndex
  35268. +
  35269. +register generic resourse for a server and client
  35270. +================
  35271. +*/
  35272. int SV_GenericIndex( const char *filename )
  35273. {
  35274. char name[64];
  35275. @@ -181,8 +209,8 @@ get entity script for current map
  35276. char *SV_EntityScript( void )
  35277. {
  35278. string entfilename;
  35279. - char *ents;
  35280. size_t ft1, ft2;
  35281. + char *ents;
  35282.  
  35283. if( !sv.worldmodel )
  35284. return NULL;
  35285. @@ -224,14 +252,11 @@ baseline will be transmitted
  35286. */
  35287. void SV_CreateBaseline( void )
  35288. {
  35289. - edict_t *pEdict;
  35290. int e;
  35291.  
  35292. for( e = 0; e < svgame.numEntities; e++ )
  35293. {
  35294. - pEdict = EDICT_NUM( e );
  35295. - if( !SV_IsValidEdict( pEdict )) continue;
  35296. - SV_BaselineForEntity( pEdict );
  35297. + SV_BaselineForEntity( EDICT_NUM( e ));
  35298. }
  35299.  
  35300. // create the instanced baselines
  35301. @@ -279,7 +304,6 @@ void SV_ActivateServer( void )
  35302. return;
  35303.  
  35304. // custom muzzleflashes
  35305. - pfnPrecacheModel( "sprites/muzzleflash.spr" );
  35306. pfnPrecacheModel( "sprites/muzzleflash1.spr" );
  35307. pfnPrecacheModel( "sprites/muzzleflash2.spr" );
  35308. pfnPrecacheModel( "sprites/muzzleflash3.spr" );
  35309. @@ -293,6 +317,26 @@ void SV_ActivateServer( void )
  35310. // Activate the DLL server code
  35311. svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svgame.globals->maxClients );
  35312.  
  35313. + if( sv.loadgame || svgame.globals->changelevel )
  35314. + {
  35315. + sv.frametime = 0.001;
  35316. + numFrames = 1;
  35317. + }
  35318. + else if( sv_maxclients->integer <= 1 )
  35319. + {
  35320. + sv.frametime = 0.1f;
  35321. + numFrames = 2;
  35322. + }
  35323. + else
  35324. + {
  35325. + sv.frametime = 0.1f;
  35326. + numFrames = 8;
  35327. + }
  35328. +
  35329. + // run some frames to allow everything to settle
  35330. + for( i = 0; i < numFrames; i++ )
  35331. + SV_Physics();
  35332. +
  35333. // create a baseline for more efficient communications
  35334. SV_CreateBaseline();
  35335.  
  35336. @@ -309,21 +353,6 @@ void SV_ActivateServer( void )
  35337. }
  35338. }
  35339.  
  35340. - numFrames = (sv.loadgame) ? 1 : 2;
  35341. - if( !sv.loadgame || svgame.globals->changelevel )
  35342. - host.frametime = 0.1f;
  35343. -
  35344. - // GoldSrc rules
  35345. - // NOTE: this stuff is breaking sound from func_rotating in multiplayer
  35346. - // e.g. ambience\boomer.wav on snark_pit.bsp
  35347. - numFrames *= sv_maxclients->integer;
  35348. -
  35349. - // run some frames to allow everything to settle
  35350. - for( i = 0; i < numFrames; i++ )
  35351. - {
  35352. - SV_Physics();
  35353. - }
  35354. -
  35355. // invoke to refresh all movevars
  35356. memset( &svgame.oldmovevars, 0, sizeof( movevars_t ));
  35357. svgame.globals->changelevel = false; // changelevel ends here
  35358. @@ -344,10 +373,9 @@ void SV_ActivateServer( void )
  35359. MsgDev( D_INFO, "Game started\n" );
  35360. }
  35361.  
  35362. + // dedicated server purge unused resources here
  35363. if( host.type == HOST_DEDICATED )
  35364. - {
  35365. Mod_FreeUnused ();
  35366. - }
  35367.  
  35368. sv.state = ss_active;
  35369. physinfo->modified = true;
  35370. @@ -356,10 +384,29 @@ void SV_ActivateServer( void )
  35371.  
  35372. Host_SetServerState( sv.state );
  35373.  
  35374. - if( sv_maxclients->integer > 1 && public_server->integer )
  35375. + if( sv_maxclients->integer > 1 )
  35376. {
  35377. - MsgDev( D_INFO, "Add your server, to master server list\n" );
  35378. - Master_Add( );
  35379. + // listenserver is executed on every map change in multiplayer
  35380. + if( host.type != HOST_DEDICATED )
  35381. + {
  35382. +#if 0
  35383. + // temporare disable because it's broken TFC multiplayer
  35384. + char *plservercfgfile = Cvar_VariableString( "lservercfgfile" );
  35385. + if( *plservercfgfile ) Cbuf_AddText( va( "exec %s\n", plservercfgfile ));
  35386. +#endif
  35387. + }
  35388. +
  35389. + if( public_server->integer )
  35390. + {
  35391. + MsgDev( D_INFO, "Adding your server to master server list\n" );
  35392. + Master_Add( );
  35393. + }
  35394. + }
  35395. +
  35396. + // mapchangecfgfile
  35397. + {
  35398. + char *mapchangecfgfile = Cvar_VariableString( "mapchangecfgfile" );
  35399. + if( *mapchangecfgfile ) Cbuf_AddText( va( "exec %s\n", mapchangecfgfile ));
  35400. }
  35401. }
  35402.  
  35403. @@ -379,13 +426,16 @@ void SV_DeactivateServer( void )
  35404.  
  35405. sv.state = ss_dead;
  35406.  
  35407. + svgame.dllFuncs.pfnServerDeactivate();
  35408. +
  35409. SV_FreeEdicts ();
  35410.  
  35411. SV_ClearPhysEnts ();
  35412.  
  35413. Mem_EmptyPool( svgame.stringspool );
  35414.  
  35415. - svgame.dllFuncs.pfnServerDeactivate();
  35416. + if( sv_maxclients->integer > 32 )
  35417. + Cvar_SetFloat( "maxplayers", 32.0f );
  35418.  
  35419. for( i = 0; i < sv_maxclients->integer; i++ )
  35420. {
  35421. @@ -473,7 +523,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
  35422. if( sv.state == ss_dead )
  35423. SV_InitGame(); // the game is just starting
  35424. else if( !sv_maxclients->modified )
  35425. - Cmd_ExecuteString( "latch\n", src_command );
  35426. + Cmd_ExecuteString( "latch\n" );
  35427. else MsgDev( D_ERROR, "SV_SpawnServer: while 'maxplayers' was modified.\n" );
  35428.  
  35429. sv_maxclients->modified = false;
  35430. @@ -510,8 +560,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
  35431. svgame.globals->time = sv.time;
  35432.  
  35433. // initialize buffers
  35434. - MSG_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf ));
  35435. - MSG_Init( &sv.reliable_datagram, "Datagram R", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
  35436. + MSG_Init( &sv.reliable_datagram, "Reliable Datagram", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
  35437. MSG_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
  35438. MSG_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
  35439. MSG_Init( &sv.spectator_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
  35440. @@ -568,9 +617,6 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
  35441. // clear physics interaction links
  35442. SV_ClearWorld();
  35443.  
  35444. - // tell dlls about new level started
  35445. - svgame.dllFuncs.pfnParmsNewLevel();
  35446. -
  35447. return true;
  35448. }
  35449.  
  35450. @@ -584,7 +630,7 @@ A brand new game has been started
  35451. void SV_InitGame( void )
  35452. {
  35453. edict_t *ent;
  35454. - int i;
  35455. + int i, load = sv.loadgame;
  35456.  
  35457. if( svs.initialized )
  35458. {
  35459. @@ -609,7 +655,7 @@ void SV_InitGame( void )
  35460. }
  35461.  
  35462. // now apply latched commands
  35463. - Cmd_ExecuteString( "latch\n", src_command );
  35464. + Cmd_ExecuteString( "latch\n" );
  35465.  
  35466. if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" ))
  35467. {
  35468. @@ -649,9 +695,10 @@ void SV_InitGame( void )
  35469. SV_UPDATE_BACKUP = ( svgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
  35470.  
  35471. svs.clients = Z_Malloc( sizeof( sv_client_t ) * sv_maxclients->integer );
  35472. - svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * 64;
  35473. + svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
  35474. svs.packet_entities = Z_Malloc( sizeof( entity_state_t ) * svs.num_client_entities );
  35475. svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
  35476. + if( !load ) MsgDev( D_INFO, "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
  35477.  
  35478. // client frames will be allocated in SV_DirectConnect
  35479.  
  35480. @@ -661,7 +708,7 @@ void SV_InitGame( void )
  35481. // copy gamemode into svgame.globals
  35482. svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
  35483. svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
  35484. - svgame.globals->coop = Cvar_VariableInteger( "coop" );
  35485. + svgame.globals->coop = ( sv_maxclients->integer > 1 ) ? Cvar_VariableInteger( "coop" ) : 0;
  35486.  
  35487. // heartbeats will always be sent to the id master
  35488. svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
  35489. @@ -671,8 +718,8 @@ void SV_InitGame( void )
  35490. {
  35491. // setup all the clients
  35492. ent = EDICT_NUM( i + 1 );
  35493. - SV_InitEdict( ent );
  35494. svs.clients[i].edict = ent;
  35495. + SV_InitEdict( ent );
  35496. }
  35497.  
  35498. // get actual movevars
  35499. diff --git b/engine/server/sv_main.c a/engine/server/sv_main.c
  35500. index 45c0546..2033d2f 100644
  35501. --- b/engine/server/sv_main.c
  35502. +++ a/engine/server/sv_main.c
  35503. @@ -113,7 +113,7 @@ void SV_CalcPings( void )
  35504. {
  35505. cl = &svs.clients[i];
  35506.  
  35507. - if( cl->state != cs_spawned || cl->fakeclient )
  35508. + if( cl->state != cs_spawned || FBitSet( cl->flags, FCL_FAKECLIENT ))
  35509. continue;
  35510.  
  35511. total = count = 0;
  35512. @@ -152,7 +152,7 @@ int SV_CalcPacketLoss( sv_client_t *cl )
  35513. lost = 0;
  35514. count = 0;
  35515.  
  35516. - if( cl->fakeclient )
  35517. + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
  35518. return 0;
  35519.  
  35520. numsamples = SV_UPDATE_BACKUP / 2;
  35521. @@ -160,9 +160,9 @@ int SV_CalcPacketLoss( sv_client_t *cl )
  35522. for( i = 0; i < numsamples; i++ )
  35523. {
  35524. frame = &cl->frames[(cl->netchan.incoming_acknowledged - 1 - i) & SV_UPDATE_MASK];
  35525. - count++;
  35526. if( frame->latency == -1 )
  35527. lost++;
  35528. + count++;
  35529. }
  35530.  
  35531. if( !count ) return 100;
  35532. @@ -208,7 +208,18 @@ void SV_UpdateMovevars( qboolean initialize )
  35533.  
  35534. // check range
  35535. if( sv_zmax->value < 256.0f ) Cvar_SetFloat( "sv_zmax", 256.0f );
  35536. - if( sv_zmax->value > 131070.0f ) Cvar_SetFloat( "sv_zmax", 131070.0f );
  35537. +
  35538. + // clamp it right
  35539. + if( host.features & ENGINE_WRITE_LARGE_COORD )
  35540. + {
  35541. + if( sv_zmax->value > 131070.0f )
  35542. + Cvar_SetFloat( "sv_zmax", 131070.0f );
  35543. + }
  35544. + else
  35545. + {
  35546. + if( sv_zmax->value > 32767.0f )
  35547. + Cvar_SetFloat( "sv_zmax", 32767.0f );
  35548. + }
  35549.  
  35550. svgame.movevars.gravity = sv_gravity->value;
  35551. svgame.movevars.stopspeed = sv_stopspeed->value;
  35552. @@ -320,7 +331,8 @@ SV_ReadPackets
  35553. void SV_ReadPackets( void )
  35554. {
  35555. sv_client_t *cl;
  35556. - int i, qport, curSize;
  35557. + int i, qport;
  35558. + size_t curSize;
  35559.  
  35560. while( NET_GetPacket( NS_SERVER, &net_from, net_message_buffer, &curSize ))
  35561. {
  35562. @@ -329,7 +341,22 @@ void SV_ReadPackets( void )
  35563. // check for connectionless packet (0xffffffff) first
  35564. if( MSG_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 )
  35565. {
  35566. - SV_ConnectionlessPacket( net_from, &net_message );
  35567. + if( !svs.initialized )
  35568. + {
  35569. + char *args, *c;
  35570. +
  35571. + MSG_Clear( &net_message );
  35572. + MSG_ReadLong( &net_message );// skip the -1 marker
  35573. +
  35574. + args = MSG_ReadStringLine( &net_message );
  35575. + Cmd_TokenizeString( args );
  35576. + c = Cmd_Argv( 0 );
  35577. +
  35578. + if( !Q_strcmp( c, "rcon" ))
  35579. + SV_RemoteCommand( net_from, &net_message );
  35580. + }
  35581. + else SV_ConnectionlessPacket( net_from, &net_message );
  35582. +
  35583. continue;
  35584. }
  35585.  
  35586. @@ -343,7 +370,7 @@ void SV_ReadPackets( void )
  35587. // check for packets from connected clients
  35588. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  35589. {
  35590. - if( cl->state == cs_free || cl->fakeclient )
  35591. + if( cl->state == cs_free || FBitSet( cl->flags, FCL_FAKECLIENT ))
  35592. continue;
  35593.  
  35594. if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address ))
  35595. @@ -354,21 +381,21 @@ void SV_ReadPackets( void )
  35596.  
  35597. if( cl->netchan.remote_address.port != net_from.port )
  35598. {
  35599. - MsgDev( D_INFO, "SV_ReadPackets: fixing up a translated port\n");
  35600. + MsgDev( D_NOTE, "SV_ReadPackets: fixing up a translated port\n");
  35601. cl->netchan.remote_address.port = net_from.port;
  35602. }
  35603.  
  35604. if( Netchan_Process( &cl->netchan, &net_message ))
  35605. {
  35606. - if( sv_maxclients->integer == 1 || cl->state != cs_spawned )
  35607. - cl->send_message = true; // reply at end of frame
  35608. + if(( sv_maxclients->integer == 1 && !FBitSet( host.features, ENGINE_FIXED_FRAMERATE )) || cl->state != cs_spawned )
  35609. + SetBits( cl->flags, FCL_SEND_NET_MESSAGE ); // reply at end of frame
  35610.  
  35611. // this is a valid, sequenced packet, so process it
  35612. if( cl->state != cs_zombie )
  35613. {
  35614. cl->lastmessage = host.realtime; // don't timeout
  35615. SV_ExecuteClientMessage( cl, &net_message );
  35616. - svgame.globals->frametime = host.frametime;
  35617. + svgame.globals->frametime = sv.frametime;
  35618. svgame.globals->time = sv.time;
  35619. }
  35620. }
  35621. @@ -393,6 +420,9 @@ void SV_ReadPackets( void )
  35622. if( i != sv_maxclients->integer )
  35623. continue;
  35624. }
  35625. +
  35626. + svs.currentPlayer = NULL;
  35627. + svs.currentPlayerNum = -1;
  35628. }
  35629.  
  35630. /*
  35631. @@ -422,12 +452,13 @@ void SV_CheckTimeouts( void )
  35632. {
  35633. if( cl->state >= cs_connected )
  35634. {
  35635. - if( cl->edict && !( cl->edict->v.flags & (FL_SPECTATOR|FL_FAKECLIENT)))
  35636. + if( cl->edict && !FBitSet( cl->edict->v.flags, FL_SPECTATOR|FL_FAKECLIENT ))
  35637. numclients++;
  35638. }
  35639.  
  35640. // fake clients do not timeout
  35641. - if( cl->fakeclient ) cl->lastmessage = host.realtime;
  35642. + if( FBitSet( cl->flags, FCL_FAKECLIENT ))
  35643. + cl->lastmessage = host.realtime;
  35644.  
  35645. // message times may be wrong across a changelevel
  35646. if( cl->lastmessage > host.realtime )
  35647. @@ -439,11 +470,14 @@ void SV_CheckTimeouts( void )
  35648. continue;
  35649. }
  35650.  
  35651. - if(( cl->state == cs_connected || cl->state == cs_spawned ) && cl->lastmessage < droppoint && !NET_IsLocalAddress( cl->netchan.remote_address ))
  35652. + if(( cl->state == cs_connected || cl->state == cs_spawned ) && cl->lastmessage < droppoint )
  35653. {
  35654. - SV_BroadcastPrintf( PRINT_HIGH, "%s timed out\n", cl->name );
  35655. - SV_DropClient( cl );
  35656. - cl->state = cs_free; // don't bother with zombie state
  35657. + if( !NET_IsLocalAddress( cl->netchan.remote_address ))
  35658. + {
  35659. + SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s timed out\n", cl->name );
  35660. + SV_DropClient( cl );
  35661. + cl->state = cs_free; // don't bother with zombie state
  35662. + }
  35663. }
  35664. }
  35665.  
  35666. @@ -472,7 +506,7 @@ void SV_PrepWorldFrame( void )
  35667. ent = EDICT_NUM( i );
  35668. if( ent->free ) continue;
  35669.  
  35670. - ent->v.effects &= ~(EF_MUZZLEFLASH|EF_NOINTERP);
  35671. + ClearBits( ent->v.effects, EF_MUZZLEFLASH|EF_NOINTERP );
  35672. }
  35673. }
  35674.  
  35675. @@ -501,12 +535,15 @@ qboolean SV_IsSimulating( void )
  35676. return true; // force simulating for background map
  35677. }
  35678.  
  35679. - if( sv.hostflags & SVF_PLAYERSONLY )
  35680. + if( FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
  35681. return false;
  35682. +
  35683. if( !SV_HasActivePlayers())
  35684. return false;
  35685. +
  35686. if( !sv.paused && CL_IsInGame( ))
  35687. return true;
  35688. +
  35689. return false;
  35690. }
  35691.  
  35692. @@ -515,13 +552,38 @@ qboolean SV_IsSimulating( void )
  35693. SV_RunGameFrame
  35694. =================
  35695. */
  35696. -void SV_RunGameFrame( void )
  35697. +/*
  35698. +=================
  35699. +SV_RunGameFrame
  35700. +=================
  35701. +*/
  35702. +qboolean SV_RunGameFrame( void )
  35703. {
  35704. - if( !SV_IsSimulating( )) return;
  35705. + int numFrames = 0;
  35706.  
  35707. - SV_Physics();
  35708. + if( !( sv.simulating = SV_IsSimulating( )))
  35709. + return true;
  35710.  
  35711. - sv.time += host.frametime;
  35712. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  35713. + {
  35714. + while( sv.time_residual >= sv.frametime )
  35715. + {
  35716. + SV_Physics();
  35717. +
  35718. + sv.time_residual -= sv.frametime;
  35719. + sv.time += sv.frametime;
  35720. + numFrames++;
  35721. + }
  35722. + return (numFrames != 0);
  35723. + }
  35724. + else
  35725. + {
  35726. + SV_Physics();
  35727. +
  35728. + sv.time += sv.frametime;
  35729. +
  35730. + return true;
  35731. + }
  35732. }
  35733.  
  35734. /*
  35735. @@ -535,7 +597,14 @@ void Host_ServerFrame( void )
  35736. // if server is not active, do nothing
  35737. if( !svs.initialized ) return;
  35738.  
  35739. - svgame.globals->frametime = host.frametime;
  35740. + if( FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
  35741. + sv.frametime = ( 1.0 / (double)( GAME_FPS - 0.01 )); // FP issues
  35742. + else sv.frametime = host.frametime;
  35743. +
  35744. + if( sv.simulating || sv.state != ss_active )
  35745. + sv.time_residual += host.frametime;
  35746. +
  35747. + svgame.globals->frametime = sv.frametime;
  35748.  
  35749. // check timeouts
  35750. SV_CheckTimeouts ();
  35751. @@ -556,7 +625,7 @@ void Host_ServerFrame( void )
  35752. SV_UpdateMovevars ( false );
  35753.  
  35754. // let everything in the world think and move
  35755. - SV_RunGameFrame ();
  35756. + if( !SV_RunGameFrame ()) return;
  35757.  
  35758. // send messages back to the clients that had packets read this frame
  35759. SV_SendClientMessages ();
  35760. @@ -584,7 +653,7 @@ void Master_Add( void )
  35761. if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
  35762. MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
  35763.  
  35764. - NET_SendPacket( NS_SERVER, 1, "q", adr );
  35765. + NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
  35766. }
  35767.  
  35768. /*
  35769. @@ -631,6 +700,54 @@ void Master_Shutdown( void )
  35770. NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
  35771. }
  35772.  
  35773. +/*
  35774. +=================
  35775. +SV_AddToMaster
  35776. +
  35777. +A server info answer to master server.
  35778. +Master will validate challenge and this server to public list
  35779. +=================
  35780. +*/
  35781. +void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
  35782. +{
  35783. + uint challenge;
  35784. + char s[MAX_INFO_STRING] = "0\n"; // skip 2 bytes of header
  35785. + int clients = 0, bots = 0, index;
  35786. +
  35787. + if( svs.clients )
  35788. + {
  35789. + for( index = 0; index < sv_maxclients->integer; index++ )
  35790. + {
  35791. + if( svs.clients[index].state >= cs_connected )
  35792. + {
  35793. + if( FBitSet( svs.clients[index].flags, FCL_FAKECLIENT ))
  35794. + bots++;
  35795. + else clients++;
  35796. + }
  35797. + }
  35798. + }
  35799. +
  35800. + challenge = MSG_ReadUBitLong( msg, sizeof( uint ) << 3 );
  35801. +
  35802. + Info_SetValueForKey( s, "protocol", va( "%d", PROTOCOL_VERSION ) ); // protocol version
  35803. + Info_SetValueForKey( s, "challenge", va( "%u", challenge ) ); // challenge number
  35804. + Info_SetValueForKey( s, "players", va( "%d", clients ) ); // current player number, without bots
  35805. + Info_SetValueForKey( s, "max", sv_maxclients->string ); // max_players
  35806. + Info_SetValueForKey( s, "bots", va( "%d", bots ) ); // bot count
  35807. + Info_SetValueForKey( s, "gamedir", GI->gamedir ); // gamedir
  35808. + Info_SetValueForKey( s, "map", sv.name ); // current map
  35809. + Info_SetValueForKey( s, "type", (host.type == HOST_DEDICATED) ? "d" : "l" ); // dedicated or local
  35810. + Info_SetValueForKey( s, "password", "0" ); // is password set
  35811. + Info_SetValueForKey( s, "os", "w" ); // Windows
  35812. + Info_SetValueForKey( s, "secure", "0" ); // server anti-cheat
  35813. + Info_SetValueForKey( s, "lan", "0" ); // LAN servers doesn't send info to master
  35814. + Info_SetValueForKey( s, "version", va( "%g", XASH_VERSION )); // server region. 255 -- all regions
  35815. + Info_SetValueForKey( s, "region", "255" ); // server region. 255 -- all regions
  35816. + Info_SetValueForKey( s, "product", GI->gamefolder ); // product? Where is the difference with gamedir?
  35817. +
  35818. + NET_SendPacket( NS_SERVER, Q_strlen( s ), s, from );
  35819. +}
  35820. +
  35821. //============================================================================
  35822.  
  35823. /*
  35824. @@ -773,11 +890,11 @@ void SV_FinalMessage( char *message, qboolean reconnect )
  35825. // send it twice
  35826. // stagger the packets to crutch operating system limited buffers
  35827. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  35828. - if( cl->state >= cs_connected && !cl->fakeclient )
  35829. + if( cl->state >= cs_connected && !FBitSet( cl->flags, FCL_FAKECLIENT ))
  35830. Netchan_Transmit( &cl->netchan, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ));
  35831.  
  35832. for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
  35833. - if( cl->state >= cs_connected && !cl->fakeclient )
  35834. + if( cl->state >= cs_connected && !FBitSet( cl->flags, FCL_FAKECLIENT ))
  35835. Netchan_Transmit( &cl->netchan, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ));
  35836. }
  35837.  
  35838. diff --git b/engine/server/sv_phys.c a/engine/server/sv_phys.c
  35839. index 7e6a23d..2c3ee29 100644
  35840. --- b/engine/server/sv_phys.c
  35841. +++ a/engine/server/sv_phys.c
  35842. @@ -66,12 +66,19 @@ SV_CheckAllEnts
  35843. */
  35844. void SV_CheckAllEnts( void )
  35845. {
  35846. - edict_t *e;
  35847. - int i;
  35848. + static double nextcheck;
  35849. + edict_t *e;
  35850. + int i;
  35851.  
  35852. if( !sv_check_errors->integer || sv.state != ss_active )
  35853. return;
  35854.  
  35855. + if(( nextcheck - Sys_DoubleTime()) > 0.0 )
  35856. + return;
  35857. +
  35858. + // don't check entities every frame (but every 5 secs)
  35859. + nextcheck = Sys_DoubleTime() + 5.0;
  35860. +
  35861. // check edicts errors
  35862. for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
  35863. {
  35864. @@ -193,7 +200,7 @@ qboolean SV_RunThink( edict_t *ent )
  35865. if(!( ent->v.flags & FL_KILLME ))
  35866. {
  35867. thinktime = ent->v.nextthink;
  35868. - if( thinktime <= 0.0f || thinktime > sv.time + host.frametime )
  35869. + if( thinktime <= 0.0f || thinktime > sv.time + sv.frametime )
  35870. return true;
  35871.  
  35872. if( thinktime < sv.time )
  35873. @@ -225,21 +232,23 @@ qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time )
  35874. {
  35875. float thinktime;
  35876.  
  35877. - if(!( ent->v.flags & (FL_KILLME|FL_DORMANT )))
  35878. + if( !FBitSet( ent->v.flags, FL_KILLME|FL_DORMANT ))
  35879. {
  35880. thinktime = ent->v.nextthink;
  35881. - if( thinktime <= 0.0f || thinktime > time + frametime )
  35882. + if( thinktime <= 0.0f || (time + frametime) < thinktime )
  35883. return true;
  35884.  
  35885. - if( thinktime > time )
  35886. - thinktime = time;
  35887. + if( thinktime < time )
  35888. + thinktime = time; // don't let things stay in the past.
  35889. + // it is possible to start that way
  35890. + // by a trigger with a local time.
  35891.  
  35892. ent->v.nextthink = 0.0f;
  35893. svgame.globals->time = thinktime;
  35894. svgame.dllFuncs.pfnThink( ent );
  35895. }
  35896.  
  35897. - if( ent->v.flags & FL_KILLME )
  35898. + if( FBitSet( ent->v.flags, FL_KILLME ))
  35899. SV_FreeEdict( ent );
  35900.  
  35901. return !ent->free;
  35902. @@ -696,8 +705,8 @@ void SV_AddGravity( edict_t *ent )
  35903. else ent_gravity = 1.0f;
  35904.  
  35905. // add gravity incorrectly
  35906. - ent->v.velocity[2] -= ( ent_gravity * sv_gravity->value * host.frametime );
  35907. - ent->v.velocity[2] += ( ent->v.basevelocity[2] * host.frametime );
  35908. + ent->v.velocity[2] -= ( ent_gravity * sv_gravity->value * sv.frametime );
  35909. + ent->v.velocity[2] += ( ent->v.basevelocity[2] * sv.frametime );
  35910. ent->v.basevelocity[2] = 0.0f;
  35911.  
  35912. // bound velocity
  35913. @@ -720,7 +729,7 @@ void SV_AddHalfGravity( edict_t *ent, float timestep )
  35914.  
  35915. // Add 1/2 of the total gravitational effects over this timestep
  35916. ent->v.velocity[2] -= ( 0.5f * ent_gravity * sv_gravity->value * timestep );
  35917. - ent->v.velocity[2] += ( ent->v.basevelocity[2] * host.frametime );
  35918. + ent->v.velocity[2] += ( ent->v.basevelocity[2] * sv.frametime );
  35919. ent->v.basevelocity[2] = 0.0f;
  35920.  
  35921. // bound velocity
  35922. @@ -1121,12 +1130,12 @@ void SV_Physics_Pusher( edict_t *ent )
  35923. oldtime = ent->v.ltime;
  35924. thinktime = ent->v.nextthink;
  35925.  
  35926. - if( thinktime < oldtime + host.frametime )
  35927. + if( thinktime < oldtime + sv.frametime )
  35928. {
  35929. movetime = thinktime - oldtime;
  35930. if( movetime < 0.0f ) movetime = 0.0f;
  35931. }
  35932. - else movetime = host.frametime;
  35933. + else movetime = sv.frametime;
  35934.  
  35935. if( movetime )
  35936. {
  35937. @@ -1240,7 +1249,7 @@ void SV_Physics_Compound( edict_t *ent )
  35938. {
  35939. VectorCopy( parent->v.origin, ent->v.oldorigin );
  35940. VectorCopy( parent->v.angles, ent->v.avelocity );
  35941. - ent->v.ltime = host.frametime;
  35942. + ent->v.ltime = sv.frametime;
  35943. return;
  35944. }
  35945.  
  35946. @@ -1296,8 +1305,8 @@ void SV_Physics_Noclip( edict_t *ent )
  35947.  
  35948. SV_CheckWater( ent );
  35949.  
  35950. - VectorMA( ent->v.origin, host.frametime, ent->v.velocity, ent->v.origin );
  35951. - VectorMA( ent->v.angles, host.frametime, ent->v.avelocity, ent->v.angles );
  35952. + VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin );
  35953. + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles );
  35954.  
  35955. // noclip ents never touch triggers
  35956. SV_LinkEdict( ent, false );
  35957. @@ -1437,10 +1446,10 @@ void SV_Physics_Toss( edict_t *ent )
  35958. {
  35959. case MOVETYPE_TOSS:
  35960. case MOVETYPE_BOUNCE:
  35961. - SV_AngularMove( ent, host.frametime, ent->v.friction );
  35962. + SV_AngularMove( ent, sv.frametime, ent->v.friction );
  35963. break;
  35964. default:
  35965. - SV_AngularMove( ent, host.frametime, 0.0f );
  35966. + SV_AngularMove( ent, sv.frametime, 0.0f );
  35967. break;
  35968. }
  35969.  
  35970. @@ -1450,7 +1459,7 @@ void SV_Physics_Toss( edict_t *ent )
  35971. VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
  35972.  
  35973. SV_CheckVelocity( ent );
  35974. - VectorScale( ent->v.velocity, host.frametime, move );
  35975. + VectorScale( ent->v.velocity, sv.frametime, move );
  35976.  
  35977. VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
  35978.  
  35979. @@ -1489,7 +1498,7 @@ void SV_Physics_Toss( edict_t *ent )
  35980. VectorAdd( ent->v.velocity, ent->v.basevelocity, move );
  35981. vel = DotProduct( move, move );
  35982.  
  35983. - if( ent->v.velocity[2] < sv_gravity->value * host.frametime )
  35984. + if( ent->v.velocity[2] < sv_gravity->value * sv.frametime )
  35985. {
  35986. // we're rolling on the ground, add static friction.
  35987. ent->v.groundentity = trace.ent;
  35988. @@ -1506,8 +1515,8 @@ void SV_Physics_Toss( edict_t *ent )
  35989. }
  35990. else
  35991. {
  35992. - VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move );
  35993. - VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move );
  35994. + VectorScale( ent->v.velocity, (1.0f - trace.fraction) * sv.frametime * 0.9f, move );
  35995. + VectorMA( move, (1.0f - trace.fraction) * sv.frametime * 0.9f, ent->v.basevelocity, move );
  35996. trace = SV_PushEntity( ent, move, vec3_origin, NULL );
  35997. if( ent->free ) return;
  35998. }
  35999. @@ -1554,7 +1563,7 @@ void SV_Physics_Step( edict_t *ent )
  36000.  
  36001. if( ent->v.flags & FL_FLOAT && ent->v.waterlevel > 0 )
  36002. {
  36003. - float buoyancy = SV_Submerged( ent ) * ent->v.skin * host.frametime;
  36004. + float buoyancy = SV_Submerged( ent ) * ent->v.skin * sv.frametime;
  36005.  
  36006. SV_AddGravity( ent );
  36007. ent->v.velocity[2] += buoyancy;
  36008. @@ -1585,7 +1594,7 @@ void SV_Physics_Step( edict_t *ent )
  36009. if( wasonmover ) friction *= 0.5f; // add a little friction
  36010.  
  36011. control = (speed < sv_stopspeed->value) ? sv_stopspeed->value : speed;
  36012. - newspeed = speed - (host.frametime * control * friction);
  36013. + newspeed = speed - (sv.frametime * control * friction);
  36014. if( newspeed < 0 ) newspeed = 0;
  36015. newspeed /= speed;
  36016.  
  36017. @@ -1597,7 +1606,7 @@ void SV_Physics_Step( edict_t *ent )
  36018. VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );
  36019. SV_CheckVelocity( ent );
  36020.  
  36021. - SV_FlyMove( ent, host.frametime, NULL );
  36022. + SV_FlyMove( ent, sv.frametime, NULL );
  36023. if( ent->free ) return;
  36024.  
  36025. SV_CheckVelocity( ent );
  36026. @@ -1678,7 +1687,7 @@ static void SV_Physics_Entity( edict_t *ent )
  36027. if(!( ent->v.flags & FL_BASEVELOCITY ) && !VectorIsNull( ent->v.basevelocity ))
  36028. {
  36029. // Apply momentum (add in half of the previous frame of velocity first)
  36030. - VectorMA( ent->v.velocity, 1.0f + (host.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
  36031. + VectorMA( ent->v.velocity, 1.0f + (sv.frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
  36032. VectorClear( ent->v.basevelocity );
  36033. }
  36034.  
  36035. @@ -1770,7 +1779,7 @@ void SV_Physics( void )
  36036. if( sv_skyspeed->value )
  36037. {
  36038. // evaluate sky rotation.
  36039. - float skyAngle = sv_skyangle->value + sv_skyspeed->value * host.frametime;
  36040. + float skyAngle = sv_skyangle->value + sv_skyspeed->value * sv.frametime;
  36041. Cvar_SetFloat( "sv_skyangle", anglemod( skyAngle ));
  36042. }
  36043.  
  36044. @@ -1802,7 +1811,7 @@ Inplementation for new physics interface
  36045. */
  36046. double SV_GetFrameTime( void )
  36047. {
  36048. - return host.frametime;
  36049. + return sv.frametime;
  36050. }
  36051.  
  36052. /*
  36053. @@ -1919,9 +1928,46 @@ static void *pfnMem_Alloc( size_t cb, const char *filename, const int fileline )
  36054.  
  36055. static void pfnMem_Free( void *mem, const char *filename, const int fileline )
  36056. {
  36057. + if( !mem ) return;
  36058. _Mem_Free( mem, filename, fileline );
  36059. }
  36060.  
  36061. +/*
  36062. +=============
  36063. +pfnPointContents
  36064. +
  36065. +=============
  36066. +*/
  36067. +static int pfnPointContents( const float *pos, int groupmask )
  36068. +{
  36069. + int oldmask, cont;
  36070. +
  36071. + if( !pos ) return CONTENTS_NONE;
  36072. + oldmask = svs.groupmask;
  36073. +
  36074. + svs.groupmask = groupmask;
  36075. + cont = SV_PointContents( pos );
  36076. + svs.groupmask = oldmask; // restore old mask
  36077. +
  36078. + return cont;
  36079. +}
  36080. +
  36081. +const byte *pfnLoadImagePixels( const char *filename, int *width, int *height )
  36082. +{
  36083. + rgbdata_t *pic = FS_LoadImage( filename, NULL, 0 );
  36084. + byte *buffer;
  36085. +
  36086. + if( !pic ) return NULL;
  36087. +
  36088. + buffer = Mem_Alloc( svgame.mempool, pic->size );
  36089. + if( buffer ) memcpy( buffer, pic->buffer, pic->size );
  36090. + if( width ) *width = pic->width;
  36091. + if( height ) *height = pic->height;
  36092. + FS_FreeImage( pic );
  36093. +
  36094. + return buffer;
  36095. +}
  36096. +
  36097. static server_physics_api_t gPhysicsAPI =
  36098. {
  36099. SV_LinkEdict,
  36100. @@ -1944,6 +1990,16 @@ static server_physics_api_t gPhysicsAPI =
  36101. GL_TextureData,
  36102. pfnMem_Alloc,
  36103. pfnMem_Free,
  36104. + pfnPointContents,
  36105. + SV_Move,
  36106. + SV_MoveNoEnts,
  36107. + SV_BoxInPVS,
  36108. + pfnWriteBytes,
  36109. + Mod_CheckLump,
  36110. + Mod_ReadLump,
  36111. + Mod_SaveLump,
  36112. + COM_SaveFile,
  36113. + pfnLoadImagePixels,
  36114. };
  36115.  
  36116. /*
  36117. @@ -1962,7 +2018,7 @@ qboolean SV_InitPhysicsAPI( void )
  36118. {
  36119. if( pPhysIface( SV_PHYSICS_INTERFACE_VERSION, &gPhysicsAPI, &svgame.physFuncs ))
  36120. {
  36121. - MsgDev( D_AICONSOLE, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
  36122. + MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
  36123.  
  36124. if( svgame.physFuncs.SV_CheckFeatures != NULL )
  36125. {
  36126. diff --git b/engine/server/sv_pmove.c a/engine/server/sv_pmove.c
  36127. index c478875..6137912 100644
  36128. --- b/engine/server/sv_pmove.c
  36129. +++ a/engine/server/sv_pmove.c
  36130. @@ -148,7 +148,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
  36131.  
  36132. void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
  36133. {
  36134. - if( !cl->lag_compensation || !sv_unlag->integer )
  36135. + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag->integer )
  36136. return;
  36137.  
  36138. // don't allow unlag in singleplayer
  36139. @@ -165,7 +165,7 @@ void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin )
  36140.  
  36141. void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs )
  36142. {
  36143. - if( !cl->lag_compensation || !sv_unlag->integer )
  36144. + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ) || !sv_unlag->integer )
  36145. return;
  36146.  
  36147. // don't allow unlag in singleplayer
  36148. @@ -225,12 +225,12 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
  36149. continue;
  36150.  
  36151. // ignore monsterclip brushes
  36152. - if(( check->v.flags & FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
  36153. + if( FBitSet( check->v.flags, FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
  36154. continue;
  36155.  
  36156. if( check == pl ) continue; // himself
  36157.  
  36158. - if((( check->v.flags & FL_CLIENT ) && check->v.health <= 0 ) || check->v.deadflag == DEAD_DEAD )
  36159. + if(( FBitSet( check->v.flags, FL_CLIENT|FL_FAKECLIENT ) && check->v.health <= 0.0f ) || check->v.deadflag == DEAD_DEAD )
  36160. continue; // dead body
  36161.  
  36162. if( VectorIsNull( check->v.size ))
  36163. @@ -239,7 +239,7 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
  36164. VectorCopy( check->v.absmin, mins );
  36165. VectorCopy( check->v.absmax, maxs );
  36166.  
  36167. - if( check->v.flags & FL_CLIENT )
  36168. + if( FBitSet( check->v.flags, FL_CLIENT ))
  36169. {
  36170. // trying to get interpolated values
  36171. if( svs.currentPlayer )
  36172. @@ -478,7 +478,7 @@ static void pfnPlaySound( int channel, const char *sample, float volume, float a
  36173. ent = EDICT_NUM( svgame.pmove->player_index + 1 );
  36174. if( !SV_IsValidEdict( ent )) return;
  36175.  
  36176. - SV_StartSound( ent, channel, sample, volume, attenuation, fFlags, pitch );
  36177. + SV_StartSound( ent, channel, sample, volume, attenuation, fFlags|SND_FILTER_CLIENT, pitch );
  36178. }
  36179.  
  36180. static void pfnPlaybackEventFull( int flags, int clientindex, word eventindex, float delay, float *origin,
  36181. @@ -620,14 +620,14 @@ static void PM_CheckMovingGround( edict_t *ent, float frametime )
  36182. SV_UpdateBaseVelocity( ent );
  36183. }
  36184.  
  36185. - if( !( ent->v.flags & FL_BASEVELOCITY ))
  36186. + if( !FBitSet( ent->v.flags, FL_BASEVELOCITY ))
  36187. {
  36188. // apply momentum (add in half of the previous frame of velocity first)
  36189. VectorMA( ent->v.velocity, 1.0f + (frametime * 0.5f), ent->v.basevelocity, ent->v.velocity );
  36190. VectorClear( ent->v.basevelocity );
  36191. }
  36192.  
  36193. - ent->v.flags &= ~FL_BASEVELOCITY;
  36194. + ClearBits( ent->v.flags, FL_BASEVELOCITY );
  36195. }
  36196.  
  36197. static void SV_SetupPMove( playermove_t *pmove, sv_client_t *cl, usercmd_t *ucmd, const char *physinfo )
  36198. @@ -827,7 +827,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
  36199. return;
  36200.  
  36201. // unlag disabled for current client
  36202. - if( !cl->lag_compensation )
  36203. + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ))
  36204. return;
  36205.  
  36206. has_update = true;
  36207. @@ -986,7 +986,7 @@ void SV_RestoreMoveInterpolant( sv_client_t *cl )
  36208. return;
  36209.  
  36210. // unlag disabled for current client
  36211. - if( !cl->lag_compensation )
  36212. + if( !FBitSet( cl->flags, FCL_LAG_COMPENSATION ))
  36213. return;
  36214.  
  36215. for( i = 0, check = svs.clients; i < sv_maxclients->integer; i++, check++ )
  36216. @@ -1050,7 +1050,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
  36217. return;
  36218. }
  36219.  
  36220. - if( !cl->fakeclient )
  36221. + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
  36222. {
  36223. SV_SetupMoveInterpolant( cl );
  36224. }
  36225. @@ -1095,29 +1095,37 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
  36226.  
  36227. // copy results back to client
  36228. SV_FinishPMove( svgame.pmove, cl );
  36229. -
  36230. - // link into place and touch triggers
  36231. - SV_LinkEdict( clent, true );
  36232. - VectorCopy( clent->v.velocity, oldvel ); // save velocity
  36233.  
  36234. - // touch other objects
  36235. - for( i = 0; i < svgame.pmove->numtouch; i++ )
  36236. + if( svgame.physFuncs.PM_PlayerTouch != NULL )
  36237. {
  36238. - // never touch the objects when "playersonly" is active
  36239. - if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
  36240. - break;
  36241. + // run custom impact function
  36242. + svgame.physFuncs.PM_PlayerTouch( svgame.pmove, clent );
  36243. + }
  36244. + else
  36245. + {
  36246. + // link into place and touch triggers
  36247. + SV_LinkEdict( clent, true );
  36248. + VectorCopy( clent->v.velocity, oldvel ); // save velocity
  36249.  
  36250. - pmtrace = &svgame.pmove->touchindex[i];
  36251. - touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
  36252. - if( touch == clent ) continue;
  36253. + // touch other objects
  36254. + for( i = 0; i < svgame.pmove->numtouch; i++ )
  36255. + {
  36256. + // never touch the objects when "playersonly" is active
  36257. + if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
  36258. + break;
  36259.  
  36260. - VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
  36261. - SV_ConvertPMTrace( &trace, pmtrace, touch );
  36262. - SV_Impact( touch, clent, &trace );
  36263. - }
  36264. + pmtrace = &svgame.pmove->touchindex[i];
  36265. + touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
  36266. + if( touch == clent ) continue;
  36267.  
  36268. - // restore velocity
  36269. - VectorCopy( oldvel, clent->v.velocity );
  36270. + VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
  36271. + SV_ConvertPMTrace( &trace, pmtrace, touch );
  36272. + SV_Impact( touch, clent, &trace );
  36273. + }
  36274. +
  36275. + // restore velocity
  36276. + VectorCopy( oldvel, clent->v.velocity );
  36277. + }
  36278.  
  36279. svgame.pmove->numtouch = 0;
  36280. svgame.globals->time = cl->timebase;
  36281. @@ -1127,7 +1135,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
  36282. svgame.dllFuncs.pfnPlayerPostThink( clent );
  36283. svgame.dllFuncs.pfnCmdEnd( clent );
  36284.  
  36285. - if( !cl->fakeclient )
  36286. + if( !FBitSet( cl->flags, FCL_FAKECLIENT ))
  36287. {
  36288. SV_RestoreMoveInterpolant( cl );
  36289. }
  36290. diff --git b/engine/server/sv_save.c a/engine/server/sv_save.c
  36291. index 3706313..febea2b 100644
  36292. --- b/engine/server/sv_save.c
  36293. +++ a/engine/server/sv_save.c
  36294. @@ -32,7 +32,7 @@ half-life implementation of saverestore system
  36295. #define SAVEGAME_VERSION 0x0065 // Version 0.65
  36296. #define CLIENT_SAVEGAME_VERSION 0x0068 // Version 0.68
  36297.  
  36298. -#define SAVE_AGED_COUNT 1
  36299. +#define SAVE_AGED_COUNT 2
  36300. #define SAVENAME_LENGTH 128 // matches with MAX_OSPATH
  36301.  
  36302. #define LUMP_DECALS_OFFSET 0
  36303. @@ -723,7 +723,8 @@ void SV_DirectoryCopy( const char *pPath, file_t *pFile )
  36304.  
  36305. void SV_DirectoryExtract( file_t *pFile, int fileCount )
  36306. {
  36307. - char szName[SAVENAME_LENGTH], fileName[SAVENAME_LENGTH];
  36308. + char szName[SAVENAME_LENGTH];
  36309. + char fileName[SAVENAME_LENGTH];
  36310. int i, fileSize;
  36311. file_t *pCopy;
  36312.  
  36313. @@ -1066,7 +1067,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
  36314. ClientSections_t sections;
  36315. int i, decalCount;
  36316. int id, version;
  36317. - fs_offset_t header_offset, position;
  36318. + long header_offset, position;
  36319. soundlist_t soundInfo[MAX_CHANNELS];
  36320. string curtrack, looptrack;
  36321. int soundCount = 0;
  36322. diff --git b/engine/server/sv_world.c a/engine/server/sv_world.c
  36323. index 23acc51..116f4ad 100644
  36324. --- b/engine/server/sv_world.c
  36325. +++ a/engine/server/sv_world.c
  36326. @@ -536,15 +536,14 @@ SV_FindTouchedLeafs
  36327. */
  36328. void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
  36329. {
  36330. - mplane_t *splitplane;
  36331. - int sides, leafnum;
  36332. + int sides;
  36333. mleaf_t *leaf;
  36334.  
  36335. if( node->contents == CONTENTS_SOLID )
  36336. return;
  36337.  
  36338. // add an efrag if the node is a leaf
  36339. - if( node->contents < 0 )
  36340. + if( node->contents < 0 )
  36341. {
  36342. if( ent->num_leafs > ( MAX_ENT_LEAFS - 1 ))
  36343. {
  36344. @@ -555,18 +554,16 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
  36345. else
  36346. {
  36347. leaf = (mleaf_t *)node;
  36348. - leafnum = leaf - sv.worldmodel->leafs - 1;
  36349. - ent->leafnums[ent->num_leafs] = leafnum;
  36350. + ent->leafnums[ent->num_leafs] = leaf->cluster;
  36351. ent->num_leafs++;
  36352. }
  36353. return;
  36354. }
  36355.  
  36356. // NODE_MIXED
  36357. - splitplane = node->plane;
  36358. - sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, splitplane );
  36359. + sides = BOX_ON_PLANE_SIDE( ent->v.absmin, ent->v.absmax, node->plane );
  36360.  
  36361. - if( sides == 3 && *headnode == -1 )
  36362. + if(( sides == 3 ) && ( *headnode == -1 ))
  36363. *headnode = node - sv.worldmodel->nodes;
  36364.  
  36365. // recurse down the contacted sides
  36366. @@ -575,36 +572,6 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
  36367. }
  36368.  
  36369. /*
  36370. -=============
  36371. -SV_HeadnodeVisible
  36372. -=============
  36373. -*/
  36374. -qboolean SV_HeadnodeVisible( mnode_t *node, byte *visbits, int *lastleaf )
  36375. -{
  36376. - int leafnum;
  36377. -
  36378. - if( !node || node->contents == CONTENTS_SOLID )
  36379. - return false;
  36380. -
  36381. - if( node->contents < 0 )
  36382. - {
  36383. - leafnum = ((mleaf_t *)node - sv.worldmodel->leafs) - 1;
  36384. -
  36385. - if(!( visbits[leafnum >> 3] & (1<<( leafnum & 7 ))))
  36386. - return false;
  36387. -
  36388. - if( lastleaf )
  36389. - *lastleaf = leafnum;
  36390. - return true;
  36391. - }
  36392. -
  36393. - if( SV_HeadnodeVisible( node->children[0], visbits, lastleaf ))
  36394. - return true;
  36395. -
  36396. - return SV_HeadnodeVisible( node->children[1], visbits, lastleaf );
  36397. -}
  36398. -
  36399. -/*
  36400. ===============
  36401. SV_LinkEdict
  36402. ===============
  36403. @@ -623,9 +590,9 @@ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
  36404.  
  36405. if( ent->v.movetype == MOVETYPE_FOLLOW && SV_IsValidEdict( ent->v.aiment ))
  36406. {
  36407. - ent->headnode = ent->v.aiment->headnode;
  36408. - ent->num_leafs = ent->v.aiment->num_leafs;
  36409. memcpy( ent->leafnums, ent->v.aiment->leafnums, sizeof( ent->leafnums ));
  36410. + ent->num_leafs = ent->v.aiment->num_leafs;
  36411. + ent->headnode = ent->v.aiment->headnode;
  36412. }
  36413. else
  36414. {
  36415. @@ -1470,6 +1437,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
  36416. mtexinfo_t *tex;
  36417. float front, back, scale, frac;
  36418. int i, map, size, s, t;
  36419. + int sample_size;
  36420. color24 *lm;
  36421. vec3_t mid;
  36422.  
  36423. @@ -1507,6 +1475,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
  36424.  
  36425. // check for impact on this node
  36426. surf = model->surfaces + node->firstsurface;
  36427. + sample_size = Mod_SampleSizeForFace( surf );
  36428.  
  36429. for( i = 0; i < node->numsurfaces; i++, surf++ )
  36430. {
  36431. @@ -1521,16 +1490,16 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
  36432. if(( s < 0.0f || s > surf->extents[0] ) || ( t < 0.0f || t > surf->extents[1] ))
  36433. continue;
  36434.  
  36435. - s /= LM_SAMPLE_SIZE;
  36436. - t /= LM_SAMPLE_SIZE;
  36437. + s /= sample_size;
  36438. + t /= sample_size;
  36439.  
  36440. if( !surf->samples )
  36441. return true;
  36442.  
  36443. VectorClear( sv_pointColor );
  36444.  
  36445. - lm = surf->samples + (t * ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) + s);
  36446. - size = ((surf->extents[0] / LM_SAMPLE_SIZE) + 1) * ((surf->extents[1] / LM_SAMPLE_SIZE) + 1);
  36447. + lm = surf->samples + (t * ((surf->extents[0] / sample_size) + 1) + s);
  36448. + size = ((surf->extents[0] / sample_size) + 1) * ((surf->extents[1] / sample_size) + 1);
  36449.  
  36450. for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
  36451. {
  36452. @@ -1560,7 +1529,7 @@ void SV_RunLightStyles( void )
  36453. // run lightstyles animation
  36454. for( i = 0, ls = sv.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
  36455. {
  36456. - ls->time += host.frametime;
  36457. + ls->time += sv.frametime;
  36458. ofs = (ls->time * 10);
  36459.  
  36460. if( ls->length == 0 ) ls->value = scale; // disable this light
  36461. diff --git b/engine/studio.h a/engine/studio.h
  36462. index 76b15f2..0f60f27 100644
  36463. --- b/engine/studio.h
  36464. +++ a/engine/studio.h
  36465. @@ -31,8 +31,8 @@ Studio models are position independent, so the cache manager can move them.
  36466. #define IDSEQGRPHEADER (('Q'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSQ"
  36467.  
  36468. // studio limits
  36469. -#define MAXSTUDIOTRIANGLES 32768 // max triangles per model
  36470. -#define MAXSTUDIOVERTS 4096 // max vertices per submodel
  36471. +#define MAXSTUDIOTRIANGLES 65536 // max triangles per model
  36472. +#define MAXSTUDIOVERTS 32768 // max vertices per submodel
  36473. #define MAXSTUDIOSEQUENCES 256 // total animation sequences
  36474. #define MAXSTUDIOSKINS 256 // total textures
  36475. #define MAXSTUDIOSRCBONES 512 // bones allowed at source movement
  36476. diff --git b/game_launch/game.cpp a/game_launch/game.cpp
  36477. index 337bb18..407c4b0 100644
  36478. --- b/game_launch/game.cpp
  36479. +++ a/game_launch/game.cpp
  36480. @@ -17,6 +17,11 @@ GNU General Public License for more details.
  36481.  
  36482. #define GAME_PATH "valve" // default dir to start from
  36483.  
  36484. +#ifdef WIN32
  36485. +// enable NVIDIA High Performance Graphics while using Integrated Graphics.
  36486. +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
  36487. +#endif
  36488. +
  36489. typedef void (*pfnChangeGame)( const char *progname );
  36490. typedef int (*pfnInit)( const char *progname, int bChangeGame, pfnChangeGame func );
  36491. typedef void (*pfnShutdown)( void );
  36492. diff --git b/mainui/basemenu.cpp a/mainui/basemenu.cpp
  36493. index a3f4709..bc03f81 100644
  36494. --- b/mainui/basemenu.cpp
  36495. +++ a/mainui/basemenu.cpp
  36496. @@ -253,9 +253,14 @@ void UI_DrawString( int x, int y, int w, int h, const char *string, const int co
  36497. {
  36498. if( IsColorString( l ))
  36499. {
  36500. - if( !forceColor )
  36501. + int colorNum = ColorIndex( *(l+1) );
  36502. +
  36503. + if( colorNum == 7 && color != 0 )
  36504. + {
  36505. + modulate = color;
  36506. + }
  36507. + else if( !forceColor )
  36508. {
  36509. - int colorNum = ColorIndex( *(l+1) );
  36510. modulate = PackAlpha( g_iColorTable[colorNum], UnpackAlpha( color ));
  36511. }
  36512.  
  36513. @@ -1535,7 +1540,7 @@ void UI_Init( void )
  36514. Cmd_AddCommand( "menu_multiplayer", UI_MultiPlayer_Menu );
  36515. Cmd_AddCommand( "menu_options", UI_Options_Menu );
  36516. Cmd_AddCommand( "menu_langame", UI_LanGame_Menu );
  36517. - Cmd_AddCommand( "menu_intenetgames", UI_InternetGames_Menu );
  36518. + Cmd_AddCommand( "menu_internetgames", UI_InternetGames_Menu );
  36519. Cmd_AddCommand( "menu_playersetup", UI_PlayerSetup_Menu );
  36520. Cmd_AddCommand( "menu_controls", UI_Controls_Menu );
  36521. Cmd_AddCommand( "menu_advcontrols", UI_AdvControls_Menu );
  36522. @@ -1579,7 +1584,7 @@ void UI_Shutdown( void )
  36523. Cmd_RemoveCommand( "menu_saveload" );
  36524. Cmd_RemoveCommand( "menu_multiplayer" );
  36525. Cmd_RemoveCommand( "menu_options" );
  36526. - Cmd_RemoveCommand( "menu_intenetgames" );
  36527. + Cmd_RemoveCommand( "menu_internetgames" );
  36528. Cmd_RemoveCommand( "menu_langame" );
  36529. Cmd_RemoveCommand( "menu_playersetup" );
  36530. Cmd_RemoveCommand( "menu_controls" );
  36531. @@ -1596,7 +1601,6 @@ void UI_Shutdown( void )
  36532. Cmd_RemoveCommand( "menu_defaults" );
  36533. Cmd_RemoveCommand( "menu_cinematics" );
  36534. Cmd_RemoveCommand( "menu_customgame" );
  36535. - Cmd_RemoveCommand( "menu_quit" );
  36536.  
  36537. memset( &uiStatic, 0, sizeof( uiStatic_t ));
  36538. }
  36539. diff --git b/mainui/basemenu.h a/mainui/basemenu.h
  36540. index 11ee4fd..474e6fc 100644
  36541. --- b/mainui/basemenu.h
  36542. +++ a/mainui/basemenu.h
  36543. @@ -74,7 +74,7 @@ GNU General Public License for more details.
  36544. #define UI_OUTLINE_WIDTH uiStatic.outlineWidth // outline thickness
  36545.  
  36546. #define UI_MAXGAMES 900 // slots for savegame/demos
  36547. -#define UI_MAX_SERVERS 32
  36548. +#define UI_MAX_SERVERS 64
  36549. #define UI_MAX_BGMAPS 32
  36550.  
  36551. #define MAX_HINT_TEXT 512
  36552. diff --git b/mainui/menu_creategame.cpp a/mainui/menu_creategame.cpp
  36553. index 753b065..3998c15 100644
  36554. --- b/mainui/menu_creategame.cpp
  36555. +++ a/mainui/menu_creategame.cpp
  36556. @@ -375,7 +375,7 @@ static void UI_CreateGame_Init( void )
  36557. uiCreateGame.hostName.generic.width = 205;
  36558. uiCreateGame.hostName.generic.height = 32;
  36559. uiCreateGame.hostName.generic.callback = UI_CreateGame_Callback;
  36560. - uiCreateGame.hostName.maxLength = 16;
  36561. + uiCreateGame.hostName.maxLength = 28;
  36562. strcpy( uiCreateGame.hostName.buffer, CVAR_GET_STRING( "hostname" ));
  36563.  
  36564. uiCreateGame.maxClients.generic.id = ID_MAXCLIENTS;
  36565. diff --git b/mainui/menu_internetgames.cpp a/mainui/menu_internetgames.cpp
  36566. index 301048e..75044d5 100644
  36567. --- b/mainui/menu_internetgames.cpp
  36568. +++ a/mainui/menu_internetgames.cpp
  36569. @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  36570. #define ID_YES 130
  36571. #define ID_NO 131
  36572.  
  36573. -#define GAME_LENGTH 18
  36574. +#define GAME_LENGTH 28
  36575. #define MAPNAME_LENGTH 20+GAME_LENGTH
  36576. -#define TYPE_LENGTH 16+MAPNAME_LENGTH
  36577. +#define TYPE_LENGTH 10+MAPNAME_LENGTH
  36578. #define MAXCL_LENGTH 15+TYPE_LENGTH
  36579.  
  36580. typedef struct
  36581. @@ -118,24 +118,30 @@ UI_InternetGames_GetGamesList
  36582. static void UI_InternetGames_GetGamesList( void )
  36583. {
  36584. int i;
  36585. - const char *info;
  36586. + const char *info, *host, *map;
  36587. + int colorOffset[2];
  36588.  
  36589. for( i = 0; i < uiStatic.numServers; i++ )
  36590. {
  36591. if( i >= UI_MAX_SERVERS ) break;
  36592. info = uiStatic.serverNames[i];
  36593.  
  36594. - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH );
  36595. - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH );
  36596. - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );
  36597. - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH );
  36598. + host = Info_ValueForKey( info, "host" );
  36599. + colorOffset[0] = ColorPrexfixCount( host );
  36600. + StringConcat( uiInternetGames.gameDescription[i], host, GAME_LENGTH );
  36601. + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] );
  36602. + map = Info_ValueForKey( info, "map" );
  36603. + colorOffset[1] = ColorPrexfixCount( map );
  36604. + StringConcat( uiInternetGames.gameDescription[i], map, MAPNAME_LENGTH );
  36605. + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] );
  36606. if( !strcmp( Info_ValueForKey( info, "dm" ), "1" ))
  36607. - StringConcat( uiInternetGames.gameDescription[i], "deathmatch", TYPE_LENGTH );
  36608. + StringConcat( uiInternetGames.gameDescription[i], "dm", TYPE_LENGTH );
  36609. else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" ))
  36610. StringConcat( uiInternetGames.gameDescription[i], "coop", TYPE_LENGTH );
  36611. else if( !strcmp( Info_ValueForKey( info, "team" ), "1" ))
  36612. - StringConcat( uiInternetGames.gameDescription[i], "teamplay", TYPE_LENGTH );
  36613. - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH );
  36614. + StringConcat( uiInternetGames.gameDescription[i], "team", TYPE_LENGTH );
  36615. + else StringConcat( uiInternetGames.gameDescription[i], "???", TYPE_LENGTH );
  36616. + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] );
  36617. StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH );
  36618. StringConcat( uiInternetGames.gameDescription[i], "\\", MAXCL_LENGTH );
  36619. StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH );
  36620. @@ -274,7 +280,7 @@ static void UI_InternetGames_Init( void )
  36621. StringConcat( uiInternetGames.hintText, uiEmptyString, MAPNAME_LENGTH );
  36622. StringConcat( uiInternetGames.hintText, "Type", TYPE_LENGTH );
  36623. StringConcat( uiInternetGames.hintText, uiEmptyString, TYPE_LENGTH );
  36624. - StringConcat( uiInternetGames.hintText, "Num/Max Clients", MAXCL_LENGTH );
  36625. + StringConcat( uiInternetGames.hintText, "Clients", MAXCL_LENGTH );
  36626. StringConcat( uiInternetGames.hintText, uiEmptyString, MAXCL_LENGTH );
  36627.  
  36628. uiInternetGames.background.generic.id = ID_BACKGROUND;
  36629. diff --git b/mainui/menu_langame.cpp a/mainui/menu_langame.cpp
  36630. index 7a40bf5..2098d78 100644
  36631. --- b/mainui/menu_langame.cpp
  36632. +++ a/mainui/menu_langame.cpp
  36633. @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  36634. #define ID_YES 130
  36635. #define ID_NO 131
  36636.  
  36637. -#define GAME_LENGTH 18
  36638. +#define GAME_LENGTH 28
  36639. #define MAPNAME_LENGTH 20+GAME_LENGTH
  36640. -#define TYPE_LENGTH 16+MAPNAME_LENGTH
  36641. +#define TYPE_LENGTH 10+MAPNAME_LENGTH
  36642. #define MAXCL_LENGTH 15+TYPE_LENGTH
  36643.  
  36644. typedef struct
  36645. @@ -118,24 +118,30 @@ UI_LanGame_GetGamesList
  36646. static void UI_LanGame_GetGamesList( void )
  36647. {
  36648. int i;
  36649. - const char *info;
  36650. + const char *info, *host, *map;
  36651. + int colorOffset[2];
  36652.  
  36653. for( i = 0; i < uiStatic.numServers; i++ )
  36654. {
  36655. if( i >= UI_MAX_SERVERS ) break;
  36656. info = uiStatic.serverNames[i];
  36657.  
  36658. - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH );
  36659. - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH );
  36660. - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );
  36661. - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH );
  36662. + host = Info_ValueForKey( info, "host" );
  36663. + colorOffset[0] = ColorPrexfixCount( host );
  36664. + StringConcat( uiLanGame.gameDescription[i], host, GAME_LENGTH );
  36665. + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] );
  36666. + map = Info_ValueForKey( info, "map" );
  36667. + colorOffset[1] = ColorPrexfixCount( map );
  36668. + StringConcat( uiLanGame.gameDescription[i], map, MAPNAME_LENGTH );
  36669. + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] );
  36670. if( !strcmp( Info_ValueForKey( info, "dm" ), "1" ))
  36671. - StringConcat( uiLanGame.gameDescription[i], "deathmatch", TYPE_LENGTH );
  36672. + StringConcat( uiLanGame.gameDescription[i], "dm", TYPE_LENGTH );
  36673. else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" ))
  36674. StringConcat( uiLanGame.gameDescription[i], "coop", TYPE_LENGTH );
  36675. else if( !strcmp( Info_ValueForKey( info, "team" ), "1" ))
  36676. - StringConcat( uiLanGame.gameDescription[i], "teamplay", TYPE_LENGTH );
  36677. - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH );
  36678. + StringConcat( uiLanGame.gameDescription[i], "team", TYPE_LENGTH );
  36679. + else StringConcat( uiLanGame.gameDescription[i], "???", TYPE_LENGTH );
  36680. + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] );
  36681. StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH );
  36682. StringConcat( uiLanGame.gameDescription[i], "\\", MAXCL_LENGTH );
  36683. StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH );
  36684. @@ -274,7 +280,7 @@ static void UI_LanGame_Init( void )
  36685. StringConcat( uiLanGame.hintText, uiEmptyString, MAPNAME_LENGTH );
  36686. StringConcat( uiLanGame.hintText, "Type", TYPE_LENGTH );
  36687. StringConcat( uiLanGame.hintText, uiEmptyString, TYPE_LENGTH );
  36688. - StringConcat( uiLanGame.hintText, "Num/Max Clients", MAXCL_LENGTH );
  36689. + StringConcat( uiLanGame.hintText, "Clients", MAXCL_LENGTH );
  36690. StringConcat( uiLanGame.hintText, uiEmptyString, MAXCL_LENGTH );
  36691.  
  36692. uiLanGame.background.generic.id = ID_BACKGROUND;
  36693. diff --git b/mainui/ui_title_anim.cpp a/mainui/ui_title_anim.cpp
  36694. index 85651c1..e36f2ae 100644
  36695. --- b/mainui/ui_title_anim.cpp
  36696. +++ a/mainui/ui_title_anim.cpp
  36697. @@ -92,6 +92,7 @@ void UI_DrawTitleAnim()
  36698. LerpQuad( TitleLerpQuads[f_idx], TitleLerpQuads[s_idx], frac, &c );
  36699.  
  36700. PIC_Set( TransPic, 255, 255, 255, 255 );
  36701. +
  36702. PIC_DrawAdditive( c.x, c.y, c.lx, c.ly, &r );
  36703. }
  36704.  
  36705. diff --git b/mainui/utils.cpp a/mainui/utils.cpp
  36706. index 62b5afd..89b49c3 100644
  36707. --- b/mainui/utils.cpp
  36708. +++ a/mainui/utils.cpp
  36709. @@ -67,6 +67,30 @@ int ColorStrlen( const char *str )
  36710. return len;
  36711. }
  36712.  
  36713. +int ColorPrexfixCount( const char *str )
  36714. +{
  36715. + const char *p;
  36716. +
  36717. + if( !str )
  36718. + return 0;
  36719. +
  36720. + int len = 0;
  36721. + p = str;
  36722. +
  36723. + while( *p )
  36724. + {
  36725. + if( IsColorString( p ))
  36726. + {
  36727. + len += 2;
  36728. + p += 2;
  36729. + continue;
  36730. + }
  36731. + p++;
  36732. + }
  36733. +
  36734. + return len;
  36735. +}
  36736. +
  36737. void StringConcat( char *dst, const char *src, size_t size )
  36738. {
  36739. register char *d = dst;
  36740. @@ -2184,6 +2208,7 @@ void UI_PicButton_Draw( menuPicButton_s *item )
  36741. };
  36742.  
  36743. PIC_Set( item->pic, r, g, b, 255 );
  36744. + PIC_EnableScissor( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height - 2 );
  36745. PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[state] );
  36746.  
  36747. a = (512 - (uiStatic.realTime - item->generic.lastFocusTime)) >> 1;
  36748. @@ -2193,6 +2218,7 @@ void UI_PicButton_Draw( menuPicButton_s *item )
  36749. PIC_Set( item->pic, r, g, b, a );
  36750. PIC_DrawAdditive( item->generic.x, item->generic.y, uiStatic.buttons_draw_width, uiStatic.buttons_draw_height, &rects[BUTTON_FOCUS] );
  36751. }
  36752. + PIC_DisableScissor();
  36753. }
  36754. else
  36755. {
  36756. diff --git b/mainui/utils.h a/mainui/utils.h
  36757. index 54e852d..58b0477 100644
  36758. --- b/mainui/utils.h
  36759. +++ a/mainui/utils.h
  36760. @@ -109,6 +109,7 @@ inline float RemapVal( float val, float A, float B, float C, float D)
  36761. }
  36762.  
  36763. extern int ColorStrlen( const char *str ); // returns string length without color symbols
  36764. +extern int ColorPrexfixCount( const char *str );
  36765. extern const int g_iColorTable[8];
  36766. extern void COM_FileBase( const char *in, char *out ); // ripped out from hlsdk 2.3
  36767. extern int UI_FadeAlpha( int starttime, int endtime );
Add Comment
Please, Sign In to add comment