Compare commits

...

313 commits

Author SHA1 Message Date
Denis Pauk
1f7c4d6f8e game: remove grapple by default 2025-04-19 23:19:17 +03:00
Denis Pauk
90474b023b game: fix Player_GiveStartItems hanging 2025-04-19 23:04:32 +03:00
Denis Pauk
2188f0c55d common: replace strncpy to Q_strlcpy 2025-04-19 22:59:28 +03:00
Denis Pauk
fdf74efeaf jabot: change random skin select 2025-04-19 22:58:37 +03:00
Denis Pauk
13525df995 game: astar additional bounds check 2025-04-19 22:57:08 +03:00
Denis Pauk
7c9eb023ff common: mark COM_FileExtension as never returns NULL 2025-04-19 22:55:45 +03:00
Denis Pauk
45c4d757d2 Merge remote-tracking branch 'yquake2/master' 2025-04-19 22:09:01 +03:00
Yamagi
07205fb788
Merge pull request #1199 from devnexen/modlist_menu_fix_leaks
mod list fix inner leaks
2025-04-19 08:54:28 +02:00
Denis Pauk
7ad261c047 client: hide loaded model name on map load
Checks of https://github.com/yquake2/yquake2/issues/1201

Base1 with developer 1
CL_PrintInSameLine: 0.00s:Map is loading...
CL_PrintInSameLine: 1.98s:Pics
CL_PrintInSameLine: 2.02s:Temporary models
CL_PrintInSameLine: 2.35s:Models
.....
CL_PrintInSameLine: 3.37s:Images
CL_PrintInSameLine: 3.39s:Clients
CL_PrintInSameLine: 3.41s:Sky
CL_PrintInSameLine: 3.44s:Cleanup.....
CL_PrintInSameLine: 3.44s:Map loaded.
2025-04-18 00:18:46 +03:00
Denis Pauk
7ec7abe60f sound: simplify add ogg extension 2025-04-17 23:10:11 +03:00
Denis Pauk
40886da475 fix checks for filename extension 2025-04-17 23:10:00 +03:00
Denis Pauk
d2cb3cc79f game: support dropping for grapple and blaster 2025-04-17 23:07:16 +03:00
Denis Pauk
0ea4ef02ca client: fix print message in console center
Fix of 05eee80292

Multibytes symbols is broken game terminal
2025-04-14 01:04:09 +03:00
Denis Pauk
256eb79d53 game: fix monster start position in psx/base0 2025-04-14 00:50:53 +03:00
Denis Pauk
a8080c05ed game: use model frame mins/maxs api call 2025-04-13 17:26:14 +03:00
Denis Pauk
a114062d2e models: store min/max in dmdxframegroup_t 2025-04-13 14:25:16 +03:00
Denis Pauk
c76492b832 Update documentation. 2025-04-13 00:19:40 +03:00
Denis Pauk
378fb29284 renders: don't use strlen for namewe 2025-04-12 18:37:24 +03:00
Denis Pauk
94b46e78e8 models: fix replacement name code 2025-04-12 17:00:48 +03:00
Denis Pauk
40513deff7 game: add monsters from ReRelease vault 2025-04-12 15:50:58 +03:00
Denis Pauk
9cd4a8fd17 DecompressVis: fix not enough to decompress issue 2025-04-10 00:36:32 +03:00
Denis Pauk
70112ffd94 Documentation update 2025-04-09 23:36:16 +03:00
Denis Pauk
afcf03e807 game: set items size from model box on drop 2025-04-09 23:26:02 +03:00
Denis Pauk
064b5c5ac0 models: support load on get model info 2025-04-09 23:06:05 +03:00
Denis Pauk
1a1fe112bf game: fix long color field parse 2025-04-09 22:58:19 +03:00
Denis Pauk
d4026984bb game import: GetModelInfo return mins/maxs 2025-04-09 08:47:54 +03:00
Denis Pauk
96720e2ed2 game: add animation for npc_timeminder 2025-04-09 08:44:02 +03:00
Denis Pauk
f319bb0884 game: extend animation group usage to object_big_fire 2025-04-06 17:55:17 +03:00
Denis Pauk
c63df9cab0 game: add usage of get frame animation group
And use with DoD (roarke) object_flame1 entity.
2025-04-06 15:49:27 +03:00
Denis Pauk
b74ab34610 models: rearange models save logic 2025-04-06 11:19:18 +03:00
Denis Pauk
053dcf7890 game: sync function names in import struct 2025-04-06 00:34:54 +03:00
Denis Pauk
00384e4021 renders: models load code cleanup 2025-04-06 00:11:25 +03:00
Denis Pauk
8e054bfc3e models: parse models on client side only
Render expect parsed models/sprites only.
2025-04-05 20:16:08 +03:00
David Carlier
ccf195e726
mod list fix inner leaks 2025-04-05 17:11:32 +01:00
Denis Pauk
3ee315c7da models: copy models parse code to client side 2025-04-05 17:09:26 +03:00
Denis Pauk
3c5383429f models: cache models on client side 2025-04-05 14:31:02 +03:00
Denis Pauk
74ebea5b34 Merge remote-tracking branch 'yquake2/master' 2025-04-02 21:33:50 +03:00
Yamagi
e8e0f678a9 Bump version number to 8.51pre. 2025-04-02 11:12:49 +02:00
Yamagi
c9d23fefbc Bump version number to 8.50. 2025-04-02 11:12:15 +02:00
Yamagi
cd7363a551 Update the CHANGELOG for the upcoming 8.50 release. 2025-04-02 11:11:47 +02:00
Yamagi
786adba3aa Bump minimum cmake version to 3.5.
This fixes the build with newer cmake versions which otherwise error out
with "Compatibility with CMake < 3.5 has been removed from CMake". There
are no functional changes. If someone requires such an old cmake they
can force compatibility with an older version.
2025-04-01 18:10:09 +02:00
Denis Pauk
ccc7f276a1 gl4 issues fixes
Based on 0474e4a4
2025-03-30 22:42:10 +03:00
Denis Pauk
0be9f16d3d Merge remote-tracking branch 'yquake2/master' 2025-03-30 22:30:19 +03:00
Yamagi
3637f9a758
Merge pull request #1198 from devnexen/gl3_segfault_fix
gl3 issues fixes.
2025-03-29 23:59:38 +01:00
David Carlier
0474e4a4e9
gl3 issues fixes.
segfault on video mode changes from no fullscreen to native/fullscreen
or vice-versa.
2025-03-29 22:48:44 +00:00
Denis Pauk
27e711a3d6 Fix github workflow win_msvc 2025-03-29 23:18:38 +02:00
Denis Pauk
79496131c1 Merge remote-tracking branch 'yquake2/master' 2025-03-29 21:51:41 +02:00
Denis Pauk
87836a4639 renders: fix mod_novis realloc 2025-03-29 21:44:51 +02:00
Yamagi
75b245ca54 Add 1600x900 as mdoe 32.
This was requested in #1196. After the upcoming release code should be
added which sorts the mode display in the menu.
2025-03-29 18:14:42 +01:00
Yamagi
c0cf6d5d67
Merge pull request #1197 from DanielGibson/msvc-ci
Github workflow for Visual Studio build
2025-03-29 18:02:24 +01:00
Daniel Gibson
556cbf4fa1 Github workflow for Visual Studio (x86 and x86_64) build
based on the one from dhewm3
2025-03-29 17:56:13 +01:00
Yamagi
c61e0d3266
Merge pull request #1195 from protocultor/fs_fix
Small fix for Flick Stick
2025-03-29 17:37:44 +01:00
Yamagi
c33e0ca848
Merge pull request #1193 from devnexen/atexit_mods
mod names list static allocation free at exit approach
2025-03-29 17:21:32 +01:00
Yamagi
9894b27791 Fix Visual Studio build.
strings.h is POSIX or something like that and not available when
building with Visual Studio Code.
2025-03-29 17:14:15 +01:00
Denis Pauk
a9a4202840 models: reuse Mod_LoadAllocate 2025-03-28 00:41:52 +02:00
Denis Pauk
bb17105d53 models: reuse md2 frames in md5 frame groups 2025-03-26 23:33:37 +02:00
Denis Pauk
84e4035922 models: generate animation groups from frames 2025-03-26 00:05:15 +02:00
Denis Pauk
643d8d7d2b models: use animation names from DKM format 2025-03-24 00:32:33 +02:00
Denis Pauk
76625d706e models: use animation names from SDEF 2025-03-23 22:30:28 +02:00
Denis Pauk
04ecdab2ba models: reuse Mod_LoadAllocate 2025-03-23 22:29:30 +02:00
Denis Pauk
ec30ed21d8 models: allocate single animation group
All supported models uses single animation group by default
2025-03-23 22:16:23 +02:00
Denis Pauk
159fac2993 models: allocate skins buffer separately 2025-03-23 22:08:32 +02:00
Denis Pauk
47d8091125 Cleanup Readme and CMakeLists.txt 2025-03-23 14:56:39 +02:00
Denis Pauk
500bf1b952 jabot: cleanup path usage in A* 2025-03-23 14:21:53 +02:00
Denis Pauk
0d8cba6711 jabot: remove botroam functionality
Trust A* heuristic to search path
2025-03-23 13:49:42 +02:00
Denis Pauk
8aea22e6c6 jabot: rearrange bot commands 2025-03-19 00:43:23 +02:00
Jaime Moreira
60ba33dd40 Flick Stick delta time calculation improved
Default joystick sensitivities increased
2025-03-18 12:43:26 -03:00
David Carlier
839b91b0ee
mod names list static allocation releasing 2025-03-17 18:51:12 +00:00
Denis Pauk
69409594bd jabot: check astart limits 2025-03-16 00:35:02 +02:00
Denis Pauk
04e7a303db jabot: add checkges from 0.9.3 version 2025-03-16 00:35:02 +02:00
Denis Pauk
ec60ebd7f8 jabot: use bot_debugmonster to hide debug messages 2025-03-16 00:35:02 +02:00
Denis Pauk
0fbcbbcdff jabot: Improve navigation save logic 2025-03-16 00:35:02 +02:00
Denis Pauk
5d4a2facbd client: extend multiplayer rules with ctf 2025-03-16 00:35:02 +02:00
Denis Pauk
84cc99d559 client: center chars in ttf font 2025-03-16 00:34:03 +02:00
Denis Pauk
d91c4253e8 client: use ttf fonts in menu 2025-03-15 21:28:32 +02:00
Denis Pauk
3578d4353d Merge remote-tracking branch 'yquake2/master' 2025-03-15 13:42:36 +02:00
Yamagi
d2efa1c9af Fix (potential) problematic use cases of qboolean.
Until 853f832 qboolean was always defined as an enum. Starting with
853f832 it may be defined as bool when building in C23 mode or any
newer standard. There are subtle behavioral differences between enum
and bool, fix these:

* The enum has int as underlying type, floats are cut down to the
  nearest int. Thus 0.5f becomes false. With bool everything which
  is not 0 becomes true. Gone through the code and made sure that
  there are no float to qboolean type conversions.
* Always use true and false, not something else like 1 and 0 or
  (when building under Windows) TRUE and FALSE.
* Fix some corner cases where integers >1 where missused as true.
  These should be noops.
* Fix `R_GreyscaledLight()` misusing qboolean for returning int.

Partly based upon yquake2/yquake2remaster@e3c8d26

Closes #1191
2025-03-15 11:50:37 +01:00
Yamagi
989c30e31d
Merge pull request #1192 from runlevel5/patch-1
Add header for strcasecmp()
2025-03-15 09:49:01 +01:00
Yamagi
27c412055e
Merge pull request #1190 from efliks/fix-build-failed-missing-limits
Fix missing limits header in SDL2 and SDL3 input modules
2025-03-15 09:48:44 +01:00
Denis Pauk
e3c8d26760 fix c23 warnings
https://github.com/yquake2/yquake2/issues/1191
2025-03-14 00:39:43 +02:00
efliks
294d162b06 Include limits in sdl3.c 2025-03-12 01:08:03 +01:00
Trung LĂŞ
1ed01b3033
Add header for strcasecmp() 2025-03-11 23:33:32 +11:00
efliks
6d814f6c41 Fix missing limits header in SDL2 module 2025-03-09 12:54:20 +01:00
Denis Pauk
26624ab90f game: integrate to game code 2025-03-08 12:37:24 +02:00
Denis Pauk
be2fa70e4d Add jabot code
Based on:
  https://www.moddb.com/mods/jabotq2/downloads/jabot-q2-v09x-win32-and-linux

Copyright 2001-2004 Pat AfterMoon
Copyright 2001 Steve Yeager
2025-03-08 12:10:09 +02:00
Denis Pauk
3e66c9d1fb server: fix send player name in multiplayer game 2025-03-06 23:49:44 +02:00
Denis Pauk
e8984c25f3 console overflow message cleanup 2025-03-06 00:40:53 +02:00
Denis Pauk
f833e24da6 Update readme 2025-03-02 23:06:51 +02:00
Denis Pauk
6755ecf590 gl4: add support of ttf fonts 2025-03-02 15:44:53 +02:00
Denis Pauk
7c768b7587 gl3: add support of ttf fonts 2025-03-02 15:19:40 +02:00
Denis Pauk
82ceca620b gl1, vk: share ttf font code 2025-03-02 12:07:16 +02:00
Denis Pauk
d0e8c83687 vk,gl1: improve font image generation
Change threshold of image transparncy.
2025-03-02 11:22:58 +02:00
Denis Pauk
0bbbf27b23 gl1: support ttf fonts 2025-03-02 00:53:30 +02:00
Denis Pauk
c1689345f4 Merge remote-tracking branch 'yquake2/master' 2025-03-01 22:27:13 +02:00
Yamagi
474dfcb524
Merge pull request #1186 from BjossiAlfreds/door-use-fix
Fixed doors not being usable with NULL activator
2025-03-01 16:51:58 +01:00
Yamagi
eb5a9a15d8 Rename CHAR_WIDTH to CHARACTER_WIDTH.
For some time glibc has defined a macro with the same name in limits.h.
Avoid the warning by renaming our macro.
2025-03-01 13:31:36 +01:00
Yamagi
853f832cbd Fix build with gcc in C23 mode.
I wonder why this didn't give at least a warning in C11 mode. The
pointer missmatched, regardless which C standard we are following.
2025-03-01 12:31:10 +01:00
Yamagi
049784f0df Use build-in bool type when building with C23. 2025-03-01 12:28:57 +01:00
Yamagi
b57de78150 Revert "Force C standard to gnu99 in cmake builds."
This was wrong. For yquake2 the Makefile hasn't forced a C standard
since commit 3a9b8de in 2023.
2025-03-01 12:18:52 +01:00
Denis Pauk
579af5515b refresh: share R_LoadConsoleChars 2025-02-28 00:15:05 +02:00
Denis Pauk
cebdb35774 vk: share next utf8 symbol function 2025-02-27 23:41:57 +02:00
Denis Pauk
05eee80292 client: fix utf8 strlen center print 2025-02-26 00:16:52 +02:00
Denis Pauk
125bfbb175 vk: add initial support of r_ttffont cvar 2025-02-24 23:38:50 +02:00
Denis Pauk
ac62a89259 client: renders add stb_truetype
```
wget https://raw.githubusercontent.com/NBickford-NV/stb/refs/heads/nbickford/all-fixes/stb_truetype.h -O src/client/refresh/files/stb_truetype.h
```
2025-02-24 23:29:57 +02:00
Denis Pauk
3cd8a93432 Merge remote-tracking branch 'yquake2/master' 2025-02-24 23:28:52 +02:00
BjossiAlfreds
23a3ee0cc5 Fixed doors not being usable with NULL activator 2025-02-24 14:26:45 +00:00
Yamagi
a4e23e6fd9 Force C standard to gnu99 in cmake builds.
The Makefiles forces gnu99 since ages. Additionally gcc15 started to
default to C23 and our code doesn't (yet) build with it.
2025-02-22 11:42:27 +01:00
Denis Pauk
21f0b33379 client: move DrawStringScaled implementation to renders
Unicode strings support step #3, #12
2025-02-16 23:56:23 +02:00
Denis Pauk
4ce6f058e6 maps: remove SURF_NODRAW for non BSPX maps
Improve c3638d6c9

Based on: https://github.com/Paril/q2pro/issues/132
2025-02-16 23:18:01 +02:00
Denis Pauk
67aeeacccb client: cleanup screen code
* make functions static
* remove unused remaining in SCR_DrawCenterString,

Remaining had 9999 as initial value, message has 1024 bytes buffer
size that is much smaller that remaining.
2025-02-16 22:43:42 +02:00
Denis Pauk
8f6f3b1e3f models: fix build warnings 2025-02-16 22:19:01 +02:00
Denis Pauk
4e46f83b32 8.42RR12: Version bump 2025-02-12 23:00:28 +02:00
Denis Pauk
5ca731d1f1 SiN: dynamic allocation of sub models list in .def 2025-02-11 23:29:32 +02:00
Denis Pauk
3ba7edd995 Anachronox: update MDA load code
Support select skin by tag.

Based on:
 * https://anachrodox.talonbrave.info/models/shaders.html
2025-02-10 01:02:56 +02:00
Denis Pauk
a33d6b091d Anachronox: cleanup ATD load code 2025-02-10 00:35:48 +02:00
Denis Pauk
3f74954db6 Merge remote-tracking branch 'yquake2/master' 2025-02-10 00:34:31 +02:00
Denis Pauk
3d3e7e9c98 soft: fix build with SDL3 2025-02-10 00:28:07 +02:00
Yamagi
404450d186 Add a CI build for Linux/aarch64.
It's called aarch64 instead of arm64 because that is what we are using
as internal architecture descriptor in savegames, etc.
2025-02-09 11:15:24 +01:00
Yamagi
b607eb4d42 Rename linux.yml to linux_amd64.yml in favor to upcoming aarch64 build. 2025-02-09 11:14:47 +01:00
Yamagi
ec18568bd7 Make clear that the Win64 build is SDL3 instead of SDL2. 2025-02-09 11:07:11 +01:00
Yamagi
4b18825805
Merge pull request #1184 from 0lvin/partial_fix_stb
sdl3: Fix memory leak in IN_Controller_Init
2025-02-09 11:06:08 +01:00
Yamagi
aa43b2df8c Update CI to use 4 CPUs on Linux and Windows. 2025-02-09 10:58:58 +01:00
Denis Pauk
971b2d1360 sdl3: Fix memory leak in IN_Controller_Init
Detected by ASAN=1
Build Win64-SDL3 as part of github actions
2025-02-09 00:58:00 +02:00
Yamagi
4fe0d0be6b
Merge pull request #1183 from protocultor/sdl3_buttons
Consistent binding between multiple gamepad types + labels by style
2025-02-08 16:55:59 +01:00
Yamagi
39c81b8afc
Merge pull request #1181 from 0lvin/partial_fix_stb
update stb_* codes to latest master
2025-02-08 16:48:24 +01:00
Denis Pauk
ae21db84d8 images: support initial ATD sprites
Based on:
  https://anachrodox.talonbrave.info/veffects/procedural/proc_animate.html
2025-02-07 00:47:34 +02:00
Denis Pauk
720223bcb0 Add MacOS DMG build
Based on #542
2025-02-04 00:36:51 +02:00
Denis Pauk
c780c866e9 Update binary builds 2025-02-04 00:31:38 +02:00
Denis Pauk
b55452f20c Update stb from NBickford-NV/stb fork
wget https://raw.githubusercontent.com/NBickford-NV/stb/ce191b546e4efd91b9e35ab9de0a320eb02ddc1b/stb_image.h -O src/client/refresh/files/stb_image.h
wget https://raw.githubusercontent.com/NBickford-NV/stb/ce191b546e4efd91b9e35ab9de0a320eb02ddc1b/stb_image_write.h -O src/client/vid/header/stb_image_write.h
wget https://raw.githubusercontent.com/NBickford-NV/stb/ce191b546e4efd91b9e35ab9de0a320eb02ddc1b/stb_vorbis.c -O src/client/sound/header/stb_vorbis.h
2025-02-03 23:26:14 +02:00
Denis Pauk
074c938c56 update stb_* codes to latest master (5c205738c191bcb0abc65c4febfa9bd25ff35234)
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h -O src/client/refresh/files/stb_image.h
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h -O src/client/vid/header/stb_image_write.h
2025-02-03 23:19:01 +02:00
Jaime Moreira
a7551dae26 Refactor for joy_confirm operation
Removed consecutive comparisons in Key_GetMenuKey()
2025-02-03 14:29:56 -03:00
Jaime Moreira
29d95e3388 Fixed gyro_mode irregular behavior
"Always on" now works properly.
New default values for gyro sensitivity.
2025-02-03 10:07:00 -03:00
Jaime Moreira
c27ce2a7bf Gamepad's left stick allowed to navigate menus
Uses logic from the triggers handling.
2025-02-02 17:44:39 -03:00
Jaime Moreira
9e07dc2485 Cvar to set gamepad's confirm & cancel buttons
Autodetect again needs SDL 2.0.12.
Status bar has correct button prompts in gamepad binding menus.
2025-02-02 16:58:22 -03:00
Jaime Moreira
1d6d17beb3 Button labels by type of Gamepad
Visible only in "customize button" menus.
Cvar set to 'autodetect' by default, which requires SDL 2.0.12
2025-02-02 15:49:37 -03:00
Jaime Moreira
f995839e4b Don't use keynames for gamepad button names
Faster to look for them in their own array.
Fixed GLES1 warning on compilation with SDL3.
2025-02-02 12:41:17 -03:00
Jaime Moreira
b23bfb6ee2 Gamepad buttons are now SDL3 style
Uses button position instead of label.
SDL2 has to be forced to do this by disabling a hint.
Deleted redundant JOY_BACK definition, it's just the Escape key.
Renamed 'in_sdlbackbutton' to 'joy_escbutton'.
2025-02-02 11:38:43 -03:00
Denis Pauk
f7934b1936 update stb_* codes to latest master (5c205738c191bcb0abc65c4febfa9bd25ff35234)
wget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h -O src/client/refresh/files/stb_image.h
2025-02-02 13:09:47 +02:00
Denis Pauk
43eeb49fad Merge remote-tracking branch 'yquake2/master' 2025-02-02 13:02:55 +02:00
Yamagi
b8a6f2b760 Remove superfluous hints regarding rumble on Playstation gamepads.
SDL3 replaced the Playstation specific hint to the more generic
SDL_HINT_JOYSTICK_ENHANCED_REPORTS hint which is enabled by default.

Pointed out by @erysdren and @protocultor in #1178.

Based on PR #1178 by @erysdren.

Closes #1178.
2025-02-02 10:25:33 +01:00
Denis Pauk
42b578b2bb pmove: code style cleanup 2025-01-12 23:42:26 +02:00
Denis Pauk
5030d9d046 pmove: code cleanup 2025-01-08 23:23:51 +02:00
Denis Pauk
5440d6b94a pmove: PM_Friction cleanup 2025-01-05 23:41:14 +02:00
Denis Pauk
e71fce25a4 protocol: extend MAX_MSGLEN to 32k
ReRelease uses 19104 as first package size in demo
2025-01-04 22:56:57 +02:00
Denis Pauk
9e3de04388 protocol: partial support of 29.3 player coordinates
Changed only protocol without internal variables changes
2025-01-01 22:46:28 +02:00
Denis Pauk
33fd4579fb client: code style cleanup 2025-01-01 22:34:21 +02:00
Denis Pauk
89719b4a27 game: code style cleanup 2025-01-01 14:36:38 +02:00
Denis Pauk
1fdb0f81e6 renders: check min/max on nodes load 2024-12-31 15:22:43 +02:00
Denis Pauk
50a0609af8 protocol: use MSG_WritePos with protocol version 2024-12-31 13:14:28 +02:00
Denis Pauk
d6da3a5362 protocol: extend entity_xstate_t.origin to floats 2024-12-31 01:23:37 +02:00
Denis Pauk
13bd293c17 client: cleanup statusbar line 2024-12-28 18:35:21 +02:00
Denis Pauk
fd4a7abc58 game: sync target_camera with ReRelease
Based on: https://github.com/Paril/quake2-rerelease-dll.git
2024-12-27 17:26:46 +02:00
Denis Pauk
05b2b3928a readme: update videos 2024-12-26 17:25:25 +02:00
Denis Pauk
4e22fc255d game: add misc_player_mannequin from ReRelease code
Based on: https://github.com/Paril/quake2-rerelease-dll.git
2024-12-26 00:37:21 +02:00
Denis Pauk
c6338f0c36 game: add ai_model_scale from ReRelease code
Based on: https://github.com/Paril/quake2-rerelease-dll.git
2024-12-25 16:42:23 +02:00
Denis Pauk
9029beb87d game: Add npc_timeminder from Anachronox 2024-12-25 12:13:34 +02:00
Denis Pauk
ded38bbf44 game: sync target_autosave with ReRelease code
Based on: https://github.com/Paril/quake2-rerelease-dll.git
2024-12-25 11:30:36 +02:00
Denis Pauk
f7b9c8c518 game: sync target_sky with ReRelease code
Based on: https://github.com/Paril/quake2-rerelease-dll.git
2024-12-25 11:24:41 +02:00
Denis Pauk
dbcd1d0d6d game: allocate translation and dynamic entities by malloc
gi.TagMalloc can't be used as free up all tags on save load
2024-12-25 00:35:36 +02:00
Denis Pauk
b6f69da662 renders: use bigger light blocks
Fixes: n64jam_palmlix
2024-12-23 16:36:07 +02:00
Denis Pauk
a4511bd7f0 Merge remote-tracking branch 'yquake2/master' 2024-12-23 00:25:43 +02:00
Denis Pauk
54e32cb79d renders: dynamic allocation of PVS/PHS buffer 2024-12-23 00:11:08 +02:00
Denis Pauk
de20289cb1 collision: dynamic allocation of PVS/PHS buffer 2024-12-23 00:11:08 +02:00
Denis Pauk
1ca588ef5e maps: share Vis decode code 2024-12-23 00:11:08 +02:00
Denis Pauk
726e4616db renders: dynamic allocate buffer in *_MarkLeaves 2024-12-23 00:11:08 +02:00
Denis Pauk
0a346113dd maps: dynamic allocate buffer in Mod_LoadQBSPNodes 2024-12-23 00:11:08 +02:00
Denis Pauk
a21e1f27ed renders: validate count of clusters in visibility lump 2024-12-23 00:11:08 +02:00
Denis Pauk
14a832c710 game: fix pickup chainfist 2024-12-23 00:11:08 +02:00
Denis Pauk
27d1a87ab0 maps: reuse CM_Cluster code 2024-12-23 00:11:08 +02:00
Denis Pauk
9079f610d0 maps: make visibility entity optional
Based on q2pro.

Checked with n64jam_chnuckierdbeer map from https://www.moddb.com/games/quake-2/addons/quake-2-re-release-n64-sp-map-jam
2024-12-22 23:57:53 +02:00
Yamagi
9e127cf71f
Merge pull request #1175 from 0lvin/1173_crash
Make more function local and use const with names
2024-12-22 19:28:16 +01:00
SiemensSchuckert
49b4e97f5d
disable certificate validation for HTTPS (#1174)
disable certificate check for HTTPS

disable SSL certificate check - to allow download from servers with self-signed cert, or when some certs are missing from system certificate store that CURL uses

add new cvar `cl_http_verifypeer`
2024-12-22 19:12:48 +01:00
Denis Pauk
4025b1aa46 protocol: configstring should checked to negative values
partial revert of 91103f90
2024-12-21 16:06:49 +02:00
Denis Pauk
f70ec69470 hide local functions under static
Also apply recomentadion of msvc for use size_t with strlen.
2024-12-21 13:50:08 +02:00
Denis Pauk
02e6784111 renders: make pic name const 2024-12-21 13:03:44 +02:00
Denis Pauk
dfd2cb3700 Merge remote-tracking branch 'yquake2/master' 2024-12-21 12:19:57 +02:00
Yamagi
7211e06c8c Fix drawing of UDP download progress bar with r_consolescale > 1.
When calculating the Y position of the UDP download progress bar the
scale factor must be taken into account. Otherwise the bar will be drawn
outside the visible area of the console. This was missed when scaling
was first implemented years ago and broken since then.

Reported by @SiemensSchuckert, closes #1172.
2024-12-21 10:10:42 +01:00
Yamagi
290c9ecabe
Merge pull request #1170 from protocultor/wpn_preview
Sound backend selector + weapon preview for cycleweap
2024-12-21 09:51:42 +01:00
Denis Pauk
8d03b22a2f maps: fix yellow wall in daikatana e2m2a
Issue introduced in a09cbe20
2024-12-20 23:34:09 +02:00
Denis Pauk
c388d5b31d Merge remote-tracking branch 'yquake2/master' 2024-12-20 22:46:30 +02:00
Jaime Moreira
d3a98cf66b Text simplified for sound backend menu option
"Quality vs performance" might not correspond to reality; text deleted.
Documentation updated to reflect current state of both OpenAL and SDL
sound systems.
Authored by @Yamagi.
2024-12-20 16:36:53 -03:00
Yamagi
8c8488657c Fix less planes reserved for hull box testing than used down below.
This is an original bug, already present in Vanilla Quake 2.

Reported by @m-x-d, closes #1171.
2024-12-20 15:30:32 +01:00
Yamagi
cdf1cba106 Correct strncmp() checks in download code.
Reported by @m-x-d, closes #1167.
2024-12-20 15:24:27 +01:00
Denis Pauk
cbd1665239 game: fix spirit models on start points 2024-12-20 16:13:15 +02:00
Denis Pauk
c3d7def63d cmakefile: add vulkan build 2024-12-20 16:12:41 +02:00
Denis Pauk
ea94f56f18 cmakefile: add gl4 target 2024-12-20 16:12:32 +02:00
Denis Pauk
9d68b161bd readme: add new video 2024-12-20 16:12:19 +02:00
Denis Pauk
4293f1e73a cin: fix regression from c8985738 2024-12-20 16:12:02 +02:00
Denis Pauk
91103f907b add static for local function and use size_t with string length 2024-12-20 16:11:53 +02:00
Denis Pauk
8f0906704a Merge remote-tracking branch 'yquake2/master' 2024-12-20 16:10:28 +02:00
Yamagi
9522e9e490
Merge pull request #1169 from SiemensSchuckert/HTTP_dnl2
fix HTTP download crash (on 404)
2024-12-20 11:38:07 +01:00
Yamagi
bc168a7bfa
Merge pull request #1168 from SiemensSchuckert/HTTP_dnl1
fix HTTP download crash (on empty file)
2024-12-20 11:37:41 +01:00
Denis Pauk
5a0def601a client: improve autodetect heretic2 map 2024-12-18 22:39:06 +02:00
Denis Pauk
f931f9c8bc ReadMe: prepare for 8.42RR11 release 2024-12-18 19:35:50 +02:00
Denis Pauk
67052ec008 client: rework flashlight 2024-12-18 18:17:53 +02:00
Denis Pauk
7a3ebc7e99 game: Add support 'g_start_item'
Based on:
 * https://github.com/id-Software/quake2-rerelease-dll.git
2024-12-18 15:24:24 +02:00
Denis Pauk
fdeabf515c client: mesh mask in model preview 2024-12-17 21:41:10 +02:00
Jaime Moreira
60f0fdd969 Makefile parameter to disable SDL Gyro support
"make NO_SDL_GYRO=1" disables sensor reading support and forces
behavior of SDL < 2.0.14 under any version, even SDL 3.
Meant for Arch Linux ARM, which supports 2.30.10 at this time, but
doesn't support gyro readings (no HIDAPI support?), even if it shows
an additional "IMU joystick" when connecting Nintendo gamepads.
This commit allows to use the "IMU joystick" in game, extending #990.
Identification of joysticks as "IMU" or "Left Joy-Con" is more
generic now, covering more possible naming conventions.
2024-12-15 22:51:56 -03:00
Jaime Moreira
661761f047 Gamepad Gyro properly detected in SDL3
Using correct return value for SDL_SetGamepadSensorEnabled now.
Added menu command for gamepad sticks.
2024-12-15 22:22:28 -03:00
Jaime Moreira
5d201fce9a GL1 water warp effect
A basic "squeeze/stretch" effect to fov when diving underwater.
Intensity is controlled by gl1_waterwarp, 0 disables the effect.
Original from Fitzquake.
2024-12-11 21:05:27 -03:00
Jaime Moreira
6a3a081b4b Refactored gluPerspective-like function in GL1
It was being called repeteadly with the same parameters, so it was
re-written with only one needed parameter, with the rest of the data
being obtained inside the function, to avoid logic duplication.
2024-12-11 20:46:53 -03:00
Denis Pauk
5e8ffa3630 maps: Add support of Anachronox material flags 2024-12-10 23:20:53 +02:00
Denis Pauk
baa4d8153a protocol: restore ReRelease scale 2024-12-08 23:45:51 +02:00
Denis Pauk
032b66b062 protocol: Use combined entity state structure 2024-12-08 23:45:43 +02:00
Denis Pauk
d4b4266758 protocol: partial revert f856be35
protocol changes broke backward compatibility, temporary disable
2024-12-08 23:45:33 +02:00
Denis Pauk
b95ce55edc maps: add materials support check for other games 2024-12-07 18:01:03 +02:00
Denis Pauk
af7b8f6c61 client: add support foodstep based on floor material
Based on:
 * https://github.com/Paril/q2pro.git
2024-12-06 00:31:32 +02:00
Denis Pauk
05499dd331 maps: initial load material definitions 2024-12-06 00:29:50 +02:00
Denis Pauk
0c6c51f903 game: Add support health_multiplier from ReRelaes
Based on:
 * https://github.com/id-Software/quake2-rerelease-dll.git
2024-12-06 00:28:57 +02:00
Jaime Moreira
6b8cd8fdf9 Weapon preview for cycleweap
'Pickup style' just like weapprev/weapnext, only works when cycleweap
is called with 3 or more parameters.
Weapon binds in gamepad menus now include xatrix and rogue weapons.
2024-12-04 18:57:19 -03:00
Jaime Moreira
1825aa9723 Sound backend selector
Changes s_openal, replaces sound quality selector.
2024-12-04 18:53:57 -03:00
SiemensSchuckert
4cb319216f
fix HTTP download crash (on 404)
change parameter type to match CURL lib

(prevents crash on HTTP download)


example

test server:
q2.bot.nu:27912

server config:
set sv_downloadserver "https://quake2.pages.dev/"
map DEBEQUA2


Client connects, and three files added to queue:

HTTP download: /.filelist - Queued
HTTP download: /maps/DEBEQUA2.filelist - Queued
HTTP download: maps/DEBEQUA2.bsp - Queued


 from URL:
https://quake2.pages.dev/.filelist		- no file
https://quake2.pages.dev/maps/DEBEQUA2.filelist	- no file
https://quake2.pages.dev/maps/DEBEQUA2.bsp	- exists

when 404 response received for '.filelist' file,
CL_HTTP_Recv() is called and uses wrong file length in malloc()


one of tests:

==43024==ERROR: AddressSanitizer: requested allocation size 0x8000000000000000 (0x8000000000001000 after adjustments for alignment, red zones etc.) exceeds maximum supported size of 0x10000000000 (thread T0)
    0 0x7ffff74b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    1 0x55555566b023 in CL_HTTP_Recv src/client/curl/download.c:98
    2 0x7fffcbcc257a  (/lib/x86_64-linux-gnu/libcurl.so.4+0x5157a)
2024-12-04 18:54:45 +03:00
SiemensSchuckert
03d22045ad
fix HTTP download crash (on empty file)
when empty filelist downloaded from HTTP server,
CL_ParseFileList() uses unallocated buffer for strchr()

segfault happens:

0  __strchr_avx2 () at ../sysdeps/x86_64/multiarch/strchr-avx2.S:65
1  0x00007ffff743de2c in __interceptor_strchr (s=0x0, c=<optimized out>)
    at ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:705
2  0x000055555566d7f8 in CL_ParseFileList (dl=0x55555587a178 <cls+20984>)
    at src/client/curl/download.c:484
3  0x000055555566e26c in CL_FinishHTTPDownload ()
    at src/client/curl/download.c:670
2024-12-04 18:51:47 +03:00
Denis Pauk
5518640473 client: Add alttext to main menu
Workaround if game does not have any main menu images.
2024-12-01 23:38:24 +02:00
Denis Pauk
37b0e7a1f3 renders: add support of alt text for scaled image 2024-12-01 23:01:59 +02:00
Denis Pauk
65abf0188a game: add custom status bar for DoD(roarke) 2024-12-01 17:06:45 +02:00
Denis Pauk
94fc9a96ae game: update heretic2 items description 2024-12-01 01:25:48 +02:00
Denis Pauk
5055774a3d Merge remote-tracking branch 'yquake2/master' 2024-11-30 23:08:52 +02:00
Yamagi
9f6c455b45 Fix usage, the command is named dumpuser and not info.
This is likely a left over from some earlier version. Noticed by @m-x-d.
Closes #1166.
2024-11-30 16:30:55 +01:00
Denis Pauk
808f748f4a game: fix flashlight flag 2024-11-27 00:40:29 +02:00
Denis Pauk
58363c6696 game: Add BoB effect for items support
Based on:
 * https://github.com/Paril/q2pro.git
2024-11-26 23:37:04 +02:00
Denis Pauk
c7f74a3fa6 client: move flashlight to separate field 2024-11-26 23:34:22 +02:00
Denis Pauk
3314fc941e client: support of EF_FLASHLIGHT effect
Based on:
 * https://github.com/Paril/q2pro.git
2024-11-25 00:45:49 +02:00
Denis Pauk
5d21429c36 client: code style cleanup 2024-11-24 23:27:45 +02:00
Denis Pauk
27b41be951 game: add 'trigger_flashlight' support
Based on:
 * https://github.com/id-Software/quake2-rerelease-dll.git
2024-11-24 23:26:56 +02:00
Denis Pauk
42d5958d98 Merge remote-tracking branch 'yquake2/master' 2024-11-23 23:03:06 +02:00
Yamagi
6ff7413b65
Merge pull request #1163 from ps5-payload-dev/master
Simplify compiling for targets that lack GL drivers
2024-11-23 14:52:46 +01:00
John Törnblom
e21e057b04 backends: ensure _wgetcwd() is declared when compiling for windows 2024-11-23 13:39:40 +01:00
John Törnblom
24888cc3c1 backends: add portable variant of getcwd 2024-11-23 13:12:36 +01:00
John Törnblom
e87bcfb906 backends: ensure unistd.h is included when compiling for apple OSes 2024-11-23 13:11:19 +01:00
Yamagi
8b9f506a50
Merge pull request #1162 from devnexen/cmdparser_optim
cmdparser/server command little optimisations.
2024-11-23 08:49:48 +01:00
Denis Pauk
12fa246a6d game: fix scale for non dynamic definitions 2024-11-21 00:15:47 +02:00
Denis Pauk
e0ea452e9a renders: Add initial scale logic in renders
Based on rerelease code.

Checked with monster_boss2 on mgu1m3 map.
2024-11-19 23:48:39 +02:00
Denis Pauk
ddda42244d gl4: Disable too bright FRAMEBUFFER_SRGB 2024-11-18 00:53:10 +02:00
Denis Pauk
f856be3512 game: Add scale entity field (without real usage) 2024-11-18 00:48:31 +02:00
Denis Pauk
3f4efa05a1 models: ignore MDA tag before load 2024-11-17 18:32:27 +02:00
Denis Pauk
4981c8b972 maps: use shared function to replace backslashes 2024-11-17 16:54:37 +02:00
Denis Pauk
53e93824ca protocol: CUSTOM_PLAYER_MODEL(MAX_MODELS - 1) as player model 2024-11-17 14:58:30 +02:00
John Törnblom
9700eb6baf cmake: only gl1 renderer needs to be specifically linked 2024-11-17 01:34:07 +01:00
John Törnblom
38843f0f33 backends: when failing to determine executable path, print full path to cwd instead of just ./ 2024-11-16 15:53:43 +01:00
John Törnblom
c0eda78e43 sdl2: avoid spamming warnings when setting relative mouse mode fails 2024-11-16 15:52:24 +01:00
John Törnblom
0ea0dbf4ac ref_soft: check if renderer and texture are created correctly during context initialization 2024-11-16 15:51:58 +01:00
John Törnblom
ccc9027b1a ref_soft: if SDL renderer does not support SDL_RENDERER_ACCELERATED, fallback to SDL_RENDERER_SOFTWARE 2024-11-16 15:51:44 +01:00
John Törnblom
0babeb62c1 cmake: optionally disable the building of rendering libraries
default options are kept as before, i.e., all but GLES1 are enabled by default
2024-11-16 15:51:19 +01:00
David Carlier
d73f94d034
cmdparser/server command little optimisations. 2024-11-11 19:43:50 +00:00
Denis Pauk
a09cbe20bd maps: fix daikatana context flag convert 2024-11-10 22:30:37 +02:00
Denis Pauk
c3638d6c9a renders: skip SURF_NODRAW surfaces
Cheked with remaster psx/base0 map
2024-11-10 22:28:21 +02:00
Denis Pauk
6fd9e0ecc4 game: code style 2024-11-10 21:48:15 +02:00
Denis Pauk
03cb2be1e6 game: add 'g_language' localization cvar 2024-11-10 21:47:56 +02:00
Denis Pauk
1f0b9904ea Merge remote-tracking branch 'yquake2/master' 2024-11-10 21:43:50 +02:00
Yamagi
b64ae0ed6e
Merge pull request #1161 from devnexen/filesystem_littleoptim
FS_Dir_f little optimisation.
2024-11-10 14:50:25 +01:00
Yamagi
b31d187166
Merge pull request #1158 from BjossiAlfreds/sdl3-clipboard-fix
Small fix for SDL3 API change for SetClipboardText
2024-11-10 14:47:08 +01:00
Denis Pauk
af51dfbed4 Add mention about Q2Game.kpf for localization
Fixes: #32
2024-11-05 00:08:36 +02:00
Denis Pauk
67b2bc80ac game: add choose_cdtrack 2024-11-04 23:31:14 +02:00
Denis Pauk
be83c229e0 game: fix position of dropped objects 2024-11-03 00:48:32 +02:00
David Carlier
1b7ceada59
FS_Dir_f little optimisation. 2024-11-02 14:05:47 +00:00
Denis Pauk
dce9415411 game: Add key_yellow_key item definition
Based on:
 * https://github.com/id-Software/quake2-rerelease-dll/blob/main/rerelease/g_items.cpp
2024-11-01 23:36:23 +02:00
Denis Pauk
1f147f2fa8 game: sort spawn functions 2024-11-01 23:36:23 +02:00
Denis Pauk
f5eb462fc1 filesystem: fix usage of 'void *' in pointer arithmetic
Fixes: #30
2024-11-01 08:49:08 +02:00
Denis Pauk
12f4384a5f Add sample video of 8.42RR10 release 2024-10-27 21:57:31 +02:00
Denis Pauk
61bba6c6fd Merge remote-tracking branch 'yquake2/master' 2024-10-27 21:40:35 +02:00
Daniel Gibson
19a119417c Fix last commit (had SDL2 and SDL3 code switched in one case)
fix #1159
2024-10-27 16:39:45 +01:00
Denis Pauk
ba89fa6ca6 Version bump 8.42RR10 2024-10-27 02:00:57 +03:00
Denis Pauk
fc2d44f43c game: Add Heretic 2 entities description 2024-10-27 01:51:02 +03:00
Denis Pauk
bc7567fd30 game: Add Dawn of Darkness entities description 2024-10-26 23:37:54 +03:00
Denis Pauk
2ff7e8e6d0 game: implement env_fire with TE_FLAME 2024-10-26 23:37:54 +03:00
Denis Pauk
d5dad22f8d game: do not replace backslash in noise field
Add new field type F_LRAWSTRING for level strings with path.
2024-10-26 23:37:54 +03:00
Denis Pauk
b5fe2df7f8 game: show classname of dynamic spawn entities without description 2024-10-26 23:37:54 +03:00
Denis Pauk
d226454821 game: minimal implementation of SP_target_camera
Based on:
 * https://github.com/id-Software/quake2-rerelease-dll/blob/main/rerelease/g_target.cpp
2024-10-26 23:37:54 +03:00
Denis Pauk
f116fb44eb game: show description of dynamic spawn entities 2024-10-26 23:37:54 +03:00
Denis Pauk
db110ddc7e client: Restore CL_FlameEffect
Based on:
* https://github.com/id-Software/Quake-2/blob/master/client/cl_newfx.c
2024-10-26 23:37:54 +03:00
Denis Pauk
2c82f906e1 game: Partial implement misc_model, misc_flare
Based on:
* https://github.com/id-Software/quake2-rerelease-dll/blob/main/rerelease/g_misc.cpp
2024-10-26 23:37:54 +03:00
Denis Pauk
da8ee87f37 game: code style remove space before tab 2024-10-26 23:37:54 +03:00
Denis Pauk
17603050b6 game: Add fields used in misc_flare
Based on [ED_LoadColor](https://github.com/id-Software/quake2-rerelease-dll).
2024-10-26 23:37:54 +03:00
Denis Pauk
4f1e668eb7 game: support of item_invisibility 2024-10-26 23:37:54 +03:00
Jaime Moreira
d9de3ea0df vk: Support for the SDL 3.1.3 Preview release
https://github.com/yquake2/ref_vk/pull/51
https://github.com/yquake2/yquake2/issues/1156
2024-10-26 23:37:53 +03:00
Denis Pauk
e905ae1e09 Merge remote-tracking branch 'yquake2/master' 2024-10-26 23:37:15 +03:00
BjossiAlfreds
4f52c04b3b Small fix for SDL3 API change for SetClipboardText 2024-10-26 19:56:02 +00:00
Daniel Gibson
07ee830712 SDL3 return value fixes in gl1_sdl.c and gl3_sdl.c
and removed unused code from glimp_sdl3.c
2024-10-26 17:57:58 +02:00
Yamagi
b74d1a5247 Fix window flag handling with SDL3.
These are two problems breaking the window flags for renderers which
don't use OpenGL or enforce their own flags:

* In SDL 3 the window flags were increased from 32 bit to 64 bit. SDL
  3.1.3 introduced a new type SDL_WindowFlags for them. Use it to
  represent the window flags. This is currently a noop, becaue SDL 3
  doesn't have any flags above 32 bit yet. This might require another
  breakage of the renderer API in the future, because currently
  renderers pass a 32 bit flags thing to the client.
* `SDL_SetNumberProperty()` got a new type
  `SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER` to represent the flags. It must
  be used, otherwise strange things happen.

Closes #1156.
2024-10-26 17:28:31 +02:00
Yamagi
c719a18d54
Merge pull request #1157 from BjossiAlfreds/menu-input-ext
Clipboard and in-line editing for menu input fields
2024-10-26 16:11:10 +02:00
Yamagi
b134bb1770
Merge pull request #1154 from 0lvin/sdl2_soft_fix
soft: fix texture lock
2024-10-26 16:03:16 +02:00
BjossiAlfreds
993365cc6d END key jumps between start and end of current input string 2024-10-18 11:34:22 +00:00
BjossiAlfreds
c49a703467 Reset field cursor position when it leaves focus 2024-10-18 10:56:48 +00:00
BjossiAlfreds
b26be3ff5d CTRL+l,c,x,v shortcuts for menu input fields 2024-10-16 14:02:48 +00:00
BjossiAlfreds
8d5d86cbaf Q_strisnum shared helper function 2024-10-16 13:54:38 +00:00
BjossiAlfreds
aae0524687 Left/right arrow nav in menu fields 2024-10-16 02:00:53 +00:00
Denis Pauk
15a5f65fdf game: rename Quake Fish to rotfish 2024-10-09 23:59:45 +03:00
Denis Pauk
14db96211b soft: fix texture lock
Regression is introduced in 39d2c7dbb4
as sdl3 has changed logic of SDL_LockTexture function call.
2024-10-07 23:07:12 +03:00
Denis Pauk
091b3898c9 game: update entity.dat with models required for ssdocks heretic 2 map 2024-10-07 00:01:20 +03:00
Denis Pauk
8c233f78c3 Merge remote-tracking branch 'yquake2/master' 2024-10-06 22:35:23 +03:00
Yamagi
6408cc7099 Fix SDL3 build after merging sdl3-current into master.
One function call wasn't renamed, the missing function prevented the
build. Patch submitted by @protocultor in a comment to #1153.
2024-10-06 21:35:01 +02:00
erysdren
e8eb810c01 SDL3: Fix inconsistent name for deleting GL context 2024-10-06 10:20:00 +02:00
erysdren
39d2c7dbb4 Bump to SDL3 gitrev 8db3b47 2024-10-06 10:19:59 +02:00
erysdren
219b1b93fb Bump to SDL3 gitrev f6fc5e2 2024-10-06 10:19:59 +02:00
erysdren
2c212ae0b2 SDL3: Moved SDL_StartTextInput() to glimp_sdl3.c 2024-10-06 10:19:59 +02:00
erysdren
5ace09caac Partial fixes for SDL3 2024-10-06 10:19:55 +02:00
Yamagi
667ddafd83
Merge pull request #1152 from protocultor/gles1_addendum
Improvements for GL1/GLES1
2024-10-06 10:16:24 +02:00
Denis Pauk
ea6b135631 game: update entity.dat from fgd files
Based on:
 * https://github.com/TrenchBroom/TrenchBroom/blob/master/app/resources/games/Heretic2/heretic2.fgd
 * https://github.com/TrenchBroom/TrenchBroom/blob/master/app/resources/games/Kingpin/kingpin.fgd
 * https://github.com/TrenchBroom/TrenchBroom/blob/master/app/resources/games/Quake2/Quake2.fgd
2024-10-06 01:23:15 +03:00
Denis Pauk
4196a6104a game: use semicolon as model path separation
Use semicolon in model path for separation models for entity class
with several models, e.g.: head, body, legs.
2024-10-01 12:10:00 +03:00
Denis Pauk
711d07561c game: Add remaster repository entities 2024-09-30 00:24:54 +03:00
Denis Pauk
fa1132e247 game: initial known entities definitions
Add initial version without description and model path for now,
based on QUAKED comment get by grep code.
need to parse fgd files for add real definition and models or
check in code what model used.
2024-09-29 19:03:46 +03:00
Denis Pauk
473a4f3adc game: use dynamic definitions as defaults 2024-09-29 11:35:16 +03:00
Denis Pauk
d443fdc092 game: Add support of target_gravity, target_soundfx 2024-09-29 11:27:34 +03:00
Jaime Moreira
dbba5b5fd5 GL1: force vid_restart when changing stereo mode
Avoids spam to console
2024-09-29 00:07:59 -03:00
Jaime Moreira
45a84389db Removed unused parameter in 3 functions 2024-09-25 17:07:11 -03:00
Jaime Moreira
f2ea0b51b5 gl1_discardfb functionality expanded
Now also available in GL1. Includes a call to glClear at the beginning
of each frame, pointing to the same buffers that are discarded at the
end. When value is 1, operates over color, depth and stencil buffers.
When it's 2, only does depth and stencil, ignoring color. These
changes provide a performance improvement on mobile/embedded.
2024-09-24 16:33:39 -03:00
Denis Pauk
660412a525 cmake: update for minimal build
Fixes #28
2024-09-22 22:14:11 +03:00
Denis Pauk
98baf8223b model: replace ctc by md2 models on load
Temporary fix for ctc model load.
2024-09-22 14:53:06 +03:00
Denis Pauk
8d3d318b95 Update ReadMe 2024-09-22 14:49:28 +03:00
Denis Pauk
5bcb204623 models: support Anachronox 14 version 2024-09-22 13:32:12 +03:00
Jaime Moreira
e21479cbd2 Stereo 3D modes (gl1_stereo) allowed in GLES1
Availability of each mode depends on GPU support
2024-09-20 18:29:21 -03:00
Jaime Moreira
676e05ad1f Fixed GL1 stencil shadow when gl1_stereo = 3 to 5
Disabling stencil for shadowing in these stereo modes,
otherwise entities appear behind solid walls.
2024-09-20 16:56:58 -03:00
245 changed files with 27242 additions and 7196 deletions

View file

@ -1,63 +0,0 @@
name: Testbuild for Linux
run-name: testbuild_linux
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_x86_64:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Install build dependencies
run: |
sudo apt update
sudo apt install libgl1-mesa-dev libsdl2-dev libopenal-dev libcurl4-openssl-dev \
libavformat-dev libswscale-dev libvulkan-dev build-essential
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
sed -i 's|WITH_AVCODEC:=yes|WITH_AVCODEC:=no|g' Makefile
# Public runners come with 2 CPUs.
make -j2
make -j2 ref_gles1
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-linux-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-linux-${{github.sha}}/
# Copy misc assets
cp -r stuff/yq2.cfg publish/quake2-linux-${{github.sha}}/misc/yq2.cfg
cp -r stuff/mapfixes publish/quake2-linux-${{github.sha}}/misc
cp LICENSE publish/quake2-linux-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-linux-${{github.sha}}/misc/docs/README.txt
cp doc/010_index.md publish/quake2-linux-${{github.sha}}/misc/docs/010_index.txt
cp doc/020_installation.md publish/quake2-linux-${{github.sha}}/misc/docs/020_installation.txt
cp doc/030_configuration.md publish/quake2-linux-${{github.sha}}/misc/docs/030_configuration.txt
cp doc/040_cvarlist.md publish/quake2-linux-${{github.sha}}/misc/docs/040_cvarlist.txt
cp doc/050_commands.md publish/quake2-linux-${{github.sha}}/misc/docs/050_commands.txt
cp doc/060_multiplayer.md publish/quake2-linux-${{github.sha}}/misc/docs/060_multiplayer.txt
cp doc/070_packaging.md publish/quake2-linux-${{github.sha}}/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/quake2-linux-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-linux-${{github.sha}}/misc/docs/090_filelists.md
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-linux-${{github.sha}}
path: publish/
if-no-files-found: error

63
.github/workflows/linux_aarch64.yml vendored Normal file
View file

@ -0,0 +1,63 @@
name: Testbuild for Linux (aarch64)
run-name: testbuild_linux_aarch64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_aarch64:
runs-on: ubuntu-22.04-arm
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Install build dependencies
run: |
sudo apt update
sudo apt install libgl1-mesa-dev libsdl2-dev libopenal-dev libcurl4-openssl-dev \
libavformat-dev libswscale-dev libvulkan-dev build-essential
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
sed -i 's|WITH_AVCODEC:=yes|WITH_AVCODEC:=no|g' Makefile
# Public runners come with 4 CPUs.
make -j4
make -j4 ref_gles1
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-linux_aarch64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-linux_aarch64-${{github.sha}}/
# Copy misc assets
cp -r stuff/yq2.cfg publish/quake2-linux_aarch64-${{github.sha}}/misc/yq2.cfg
cp -r stuff/mapfixes publish/quake2-linux_aarch64-${{github.sha}}/misc
cp LICENSE publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/README.txt
cp doc/010_index.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/010_index.txt
cp doc/020_installation.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/020_installation.txt
cp doc/030_configuration.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/030_configuration.txt
cp doc/040_cvarlist.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/040_cvarlist.txt
cp doc/050_commands.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/050_commands.txt
cp doc/060_multiplayer.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/060_multiplayer.txt
cp doc/070_packaging.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-linux_aarch64-${{github.sha}}/misc/docs/090_filelists.md
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-linux_aarch64-${{github.sha}}
path: publish/
if-no-files-found: error

63
.github/workflows/linux_x86_64.yml vendored Normal file
View file

@ -0,0 +1,63 @@
name: Testbuild for Linux (x86_64)
run-name: testbuild_linux_x86_64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_x86_64:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Install build dependencies
run: |
sudo apt update
sudo apt install libgl1-mesa-dev libsdl2-dev libopenal-dev libcurl4-openssl-dev \
libavformat-dev libswscale-dev libvulkan-dev build-essential
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
sed -i 's|WITH_AVCODEC:=yes|WITH_AVCODEC:=no|g' Makefile
# Public runners come with 4 CPUs.
make -j4
make -j4 ref_gles1
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-linux_x86_64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-linux_x86_64-${{github.sha}}/
# Copy misc assets
cp -r stuff/yq2.cfg publish/quake2-linux_x86_64-${{github.sha}}/misc/yq2.cfg
cp -r stuff/mapfixes publish/quake2-linux_x86_64-${{github.sha}}/misc
cp LICENSE publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/README.txt
cp doc/010_index.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/010_index.txt
cp doc/020_installation.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/020_installation.txt
cp doc/030_configuration.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/030_configuration.txt
cp doc/040_cvarlist.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/040_cvarlist.txt
cp doc/050_commands.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/050_commands.txt
cp doc/060_multiplayer.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/060_multiplayer.txt
cp doc/070_packaging.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-linux_x86_64-${{github.sha}}/misc/docs/090_filelists.md
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-linux_x86_64-${{github.sha}}
path: publish/
if-no-files-found: error

View file

@ -54,6 +54,29 @@ jobs:
cp doc/070_packaging.md publish/quake2-macos-${{github.sha}}/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/quake2-macos-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-macos-${{github.sha}}/misc/docs/090_filelists.md
- name: Create dmg package
run: |
rm -rf build/macos-dmg
mkdir -p build/macos-dmg
# start with app bundle template
unzip stuff/osx/quake2-appbundle.zip -d build/macos-dmg
# add files in root of disk image
cp LICENSE README.md build/macos-dmg
# copy all binaries to Resources dir
cp -r release/* "build/macos-dmg/Quake 2.app/Contents/Resources"
# dependency: libSDL2
cp -R /opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib "build/macos-dmg/Quake 2.app/Contents/Resources"
install_name_tool -id "libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/libSDL2-2.0.0.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/quake2"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_gl1.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_gl3.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_gles3.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_gl4.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_soft.dylib"
install_name_tool -change "/opt/homebrew/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Resources/libSDL2-2.0.0.dylib" "build/macos-dmg/Quake 2.app/Contents/Resources/ref_vk.dylib"
# make disk image
hdiutil create -srcfolder build/macos-dmg -layout SPUD -fs HFS+ -volname "Yamagi Quake II" "release/yquake2.dmg"
cp release/yquake2.dmg publish/quake2-macos-${{github.sha}}/
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
@ -65,6 +88,7 @@ jobs:
run: |
# create archive
mkdir yquake2remaster-${{matrix.env}}-${{github.ref_name}}
mv publish/quake2-macos-${{github.sha}}/yquake2.dmg yquake2remaster-${{matrix.env}}-${{github.ref_name}}.dmg
cp -rv publish/quake2-macos-${{github.sha}}/* yquake2remaster-${{matrix.env}}-${{github.ref_name}}
zip -9r yquake2remaster-${{matrix.env}}-${{github.ref_name}}.zip yquake2remaster-${{matrix.env}}-${{github.ref_name}}
- name: Upload Release Asset
@ -73,3 +97,4 @@ jobs:
with:
files: |
yquake2remaster-${{matrix.env}}-${{github.ref_name}}.zip
yquake2remaster-${{matrix.env}}-${{github.ref_name}}.dmg

View file

@ -46,8 +46,8 @@ jobs:
shell: msys2 {0}
run: |
sed -i 's|WITH_AVCODEC:=yes|WITH_AVCODEC:=no|g' Makefile
# Public runners come with 2 CPUs.
make -j2
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
shell: msys2 {0}
run: |
@ -70,8 +70,8 @@ jobs:
cp doc/080_contributing.md publish/quake2-win32-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-win32-${{github.sha}}/misc/docs/090_filelists.md
# SDL2
wget -c https://github.com/libsdl-org/SDL/releases/download/release-2.30.7/SDL2-2.30.7-win32-x86.zip
unzip -o SDL2-2.30.7-win32-x86.zip
wget -c https://github.com/libsdl-org/SDL/releases/download/release-2.32.0/SDL2-2.32.0-win32-x86.zip
unzip -o SDL2-2.32.0-win32-x86.zip
cp SDL2.dll publish/quake2-win32-${{github.sha}}/
# openal-soft
wget -c https://github.com/kcat/openal-soft/releases/download/1.23.1/openal-soft-1.23.1-bin.zip

View file

@ -1,4 +1,4 @@
name: Testbuild for Win64
name: Testbuild for Win64 (SDL3)
run-name: testbuild_win64
on:
push:
@ -8,8 +8,9 @@ on:
- "*"
pull_request:
types:
- opened
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
@ -37,17 +38,19 @@ jobs:
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-make
mingw-w64-${{matrix.env}}-openal
mingw-w64-${{matrix.env}}-SDL2
mingw-w64-${{matrix.env}}-sdl3
mingw-w64-${{matrix.env}}-vulkan-headers
mingw-w64-${{matrix.env}}-wget
mingw-w64-${{matrix.env}}-pkgconf
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
shell: msys2 {0}
run: |
# Public runners come with 2 CPUs.
make -j2
make -j2 ref_gles1
sed -i 's|WITH_SDL3:=no|WITH_SDL3:=yes|g' Makefile
# Public runners come with 4 CPUs.
make -j4
make -j4 ref_gles1
- name: Create testbuild package
shell: msys2 {0}
run: |
@ -69,10 +72,10 @@ jobs:
cp doc/070_packaging.md publish/quake2-win64-${{github.sha}}/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/quake2-win64-${{github.sha}}/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/quake2-win64-${{github.sha}}/misc/docs/090_filelists.md
# SDL2
wget -c https://github.com/libsdl-org/SDL/releases/download/release-2.30.7/SDL2-2.30.7-win32-x64.zip
unzip -o SDL2-2.30.7-win32-x64.zip
cp SDL2.dll publish/quake2-win64-${{github.sha}}/
# SDL3
wget -c https://github.com/libsdl-org/SDL/releases/download/release-3.2.4/SDL3-3.2.4-win32-x64.zip
unzip -o SDL3-3.2.4-win32-x64.zip
cp SDL3.dll publish/quake2-win64-${{github.sha}}/
# static ffmpeg
wget -c https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-08-31-12-50/ffmpeg-n7.0.2-6-g7e69129d2f-win64-lgpl-shared-7.0.zip
unzip -o ffmpeg-n7.0.2-6-g7e69129d2f-win64-lgpl-shared-7.0.zip
@ -84,9 +87,9 @@ jobs:
unzip -o openal-soft-1.23.1-bin.zip
cp openal-soft-1.23.1-bin/bin/Win64/soft_oal.dll publish/quake2-win64-${{github.sha}}/openal32.dll
# curl (releases use a custom build curl.dll)
wget -c https://curl.se/windows/dl-8.9.1_1/curl-8.9.1_1-win64-mingw.zip
unzip -o curl-8.9.1_1-win64-mingw.zip
cp curl-8.9.1_1-win64-mingw/bin/libcurl-x64.dll publish/quake2-win64-${{github.sha}}/curl.dll
wget -c -O curl-mingw-latest.zip "https://curl.se/windows/latest.cgi?p=win64-mingw.zip"
unzip -o curl-mingw-latest.zip
cp curl-*-win64-mingw/bin/libcurl-x64.dll publish/quake2-win64-${{github.sha}}/curl.dll
- name: Upload testbuild package
uses: actions/upload-artifact@v4
if: ${{ ! startsWith(github.ref, 'refs/tags/') }}

180
.github/workflows/win_msvc.yml vendored Normal file
View file

@ -0,0 +1,180 @@
name: Testbuild for x86 and x86_64 Windows with MSVC
run-name: testbuild_windows
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_win_x86_msvc:
runs-on: windows-latest
defaults:
run:
# use git bash for for all steps (unless specified otherwise per step)
shell: bash
strategy:
fail-fast: false
steps:
- name: Install build dependencies
run: |
# Download and extract dhewm3-libs
# as the repo will be cloned into the directory we're currently in (O_o)
# go one directory up to D:\a\yquake2\ (or similar) and put the dhewm3libs there
cd ..
# https://github.com/dhewm/dhewm3-libs/archive/refs/heads/master.zip
# for some reason the following downloads an empty file, so use the other URL I got from
# "Copy Download Link" in Firefox (after downloading the file there) instead
#curl -o dhewm3libs.zip https://github.com/dhewm/dhewm3-libs/archive/refs/heads/master.zip
curl -o dhewm3libs.zip https://codeload.github.com/dhewm/dhewm3-libs/zip/refs/heads/master
# only unpack the stuff needed (no x86_64 stuff, no docs from share/)
unzip dhewm3libs.zip "dhewm3-libs-master/i686-w64-mingw32/**" -x "dhewm3-libs-master/i686-w64-mingw32/share/**"
# vulkan
curl -o vulkan_headers.zip https://codeload.github.com/KhronosGroup/Vulkan-Headers/zip/refs/heads/master
unzip vulkan_headers.zip "Vulkan-Headers-master/include/**"
cp -rv Vulkan-Headers-master/include/* dhewm3-libs-master/i686-w64-mingw32/include/
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# build with cmake and visual studio
#echo $PWD # /d/a/dhewm3/dhewm3
# NOTE: not setting -G "Visual Studio 17 2022" so it just uses the default VS version it can find
cmake -A Win32 -DYQUAKE2LIBS="../dhewm3-libs-master/i686-w64-mingw32/" -S . -B build
time cmake --build build/ --config RelWithDebInfo
- name: Create testbuild package
run: |
# Create release directory tree
export PKGDIR="yquake2-win32-$(git rev-parse --short HEAD)"
echo "pkgname=$PKGDIR" >> $GITHUB_ENV
mkdir -p publish/$PKGDIR/misc/docs
mkdir -p publish/$PKGDIR/baseq2
# debug symbols (*.pdb) are put in a separate zip
mkdir -p debug-syms/$PKGDIR
# Copy release assets
cd build/release/RelWithDebInfo/
cp *.exe *.dll ../../../publish/$PKGDIR/
cp baseq2/*.dll ../../../publish/$PKGDIR/baseq2/
cp *.pdb ../../../debug-syms/$PKGDIR/
cp baseq2/*.pdb ../../../debug-syms/$PKGDIR/
cd ../../..
# Copy misc assets
cp -r stuff/yq2.cfg publish/$PKGDIR/misc/yq2.cfg
cp -r stuff/mapfixes publish/$PKGDIR/misc
cp LICENSE publish/$PKGDIR/misc/docs/LICENSE.txt
cp README.md publish/$PKGDIR/misc/docs/README.txt
cp doc/010_index.md publish/$PKGDIR/misc/docs/010_index.txt
cp doc/020_installation.md publish/$PKGDIR/misc/docs/020_installation.txt
cp doc/030_configuration.md publish/$PKGDIR/misc/docs/030_configuration.txt
cp doc/040_cvarlist.md publish/$PKGDIR/misc/docs/040_cvarlist.txt
cp doc/050_commands.md publish/$PKGDIR/misc/docs/050_commands.txt
cp doc/060_multiplayer.md publish/$PKGDIR/misc/docs/060_multiplayer.txt
cp doc/070_packaging.md publish/$PKGDIR/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/$PKGDIR/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/$PKGDIR/misc/docs/090_filelists.md
# copy runtime libraries (SDL, OpenAL, cURL)
cd ../dhewm3-libs-master/i686-w64-mingw32/bin/
cp OpenAL32.dll SDL2.dll ../../../yquake2remaster/publish/$PKGDIR/
cp libcurl-4.dll ../../../yquake2remaster/publish/$PKGDIR/curl.dll
cd -
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: ${{ env.pkgname }}
path: publish/
if-no-files-found: error
- name: Upload testbuild debug symbols
uses: actions/upload-artifact@v4
with:
name: ${{ env.pkgname }}-debugsyms
path: debug-syms/
if-no-files-found: error
build_win_x86_64_msvc:
runs-on: windows-latest
defaults:
run:
# use git bash for for all steps (unless specified otherwise per step)
shell: bash
strategy:
fail-fast: false
steps:
- name: Install build dependencies
run: |
# Download and extract dhewm3-libs
#echo $PWD # /d/a/dhewm3/dhewm3
# as the repo will be cloned into the directory we're currently in (O_o)
# go one directory up to D:\a\dhewm3\ and put the dhewm3libs there
cd ..
# https://github.com/dhewm/dhewm3-libs/archive/refs/heads/master.zip
# for some reason the following downloads an empty file, so use the other URL I got from
# "Copy Download Link" in Firefox (after downloading the file there) instead
#curl -o dhewm3libs.zip https://github.com/dhewm/dhewm3-libs/archive/refs/heads/master.zip
curl -o dhewm3libs.zip https://codeload.github.com/dhewm/dhewm3-libs/zip/refs/heads/master
# only unpack the stuff needed (no i686 stuff, no docs from share/)
unzip dhewm3libs.zip "dhewm3-libs-master/x86_64-w64-mingw32/**" -x "dhewm3-libs-master/x86_64-w64-mingw32/share/**"
# vulkan
curl -o vulkan_headers.zip https://codeload.github.com/KhronosGroup/Vulkan-Headers/zip/refs/heads/master
unzip vulkan_headers.zip "Vulkan-Headers-master/include/**"
cp -rv Vulkan-Headers-master/include/* dhewm3-libs-master/x86_64-w64-mingw32/include/
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# build with cmake and visual studio
# NOTE: not setting -G "Visual Studio 17 2022" so it just uses the default VS version it can find
cmake -A x64 -DYQUAKE2LIBS="../dhewm3-libs-master/x86_64-w64-mingw32/" -S . -B build
time cmake --build build/ --config RelWithDebInfo
- name: Create testbuild package
run: |
# Create release directory tree
export PKGDIR="yquake2-win64-$(git rev-parse --short HEAD)"
echo "pkgname=$PKGDIR" >> $GITHUB_ENV
mkdir -p publish/$PKGDIR/misc/docs
mkdir -p publish/$PKGDIR/baseq2
# debug symbols (*.pdb) are put in a separate zip
mkdir -p debug-syms/$PKGDIR
# Copy release assets
cd build/release/RelWithDebInfo/
cp *.exe *.dll ../../../publish/$PKGDIR/
cp baseq2/*.dll ../../../publish/$PKGDIR/baseq2/
cp *.pdb ../../../debug-syms/$PKGDIR/
cp baseq2/*.pdb ../../../debug-syms/$PKGDIR/
cd ../../..
# Copy misc assets
cp -r stuff/yq2.cfg publish/$PKGDIR/misc/yq2.cfg
cp -r stuff/mapfixes publish/$PKGDIR/misc
cp LICENSE publish/$PKGDIR/misc/docs/LICENSE.txt
cp README.md publish/$PKGDIR/misc/docs/README.txt
cp doc/010_index.md publish/$PKGDIR/misc/docs/010_index.txt
cp doc/020_installation.md publish/$PKGDIR/misc/docs/020_installation.txt
cp doc/030_configuration.md publish/$PKGDIR/misc/docs/030_configuration.txt
cp doc/040_cvarlist.md publish/$PKGDIR/misc/docs/040_cvarlist.txt
cp doc/050_commands.md publish/$PKGDIR/misc/docs/050_commands.txt
cp doc/060_multiplayer.md publish/$PKGDIR/misc/docs/060_multiplayer.txt
cp doc/070_packaging.md publish/$PKGDIR/misc/docs/070_packaging.txt
cp doc/080_contributing.md publish/$PKGDIR/misc/docs/080_contributing.txt
cp doc/090_filelists.md publish/$PKGDIR/misc/docs/090_filelists.md
# copy runtime libraries (SDL, OpenAL, cURL)
cd ../dhewm3-libs-master/x86_64-w64-mingw32/bin/
cp OpenAL32.dll SDL2.dll ../../../yquake2remaster/publish/$PKGDIR/
cp libcurl-4.dll ../../../yquake2remaster/publish/$PKGDIR/curl.dll
cd -
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: ${{ env.pkgname }}
path: publish/
if-no-files-found: error
- name: Upload testbuild debug symbols
uses: actions/upload-artifact@v4
with:
name: ${{ env.pkgname }}-debugsyms
path: debug-syms/
if-no-files-found: error

View file

@ -1,3 +1,86 @@
Quake II 8.41 to 8.50:
- Consistent bindings between multiple gamepad types. (by protocultor)
- Improved menu navigation with gamepads. (by protocultor)
- The SDL 3 code now supports the stable SDL 3 API. Several bugs with
SDL 3 were fixed. (by 0lvin, BjossiAlfreds, erysdren and protocultor)
- Water warp effect for the OpenGL 1.4 renderer. (by protocultor)
- Add a sound backend selector to the menu. (by protocultor)
- Fix several problems with HTTP downloads. (by SiemensSchuckert)
- Better navigation in input fields in the menu. Support left and right
navigation, add support for the ctrl-l,c,x,v shortcuts. (by
BjossiAlfreds)
- Performance optimizations for the OpenGL 1.4 renderer, especially on
embedded and mobile GPUs. Includes an alternative GL ES 1.0 renderer.
(by protocultor)
- Several fixes to `gl1_stereo`. (by protocultor)
- Fix the SDL2 sound backend not working with modern backends.
- Make the Windows key bindable. (by Andrew Malchuk)
- Support true randomness when shuffling audio tracks. (by
apartfromtime)
- Fix leaking temporary spawnflags into entities spawned mid-level. (by
BjossiAlfreds)
- Support the unofficial GL4 renderer lib in the video menu (by atsb)
- Clipboard support for the console and better navigation in the console
line editor. (By BjossiAlfreds)
- Support player models inside pak files in the menu. (by 0lvin)
- Support 24 bit PCX files. (by 0lvin)
- Check if an entity file matches the current map before loading it.
This fixes problems with loading entity files from Quake II against
Quake II Remaster maps and the other way round. (by 0lvin)
Quake 2 8.42RR12:
- Fix intro .cin video crash
- Update CMakefile with vulkan and gl4 targets
- maps: remove spirit of player models on start points
- maps: fix yellow wall in daikatana e2m2a
- maps: make visibility entity optional
- game: fix pickup chainfist
- game: fix allocation code for translation and dynamic entities
- game: sync target_sky, sync target_camera, target_autosave with ReRelease code
- game: Add npc_timeminder from Anachronox
- game: add ai_model_scale, misc_player_mannequin from ReRelease code
- Add MacOS DMG and use windows x64 SDL3 build
- Anachronox: support initial ATD sprites
- Anachronox: update MDA load code
- SiN: dynamic allocation of sub models list in .def
Quake 2 8.42RR11:
- ReRelease: add support `flashlight` item
- ReRelease: add support `trigger_flashlight`
- ReRelease: add support `start_item` cvar/map property
- ReRelease: add material support for custom footstep sound
- ReRelease: add support `health_multiplier`
- ReRelease: add support `g_itemsbobeffect` (bob effect for items)
- ReRelease: add models scale support
- ReRelease: ignore nodraw surfaces
- ReRelease: add `g_language` localization cvar
- ReRelease: update docs about localization
- ReRelease: fix `key_yellow_key` item definition
- ReRelease: sort spawn function before search
- Other games maps: alternative text for unexisted iamges in menu
- Other games maps: convert map suface flags to material type
- Other games maps: update entities definition file
- Other games maps: support mesh hide mask for player model preview
- Other games maps: `choose_cdtrack` triger support
- Anachronox: ignore tag name in model for now
- DoD: add custom status bar
- Daikatana: fix surface flags convert
- yquake2: improve backends support @john-tornblom
- yquake2: clipboard fix @BjossiAlfreds
- yquake2: update cmd parser @devnexen
- yquake2: update soft render with unaccelerated render support @john-tornblom
- yquake2: fix compile without gl targets @john-tornblom
- renders: sync gl4 with gl3 codes
- game: use player model id based on max models limit
- filesystem: fix pointers arithmetic
Quake 2 8.42RR10:
- client: updated console logic,
- game: Update default entities descriptor file,
- game: Add hack for next level change in q64/outpost
- game: Restore flame effect, currently used only as torch fire in
Heretic 2 fire as example.
Quake 2 8.42RR9:
- vk: fixed vulkan call groups,
- game: Add ReRelease translated messages (English only)

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# Print a message that using the Makefiles is recommended.
message(NOTICE: " The CMakeLists.txt is unmaintained. Use the Makefile if possible.")
@ -65,6 +65,13 @@ option(CURL_SUPPORT "cURL support" ON)
option(OPENAL_SUPPORT "OpenAL support" ON)
option(SYSTEMWIDE_SUPPORT "Enable systemwide installation of game assets" OFF)
option(SDL3_SUPPORT "Build against SDL 3 instead of SDL2" OFF)
option(GL1_RENDERER "Build the GL1 renderer" ON)
option(GL3_RENDERER "Build the GL3 renderer" ON)
option(GL4_RENDERER "Build the GL4 renderer" ON)
option(GLES1_RENDERER "Build the GLES1 renderer" OFF)
option(GLES3_RENDERER "Build the GLES3 renderer" ON)
option(SOFT_RENDERER "Build the software renderer" ON)
option(VK_RENDERER "Build the Vulkan renderer" ON)
set(SYSTEMDIR "" CACHE STRING "Override the system default directory")
@ -164,10 +171,10 @@ unset(cpu)
# Systemwide installation of game assets.
if(${SYSTEMWIDE_SUPPORT})
add_definitions(-DSYSTEMWIDE)
if(NOT ${SYSTEMDIR} STREQUAL "")
add_definitions(-DSYSTEMDIR="${SYSTEMDIR}")
endif()
add_definitions(-DSYSTEMWIDE)
if(NOT ${SYSTEMDIR} STREQUAL "")
add_definitions(-DSYSTEMDIR="${SYSTEMDIR}")
endif()
endif()
# We need to pass some options to minizip / unzip.
@ -189,11 +196,13 @@ else()
list(APPEND yquake2SDLLinkerFlags ${SDL2_LIBRARY})
endif()
# We need an OpenGL implementation.
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
list(APPEND yquake2IncludeDirectories ${OPENGL_INCLUDE_DIR})
list(APPEND yquake2OpenGLLinkerFlags ${OPENGL_LIBRARIES})
if(GL1_RENDERER)
# We need an OpenGL implementation.
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
list(APPEND yquake2IncludeDirectories ${OPENGL_INCLUDE_DIR})
list(APPEND yquake2OpenGLLinkerFlags ${OPENGL_LIBRARIES})
endif()
# backtrace lookup
# Some systems like Linux has it within the libc some like the BSD, Haiku ...
@ -253,7 +262,7 @@ else()
list(APPEND yquake2LinkerFlags "-rdynamic")
else()
list(APPEND yquake2LinkerFlags "-lnetwork")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
list(APPEND yquake2LinkerFlags "-lsocket -lnsl")
@ -336,45 +345,102 @@ set(Game-Source
${COMMON_SRC_DIR}/shared/flash.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${GAME_SRC_DIR}/bot/ai_class_dmbot.c
${GAME_SRC_DIR}/bot/ai_class_monster_default.c
${GAME_SRC_DIR}/bot/ai_dropnodes.c
${GAME_SRC_DIR}/bot/ai_items.c
${GAME_SRC_DIR}/bot/ai_links.c
${GAME_SRC_DIR}/bot/ai_local.h
${GAME_SRC_DIR}/bot/ai_main.c
${GAME_SRC_DIR}/bot/ai_movement.c
${GAME_SRC_DIR}/bot/ai_navigation.c
${GAME_SRC_DIR}/bot/ai_nodes.c
${GAME_SRC_DIR}/bot/ai_nodes_local.h
${GAME_SRC_DIR}/bot/ai_nodes_shared.h
${GAME_SRC_DIR}/bot/ai_tools.c
${GAME_SRC_DIR}/bot/ai_weapons.c
${GAME_SRC_DIR}/bot/ai_weapons.h
${GAME_SRC_DIR}/bot/astar.c
${GAME_SRC_DIR}/bot/bot_spawn.c
${GAME_SRC_DIR}/dm/ball.c
${GAME_SRC_DIR}/dm/tag.c
${GAME_SRC_DIR}/g_ai.c
${GAME_SRC_DIR}/g_chase.c
${GAME_SRC_DIR}/g_cmds.c
${GAME_SRC_DIR}/g_combat.c
${GAME_SRC_DIR}/g_ctf.c
${GAME_SRC_DIR}/g_func.c
${GAME_SRC_DIR}/g_items.c
${GAME_SRC_DIR}/g_light.c
${GAME_SRC_DIR}/g_main.c
${GAME_SRC_DIR}/g_misc.c
${GAME_SRC_DIR}/g_monster.c
${GAME_SRC_DIR}/g_newai.c
${GAME_SRC_DIR}/g_newdm.c
${GAME_SRC_DIR}/g_newfnc.c
${GAME_SRC_DIR}/g_newtarg.c
${GAME_SRC_DIR}/g_newtrig.c
${GAME_SRC_DIR}/g_newweap.c
${GAME_SRC_DIR}/g_obj.c
${GAME_SRC_DIR}/g_phys.c
${GAME_SRC_DIR}/g_spawn.c
${GAME_SRC_DIR}/g_sphere.c
${GAME_SRC_DIR}/g_svcmds.c
${GAME_SRC_DIR}/g_target.c
${GAME_SRC_DIR}/g_translate.c
${GAME_SRC_DIR}/g_trigger.c
${GAME_SRC_DIR}/g_turret.c
${GAME_SRC_DIR}/g_utils.c
${GAME_SRC_DIR}/g_weapon.c
${GAME_SRC_DIR}/menu/menu.c
${GAME_SRC_DIR}/monster/actor/actor.c
${GAME_SRC_DIR}/monster/arachnid/arachnid.c
${GAME_SRC_DIR}/monster/army/army.c
${GAME_SRC_DIR}/monster/berserker/berserker.c
${GAME_SRC_DIR}/monster/boss2/boss2.c
${GAME_SRC_DIR}/monster/boss3/boss3.c
${GAME_SRC_DIR}/monster/boss3/boss31.c
${GAME_SRC_DIR}/monster/boss3/boss32.c
${GAME_SRC_DIR}/monster/boss3/boss3.c
${GAME_SRC_DIR}/monster/boss5/boss5.c
${GAME_SRC_DIR}/monster/brain/brain.c
${GAME_SRC_DIR}/monster/carrier/carrier.c
${GAME_SRC_DIR}/monster/chick/chick.c
${GAME_SRC_DIR}/monster/demon/demon.c
${GAME_SRC_DIR}/monster/dog/dog.c
${GAME_SRC_DIR}/monster/enforcer/enforcer.c
${GAME_SRC_DIR}/monster/fixbot/fixbot.c
${GAME_SRC_DIR}/monster/flipper/flipper.c
${GAME_SRC_DIR}/monster/float/float.c
${GAME_SRC_DIR}/monster/flyer/flyer.c
${GAME_SRC_DIR}/monster/gekk/gekk.c
${GAME_SRC_DIR}/monster/gladiator/gladb.c
${GAME_SRC_DIR}/monster/gladiator/gladiator.c
${GAME_SRC_DIR}/monster/guardian/guardian.c
${GAME_SRC_DIR}/monster/gunner/gunner.c
${GAME_SRC_DIR}/monster/hknight/hknight.c
${GAME_SRC_DIR}/monster/hover/hover.c
${GAME_SRC_DIR}/monster/infantry/infantry.c
${GAME_SRC_DIR}/monster/insane/insane.c
${GAME_SRC_DIR}/monster/knight/knight.c
${GAME_SRC_DIR}/monster/medic/medic.c
${GAME_SRC_DIR}/monster/misc/move.c
${GAME_SRC_DIR}/monster/mutant/mutant.c
${GAME_SRC_DIR}/monster/ogre/ogre.c
${GAME_SRC_DIR}/monster/parasite/parasite.c
${GAME_SRC_DIR}/monster/rotfish/fish.c
${GAME_SRC_DIR}/monster/shalrath/shalrath.c
${GAME_SRC_DIR}/monster/shambler/shambler.c
${GAME_SRC_DIR}/monster/soldier/soldier.c
${GAME_SRC_DIR}/monster/stalker/stalker.c
${GAME_SRC_DIR}/monster/supertank/supertank.c
${GAME_SRC_DIR}/monster/tank/tank.c
${GAME_SRC_DIR}/monster/tarbaby/tarbaby.c
${GAME_SRC_DIR}/monster/turret/turret.c
${GAME_SRC_DIR}/monster/widow/widow2.c
${GAME_SRC_DIR}/monster/widow/widow.c
${GAME_SRC_DIR}/monster/wizard/wizard.c
${GAME_SRC_DIR}/monster/zombie/zombie.c
${GAME_SRC_DIR}/player/chase.c
${GAME_SRC_DIR}/player/client.c
${GAME_SRC_DIR}/player/hud.c
${GAME_SRC_DIR}/player/trail.c
@ -452,18 +518,26 @@ set(Client-Source
${COMMON_SRC_DIR}/collision.c
${COMMON_SRC_DIR}/crc.c
${COMMON_SRC_DIR}/cmdparser.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/cvar.c
${COMMON_SRC_DIR}/filesystem.c
${COMMON_SRC_DIR}/glob.c
${COMMON_SRC_DIR}/maps.c
${COMMON_SRC_DIR}/md4.c
${COMMON_SRC_DIR}/movemsg.c
${COMMON_SRC_DIR}/models/loadfile.c
${COMMON_SRC_DIR}/models/models.c
${COMMON_SRC_DIR}/models/models_md5.c
${COMMON_SRC_DIR}/models/models_mdr.c
${COMMON_SRC_DIR}/frame.c
${COMMON_SRC_DIR}/netchan.c
${COMMON_SRC_DIR}/pmove.c
${COMMON_SRC_DIR}/protocol.c
${COMMON_SRC_DIR}/szone.c
${COMMON_SRC_DIR}/zone.c
${COMMON_SRC_DIR}/shared/flash.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/unzip/ioapi.c
${COMMON_SRC_DIR}/unzip/unzip.c
@ -517,6 +591,8 @@ set(Client-Header
${COMMON_SRC_DIR}/header/glob.h
${COMMON_SRC_DIR}/header/shared.h
${COMMON_SRC_DIR}/header/zone.h
${COMMON_SRC_DIR}/models/anorms.h
${COMMON_SRC_DIR}/models/models.h
${COMMON_SRC_DIR}/unzip/ioapi.h
${COMMON_SRC_DIR}/unzip/unzip.h
${COMMON_SRC_DIR}/unzip/miniz/miniz.h
@ -532,14 +608,21 @@ set(Server-Source
${COMMON_SRC_DIR}/collision.c
${COMMON_SRC_DIR}/crc.c
${COMMON_SRC_DIR}/cmdparser.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/cvar.c
${COMMON_SRC_DIR}/filesystem.c
${COMMON_SRC_DIR}/glob.c
${COMMON_SRC_DIR}/maps.c
${COMMON_SRC_DIR}/models/loadfile.c
${COMMON_SRC_DIR}/models/models.c
${COMMON_SRC_DIR}/models/models_md5.c
${COMMON_SRC_DIR}/models/models_mdr.c
${COMMON_SRC_DIR}/md4.c
${COMMON_SRC_DIR}/frame.c
${COMMON_SRC_DIR}/movemsg.c
${COMMON_SRC_DIR}/netchan.c
${COMMON_SRC_DIR}/pmove.c
${COMMON_SRC_DIR}/protocol.c
${COMMON_SRC_DIR}/szone.c
${COMMON_SRC_DIR}/zone.c
${COMMON_SRC_DIR}/shared/rand.c
@ -570,6 +653,8 @@ set(Server-Header
${COMMON_SRC_DIR}/header/zone.h
${COMMON_SRC_DIR}/unzip/ioapi.h
${COMMON_SRC_DIR}/unzip/unzip.h
${COMMON_SRC_DIR}/models/anorms.h
${COMMON_SRC_DIR}/models/models.h
${COMMON_SRC_DIR}/unzip/miniz/miniz.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tdef.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tinfl.h
@ -592,13 +677,17 @@ set(GL1-Source
${REF_SRC_DIR}/gl1/gl1_warp.c
${REF_SRC_DIR}/gl1/gl1_sdl.c
${REF_SRC_DIR}/gl1/gl1_buffer.c
${REF_SRC_DIR}/files/light.c
${REF_SRC_DIR}/files/maps.c
${REF_SRC_DIR}/files/mesh.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${REF_SRC_DIR}/files/warp.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/md4.c
)
@ -606,7 +695,6 @@ set(Glad-GLES1-Source ${REF_SRC_DIR}/gl1/glad-gles1/src/glad.c)
set(GL1-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anorms.h
${REF_SRC_DIR}/constants/anormtab.h
${REF_SRC_DIR}/constants/warpsin.h
${REF_SRC_DIR}/files/stb_image.h
@ -635,13 +723,18 @@ set(GL3-Source
${REF_SRC_DIR}/gl3/gl3_surf.c
${REF_SRC_DIR}/gl3/gl3_warp.c
${REF_SRC_DIR}/gl3/gl3_shaders.c
${REF_SRC_DIR}/files/glshaders.c
${REF_SRC_DIR}/files/light.c
${REF_SRC_DIR}/files/maps.c
${REF_SRC_DIR}/files/mesh.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${REF_SRC_DIR}/files/warp.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/md4.c
)
@ -650,12 +743,11 @@ set(Glad-GLES3-Source ${REF_SRC_DIR}/gl3/glad-gles3/src/glad.c)
set(GL3-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anorms.h
${REF_SRC_DIR}/constants/anormtab.h
${REF_SRC_DIR}/constants/warpsin.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/gl3/header/DG_dynarr.h
${REF_SRC_DIR}/gl3/header/HandmadeMath.h
${REF_SRC_DIR}/files/DG_dynarr.h
${REF_SRC_DIR}/files/HandmadeMath.h
${REF_SRC_DIR}/gl3/header/local.h
${REF_SRC_DIR}/gl3/header/model.h
${COMMON_SRC_DIR}/header/shared.h
@ -671,6 +763,53 @@ set(Glad-GLES3-Header
${REF_SRC_DIR}/gl3/glad-gles3/include/KHR/khrplatform.h
)
set(GL4-Source
${REF_SRC_DIR}/gl4/gl4_draw.c
${REF_SRC_DIR}/gl4/gl4_image.c
${REF_SRC_DIR}/gl4/gl4_light.c
${REF_SRC_DIR}/gl4/gl4_lightmap.c
${REF_SRC_DIR}/gl4/gl4_main.c
${REF_SRC_DIR}/gl4/gl4_mesh.c
${REF_SRC_DIR}/gl4/gl4_misc.c
${REF_SRC_DIR}/gl4/gl4_model.c
${REF_SRC_DIR}/gl4/gl4_sdl.c
${REF_SRC_DIR}/gl4/gl4_surf.c
${REF_SRC_DIR}/gl4/gl4_warp.c
${REF_SRC_DIR}/gl4/gl4_shaders.c
${REF_SRC_DIR}/files/glshaders.c
${REF_SRC_DIR}/files/light.c
${REF_SRC_DIR}/files/maps.c
${REF_SRC_DIR}/files/mesh.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/warp.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/md4.c
)
set(Glad-GL4-Source ${REF_SRC_DIR}/gl4/glad/src/glad.c)
set(GL4-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anormtab.h
${REF_SRC_DIR}/constants/warpsin.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/files/DG_dynarr.h
${REF_SRC_DIR}/files/HandmadeMath.h
${REF_SRC_DIR}/gl4/header/local.h
${REF_SRC_DIR}/gl4/header/model.h
${COMMON_SRC_DIR}/header/shared.h
)
set(Glad-GL4-Header
${REF_SRC_DIR}/gl4/glad/include/glad/glad.h
${REF_SRC_DIR}/gl4/glad/include/KHR/khrplatform.h
)
set(SOFT-Source
${REF_SRC_DIR}/soft/sw_aclip.c
${REF_SRC_DIR}/soft/sw_alias.c
@ -689,13 +828,18 @@ set(SOFT-Source
${REF_SRC_DIR}/soft/sw_scan.c
${REF_SRC_DIR}/soft/sw_sprite.c
${REF_SRC_DIR}/soft/sw_surf.c
${REF_SRC_DIR}/soft/sw_warp.c
${REF_SRC_DIR}/files/light.c
${REF_SRC_DIR}/files/maps.c
${REF_SRC_DIR}/files/mesh.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${REF_SRC_DIR}/files/warp.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/md4.c
)
@ -708,6 +852,54 @@ set(SOFT-Header
${COMMON_SRC_DIR}/header/shared.h
)
set(VK-Source
${REF_SRC_DIR}/vk/vk_buffer.c
${REF_SRC_DIR}/vk/vk_cmd.c
${REF_SRC_DIR}/vk/vk_common.c
${REF_SRC_DIR}/vk/vk_device.c
${REF_SRC_DIR}/vk/vk_draw.c
${REF_SRC_DIR}/vk/vk_image.c
${REF_SRC_DIR}/vk/vk_light.c
${REF_SRC_DIR}/vk/vk_lightmap.c
${REF_SRC_DIR}/vk/vk_main.c
${REF_SRC_DIR}/vk/vk_mesh.c
${REF_SRC_DIR}/vk/vk_misc.c
${REF_SRC_DIR}/vk/vk_model.c
${REF_SRC_DIR}/vk/vk_pipeline.c
${REF_SRC_DIR}/vk/vk_shaders.c
${REF_SRC_DIR}/vk/vk_surf.c
${REF_SRC_DIR}/vk/vk_swapchain.c
${REF_SRC_DIR}/vk/vk_util.c
${REF_SRC_DIR}/vk/vk_validation.c
${REF_SRC_DIR}/vk/vk_warp.c
${REF_SRC_DIR}/vk/volk/volk.c
${REF_SRC_DIR}/files/light.c
${REF_SRC_DIR}/files/maps.c
${REF_SRC_DIR}/files/mesh.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/warp.c
${COMMON_SRC_DIR}/shared/utils.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/cmodels.c
${COMMON_SRC_DIR}/md4.c
)
set(VK-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/files/stb_image_resize.h
${REF_SRC_DIR}/vk/header/local.h
${REF_SRC_DIR}/vk/header/model.h
${REF_SRC_DIR}/vk/header/qvk.h
${REF_SRC_DIR}/vk/header/shaders.h
${REF_SRC_DIR}/vk/header/util.h
${REF_SRC_DIR}/vk/volk/volk.h
${COMMON_SRC_DIR}/header/shared.h
)
# Main Quake 2 executable
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
@ -781,6 +973,8 @@ else() # single-config, like normal Makefiles
endif()
target_link_libraries(game ${yquake2LinkerFlags})
if(${GL1_RENDERER})
# Build the GL1 dynamic library
add_library(ref_gl1 MODULE ${GL1-Source} ${GL1-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gl1 PROPERTIES
@ -795,6 +989,10 @@ if(SDL3_SUPPORT)
target_link_libraries(ref_gl1 SDL3::SDL3)
endif()
endif()
if(${GL3_RENDERER})
# Build the GL3 dynamic library
add_library(ref_gl3 MODULE ${GL3-Source} ${Glad-GL3-Source} ${GL3-Header} ${Glad-GL3-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gl3 PROPERTIES
@ -809,6 +1007,28 @@ if(SDL3_SUPPORT)
target_link_libraries(ref_gl3 SDL3::SDL3)
endif()
endif()
if(${GL4_RENDERER})
# Build the GL4 dynamic library
add_library(ref_gl4 MODULE ${GL4-Source} ${Glad-GL4-Source} ${GL4-Header} ${Glad-GL4-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gl4 PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_include_directories(ref_gl4 PRIVATE ${CMAKE_SOURCE_DIR}/src/client/refresh/gl4/glad/include)
target_link_libraries(ref_gl4 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_gl4 SDL3::SDL3)
endif()
endif()
if(${GLES3_RENDERER})
# Build the GLES3 dynamic library
add_library(ref_gles3 MODULE ${GL3-Source} ${Glad-GLES3-Source} ${GL3-Header} ${Glad-GLES3-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gles3 PROPERTIES
@ -825,6 +1045,10 @@ if(SDL3_SUPPORT)
target_link_libraries(ref_gles3 SDL3::SDL3)
endif()
endif()
if(${SOFT_RENDERER})
# Build the soft renderer dynamic library
add_library(ref_soft MODULE ${SOFT-Source} ${SOFT-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_soft PROPERTIES
@ -838,7 +1062,26 @@ if(SDL3_SUPPORT)
target_link_libraries(ref_soft SDL3::SDL3)
endif()
if(FALSE)
endif()
if(${VK_RENDERER})
# Build the vk renderer dynamic library
add_library(ref_vk MODULE ${VK-Source} ${VK-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_vk PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_link_libraries(ref_vk ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_vk SDL3::SDL3)
endif()
endif()
if(${GLES1_RENDERER})
# Build the GLES1 dynamic library
add_library(ref_gles1 MODULE ${GL1-Source} ${Glad-GLES1-Source} ${GL1-Header} ${Glad-GLES1-Header} ${REF-Platform-Specific-Source})

View file

@ -150,7 +150,7 @@ endif
# Highest supported optimizations are -O2, higher levels
# will likely break this crappy code.
ifdef DEBUG
CFLAGS ?= -O0 -g -Wall -pipe -DDEBUG
CFLAGS ?= -O0 -g -Wall -Wpointer-arith -pipe -DDEBUG
ifdef ASAN
override CFLAGS += -fsanitize=address -DUSE_SANITIZER
endif
@ -158,7 +158,7 @@ ifdef UBSAN
override CFLAGS += -fsanitize=undefined -DUSE_SANITIZER
endif
else
CFLAGS ?= -O2 -Wall -pipe -fomit-frame-pointer
CFLAGS ?= -O2 -Wall -Wpointer-arith -pipe -fomit-frame-pointer
endif
# Always needed are:
@ -289,6 +289,10 @@ else
SDLCFLAGS := $(shell sdl2-config --cflags)
endif
ifdef NO_SDL_GYRO
SDLCFLAGS += -DNO_SDL_GYRO
endif
# ----------
# Base include path.
@ -383,10 +387,17 @@ SDLLDFLAGS := $(shell sdl2-config --libs)
endif
endif
ifeq ($(WITH_SDL3),yes)
# The renderer libs don't need libSDL3main, libmingw32 or -mwindows.
ifeq ($(YQ2_OSTYPE), Windows)
DLL_SDLLDFLAGS = $(subst -mwindows,,$(subst -lmingw32,,$(subst -lSDL3main,,$(SDLLDFLAGS))))
endif
else
# The renderer libs don't need libSDL2main, libmingw32 or -mwindows.
ifeq ($(YQ2_OSTYPE), Windows)
DLL_SDLLDFLAGS = $(subst -mwindows,,$(subst -lmingw32,,$(subst -lSDL2main,,$(SDLLDFLAGS))))
endif
endif
# ----------
@ -892,10 +903,12 @@ build/ref_vk/%.o: %.c
# The baseq2 game
ifeq ($(YQ2_OSTYPE), Windows)
game:
game: stuff/models/entity.dat
@echo "===> Building baseq2/game.dll"
${Q}mkdir -p release/baseq2
$(MAKE) release/baseq2/game.dll
${Q}mkdir -p release/baseq2/models
${Q}cp stuff/models/entity.dat release/baseq2/models
build/baseq2/%.o: %.c
@echo "===> CC $<"
@ -906,10 +919,12 @@ release/baseq2/game.dll : LDFLAGS += -shared
else ifeq ($(YQ2_OSTYPE), Darwin)
game:
game: stuff/models/entity.dat
@echo "===> Building baseq2/game.dylib"
${Q}mkdir -p release/baseq2
$(MAKE) release/baseq2/game.dylib
${Q}mkdir -p release/baseq2/models
${Q}cp stuff/models/entity.dat release/baseq2/models
build/baseq2/%.o: %.c
@echo "===> CC $<"
@ -921,10 +936,12 @@ release/baseq2/game.dylib : LDFLAGS += -shared
else # not Windows or Darwin
game:
game: stuff/models/entity.dat
@echo "===> Building baseq2/game.so"
${Q}mkdir -p release/baseq2
$(MAKE) release/baseq2/game.so
${Q}mkdir -p release/baseq2/models
${Q}cp stuff/models/entity.dat release/baseq2/models
build/baseq2/%.o: %.c
@echo "===> CC $<"
@ -942,6 +959,19 @@ GAME_OBJS_ = \
src/common/shared/flash.o \
src/common/shared/rand.o \
src/common/shared/shared.o \
src/game/bot/ai_class_dmbot.o \
src/game/bot/ai_class_monster_default.o \
src/game/bot/ai_dropnodes.o \
src/game/bot/ai_items.o \
src/game/bot/ai_links.o \
src/game/bot/ai_main.o \
src/game/bot/ai_movement.o \
src/game/bot/ai_navigation.o \
src/game/bot/ai_nodes.o \
src/game/bot/ai_tools.o \
src/game/bot/ai_weapons.o \
src/game/bot/astar.o \
src/game/bot/bot_spawn.o \
src/game/g_ai.o \
src/game/g_chase.o \
src/game/g_cmds.o \
@ -949,6 +979,7 @@ GAME_OBJS_ = \
src/game/g_combat.o \
src/game/g_func.o \
src/game/g_items.o \
src/game/g_light.o \
src/game/g_main.o \
src/game/g_misc.o \
src/game/g_monster.o \
@ -958,6 +989,7 @@ GAME_OBJS_ = \
src/game/g_newtarg.o \
src/game/g_newtrig.o \
src/game/g_newweap.o \
src/game/g_obj.o \
src/game/g_phys.o \
src/game/g_spawn.o \
src/game/g_sphere.o \
@ -986,7 +1018,6 @@ GAME_OBJS_ = \
src/game/monster/demon/demon.o \
src/game/monster/dog/dog.o \
src/game/monster/enforcer/enforcer.o \
src/game/monster/fish/fish.o \
src/game/monster/fixbot/fixbot.o \
src/game/monster/flipper/flipper.o \
src/game/monster/float/float.o \
@ -1006,6 +1037,7 @@ GAME_OBJS_ = \
src/game/monster/mutant/mutant.o \
src/game/monster/ogre/ogre.o \
src/game/monster/parasite/parasite.o \
src/game/monster/rotfish/fish.o \
src/game/monster/shalrath/shalrath.o \
src/game/monster/shambler/shambler.o \
src/game/monster/soldier/soldier.o \
@ -1072,7 +1104,10 @@ CLIENT_OBJS_ := \
src/common/glob.o \
src/common/md4.o \
src/common/maps.o \
src/common/models.o \
src/common/models/loadfile.o \
src/common/models/models.o \
src/common/models/models_md5.o \
src/common/models/models_mdr.o \
src/common/movemsg.o \
src/common/frame.o \
src/common/netchan.o \
@ -1147,12 +1182,9 @@ REFGL1_OBJS_ := \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \
src/client/refresh/files/models_md5.o \
src/client/refresh/files/models_mdr.o \
src/client/refresh/files/stb.o \
src/client/refresh/files/wal.o \
src/client/refresh/files/warp.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/cmodels.o \
@ -1190,12 +1222,9 @@ REFGL3_OBJS_ := \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \
src/client/refresh/files/models_md5.o \
src/client/refresh/files/models_mdr.o \
src/client/refresh/files/stb.o \
src/client/refresh/files/wal.o \
src/client/refresh/files/warp.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/cmodels.o \
@ -1236,12 +1265,9 @@ REFGL4_OBJS_ := \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \
src/client/refresh/files/models_md5.o \
src/client/refresh/files/models_mdr.o \
src/client/refresh/files/stb.o \
src/client/refresh/files/wal.o \
src/client/refresh/files/warp.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/cmodels.o \
src/common/md4.o
@ -1283,12 +1309,9 @@ REFSOFT_OBJS_ := \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \
src/client/refresh/files/models_md5.o \
src/client/refresh/files/models_mdr.o \
src/client/refresh/files/stb.o \
src/client/refresh/files/wal.o \
src/client/refresh/files/warp.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/cmodels.o \
@ -1330,12 +1353,9 @@ REFVK_OBJS_ := \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \
src/client/refresh/files/models_md5.o \
src/client/refresh/files/models_mdr.o \
src/client/refresh/files/stb.o \
src/client/refresh/files/wal.o \
src/client/refresh/files/warp.o \
src/client/refresh/files/pvs.o \
src/common/shared/shared.o \
src/common/shared/utils.o \
src/common/cmodels.o \
@ -1366,7 +1386,10 @@ SERVER_OBJS_ := \
src/common/md4.o \
src/common/frame.o \
src/common/maps.o \
src/common/models.o \
src/common/models/loadfile.o \
src/common/models/models.o \
src/common/models/models_md5.o \
src/common/models/models_mdr.o \
src/common/movemsg.o \
src/common/netchan.o \
src/common/pmove.o \

322
README.md
View file

@ -8,27 +8,9 @@ Feel free to try this code but you mileage may vary.
Have a look at the yquake2 repository for the "normal" Yamagi Quake II:
<https://github.com/yquake2/yquake2>
Alpha windows 64 bit [binaries](https://github.com/yquake2/yquake2remaster/releases).
Saves format is unstabled and could change between alpha releases.
State:
* GL1/GLES3/GL3/GL4/VK:
* base1: no known issues,
* base2: no known issues,
* q64/outpost: broken level change,
* mguhub: sometimes broken logic for surface fall in next maps.
* SOFT:
* base1: broken wall light and wall glitch,
* base2: broken wall light and wall glitch,
* q64/outpost: broken level change, scale textures unsupported,
* mguhub: broken wall light, sometimes broken logic for surface fall
in next maps.
Monsters:
* incorrect dead animation for Arachnid,
* broken fire effect for Guardian.
* Alpha windows 64 bit [binaries](https://github.com/yquake2/yquake2remaster/releases).
* Saves format is unstabled and could change between alpha releases.
* MacOS build is only build tested and run is not checked.
Models support:
@ -36,10 +18,10 @@ Models support:
| ------ | --------------- | ------------ | -------- | --------------------------------------- |
| mdl | Quake 1 | 8 bit | Single | Unsupported grouped textures |
| md2 | Quake 2 | 8 bit | Single | |
| mda | Anachronox | Part of md2 | Single | No tagged surfaces |
| md2 | Anachronox | 8/10/16 bit | Single | No tagged surfaces, unchecked with game |
| mda | Anachronox | Part of md2 | Single | Unsupported skin pass combine |
| md2 | Anachronox | 8/10/16 bit | Single | Unchecked with game |
| mdx | Kingpin | 8 bit | Multiple | No sfx support, unchecked with game |
| fm | Heretic 2 | 8 bit | Multiple | |
| fm | Heretic 2 | 8 bit | Multiple | Without skeletal animation |
| def | SiN | Part of sam | Multiple | Unchecked with game |
| dkm | Daikatana DKM1 | 8 bit | Multiple | Unchecked with game |
| dkm | Daikatana DKM2 | 10 bit | Multiple | Unchecked with game |
@ -66,6 +48,13 @@ Texture support:
| jpg | retexturing | 24 bit |
| bmp | Daikatana | 24 bit |
Sprites support:
| Format | Original Game | Comments |
| ------ | -------------- | ----------------------------- |
| sp2 | Quake 2 | |
| atd | Anachronox | Show first frame of animation |
Maps support:
| Format | Version | Game |
@ -78,18 +67,20 @@ Maps support:
Note:
* Non Quake 2 maps are limmited mostly view only, and could have issues
* Non Quake 2 maps are limited mostly view only, and could have issues
with tranparency or some animations flags and properties.
* If you like support some other maps type, create pull request for Mod_Load2QBSP
function and provide a link to demo maps.
* Use `maptype 1` before load any Heretic 2 maps. Look to
[maptype_t](src/common/header/cmodel.h#L42) for more info.
* Use `maptype 1` before load any Heretic 2 maps, or place game data to `heretic2` directory.
Look to [maptype_t](src/common/header/cmodel.h#L42) for more info.
Games:
* Quake 2:
* Quake 2 ReRelease:
* SDK: <https://github.com/id-Software/quake2-rerelease-dll>
* Tech info: <https://bethesda.net/en/article/6NIyBxapXOurTKtF4aPiF4/enhancing-quake-ii>
* PSX source: <https://www.moddb.com/mods/quake-ii-psx/downloads/quake-ii-psx-10-sources>
* PSX Mod: <https://www.moddb.com/mods/quake-ii-psx>
* Anachronox:
* SDK: <https://github.com/hogsy/chronon>
* SDK: <https://code.idtech.space/ion-storm/anachronox-sdk>
@ -108,46 +99,261 @@ Games:
* Tools: [SiNview](https://web.archive.org/web/20001212060900/http://starbase.neosoft.com:80/~otaku/program.html)
* Tools: <https://www.moddb.com/games/sin/downloads/sin-modding-tools-and-other-stuff>
* SDK: <https://github.com/NightDive-Studio/sin-ex-game>
* SDK: <https://github.com/jimdose/SiN_110_Source>
* SDK: <https://code.idtech.space/ritual/sin-sdk>
* Dawn of Darkness:
* Docs: <https://www.moddb.com/mods/dawn-of-darkness1/downloads/dod-mood-scripts-gsm-tutorials-fgd-and-def-file>
* Demo: [Episode 1](https://www.moddb.com/mods/dawn-of-darkness1/downloads/dawn-of-darkness-episode-1)
* JaBot:
* SDK: <https://www.moddb.com/mods/jabotq2/downloads/jabot-q2-v09x-win32-and-linux>
* Additional maps used for check maps support:
* PSX: <https://www.moddb.com/mods/quake-ii-psx/downloads/quake-ii-psx-10>
* ReRelease N64 Jam: <https://www.moddb.com/games/quake-2/addons/quake-2-re-release-n64-sp-map-jam>
* ReRelease Basic Jam: <https://www.moddb.com/games/quake-2/addons/quake-2-re-release-back-to-baseq2ics-jam-1>
* ReRelease PSX Jam: <https://www.moddb.com/mods/psx-jam-1/downloads/quake-2-re-release-psx-jam-1>
Goals:
Games check videos:
* [x] BSPX DECOUPLEDLM light map support (base1),
* [x] QBSP map format support (mguhub),
* [x] Use ffmpeg for load any video,
* [x] RoQ and Theora cinematic videos support.
* [x] Cinematic videos support in smk, mpeg, ogv format,
* [x] Daikatana/Heretic 2 map partial format support,
* [x] md5 improve load speed,
* [x] support Anachronox .dat format,
* [x] suport Daikatana/SiN .pak/.sin format from pakextract,
* [x] Support flow/scale flags for Q64 maps,
* [x] Add debug progress loading code for maps,
* [x] MDR model format from Star Trek: Voyager – Elite Force,
* [ ] MDA entity format from Anachronox,
* [x] RGB particles support instead palette based one,
* [x] Get rid of VID_PaletteColor client internal api use,
* [x] Broken maps groups from base2 to next,
* [ ] Single player ReRelease support,
* [ ] Support effects and additional flags for ReRelease when possible.
* [ ] Use shared model cache in client code insted reimplemnet in each render,
* [x] Check load soft colormap as 24bit color from loaded image,
* [ ] Fix transparent textures in Daikatana/SiN maps,
* [ ] Use separete texture hi-color buffer for ui in soft render,
* [ ] Cleanup function declarations in game save code,
* [ ] Fix broken base3 with sorted fields names,
* [x] Use 3 bytes vertex normal,
* [ ] Support scalled textures for models and walls in soft render and fix
* 8.42RR12+:
[![JaBot check](https://img.youtube.com/vi/uW3XDxrjQOU/0.jpg)](https://www.youtube.com/watch?v=uW3XDxrjQOU)
[![Translation check](https://img.youtube.com/vi/8Tlm8lSY5x8/0.jpg)](https://www.youtube.com/watch?v=8Tlm8lSY5x8)
[![Anacronox dance sector issue](https://img.youtube.com/vi/PR2_nK7DFJM/0.jpg)](https://www.youtube.com/watch?v=PR2_nK7DFJM)
* 8.42RR11:
[![First episode](https://img.youtube.com/vi/Ha1FuVXaQSE/0.jpg)](https://www.youtube.com/watch?v=Ha1FuVXaQSE)
[![Q2DQ2](https://img.youtube.com/vi/6P3wJojExyI/0.jpg)](https://www.youtube.com/watch?v=6P3wJojExyI)
[![8.42RR11](https://img.youtube.com/vi/ukqBrx80ESM/0.jpg)](https://www.youtube.com/watch?v=ukqBrx80ESM)
* 8.42RR10:
[![8.42RR10](https://img.youtube.com/vi/obIrzYsNxBY/0.jpg)](https://www.youtube.com/watch?v=obIrzYsNxBY)
* 8.42RR9:
[![8.42RR9](https://img.youtube.com/vi/N0iHhEDkZFg/0.jpg)](https://www.youtube.com/watch?v=N0iHhEDkZFg)
* 8.42RR8:
[![8.42RR8](https://img.youtube.com/vi/NJ7T0cdyqk8/0.jpg)](https://www.youtube.com/watch?v=NJ7T0cdyqk8)
* 8.31RR7:
[![8.31RR7](https://img.youtube.com/vi/VAFs1HtQU_0/0.jpg)](https://www.youtube.com/watch?v=VAFs1HtQU_0)
Goals, fully finished goals could be checked in [here](CHANGELOG):
* [ ] jabot: fix crash in SZ_GetSpace,
* [ ] Anachronox: skins load broken with mingw win64 build,
* [ ] Anachronox: rowdys map models disappear on dance space,
* [ ] Anachronox: CTC entity format,
* [ ] Anachronox: support material load textures/textureinfo.dat,
* [ ] soft: fix crash with md5 models in player model select and ASAN=1
* [ ] soft: q64/outpost scale textures unsupported,
* [ ] soft: broken wall light and wall glitch,
* [ ] soft: build with SDL3 has glitch in menu,
* [ ] soft: support custom ttf fonts,
* [ ] soft: support scalled textures for models and walls, and fix
lighting with remastered maps,
* [ ] Modified ReRelease game code support with removed KEX only related code.
* [ ] soft: use separete texture hi-color buffer for ui in soft render,
* [ ] DoD: fix statusbar `roarke`,
* [ ] vulkan: group `it_pic` images,
* [ ] vulkan: rearange surfaces before render,
* [x] Use shared model cache in client code insted reimplement in each render,
* [ ] reuse memory from models cache in renders model list,
* [ ] reuse memory from models cache for bsp,
* [ ] Fix transparent textures in Daikatana/SiN maps,
* [ ] game: cleanup function declarations in game save code,
* [ ] game: fix broken base3 with sorted fields names,
* [x] game: remove grapple by default,
* [x] ReRelease: crash on exit from psx/base2,
* [ ] ReRelease: mguhub map has sometimes broken logic for surface fall in next maps,
* [ ] ReRelease: incorrect light apply to models (wall looks fine),
* [ ] ReRelease: incorrect dead animation for Arachnid,
* [ ] ReRelease: broken fire effect for Guardian.
* [ ] ReRelease: fix invisiable entities in basicsjam1_ziutek,
* [ ] ReRelease: make lightmap textures dynamic n64jam_palmlix,
* [x] ReRelease: support textures/*/*.mat load (footstep),
* [ ] ReRelease: support textures/*/*.mat load texture effects,
* [ ] ReRelease: support textures/*/*_glow.png load,
* [ ] ReRelease: support tactile/*/*.bnvib/.wav feedback load,
* [x] ReRelease: fix physics with incorrect floor height in psx/base0.bsp,
* [ ] ReRelease: console `~` incorrectly show multibyte characters,
* [ ] ReRelease: basicsjam1_detrohogga: Make pmove_state_t.origin 29.3 (PS_M_ORIGIN) > 4k coord values support,
* [ ] ReRelease: fully implement `misc_flare`,
* [ ] ReRelease: single player support,
* [ ] ReRelease: support effects and additional flags when possible.
* [ ] ReRelease: modified game code support with removed KEX only related code.
Not a goal:
* [ ] Multiplayer protocol support with KEX engine,
* [ ] Support KEX engine features (inventary, compass and so on),
* [ ] Support KEX engine features (inventory, compass and so on),
* [ ] [KEX game library support](https://github.com/id-Software/quake2-rerelease-dll).
Code tested with such [maps](doc/100_tested_maps.md).
# Additional requirements:
Localization requires `Q2Game.kpf` file in root directory of game. If you
like to support your language put it to localization/loc_<your language>.txt
and extend MAX_FONTCODE to your [max symbol code](https://en.wikipedia.org/wiki/List_of_Unicode_characters).
Used font and language file are defined by `g_language` and `r_ttffont`, as
an example could be used fonts like [unifont](https://unifoundry.com/pub/unifont/unifont-15.0.06/font-builds/unifont-15.0.06.ttf).
Additional models:
| Spawn classname | Description |
| ---------------- | ------------------------------ |
| misc_actor | Quake 2 actor (Restored) |
| misc_actorvx | ReRelease vault actor x |
| misc_actorvy | ReRelease vault actor y |
| misc_fighter | ReRelease vault fighter ship |
| misc_transprt | ReRelease vault transport ship |
| monster_arachnid | ReRelease arachnid |
| monster_army | Quake 1 army soldier |
| monster_boss5 | Xatrix boss 5 |
| monster_carrier | Rogue carrier |
| monster_demon | Quake 1 demon |
| monster_dog | Quake 1 dog |
| monster_enforcer | Quake 1 enforcer |
| monster_floaterv | ReRelease vault technician |
| monster_flyerv | ReRelease vault flyer |
| monster_fixbot | Xatrix fixbot |
| monster_gnorta | ReRelease vault gnorta |
| monster_gekk | Xatrix gekk |
| monster_hknight | Quake 1 hknight |
| monster_guardian | ReRelease guardian |
| monster_knight | Quake 1 knight |
| monster_mutantv | ReRelease vault mutant |
| monster_ogre | Quake 1 ogre |
| monster_rotfish | Quake 1 rotfish |
| monster_shalrath | Quake 1 shalrath |
| monster_shambler | Quake 1 shambler |
| monster_shockerv | ReRelease vault shocker |
| monster_stalker | Rogue stalker |
| monster_tankv | ReRelease vault tank |
| monster_tarbaby | Quake 1 tarbaby |
| monster_turret | Rogue turret |
| monster_wizard | Quake 1 wizard |
| monster_widow | Rogue widow |
| monster_widow2 | Rogue widow 2 |
| monster_zombie | Quake 1 zombie |
| npc_timeminder | Anachronox save menu |
Full list of supported entities [classnames](stuff/models/entity.dat).
Quake 1 models usage requires such files:
| source Quake 1 Path | destination Quake 2 Path | md5 hash |
| -------------------------- | --------------------------------- | -------------------------------- |
| progs/soldier.mdl | models/monsters/army/tris.mdl | 5b6c30a984872b4273dd5861412d35c5 |
| progs/demon.mdl | models/monsters/demon/tris.mdl | 4c73786e7cfb2083ca38cbc983cd6c4b |
| progs/dog.mdl | models/monsters/dog/tris.mdl | e727fbc39acc652f812972612ce37565 |
| progs/enforcer.mdl | models/monsters/enforcer/tris.mdl | 136c265f96d6077ee3312c52e134529f |
| progs/fish.mdl | models/monsters/rotfish/tris.mdl | d770d6ef92ae8b372926e6c3d49e8716 |
| progs/hknight.mdl | models/monsters/hknight/tris.mdl | ed20e30be6fdb83efbaa6d0b23671a49 |
| progs/knight.mdl | models/monsters/knight/tris.mdl | 5328915db5c53e85cf75d46e7b747fb9 |
| progs/ogre.mdl | models/monsters/ogre/tris.mdl | fbb592ca3788a576dd2f31fcf8c80fab |
| progs/shalrath.mdl | models/monsters/shalrath/tris.mdl | dac8f6077b0d2bf970573d2d2c22529f |
| progs/shambler.mdl | models/monsters/shambler/tris.mdl | 9b09375a0f614dc4081e363cc34f1185 |
| progs/tarbaby.mdl | models/monsters/tarbaby/tris.mdl | 2bfc45593a43a0191982e3cfdc112dc5 |
| progs/wizard.mdl | models/monsters/wizard/tris.mdl | bf60986594f045e60e8aa6339d553ee7 |
| progs/zombie.mdl | models/monsters/zombie/tris.mdl | a923b1d03b9d237dd5ead9bd56acc900 |
| progs/k_spike.mdl | models/proj/fireball/tris.mdl | da95b49a695b34c2c3516a8d789c6b20 |
| progs/v_spike.mdl | models/proj/pod/tris.mdl | 2bdc0b264b9fd3443c8eee816305728f |
| progs/w_spike.mdl | models/proj/spit/tris.mdl | 8cf9245df2164e8062b01a220b508d6b |
| sound/army/death1.wav | sound/army/death1.wav | fe25952af40b536c3bb67bfca58062eb |
| sound/army/idle.wav | sound/army/idle.wav | 4cdfbdda8fb5f40b125c7bcddb6e8914 |
| sound/army/pain1.wav | sound/army/pain1.wav | 54d3b05fdcecf7480034858f2b22b06c |
| sound/army/pain2.wav | sound/army/pain2.wav | e2bbc9d3405b9b9fdae76d2fc298fc2f |
| sound/army/sattck1.wav | sound/army/sattck1.wav | b76ac35f900f280a7a7996da7e404362 |
| sound/army/sight1.wav | sound/army/sight1.wav | e2a39533250ddd1b08053d5c4ebf7fd0 |
| sound/demon/ddeath.wav | sound/demon/ddeath.wav | 62a48dcd405ca55c9ce18497e36faa0e |
| sound/demon/dhit2.wav | sound/demon/dhit2.wav | 9e741696e4d0d66e30e718fc70ec186e |
| sound/demon/djump.wav | sound/demon/djump.wav | 791ac9d6b6593808316145443cb7e7a0 |
| sound/demon/dland2.wav | sound/demon/dland2.wav | db14c7b01838f826b7a712075f9026fd |
| sound/demon/dpain1.wav | sound/demon/dpain1.wav | 5e6c485878393c9bebb0d0e6659bc479 |
| sound/demon/idle1.wav | sound/demon/idle1.wav | 7a83f8caf3d5b1172a7dc5afdc942988 |
| sound/demon/sight2.wav | sound/demon/sight2.wav | 65171c355c22a5069520b0881677ae3c |
| sound/dog/dattack1.wav | sound/dog/dattack1.wav | 0c47c9d4aaae0bf3159a288b674f4a35 |
| sound/dog/ddeath.wav | sound/dog/ddeath.wav | b0e7760b1d7286a028ff9773f6802958 |
| sound/dog/dpain1.wav | sound/dog/dpain1.wav | 28e5ab93b41e13e2916433283a5d1a46 |
| sound/dog/dsight.wav | sound/dog/dsight.wav | 0edc290765bac1fb4fe03ca55bc7c225 |
| sound/dog/idle.wav | sound/dog/idle.wav | 42bd6026ff32bd94523ad9f8fe8362cc |
| sound/enforcer/death1.wav | sound/enforcer/death1.wav | f38d7a235e13ef8918aac0c70437320d |
| sound/enforcer/enfire.wav | sound/enforcer/enfire.wav | b080a6a53f138bef9fc4403fb9373a24 |
| sound/enforcer/enfstop.wav | sound/enforcer/enfstop.wav | 0bc39c3c88187fb37d20ef21300e7b22 |
| sound/enforcer/idle1.wav | sound/enforcer/idle1.wav | d0435763860fe54e938ad25bb1780f9e |
| sound/enforcer/pain1.wav | sound/enforcer/pain1.wav | d52bc02afe624924684b25295edaa040 |
| sound/enforcer/pain2.wav | sound/enforcer/pain2.wav | f6b0ad6485d93f5c6d7d61b847d06877 |
| sound/enforcer/sight1.wav | sound/enforcer/sight1.wav | 9e9876444ba92ed18bfce4cec3a2ff12 |
| sound/enforcer/sight2.wav | sound/enforcer/sight2.wav | 815dd4f6a890b0a35dc466005df74850 |
| sound/enforcer/sight3.wav | sound/enforcer/sight3.wav | f8c8d19905b24d4adb6760a1b3762f3b |
| sound/enforcer/sight4.wav | sound/enforcer/sight4.wav | 04e40eb925290bc56520de326df6b220 |
| sound/fish/bite.wav | sound/fish/bite.wav | 7c56712615e2a2c3de4fe0e7e35cba05 |
| sound/fish/death.wav | sound/fish/death.wav | 8d6152ee55507430a8c2eb276c4aa8ac |
| sound/fish/idle.wav | sound/fish/idle.wav | 54a02731b85eb6f8b1a8ecce09771d20 |
| sound/hknight/attack1.wav | sound/hknight/attack1.wav | 695e9d890a085addf1a607aa79137e8e |
| sound/hknight/death1.wav | sound/hknight/death1.wav | 2d68c3c86632027676b823fcff3af08c |
| sound/hknight/grunt.wav | sound/hknight/grunt.wav | 122f3d4623e0146732aa0e4deb0fe326 |
| sound/hknight/hit.wav | sound/hknight/hit.wav | fece24e2548f1d769e8fce39a5c87d01 |
| sound/hknight/idle.wav | sound/hknight/idle.wav | e9ca23c4853472750d1f56e52a3d227b |
| sound/hknight/pain1.wav | sound/hknight/pain1.wav | 52c20eb6f5b5146ece6b0ac02f423341 |
| sound/hknight/sight1.wav | sound/hknight/sight1.wav | 786d28ec653a0d512d078b32eb8cb58b |
| sound/hknight/slash1.wav | sound/hknight/slash1.wav | 83e64bb90cff2a4f9764dd53489b9d7d |
| sound/knight/idle.wav | sound/knight/idle.wav | 1b5c3981bee078318af346d8fe8090b9 |
| sound/knight/kdeath.wav | sound/knight/kdeath.wav | 11a96f48a8f2433c23beae299c8fb96e |
| sound/knight/khurt.wav | sound/knight/khurt.wav | 32c9f48dd4a6a87752aedf56fe8de668 |
| sound/knight/ksight.wav | sound/knight/ksight.wav | eb75b4af348c88e84d8c87c19d5976fa |
| sound/knight/sword1.wav | sound/knight/sword1.wav | 93045b5f3178413dc6b01ec2869d1f73 |
| sound/knight/sword2.wav | sound/knight/sword2.wav | 82d1a7c263cd3df7b060dee2f7f8b1fd |
| sound/ogre/ogdrag.wav | sound/ogre/ogdrag.wav | 658587dc89aaefae5ca3f058f7ff4227 |
| sound/ogre/ogdth.wav | sound/ogre/ogdth.wav | de98e7bb9e70586edddd3308cfded3db |
| sound/ogre/ogidle2.wav | sound/ogre/ogidle2.wav | 196ae9c33a4311160e1d5f3da878ab09 |
| sound/ogre/ogidle.wav | sound/ogre/ogidle.wav | 177c829840a87c885bbc8951e7ce962e |
| sound/ogre/ogpain1.wav | sound/ogre/ogpain1.wav | ac6d133d7720c12df49813fe10e683b5 |
| sound/ogre/ogsawatk.wav | sound/ogre/ogsawatk.wav | 7257bdfd014bb61d778b8f88cb65d560 |
| sound/ogre/ogwake.wav | sound/ogre/ogwake.wav | 3296459e495c4c12b31179d4eeffac19 |
| sound/shalrath/attack2.wav | sound/shalrath/attack2.wav | 777fbda2f81350e45920ea1c36d318e1 |
| sound/shalrath/attack.wav | sound/shalrath/attack.wav | 8814a72b399be619d14223235f78f294 |
| sound/shalrath/death.wav | sound/shalrath/death.wav | 771844c5cfb5a42e82e221a63f101ac7 |
| sound/shalrath/idle.wav | sound/shalrath/idle.wav | 1a45f12579f9cdd27152332d5f816048 |
| sound/shalrath/pain.wav | sound/shalrath/pain.wav | 6ba007b79c50d7d5347f1a29fb315422 |
| sound/shalrath/sight.wav | sound/shalrath/sight.wav | 3d3c2001cc976efc67af1552427eedd3 |
| sound/shambler/melee1.wav | sound/shambler/melee1.wav | 77fe6240973a204b757a427ebf66bcfd |
| sound/shambler/melee2.wav | sound/shambler/melee2.wav | 3be31638d769e3d690c92311dfafdeac |
| sound/shambler/sattck1.wav | sound/shambler/sattck1.wav | ec8c3f79ea42d09154cb8975ada1b21c |
| sound/shambler/sboom.wav | sound/shambler/sboom.wav | 9834601a645d7d1f62001b2a314ec18f |
| sound/shambler/sdeath.wav | sound/shambler/sdeath.wav | e0e62d229a985a6e39218c6488599059 |
| sound/shambler/shurt2.wav | sound/shambler/shurt2.wav | 1e87631ede95e061a75f9c31629ac0b8 |
| sound/shambler/sidle.wav | sound/shambler/sidle.wav | 368a240e6c3e877793352a79c1828386 |
| sound/shambler/smack.wav | sound/shambler/smack.wav | bd8c634c9894348360fec7b7419d1649 |
| sound/shambler/ssight.wav | sound/shambler/ssight.wav | 657107577460d5acf3157dec97e07a89 |
| sound/tarbaby/death1.wav | sound/tarbaby/death1.wav | 53f8c73de11c018086ba19ed036833d3 |
| sound/tarbaby/hit1.wav | sound/tarbaby/hit1.wav | 42c5a1edd02421bf6df7ddc3e395c4f8 |
| sound/tarbaby/land1.wav | sound/tarbaby/land1.wav | 5a1585ab22368a48827db9b7d3763b58 |
| sound/tarbaby/sight1.wav | sound/tarbaby/sight1.wav | df4dd7ec91e094b5c2235be3f5353e4a |
| sound/wizard/hit.wav | sound/wizard/hit.wav | 6598d669334df977f1f97b95288edf11 |
| sound/wizard/wattack.wav | sound/wizard/wattack.wav | b3568a47439f81779d40335e76f5bc2d |
| sound/wizard/wdeath.wav | sound/wizard/wdeath.wav | 99d9c71343bc23222abb92119d404400 |
| sound/wizard/widle1.wav | sound/wizard/widle1.wav | b22b1dd9f66879b3447d36ab584316c7 |
| sound/wizard/widle2.wav | sound/wizard/widle2.wav | 7178fd83df227360564adef01bed92c6 |
| sound/wizard/wpain.wav | sound/wizard/wpain.wav | bd7e59ab7d7b835f9ed8ab51950914de |
| sound/wizard/wsight.wav | sound/wizard/wsight.wav | df5949057c750528917c6cb32b7fd9fd |
| sound/zombie/idle_w2.wav | sound/zombie/idle_w2.wav | d2bb59b9d7ac71097c07123a23525641 |
| sound/zombie/z_fall.wav | sound/zombie/z_fall.wav | 6968318b2d196c6d54bc707d8a390547 |
| sound/zombie/z_gib.wav | sound/zombie/z_gib.wav | 199dda66ade8d6f0ef4897e4d7608c0d |
| sound/zombie/z_hit.wav | sound/zombie/z_hit.wav | 6c66ab3e6b149bf35956a4bbc0057acb |
| sound/zombie/z_idle1.wav | sound/zombie/z_idle1.wav | 21088a7b38b1124d7ec72e58d5ab93a6 |
| sound/zombie/z_idle.wav | sound/zombie/z_idle.wav | e5e570e38c4405111004190a79f0e925 |
| sound/zombie/z_miss.wav | sound/zombie/z_miss.wav | 96fad96a8c3bc6f7bcc5da6c82678da2 |
| sound/zombie/z_pain1.wav | sound/zombie/z_pain1.wav | fcd83b89a94b0cadbe1361a4df080ec0 |
| sound/zombie/z_pain.wav | sound/zombie/z_pain.wav | 56637968b8309bd2f825153330bbdfc0 |
| sound/zombie/z_shot1.wav | sound/zombie/z_shot1.wav | 561afb69b7851923a8fb3b54e3e13c96 |
Look to [infighter](https://github.com/decino/q2-infighter) for more info.
# Yamagi Quake II

View file

@ -39,18 +39,17 @@ Yamagi Quake II ships with 4 renderers:
## Choosing a Sound System
Yamagi Quake II ships with 2 sound system:
Yamagi Quake II ships with 2 sound systems:
* The **OpenAL** sound system: This is the default and highly
recommended. It provides full surround sound support and even HRTF for
recommended. It provides full surround sound support and HRTF for
headphones. But also the plain stereo playback is much better than in
the original sound system. The setup is done mostly through OpenAL,
have a look at the documentation of your OpenAL library.
* The **SDL** sound system: This is the classic sound system, providing
an experience like the original client. Set `s_openal` to `0` and
execute an `snd_restart` to activate it. The classic sound system may
be somewhat problematic on modern systems like Windows 10 or Linux
with Pulseaudio.
an experience like the original client. It's less CPU demanding than
OpenAL. Choose it in the options menu, or set `s_openal` to `0` and
execute an `snd_restart`, to activate it.
## Tuning for Precise Timings

View file

@ -106,6 +106,9 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
* **cl_http_max_connections**: Maximum number of parallel downloads. Set
to `4` by default. A higher number may help with slow servers.
* **cl_http_verifypeer**: SSL certificate validation. Set to `1`
by default, set to `0` to disable.
* **cl_http_proxy**: Proxy to use, empty by default.
* **cl_http_show_dw_progress**: Show a HTTP download progress bar.
@ -146,6 +149,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
preview. `-1` - don't show animation. Defaults to `94` for show
salute animation.
* **cl_model_mesh_hide**: Mesh mask to hide in multiplayer model preview.
`0` - show whole model, `2` - hide second mesh from model. Defaults
to `0` for show whole model.
* **cl_nodownload_list**: Whitespace separated list of substrings, files
having one these strings in their name are never downloaded. Empty by
default. Note that some substrings are always forbidden, for security
@ -249,6 +256,14 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
By default this cvar is set to `1`, and will only work if the
game.dll implements this behaviour.
* **g_language**: Default language for ReRelease game, requires `Q2Game.kpf`
or other source of `localization/loc_english.txt` like file.
Defaults to `english`.
* **g_itemsbobeffect**: Bob effect of items like in ReRelease. Defaults to `0`.
* **g_start_items**: List of start items on level.
* **g_swap_speed**: Sets the speed of the "changing weapon" animation.
Default is `1`. If set to `2`, it will be double the speed, `3` is
the triple... up until the max of `8`, since there are at least 2
@ -481,6 +496,8 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
* **r_flashblend**: Flash blend enable in gl1, gl3 and vulkan.
* **r_ttffont**: Use `ttf` font for game messages.
## Graphics (GL renderers only)
* **gl_zfix**: Sometimes two or even more surfaces overlap and flicker.
@ -532,7 +549,12 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
squares.
* **gl1_stencilshadow**: If `gl_shadows` is set to `1`, this makes them
look a bit better (no flickering) by using the stencil buffer.
look a bit better (no flickering) by using the stencil buffer. Does
not work when `gl1_stereo` is `3`, `4` or `5`.
* **gl1_waterwarp**: Intensity of the "squeeze/stretch" effect on the
FOV when diving underwater. Can be any floating point number, `0`
disables it (Vanilla Quake II look). Default `1.0`.
* **gl1_lightmapcopies**: When enabled (`1`), keep 3 copies of the same
lightmap rotating, shifting to another one when drawing a new frame.
@ -540,9 +562,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
(dynamic lighting) causes slowdown. By default in GL1 is disabled,
while in GLES1 is enabled. Needs `gl1_multitexture 1` & `vid_restart`.
* **gl1_discardfb**: Only available in ES1. If set to `1` (default),
send a hint to discard framebuffers after finishing a frame. Useful
for GPUs that attempt to reuse them, something Quake 2 doesn't do.
* **gl1_discardfb**: If `1`, clear color, depth and stencil buffers at
the start of a frame, and discard them at the end if possible. If
`2`, do only depth and stencil, no color. Increases performance in
mobile / embedded. Default in GL1 is `0`, while in GLES1 is `1`.
## Graphics (OpenGL 3.2 and OpenGL ES3 only)
@ -596,18 +619,33 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
* **sw_colorlight**: enable experimental color lighting.
## Game Controller
## Gamepad
* **in_initjoy**: Toggles initialization of game controller. Default is
`1`, which enables gamepad usage; `0` disables its detection at
startup. Can only be set from command line.
* **in_sdlbackbutton**: Defines which button is used in the gamepad as
* **joy_escbutton**: Defines which button is used in the gamepad as
the `Esc` key, to pull the main menu and 'cancel' / 'go back' on its
options. Valid values are `0` = Back / Select / Minus, `1` = Start /
Menu / Plus (default), or `2` = Guide / Home / PS. Requires a game
options. Valid values are `0` = Start / Menu / Plus (default), `1` =
Back / Select / Minus, or `2` = Guide / Home / PS. Requires a game
restart, or gamepad replug, when changed.
* **joy_labels**: Defines style of button labels in binding menus. Note
that binding through console only uses the SDL nomenclature (`0`).
Default is `-1`, which requires at least SDL 2.0.12 to work.
- `-1`: *Autodetect*, sets to `0` if gamepad type isn't detected
- `0`: *SDL*, face buttons appear as cardinal points
- `1`: *Xbox*, with One / Series X / S labels
- `2`: *Playstation*, 4 & 5 format
- `3`: *Switch*, traditional Nintendo button format
* **joy_confirm**: Style of *confirm* and *cancel* buttons in menus. As
with the previous one, SDL 2.0.12 is required for `-1` to work.
- `-1`: *Autodetect*, sets to `1` if Nintendo, `0` otherwise
- `0`: SOUTH to confirm, EAST to cancel (standard style)
- `1`: EAST to confirm, SOUTH to cancel (Japanese style)
* **joy_layout**: Allows to select the stick layout of the gamepad.
- `0`: *Default*, left stick moves, right aims
- `1`: *Southpaw*, same as previous one with inverted sticks

View file

@ -48,3 +48,16 @@ original clients (Vanilla Quake II) commands are still in place.
* **listlights**: Show lights style and dlights list.
* **thirdperson**: Third person view.
## Jabot
* **sv makenodes**: Start creating a navigation file from scratch.
* **sv editnodes**: Modify the loaded navigation file.
* **sv savenodes**: Save nodes file
* **sv addbot <team> <name> <skin>**: Spawn a bot (consult ACEbot readme,
it's just the same thing)
* **sv removebot <name>**: Remove a bot ("all" removes every bot in the map).

View file

@ -35,6 +35,8 @@ level.
/ref_gl1.dll
/ref_gl3.dll
/ref_gles3.dll
/ref_gl4.dll
/ref_vk.dll
/ref_soft.dll
# The Executables:
@ -391,6 +393,238 @@ level.
```
# Remaster
Remaster does not requires files from original release. In game directory
should be placed only files provided with rerelease.
```
/baseq2/music/D_DDTBLU.ogg
/baseq2/music/track02.ogg
/baseq2/music/track03.ogg
/baseq2/music/track04.ogg
/baseq2/music/track05.ogg
/baseq2/music/track06.ogg
/baseq2/music/track07.ogg
/baseq2/music/track08.ogg
/baseq2/music/track09.ogg
/baseq2/music/track10.ogg
/baseq2/music/track11.ogg
/baseq2/music/track12.ogg
/baseq2/music/track13.ogg
/baseq2/music/track14.ogg
/baseq2/music/track15.ogg
/baseq2/music/track16.ogg
/baseq2/music/track17.ogg
/baseq2/music/track18.ogg
/baseq2/music/track19.ogg
/baseq2/music/track20.ogg
/baseq2/music/track21.ogg
/baseq2/music/track64.ogg
/baseq2/music/track65.ogg
/baseq2/music/track66.ogg
/baseq2/music/track67.ogg
/baseq2/music/track68.ogg
/baseq2/music/track69.ogg
/baseq2/music/track70.ogg
/baseq2/music/track71.ogg
/baseq2/music/track72.ogg
/baseq2/music/track73.ogg
/baseq2/music/track74.ogg
/baseq2/music/track75.ogg
/baseq2/music/track76.ogg
/baseq2/music/track77.ogg
/baseq2/music/track78.ogg
/baseq2/music/track79.ogg
/baseq2/video/ects.ogv
/baseq2/video/end_de.srt
/baseq2/video/end_es.srt
/baseq2/video/end_fr.srt
/baseq2/video/end_it.srt
/baseq2/video/end.ogv
/baseq2/video/end_ru.srt
/baseq2/video/end.srt
/baseq2/video/eou1__de.srt
/baseq2/video/eou1__es.srt
/baseq2/video/eou1__fr.srt
/baseq2/video/eou1__it.srt
/baseq2/video/eou1_.ogv
/baseq2/video/eou1__ru.srt
/baseq2/video/eou1_.srt
/baseq2/video/eou2__de.srt
/baseq2/video/eou2__es.srt
/baseq2/video/eou2__fr.srt
/baseq2/video/eou2__it.srt
/baseq2/video/eou2_.ogv
/baseq2/video/eou2__ru.srt
/baseq2/video/eou2_.srt
/baseq2/video/eou3__de.srt
/baseq2/video/eou3__es.srt
/baseq2/video/eou3__fr.srt
/baseq2/video/eou3__it.srt
/baseq2/video/eou3_.ogv
/baseq2/video/eou3__ru.srt
/baseq2/video/eou3_.srt
/baseq2/video/eou4__de.srt
/baseq2/video/eou4__es.srt
/baseq2/video/eou4__fr.srt
/baseq2/video/eou4__it.srt
/baseq2/video/eou4_.ogv
/baseq2/video/eou4__ru.srt
/baseq2/video/eou4_.srt
/baseq2/video/eou5__de.srt
/baseq2/video/eou5__es.srt
/baseq2/video/eou5__fr.srt
/baseq2/video/eou5__it.srt
/baseq2/video/eou5_.ogv
/baseq2/video/eou5__ru.srt
/baseq2/video/eou5_.srt
/baseq2/video/eou6__de.srt
/baseq2/video/eou6__es.srt
/baseq2/video/eou6__fr.srt
/baseq2/video/eou6__it.srt
/baseq2/video/eou6_.ogv
/baseq2/video/eou6__ru.srt
/baseq2/video/eou6_.srt
/baseq2/video/eou7__de.srt
/baseq2/video/eou7__es.srt
/baseq2/video/eou7__fr.srt
/baseq2/video/eou7__it.srt
/baseq2/video/eou7_.ogv
/baseq2/video/eou7__ru.srt
/baseq2/video/eou7_.srt
/baseq2/video/eou8__de.srt
/baseq2/video/eou8__es.srt
/baseq2/video/eou8__fr.srt
/baseq2/video/eou8__it.srt
/baseq2/video/eou8_.ogv
/baseq2/video/eou8__ru.srt
/baseq2/video/eou8_.srt
/baseq2/video/n64/n64l0t.ogv
/baseq2/video/n64/n64l10t.ogv
/baseq2/video/n64/n64l11t.ogv
/baseq2/video/n64/n64l12t.ogv
/baseq2/video/n64/n64l13t.ogv
/baseq2/video/n64/n64l14t.ogv
/baseq2/video/n64/n64l15t.ogv
/baseq2/video/n64/n64l16t.ogv
/baseq2/video/n64/n64l17t.ogv
/baseq2/video/n64/n64l18t.ogv
/baseq2/video/n64/n64l1t.ogv
/baseq2/video/n64/n64l2t.ogv
/baseq2/video/n64/n64l3t.ogv
/baseq2/video/n64/n64l4t.ogv
/baseq2/video/n64/n64l5t.ogv
/baseq2/video/n64/n64l6t.ogv
/baseq2/video/n64/n64l7t.ogv
/baseq2/video/n64/n64l8t.ogv
/baseq2/video/n64/n64l9t.ogv
/baseq2/video/ntro_de.srt
/baseq2/video/ntro_es.srt
/baseq2/video/ntro_fr.srt
/baseq2/video/ntro_it.srt
/baseq2/video/ntro.ogv
/baseq2/video/ntro_ru.srt
/baseq2/video/ntro.srt
/baseq2/video/rend_de.srt
/baseq2/video/rend_es.srt
/baseq2/video/rend_fr.srt
/baseq2/video/rend_it.srt
/baseq2/video/rend.ogv
/baseq2/video/rend_ru.srt
/baseq2/video/rend.srt
/baseq2/video/reu1__de.srt
/baseq2/video/reu1__es.srt
/baseq2/video/reu1__fr.srt
/baseq2/video/reu1__it.srt
/baseq2/video/reu1_.ogv
/baseq2/video/reu1__ru.srt
/baseq2/video/reu1_.srt
/baseq2/video/reu2__de.srt
/baseq2/video/reu2__es.srt
/baseq2/video/reu2__fr.srt
/baseq2/video/reu2__it.srt
/baseq2/video/reu2_.ogv
/baseq2/video/reu2__ru.srt
/baseq2/video/reu2_.srt
/baseq2/video/reu3__de.srt
/baseq2/video/reu3__es.srt
/baseq2/video/reu3__fr.srt
/baseq2/video/reu3__it.srt
/baseq2/video/reu3_.ogv
/baseq2/video/reu3__ru.srt
/baseq2/video/reu3_.srt
/baseq2/video/reu4__de.srt
/baseq2/video/reu4__es.srt
/baseq2/video/reu4__fr.srt
/baseq2/video/reu4__it.srt
/baseq2/video/reu4_.ogv
/baseq2/video/reu4__ru.srt
/baseq2/video/reu4_.srt
/baseq2/video/rintro_de.srt
/baseq2/video/rintro_es.srt
/baseq2/video/rintro_fr.srt
/baseq2/video/rintro_it.srt
/baseq2/video/rintro.ogv
/baseq2/video/rintro_ru.srt
/baseq2/video/rintro.srt
/baseq2/video/xin_de.srt
/baseq2/video/xin_es.srt
/baseq2/video/xin_fr.srt
/baseq2/video/xin_it.srt
/baseq2/video/xin.ogv
/baseq2/video/xin_ru.srt
/baseq2/video/xin.srt
/baseq2/video/xout_de.srt
/baseq2/video/xout_es.srt
/baseq2/video/xout_fr.srt
/baseq2/video/xout_it.srt
/baseq2/video/xout.ogv
/baseq2/video/xout_ru.srt
/baseq2/video/xout.srt
/baseq2/video/xu1_de.srt
/baseq2/video/xu1_es.srt
/baseq2/video/xu1_fr.srt
/baseq2/video/xu1_it.srt
/baseq2/video/xu1.ogv
/baseq2/video/xu1_ru.srt
/baseq2/video/xu1.srt
/baseq2/video/xu2_de.srt
/baseq2/video/xu2_es.srt
/baseq2/video/xu2_fr.srt
/baseq2/video/xu2_it.srt
/baseq2/video/xu2.ogv
/baseq2/video/xu2_ru.srt
/baseq2/video/xu2.srt
/baseq2/video/xu3_de.srt
/baseq2/video/xu3_es.srt
/baseq2/video/xu3_fr.srt
/baseq2/video/xu3_it.srt
/baseq2/video/xu3.ogv
/baseq2/video/xu3_ru.srt
/baseq2/video/xu3.srt
/baseq2/video/xu4_de.srt
/baseq2/video/xu4_es.srt
/baseq2/video/xu4_fr.srt
/baseq2/video/xu4_it.srt
/baseq2/video/xu4.ogv
/baseq2/video/xu4_ru.srt
/baseq2/video/xu4.srt
/baseq2/pak0.pak
/Q2Game.kpf
```
Additionally could be added files from [PSX](https://www.moddb.com/mods/quake-ii-psx)
```
/psx/pak0.pak
/psx/video/psx/boss.ogv
/psx/video/psx/command.ogv
/psx/video/psx/intro.ogv
/psx/video/psx/jail.ogv
/psx/video/psx/power.ogv
```
## Checksums

View file

@ -1,345 +0,0 @@
# Map state:
* OK - no known issues,
* ML - model light issues,
* WL - wall light issues,
* G - texture glitches,
* B - can't load.
## Quake2 ReRelease
| map | gl1.4 | gl3/gles3 | gl4.6 | vk | soft |
| ------------------------------ | ------ | --------- | ------ | ------ | ----------- |
| badlands.bsp | OK | N/A | N/A | OK | N/A |
| base1.bsp | OK | OK | N/A | OK | WL/ML/G |
| base2.bsp | N/A | N/A | N/A | N/A | N/A |
| base3.bsp | N/A | N/A | N/A | N/A | N/A |
| base64.bsp | N/A | N/A | N/A | N/A | N/A |
| biggun.bsp | N/A | N/A | N/A | N/A | N/A |
| boss1.bsp | N/A | N/A | N/A | N/A | N/A |
| boss2.bsp | N/A | N/A | N/A | N/A | N/A |
| bunk1.bsp | N/A | N/A | N/A | N/A | N/A |
| city1.bsp | N/A | N/A | N/A | N/A | N/A |
| city2.bsp | N/A | N/A | N/A | N/A | N/A |
| city3.bsp | N/A | N/A | N/A | N/A | N/A |
| city64.bsp | N/A | N/A | N/A | N/A | N/A |
| command.bsp | N/A | N/A | N/A | N/A | N/A |
| cool1.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/bunk_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/fact_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/jail4_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/jail_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/lab_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/mine_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/space_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/ware1a_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/ware2_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| e3/waste_e3.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/base3_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/base_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/command_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/factx_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/jail_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/kmdm3_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/mine1_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/power_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/space_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| ec/waste_ec.bsp | N/A | N/A | N/A | N/A | N/A |
| fact1.bsp | N/A | N/A | N/A | N/A | N/A |
| fact2.bsp | N/A | N/A | N/A | N/A | N/A |
| fact3.bsp | N/A | N/A | N/A | N/A | N/A |
| hangar1.bsp | N/A | N/A | N/A | N/A | N/A |
| hangar2.bsp | N/A | N/A | N/A | N/A | N/A |
| industry.bsp | N/A | N/A | N/A | N/A | N/A |
| jail1.bsp | N/A | N/A | N/A | N/A | N/A |
| jail2.bsp | N/A | N/A | N/A | N/A | N/A |
| jail3.bsp | N/A | N/A | N/A | N/A | N/A |
| jail4.bsp | N/A | N/A | N/A | N/A | N/A |
| jail5.bsp | N/A | N/A | N/A | N/A | N/A |
| lab.bsp | N/A | N/A | N/A | N/A | N/A |
| mgdm1.bsp | OK | N/A | N/A | OK | N/A |
| mgu1m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu1m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu1m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu1m4.bsp | OK | N/A | N/A | OK | N/A |
| mgu1m5.bsp | OK | N/A | N/A | OK | N/A |
| mgu1trial.bsp | OK | N/A | N/A | OK | N/A |
| mgu2m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu2m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu2m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu3m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu3m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu3m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu3m4.bsp | OK | N/A | N/A | OK | N/A |
| mgu3secret.bsp | OK | N/A | N/A | OK | N/A |
| mgu4m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu4m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu4m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu4trial.bsp | OK | N/A | N/A | OK | N/A |
| mgu5m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu5m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu5m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu5trial.bsp | OK | N/A | N/A | OK | N/A |
| mgu6m1.bsp | OK | N/A | N/A | OK | N/A |
| mgu6m2.bsp | OK | N/A | N/A | OK | N/A |
| mgu6m3.bsp | OK | N/A | N/A | OK | N/A |
| mgu6trial.bsp | OK | N/A | N/A | OK | N/A |
| mguboss.bsp | OK | N/A | N/A | OK | N/A |
| mguhub.bsp | OK | OK | ML | OK | ML |
| mine1.bsp | N/A | N/A | N/A | N/A | N/A |
| mine2.bsp | N/A | N/A | N/A | N/A | N/A |
| mine3.bsp | N/A | N/A | N/A | N/A | N/A |
| mine4.bsp | N/A | N/A | N/A | N/A | N/A |
| mintro.bsp | N/A | N/A | N/A | N/A | N/A |
| ndctf0.bsp | N/A | N/A | N/A | N/A | N/A |
| old/baseold.bsp | N/A | N/A | N/A | N/A | N/A |
| old/city2_4.bsp | N/A | N/A | N/A | N/A | N/A |
| old/fact1.bsp | N/A | N/A | N/A | N/A | N/A |
| old/fact2.bsp | N/A | N/A | N/A | N/A | N/A |
| old/fact3.bsp | N/A | N/A | N/A | N/A | N/A |
| old/facthub.bsp | N/A | N/A | N/A | N/A | N/A |
| old/hangarold.bsp | N/A | N/A | N/A | N/A | N/A |
| old/kmdm3.bsp | N/A | N/A | N/A | N/A | N/A |
| old/pjtrain1.bsp | N/A | N/A | N/A | N/A | N/A |
| old/ware1.bsp | N/A | N/A | N/A | N/A | N/A |
| old/xcommand5.bsp | N/A | N/A | N/A | N/A | N/A |
| outbase.bsp | N/A | N/A | N/A | N/A | N/A |
| power1.bsp | N/A | N/A | N/A | N/A | N/A |
| power2.bsp | N/A | N/A | N/A | N/A | N/A |
| q2ctf1.bsp | N/A | N/A | N/A | N/A | N/A |
| q2ctf2.bsp | N/A | N/A | N/A | N/A | N/A |
| q2ctf3.bsp | N/A | N/A | N/A | N/A | N/A |
| q2ctf4.bsp | N/A | N/A | N/A | N/A | N/A |
| q2ctf5.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm1.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm2.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm3.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm4.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm5.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm6.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm7.bsp | N/A | N/A | N/A | N/A | N/A |
| q2dm8.bsp | N/A | N/A | N/A | N/A | N/A |
| q2kctf1.bsp | N/A | N/A | N/A | N/A | N/A |
| q2kctf2.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/bio.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/cargo.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/command.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/comm.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/complex.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/conduits.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/core.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm10.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm1.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm2.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm3.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm4.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm5.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm6.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm7.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm8.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/dm9.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/geo-stat.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/intel.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/jail.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/lab.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/mines.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/orbit.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/organic.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/outpost.bsp | OK | N/A | N/A | N/A | B |
| q64/process.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/rtest.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/ship.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/station.bsp | N/A | N/A | N/A | N/A | N/A |
| q64/storage.bsp | N/A | N/A | N/A | N/A | N/A |
| rammo1.bsp | N/A | N/A | N/A | N/A | N/A |
| rammo2.bsp | N/A | N/A | N/A | N/A | N/A |
| rbase1.bsp | N/A | N/A | N/A | N/A | N/A |
| rbase2.bsp | N/A | N/A | N/A | N/A | N/A |
| rboss.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm10.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm11.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm12.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm13.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm14.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm1.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm2.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm3.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm4.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm5.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm6.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm7.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm8.bsp | N/A | N/A | N/A | N/A | N/A |
| rdm9.bsp | N/A | N/A | N/A | N/A | N/A |
| refinery.bsp | N/A | N/A | N/A | N/A | N/A |
| rhangar1.bsp | N/A | N/A | N/A | N/A | N/A |
| rhangar2.bsp | N/A | N/A | N/A | N/A | N/A |
| rlava1.bsp | N/A | N/A | N/A | N/A | N/A |
| rlava2.bsp | N/A | N/A | N/A | N/A | N/A |
| rmine1.bsp | N/A | N/A | N/A | N/A | N/A |
| rmine2.bsp | N/A | N/A | N/A | N/A | N/A |
| rsewer1.bsp | N/A | N/A | N/A | N/A | N/A |
| rsewer2.bsp | N/A | N/A | N/A | N/A | N/A |
| rware1.bsp | N/A | N/A | N/A | N/A | N/A |
| rware2.bsp | N/A | N/A | N/A | N/A | N/A |
| security.bsp | N/A | N/A | N/A | N/A | N/A |
| sewer64.bsp | N/A | N/A | N/A | N/A | N/A |
| space.bsp | N/A | N/A | N/A | N/A | N/A |
| strike.bsp | N/A | N/A | N/A | N/A | N/A |
| test/base1_flashlight.bsp | OK | OK | OK | OK | OK |
| test/gekk.bsp | N/A | N/A | N/A | N/A | N/A |
| test/mals_barrier_test.bsp | N/A | N/A | N/A | N/A | N/A |
| test/mals_box.bsp | N/A | N/A | N/A | N/A | N/A |
| test/mals_ladder_test.bsp | N/A | N/A | N/A | N/A | N/A |
| test/mals_locked_door_test.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_health_relay.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_ladder.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_poi.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_scaled_monsters.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_soundstage.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_steps.bsp | N/A | N/A | N/A | N/A | N/A |
| test/paril_waterlight.bsp | N/A | N/A | N/A | N/A | N/A |
| test/skysort.bsp | N/A | N/A | N/A | N/A | N/A |
| test/spbox2.bsp | N/A | N/A | N/A | N/A | N/A |
| test/spbox.bsp | N/A | N/A | N/A | N/A | N/A |
| test/test_jerry.bsp | N/A | N/A | N/A | N/A | N/A |
| test/test_kaiser.bsp | N/A | N/A | N/A | N/A | N/A |
| test/tom_test_01.bsp | N/A | N/A | N/A | N/A | N/A |
| train.bsp | N/A | N/A | N/A | N/A | N/A |
| tutorial.bsp | N/A | N/A | N/A | N/A | N/A |
| ware1.bsp | N/A | N/A | N/A | N/A | N/A |
| ware2.bsp | N/A | N/A | N/A | N/A | N/A |
| waste1.bsp | N/A | N/A | N/A | N/A | N/A |
| waste2.bsp | N/A | N/A | N/A | N/A | N/A |
| waste3.bsp | N/A | N/A | N/A | N/A | N/A |
| w_treat.bsp | N/A | N/A | N/A | N/A | N/A |
| xcompnd1.bsp | N/A | N/A | N/A | N/A | N/A |
| xcompnd2.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm1.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm2.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm3.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm4.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm5.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm6.bsp | N/A | N/A | N/A | N/A | N/A |
| xdm7.bsp | N/A | N/A | N/A | N/A | N/A |
| xhangar1.bsp | N/A | N/A | N/A | N/A | N/A |
| xhangar2.bsp | N/A | N/A | N/A | N/A | N/A |
| xintell.bsp | N/A | N/A | N/A | N/A | N/A |
| xmoon1.bsp | N/A | N/A | N/A | N/A | N/A |
| xmoon2.bsp | N/A | N/A | N/A | N/A | N/A |
| xreactor.bsp | N/A | N/A | N/A | N/A | N/A |
| xsewer1.bsp | N/A | N/A | N/A | N/A | N/A |
| xsewer2.bsp | N/A | N/A | N/A | N/A | N/A |
| xship.bsp | N/A | N/A | N/A | N/A | N/A |
| xswamp.bsp | N/A | N/A | N/A | N/A | N/A |
| xware.bsp | N/A | N/A | N/A | N/A | N/A |
Additionally supported models:
| source Quake 1 Path | destination Quake 2 Path | md5 hash |
| -------------------------- | --------------------------------- | -------------------------------- |
| progs/soldier.mdl | models/monsters/army/tris.mdl | 5b6c30a984872b4273dd5861412d35c5 |
| progs/demon.mdl | models/monsters/demon/tris.mdl | 4c73786e7cfb2083ca38cbc983cd6c4b |
| progs/dog.mdl | models/monsters/dog/tris.mdl | e727fbc39acc652f812972612ce37565 |
| progs/enforcer.mdl | models/monsters/enforcer/tris.mdl | 136c265f96d6077ee3312c52e134529f |
| progs/fish.mdl | models/monsters/fish/tris.mdl | d770d6ef92ae8b372926e6c3d49e8716 |
| progs/hknight.mdl | models/monsters/hknight/tris.mdl | ed20e30be6fdb83efbaa6d0b23671a49 |
| progs/knight.mdl | models/monsters/knight/tris.mdl | 5328915db5c53e85cf75d46e7b747fb9 |
| progs/ogre.mdl | models/monsters/ogre/tris.mdl | fbb592ca3788a576dd2f31fcf8c80fab |
| progs/shalrath.mdl | models/monsters/shalrath/tris.mdl | dac8f6077b0d2bf970573d2d2c22529f |
| progs/shambler.mdl | models/monsters/shambler/tris.mdl | 9b09375a0f614dc4081e363cc34f1185 |
| progs/tarbaby.mdl | models/monsters/tarbaby/tris.mdl | 2bfc45593a43a0191982e3cfdc112dc5 |
| progs/wizard.mdl | models/monsters/wizard/tris.mdl | bf60986594f045e60e8aa6339d553ee7 |
| progs/zombie.mdl | models/monsters/zombie/tris.mdl | a923b1d03b9d237dd5ead9bd56acc900 |
| progs/k_spike.mdl | models/proj/fireball/tris.mdl | da95b49a695b34c2c3516a8d789c6b20 |
| progs/v_spike.mdl | models/proj/pod/tris.mdl | 2bdc0b264b9fd3443c8eee816305728f |
| progs/w_spike.mdl | models/proj/spit/tris.mdl | 8cf9245df2164e8062b01a220b508d6b |
| sound/army/death1.wav | sound/army/death1.wav | fe25952af40b536c3bb67bfca58062eb |
| sound/army/idle.wav | sound/army/idle.wav | 4cdfbdda8fb5f40b125c7bcddb6e8914 |
| sound/army/pain1.wav | sound/army/pain1.wav | 54d3b05fdcecf7480034858f2b22b06c |
| sound/army/pain2.wav | sound/army/pain2.wav | e2bbc9d3405b9b9fdae76d2fc298fc2f |
| sound/army/sattck1.wav | sound/army/sattck1.wav | b76ac35f900f280a7a7996da7e404362 |
| sound/army/sight1.wav | sound/army/sight1.wav | e2a39533250ddd1b08053d5c4ebf7fd0 |
| sound/demon/ddeath.wav | sound/demon/ddeath.wav | 62a48dcd405ca55c9ce18497e36faa0e |
| sound/demon/dhit2.wav | sound/demon/dhit2.wav | 9e741696e4d0d66e30e718fc70ec186e |
| sound/demon/djump.wav | sound/demon/djump.wav | 791ac9d6b6593808316145443cb7e7a0 |
| sound/demon/dland2.wav | sound/demon/dland2.wav | db14c7b01838f826b7a712075f9026fd |
| sound/demon/dpain1.wav | sound/demon/dpain1.wav | 5e6c485878393c9bebb0d0e6659bc479 |
| sound/demon/idle1.wav | sound/demon/idle1.wav | 7a83f8caf3d5b1172a7dc5afdc942988 |
| sound/demon/sight2.wav | sound/demon/sight2.wav | 65171c355c22a5069520b0881677ae3c |
| sound/dog/dattack1.wav | sound/dog/dattack1.wav | 0c47c9d4aaae0bf3159a288b674f4a35 |
| sound/dog/ddeath.wav | sound/dog/ddeath.wav | b0e7760b1d7286a028ff9773f6802958 |
| sound/dog/dpain1.wav | sound/dog/dpain1.wav | 28e5ab93b41e13e2916433283a5d1a46 |
| sound/dog/dsight.wav | sound/dog/dsight.wav | 0edc290765bac1fb4fe03ca55bc7c225 |
| sound/dog/idle.wav | sound/dog/idle.wav | 42bd6026ff32bd94523ad9f8fe8362cc |
| sound/enforcer/death1.wav | sound/enforcer/death1.wav | f38d7a235e13ef8918aac0c70437320d |
| sound/enforcer/enfire.wav | sound/enforcer/enfire.wav | b080a6a53f138bef9fc4403fb9373a24 |
| sound/enforcer/enfstop.wav | sound/enforcer/enfstop.wav | 0bc39c3c88187fb37d20ef21300e7b22 |
| sound/enforcer/idle1.wav | sound/enforcer/idle1.wav | d0435763860fe54e938ad25bb1780f9e |
| sound/enforcer/pain1.wav | sound/enforcer/pain1.wav | d52bc02afe624924684b25295edaa040 |
| sound/enforcer/pain2.wav | sound/enforcer/pain2.wav | f6b0ad6485d93f5c6d7d61b847d06877 |
| sound/enforcer/sight1.wav | sound/enforcer/sight1.wav | 9e9876444ba92ed18bfce4cec3a2ff12 |
| sound/enforcer/sight2.wav | sound/enforcer/sight2.wav | 815dd4f6a890b0a35dc466005df74850 |
| sound/enforcer/sight3.wav | sound/enforcer/sight3.wav | f8c8d19905b24d4adb6760a1b3762f3b |
| sound/enforcer/sight4.wav | sound/enforcer/sight4.wav | 04e40eb925290bc56520de326df6b220 |
| sound/fish/bite.wav | sound/fish/bite.wav | 7c56712615e2a2c3de4fe0e7e35cba05 |
| sound/fish/death.wav | sound/fish/death.wav | 8d6152ee55507430a8c2eb276c4aa8ac |
| sound/fish/idle.wav | sound/fish/idle.wav | 54a02731b85eb6f8b1a8ecce09771d20 |
| sound/hknight/attack1.wav | sound/hknight/attack1.wav | 695e9d890a085addf1a607aa79137e8e |
| sound/hknight/death1.wav | sound/hknight/death1.wav | 2d68c3c86632027676b823fcff3af08c |
| sound/hknight/grunt.wav | sound/hknight/grunt.wav | 122f3d4623e0146732aa0e4deb0fe326 |
| sound/hknight/hit.wav | sound/hknight/hit.wav | fece24e2548f1d769e8fce39a5c87d01 |
| sound/hknight/idle.wav | sound/hknight/idle.wav | e9ca23c4853472750d1f56e52a3d227b |
| sound/hknight/pain1.wav | sound/hknight/pain1.wav | 52c20eb6f5b5146ece6b0ac02f423341 |
| sound/hknight/sight1.wav | sound/hknight/sight1.wav | 786d28ec653a0d512d078b32eb8cb58b |
| sound/hknight/slash1.wav | sound/hknight/slash1.wav | 83e64bb90cff2a4f9764dd53489b9d7d |
| sound/knight/idle.wav | sound/knight/idle.wav | 1b5c3981bee078318af346d8fe8090b9 |
| sound/knight/kdeath.wav | sound/knight/kdeath.wav | 11a96f48a8f2433c23beae299c8fb96e |
| sound/knight/khurt.wav | sound/knight/khurt.wav | 32c9f48dd4a6a87752aedf56fe8de668 |
| sound/knight/ksight.wav | sound/knight/ksight.wav | eb75b4af348c88e84d8c87c19d5976fa |
| sound/knight/sword1.wav | sound/knight/sword1.wav | 93045b5f3178413dc6b01ec2869d1f73 |
| sound/knight/sword2.wav | sound/knight/sword2.wav | 82d1a7c263cd3df7b060dee2f7f8b1fd |
| sound/ogre/ogdrag.wav | sound/ogre/ogdrag.wav | 658587dc89aaefae5ca3f058f7ff4227 |
| sound/ogre/ogdth.wav | sound/ogre/ogdth.wav | de98e7bb9e70586edddd3308cfded3db |
| sound/ogre/ogidle2.wav | sound/ogre/ogidle2.wav | 196ae9c33a4311160e1d5f3da878ab09 |
| sound/ogre/ogidle.wav | sound/ogre/ogidle.wav | 177c829840a87c885bbc8951e7ce962e |
| sound/ogre/ogpain1.wav | sound/ogre/ogpain1.wav | ac6d133d7720c12df49813fe10e683b5 |
| sound/ogre/ogsawatk.wav | sound/ogre/ogsawatk.wav | 7257bdfd014bb61d778b8f88cb65d560 |
| sound/ogre/ogwake.wav | sound/ogre/ogwake.wav | 3296459e495c4c12b31179d4eeffac19 |
| sound/shalrath/attack2.wav | sound/shalrath/attack2.wav | 777fbda2f81350e45920ea1c36d318e1 |
| sound/shalrath/attack.wav | sound/shalrath/attack.wav | 8814a72b399be619d14223235f78f294 |
| sound/shalrath/death.wav | sound/shalrath/death.wav | 771844c5cfb5a42e82e221a63f101ac7 |
| sound/shalrath/idle.wav | sound/shalrath/idle.wav | 1a45f12579f9cdd27152332d5f816048 |
| sound/shalrath/pain.wav | sound/shalrath/pain.wav | 6ba007b79c50d7d5347f1a29fb315422 |
| sound/shalrath/sight.wav | sound/shalrath/sight.wav | 3d3c2001cc976efc67af1552427eedd3 |
| sound/shambler/melee1.wav | sound/shambler/melee1.wav | 77fe6240973a204b757a427ebf66bcfd |
| sound/shambler/melee2.wav | sound/shambler/melee2.wav | 3be31638d769e3d690c92311dfafdeac |
| sound/shambler/sattck1.wav | sound/shambler/sattck1.wav | ec8c3f79ea42d09154cb8975ada1b21c |
| sound/shambler/sboom.wav | sound/shambler/sboom.wav | 9834601a645d7d1f62001b2a314ec18f |
| sound/shambler/sdeath.wav | sound/shambler/sdeath.wav | e0e62d229a985a6e39218c6488599059 |
| sound/shambler/shurt2.wav | sound/shambler/shurt2.wav | 1e87631ede95e061a75f9c31629ac0b8 |
| sound/shambler/sidle.wav | sound/shambler/sidle.wav | 368a240e6c3e877793352a79c1828386 |
| sound/shambler/smack.wav | sound/shambler/smack.wav | bd8c634c9894348360fec7b7419d1649 |
| sound/shambler/ssight.wav | sound/shambler/ssight.wav | 657107577460d5acf3157dec97e07a89 |
| sound/tarbaby/death1.wav | sound/tarbaby/death1.wav | 53f8c73de11c018086ba19ed036833d3 |
| sound/tarbaby/hit1.wav | sound/tarbaby/hit1.wav | 42c5a1edd02421bf6df7ddc3e395c4f8 |
| sound/tarbaby/land1.wav | sound/tarbaby/land1.wav | 5a1585ab22368a48827db9b7d3763b58 |
| sound/tarbaby/sight1.wav | sound/tarbaby/sight1.wav | df4dd7ec91e094b5c2235be3f5353e4a |
| sound/wizard/hit.wav | sound/wizard/hit.wav | 6598d669334df977f1f97b95288edf11 |
| sound/wizard/wattack.wav | sound/wizard/wattack.wav | b3568a47439f81779d40335e76f5bc2d |
| sound/wizard/wdeath.wav | sound/wizard/wdeath.wav | 99d9c71343bc23222abb92119d404400 |
| sound/wizard/widle1.wav | sound/wizard/widle1.wav | b22b1dd9f66879b3447d36ab584316c7 |
| sound/wizard/widle2.wav | sound/wizard/widle2.wav | 7178fd83df227360564adef01bed92c6 |
| sound/wizard/wpain.wav | sound/wizard/wpain.wav | bd7e59ab7d7b835f9ed8ab51950914de |
| sound/wizard/wsight.wav | sound/wizard/wsight.wav | df5949057c750528917c6cb32b7fd9fd |
| sound/zombie/idle_w2.wav | sound/zombie/idle_w2.wav | d2bb59b9d7ac71097c07123a23525641 |
| sound/zombie/z_fall.wav | sound/zombie/z_fall.wav | 6968318b2d196c6d54bc707d8a390547 |
| sound/zombie/z_gib.wav | sound/zombie/z_gib.wav | 199dda66ade8d6f0ef4897e4d7608c0d |
| sound/zombie/z_hit.wav | sound/zombie/z_hit.wav | 6c66ab3e6b149bf35956a4bbc0057acb |
| sound/zombie/z_idle1.wav | sound/zombie/z_idle1.wav | 21088a7b38b1124d7ec72e58d5ab93a6 |
| sound/zombie/z_idle.wav | sound/zombie/z_idle.wav | e5e570e38c4405111004190a79f0e925 |
| sound/zombie/z_miss.wav | sound/zombie/z_miss.wav | 96fad96a8c3bc6f7bcc5da6c82678da2 |
| sound/zombie/z_pain1.wav | sound/zombie/z_pain1.wav | fcd83b89a94b0cadbe1361a4df080ec0 |
| sound/zombie/z_pain.wav | sound/zombie/z_pain.wav | 56637968b8309bd2f825153330bbdfc0 |
| sound/zombie/z_shot1.wav | sound/zombie/z_shot1.wav | 561afb69b7851923a8fb3b54e3e13c96 |
Look to [infighter](https://github.com/decino/q2-infighter) for more info.

View file

@ -30,7 +30,7 @@
#include "../../common/header/shared.h"
#include "../../common/header/common.h"
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
#if defined(__linux) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(__APPLE__)
#include <unistd.h> // readlink(), amongst others
#endif
@ -40,6 +40,7 @@
#ifdef _WIN32
#include <windows.h> // GetModuleFileNameA()
#include <wchar.h> // _wgetcwd()
#endif
#ifdef __APPLE__
@ -146,6 +147,32 @@ static void SetExecutablePath(char* exePath)
#endif
}
static qboolean
Sys_GetCwd(char *buf, size_t size)
{
#ifdef _WIN32
WCHAR wpath[PATH_MAX];
DWORD len;
if (_wgetcwd(wpath, PATH_MAX) == NULL)
{
return false;
}
len = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buf, size, NULL, NULL);
if (len <= 0 || len == size)
{
return false;
}
#else
if (getcwd(buf, size) == NULL)
{
return false;
}
#endif
return Q_strlcat(buf, "/", size) == 1;
}
const char *Sys_GetBinaryDir(void)
{
static char exeDir[PATH_MAX] = {0};
@ -157,8 +184,11 @@ const char *Sys_GetBinaryDir(void)
SetExecutablePath(exeDir);
if (exeDir[0] == '\0') {
Com_Printf("Couldn't determine executable path. Using ./ instead.\n");
Q_strlcpy(exeDir, "./", sizeof(exeDir));
if (Sys_GetCwd(exeDir, sizeof(exeDir)) == false)
{
Q_strlcpy(exeDir, "./", sizeof(exeDir));
}
Com_Printf("Couldn't determine executable path. Using %s instead.\n", exeDir);
} else {
// cut off executable name
char *lastSlash = strrchr(exeDir, '/');

View file

@ -397,7 +397,7 @@ NET_StringToSockaddr(const char *s, struct sockaddr_storage *sadr)
if (!*space)
{
Com_Printf("NET_StringToSockaddr: invalid IPv6 address %s\n", s);
return 0;
return false;
}
*space++ = '\0';
@ -417,7 +417,7 @@ NET_StringToSockaddr(const char *s, struct sockaddr_storage *sadr)
/* Error */
Com_Printf("NET_StringToSockaddr: string %s:\n%s\n", s,
gai_strerror(err));
return 0;
return false;
}
switch (resultp->ai_family)
@ -432,7 +432,7 @@ NET_StringToSockaddr(const char *s, struct sockaddr_storage *sadr)
default:
Com_Printf("NET_StringToSockaddr: string %s:\nprotocol family %d not supported\n",
s, resultp->ai_family);
return 0;
return false;
}
freeaddrinfo(resultp);

View file

@ -79,7 +79,7 @@ Hunk_Begin(int maxsize)
prot |= PROT_MAX(prot);
#endif
membase = mmap(0, maxhunksize, prot,
membase = (byte *)mmap(0, maxhunksize, prot,
flags, -1, 0);
if ((membase == NULL) || (membase == (byte *)-1))

View file

@ -406,8 +406,7 @@ Sys_GetGameAPI(void *parms)
fnAPI GetGameAPI;
char name[MAX_OSPATH];
char *path;
char *str_p;
const char *path, *str_p;
#ifdef __APPLE__
const char *gamename = "game.dylib";
#else
@ -618,21 +617,21 @@ Sys_Realpath(const char *in, char *out, size_t size)
void *
Sys_GetProcAddress(void *handle, const char *sym)
{
if (handle == NULL)
{
if (handle == NULL)
{
#ifdef RTLD_DEFAULT
return dlsym(RTLD_DEFAULT, sym);
return dlsym(RTLD_DEFAULT, sym);
#else
/* POSIX suggests that this is a portable equivalent */
static void *global_namespace = NULL;
/* POSIX suggests that this is a portable equivalent */
static void *global_namespace = NULL;
if (global_namespace == NULL)
global_namespace = dlopen(NULL, RTLD_GLOBAL|RTLD_LAZY);
if (global_namespace == NULL)
global_namespace = dlopen(NULL, RTLD_GLOBAL|RTLD_LAZY);
return dlsym(global_namespace, sym);
return dlsym(global_namespace, sym);
#endif
}
return dlsym(handle, sym);
}
return dlsym(handle, sym);
}
void

View file

@ -193,7 +193,7 @@ NET_CompareAdr(netadr_t a, netadr_t b)
if (a.type == NA_LOOPBACK)
{
return TRUE;
return true;
}
if (a.type == NA_IP)
@ -240,7 +240,7 @@ NET_CompareBaseAdr(netadr_t a, netadr_t b)
if (a.type == NA_LOOPBACK)
{
return TRUE;
return true;
}
if (a.type == NA_IP)
@ -411,7 +411,7 @@ NET_StringToSockaddr(const char *s, struct sockaddr_storage *sadr)
if (!*space)
{
Com_Printf("NET_StringToSockaddr: invalid IPv6 address %s\n", s);
return 0;
return false;
}
*space++ = '\0';
@ -431,7 +431,7 @@ NET_StringToSockaddr(const char *s, struct sockaddr_storage *sadr)
/* Error */
Com_Printf("NET_StringToSockaddr: string %s:\n%s\n", s,
gai_strerror(err));
return 0;
return false;
}
switch (resultp->ai_family)
@ -800,7 +800,7 @@ NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to)
/* ============================================================================= */
int
static int
NET_IPSocket(char *net_interface, int port, netsrc_t type, int family)
{
char Buf[BUFSIZ], *Host, *Service;
@ -1040,7 +1040,7 @@ NET_OpenIP(void)
}
}
int
static int
NET_IPXSocket(int port)
{
int newsocket;

View file

@ -275,7 +275,7 @@ Sys_Microseconds(void)
static LARGE_INTEGER freq = { 0 };
static LARGE_INTEGER base = { 0 };
if (!freq.QuadPart)
if (!freq.QuadPart)
{
QueryPerformanceFrequency(&freq);
}

View file

@ -458,8 +458,8 @@ SCR_ReadNextFrame(void)
FS_Read(compressed, size, cl.cinematic_file);
/* read sound */
start = cl.cinematicframe * cin.s_rate / cin.fps;
end = (cl.cinematicframe + 1) * cin.s_rate / cin.fps;
start = cl.cinematicframe * cin.s_rate / (int)cin.fps;
end = (cl.cinematicframe + 1) * cin.s_rate / (int)cin.fps;
count = end - start;
FS_Read(samples, count * cin.s_width * cin.s_channels,
@ -528,7 +528,8 @@ SCR_ReadNextAVFrame(void)
static qboolean
SCR_LoadAVcodec(const char *arg, const char *dot)
{
char name[MAX_OSPATH], *path = NULL;
const char *path = NULL;
char name[MAX_OSPATH];
while (1)
{
@ -599,6 +600,7 @@ SCR_RunCinematic(void)
}
cin.pic = cin.pic_pending;
cin.pic_pending = NULL;
switch (cin.video_type)
{
case video_cin:
@ -613,7 +615,8 @@ SCR_RunCinematic(void)
break;
#endif
default:
cin.pic_pending = NULL;
/* should be never called */
Com_Error(ERR_DROP, "Incorrect media data.");
}
if (!cin.pic_pending)

View file

@ -35,28 +35,6 @@ extern char key_lines[NUM_KEY_LINES][MAXCMDLINE];
extern int edit_line;
extern int key_linepos;
void
DrawStringScaled(int x, int y, const char *s, float factor)
{
while (*s)
{
Draw_CharScaled(x, y, *s, factor);
x += 8*factor;
s++;
}
}
void
DrawAltStringScaled(int x, int y, const char *s, float factor)
{
while (*s)
{
Draw_CharScaled(x, y, *s ^ 0x80, factor);
x += 8*factor;
s++;
}
}
void
Key_ClearTyping(void)
{
@ -472,7 +450,7 @@ Con_DrawInput(void)
float scale;
char *text;
char ch;
int txtlen;
size_t txtlen;
int linepos;
int draw_icon;
@ -587,12 +565,12 @@ Con_DrawNotify(void)
{
if (chat_team)
{
DrawStringScaled(8 * scale, v * scale, "say_team:", scale);
Draw_StringScaled(8 * scale, v * scale, scale, false, "say_team:");
skip = 11;
}
else
{
DrawStringScaled(8 * scale, v * scale, "say:", scale);
Draw_StringScaled(8 * scale, v * scale, scale, false, "say:");
skip = 5;
}
@ -630,7 +608,7 @@ Con_DrawConsole(float frac)
{
int i, j, x, y, n;
int rows;
int verLen;
size_t verLen;
char *text;
int row;
int lines;
@ -666,10 +644,7 @@ Con_DrawConsole(float frac)
verLen = strlen(version);
for (x = 0; x < verLen; x++)
{
Draw_CharScaled(viddef.width - ((verLen*8+5) * scale) + x * 8 * scale, lines - 35 * scale, 128 + version[x], scale);
}
Draw_StringScaled(viddef.width - ((verLen * 8 + 5) * scale), lines - 35 * scale, scale, true, version);
t = time(NULL);
today = localtime(&t);
@ -677,10 +652,7 @@ Con_DrawConsole(float frac)
Com_sprintf(tmpbuf, sizeof(tmpbuf), "%s", timebuf);
for (x = 0; x < 21; x++)
{
Draw_CharScaled(viddef.width - (173 * scale) + x * 8 * scale, lines - 25 * scale, 128 + tmpbuf[x], scale);
}
Draw_StringScaled(viddef.width - (173 * scale), lines - 25 * scale, scale, true, tmpbuf);
/* draw the text */
con.vislines = lines;
@ -790,7 +762,7 @@ Con_DrawConsole(float frac)
sprintf(dlbar + strlen(dlbar), " %02d%%", cls.downloadpercent);
/* draw it */
y = con.vislines - 12;
y = (lines - 12 * scale) / scale;
for (i = 0; i < strlen(dlbar); i++)
{

View file

@ -778,7 +778,7 @@ CL_AddMuzzleFlash2(void)
}
void
CL_TeleporterParticles(entity_state_t *ent)
CL_TeleporterParticles(const entity_xstate_t *ent)
{
int i, j;
cparticle_t *p;
@ -2046,7 +2046,7 @@ CL_TeleportParticles(vec3_t org)
extern struct sfx_s *cl_sfx_footsteps[4];
void
CL_EntityEvent(entity_state_t *ent)
CL_EntityEvent(entity_xstate_t *ent)
{
switch (ent->event)
{
@ -2064,8 +2064,52 @@ CL_EntityEvent(entity_state_t *ent)
if (cl_footsteps->value)
{
vec3_t mins = {0, 0, 0}, maxs = {0, 0, 0}, dir = { 0, 0, -1000000 };
struct sfx_s *sfx = NULL;
trace_t trace;
trace = CM_BoxTrace(ent->origin, dir, mins, maxs, 0, MASK_DEADSOLID);
/* ladder does not have separate material */
if ((trace.contents & CONTENTS_LADDER))
{
char name[MAX_QPATH];
int step;
/* material has sometime 5 steps versions */
step = randk() % 5;
Com_sprintf(name, sizeof(name), "player/ladder%i.wav",
step + 1);
sfx = S_RegisterSound(name);
}
/* step sound based onb material */
if (!sfx && trace.surface->material[0])
{
char name[MAX_QPATH];
int step;
/* material has sometime 5 steps versions */
step = randk() % 5;
Com_sprintf(name, sizeof(name), "player/%s%i.wav",
trace.surface->material, step + 1);
sfx = S_RegisterSound(name);
}
/* no material steps sound found */
if (!sfx)
{
int step;
step = randk() & 3;
sfx = cl_sfx_footsteps[step];
}
S_StartSound(NULL, ent->number, CHAN_BODY,
cl_sfx_footsteps[randk() & 3], 1, ATTN_NORM, 0);
sfx, 1, ATTN_NORM, 0);
}
break;
@ -2092,6 +2136,80 @@ CL_ClearEffects(void)
CL_ClearLightStyles();
}
void
CL_FlameEffects(vec3_t origin)
{
int n, count;
count = rand() & 0xF;
/* Particles going down */
for(n = 0; n < count; n++)
{
cparticle_t *p;
int j;
if (!free_particles)
{
return;
}
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
VectorClear(p->accel);
p->time = cl.time;
p->alpha = 1.0;
p->alphavel = -1.0 / (1 + frandk() * 0.2);
p->color = CL_CombineColors(0xff007fef, 0xff003bb7,
(float)(randk() & 15) / 15.0);
for (j = 0; j < 3; j++)
{
p->org[j] = origin[j] + crandk() * 5;
p->vel[j] = crandk() * 5;
}
p->vel[2] = crandk() * -10;
p->accel[2] = -PARTICLE_GRAVITY;
}
count = rand() & 0x7;
/* Particles go up */
for (n = 0; n < count; n++)
{
cparticle_t *p;
int j;
if (!free_particles)
{
return;
}
p = free_particles;
free_particles = p->next;
p->next = active_particles;
active_particles = p;
VectorClear(p->accel);
p->time = cl.time;
p->alpha = 1.0;
p->alphavel = -1.0 / (1 + frandk() * 0.5);
p->color = CL_CombineColors(0xff0000ff, 0xff002f2f,
(float)(randk() & 15) / 15.0);
for (j=0 ; j<3 ; j++)
{
p->org[j] = origin[j] + crandk() * 3;
}
p->vel[2] = 20 + crandk() * 5;
}
}
void
CL_Flashlight(int ent, vec3_t pos)
{

View file

@ -32,15 +32,9 @@ extern struct model_s *cl_mod_powerscreen;
void
CL_AddPacketEntities(frame_t *frame)
{
entity_t ent = {0};
entity_state_t *s1;
float autorotate;
int i;
int pnum;
centity_t *cent;
float autorotate, autobob;
int autoanim;
clientinfo_t *ci;
unsigned int effects, renderfx;
int pnum;
/* To distinguish baseq2, xatrix and rogue. */
cvar_t *gametype = Cvar_Get("gametype", "", CVAR_LATCH | CVAR_SERVERINFO);
@ -50,16 +44,26 @@ CL_AddPacketEntities(frame_t *frame)
/* brush models can auto animate their frames */
autoanim = 2 * cl.time / 1000;
autobob = 5 * sinf(cl.time / 400.0f);
for (pnum = 0; pnum < frame->num_entities; pnum++)
{
unsigned int effects, renderfx, rr_effects;
entity_xstate_t *s1;
entity_t ent = {0};
clientinfo_t *ci;
centity_t *cent;
int i;
s1 = &cl_parse_entities[(frame->parse_entities +
pnum) & (MAX_PARSE_ENTITIES - 1)];
cent = &cl_entities[s1->number];
effects = s1->effects;
rr_effects = s1->rr_effects;
renderfx = s1->renderfx;
ent.rr_mesh = s1->rr_mesh;
/* set frame */
if (effects & EF_ANIM01)
@ -132,10 +136,15 @@ CL_AddPacketEntities(frame_t *frame)
for (i = 0; i < 3; i++)
{
ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
(cent->current.origin[i] - cent->prev.origin[i]);
(cent->current.origin[i] - cent->prev.origin[i]);
}
}
if (effects & EF_BOB) {
ent.origin[2] += autobob;
ent.oldorigin[2] += autobob;
}
/* tweak the color of beams */
if (renderfx & RF_BEAM)
{
@ -156,7 +165,7 @@ CL_AddPacketEntities(frame_t *frame)
else
{
/* set skin */
if (s1->modelindex == 255)
if (s1->modelindex == CUSTOM_PLAYER_MODEL)
{
/* use custom player skin */
ent.skinnum = 0;
@ -198,6 +207,9 @@ CL_AddPacketEntities(frame_t *frame)
ent.skin = NULL;
ent.model = cl.model_draw[s1->modelindex];
}
/* store scale */
VectorCopy(s1->scale, ent.scale);
}
/* only used for black hole model right now */
@ -251,6 +263,44 @@ CL_AddPacketEntities(frame_t *frame)
}
}
if (rr_effects & EF_FLASHLIGHT) {
vec3_t forward, start, end, diff, pos;
vec3_t mins = {-1, -1, -1}, maxs = {1, 1, 1};
trace_t trace;
int len = 0, i;
float step;
AngleVectors(ent.angles, forward, NULL, NULL);
VectorMA(ent.origin, 256, forward, end);
VectorCopy(ent.origin, start);
/* search light end point */
trace = CM_BoxTrace(start, end, mins, maxs, 0, MASK_SHOT);
/* step back little bit, for cover nearest surfaces */
VectorSubtract(trace.endpos, ent.origin, diff);
len = VectorNormalize(diff);
/* get light steps */
step = (float)len / 16;
for (i = 0; i < 3; i++)
{
diff[i] *= step;
}
/* place only 16 lights in row max */
if (len > 16)
{
len = 16;
}
VectorCopy(trace.endpos, pos);
/* Add light trace */
for (i = 0; i < len; i++)
{
/* create light */
V_AddLight(pos, 128 * (len - i) / len + 64, 1, 1, 1);
VectorSubtract(pos, diff, pos);
}
}
if (s1->number == cl.playernum + 1)
{
ent.flags |= RF_VIEWERMODEL;
@ -381,7 +431,7 @@ CL_AddPacketEntities(frame_t *frame)
/* duplicate for linked models */
if (s1->modelindex2)
{
if (s1->modelindex2 == 255)
if (s1->modelindex2 == CUSTOM_PLAYER_MODEL)
{
/* custom weapon */
ci = &cl.clientinfo[s1->skinnum & 0xff];

View file

@ -41,6 +41,35 @@
#define STB_IMAGE_IMPLEMENTATION
#include "refresh/files/stb_image.h"
/* ATD types */
typedef struct
{
char *file;
} atd_bitmap_t;
typedef struct
{
int bitmap;
int next;
float wait;
int x;
int y;
} atd_frame_t;
typedef struct
{
int colortype;
int width;
int height;
int bilinear;
int clamp;
char* type;
atd_bitmap_t *bitmaps;
size_t bitmap_count;
atd_frame_t *frames;
size_t frame_count;
} atd_sprites_t;
// Fix Jennell Jaquays' name in the Quitscreen
// this is 98x11 pixels, each value an index
// into the standard baseq2/pak0/pics/quit.pcx colormap
@ -820,8 +849,11 @@ Convert24to32(unsigned *d_8to24table, byte *pal)
d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent
}
/*
* Load only static images without animation support
*/
static void
LoadImageWithPalette(const char *filename, byte **pic, byte **palette,
LoadImageWithPaletteStatic(const char *filename, byte **pic, byte **palette,
int *width, int *height, int *bitsPerPixel)
{
const char* ext;
@ -912,6 +944,268 @@ LoadImageWithPalette(const char *filename, byte **pic, byte **palette,
FS_FreeFile(raw);
}
static void
LoadImageATDFree(atd_sprites_t* anim)
{
for (size_t i = 0; i < anim->bitmap_count; i++)
{
free(anim->bitmaps[i].file);
}
free(anim->bitmaps);
free(anim->frames);
free(anim->type);
}
static void
LoadImageATD(atd_sprites_t* anim, char *tmp_buf, int len)
{
char *curr_buff;
/* get lines count */
curr_buff = tmp_buf;
while(curr_buff && *curr_buff && (curr_buff < (tmp_buf + len)))
{
const char *token;
token = COM_Parse(&curr_buff);
if (!token)
{
continue;
}
if (token[0] == '#')
{
size_t linesize;
/* skip empty */
linesize = strcspn(curr_buff, "\n\r");
curr_buff += linesize;
}
else if (!strcmp(token, "type") ||
!strcmp(token, "width") ||
!strcmp(token, "height") ||
!strcmp(token, "bilinear") ||
!strcmp(token, "clamp") ||
!strcmp(token, "colortype"))
{
char token_section[MAX_TOKEN_CHARS];
Q_strlcpy(token_section, token, sizeof(token_section));
token = COM_Parse(&curr_buff);
if (strcmp(token, "="))
{
/* should = after token */
return;
}
if (!strcmp(token_section, "type") && !anim->type)
{
anim->type = strdup(COM_Parse(&curr_buff));
}
else
{
int value;
token = COM_Parse(&curr_buff);
value = (int)strtol(token, (char **)NULL, 10);
if (!strcmp(token_section, "colortype"))
{
anim->colortype = value;
}
else if (!strcmp(token_section, "width"))
{
anim->width = value;
}
else if (!strcmp(token_section, "height"))
{
anim->height = value;
}
else if (!strcmp(token_section, "bilinear"))
{
anim->bilinear = value;
}
else if (!strcmp(token_section, "clamp"))
{
anim->clamp = value;
}
}
}
else if (!strcmp(token, "!bitmap"))
{
token = COM_Parse(&curr_buff);
if (strcmp(token, "file"))
{
/* should file after token */
return;
}
token = COM_Parse(&curr_buff);
if (strcmp(token, "="))
{
/* should = after token */
return;
}
/* save bitmap file */
anim->bitmap_count++;
anim->bitmaps = realloc(anim->bitmaps, anim->bitmap_count * sizeof(atd_bitmap_t));
anim->bitmaps[anim->bitmap_count - 1].file = strdup(COM_Parse(&curr_buff));
}
else if (!strcmp(token, "!frame"))
{
atd_frame_t *frame;
anim->frame_count++;
anim->frames = realloc(anim->frames, anim->frame_count * sizeof(frame_t));
frame = &anim->frames[anim->frame_count - 1];
frame->next = -1;
frame->wait = 0.0f;
frame->x = frame->y = 0;
frame->bitmap = -1;
while(curr_buff && *curr_buff && (curr_buff < (tmp_buf + len)))
{
size_t linesize;
/* skip empty */
linesize = strspn(curr_buff, "\n\r\t ");
curr_buff += linesize;
/* new frame? */
if (curr_buff[0] == '!')
{
break;
}
token = COM_Parse(&curr_buff);
if (token[0] == '#')
{
/* skip empty */
linesize = strcspn(curr_buff, "\n\r");
curr_buff += linesize;
}
else if (!strcmp(token, "bitmap") ||
!strcmp(token, "next") ||
!strcmp(token, "wait") ||
!strcmp(token, "x") ||
!strcmp(token, "y"))
{
char token_section[MAX_TOKEN_CHARS];
Q_strlcpy(token_section, token, sizeof(token_section));
token = COM_Parse(&curr_buff);
if (strcmp(token, "="))
{
/* should = after token */
return;
}
if (!strcmp(token_section, "wait"))
{
token = COM_Parse(&curr_buff);
frame->wait = (float)strtod(token, (char **)NULL);
}
else
{
int value;
token = COM_Parse(&curr_buff);
value = (int)strtol(token, (char **)NULL, 10);
if (!strcmp(token_section, "bitmap"))
{
frame->bitmap = value;
}
else if (!strcmp(token_section, "next"))
{
frame->next = value;
}
else if (!strcmp(token_section, "x"))
{
frame->x = value;
}
else if (!strcmp(token_section, "y"))
{
frame->y = value;
}
}
}
}
}
}
}
/* Load images with sprites */
static void
LoadImageWithPalette(const char *filename, byte **pic, byte **palette,
int *width, int *height, int *bitsPerPixel)
{
const char* ext;
ext = COM_FileExtension(filename);
if (!strcmp(ext, "atd"))
{
char *tmp_buf, *raw;
int lindent, len;
*pic = NULL;
/* load the file */
len = FS_LoadFile(filename, (void **)&raw);
if (!raw || len <= 0)
{
return;
}
if (len <= sizeof(int))
{
FS_FreeFile(raw);
return;
}
lindent = LittleLong(*((int*)raw));
len -= 4;
if (lindent == IDATDSPRITEHEADER)
{
atd_sprites_t *anim = malloc(sizeof(atd_sprites_t));
memset(anim, 0, sizeof(atd_sprites_t));
tmp_buf = malloc(len + 1);
memcpy(tmp_buf, raw + 4, len);
tmp_buf[len] = 0;
LoadImageATD(anim, tmp_buf, len);
free(tmp_buf);
if (anim->bitmap_count &&
anim->frame_count &&
(anim->frames[0].bitmap >= 0) &&
(anim->frames[0].bitmap < anim->bitmap_count))
{
int bitmap;
bitmap = anim->frames[0].bitmap;
LoadImageWithPaletteStatic(anim->bitmaps[bitmap].file,
pic, palette, width, height, bitsPerPixel);
}
LoadImageATDFree(anim);
free(anim);
}
FS_FreeFile(raw);
return;
}
else
{
LoadImageWithPaletteStatic(filename, pic, palette, width, height, bitsPerPixel);
}
}
void
SCR_LoadImageWithPalette(const char *filename, byte **pic, byte **palette,
int *width, int *height, int *bitsPerPixel)

View file

@ -139,62 +139,6 @@ keyname_t keynames[] = {
{"MWHEELUP", K_MWHEELUP},
{"MWHEELDOWN", K_MWHEELDOWN},
{"BTN_A", K_BTN_A},
{"BTN_B", K_BTN_B},
{"BTN_X", K_BTN_X},
{"BTN_Y", K_BTN_Y},
{"STICK_LEFT", K_STICK_LEFT},
{"STICK_RIGHT", K_STICK_RIGHT},
{"SHOULDR_LEFT", K_SHOULDER_LEFT},
{"SHOULDR_RIGHT", K_SHOULDER_RIGHT},
{"TRIG_LEFT", K_TRIG_LEFT},
{"TRIG_RIGHT", K_TRIG_RIGHT},
{"DP_UP", K_DPAD_UP},
{"DP_DOWN", K_DPAD_DOWN},
{"DP_LEFT", K_DPAD_LEFT},
{"DP_RIGHT", K_DPAD_RIGHT},
{"PADDLE_1", K_PADDLE_1},
{"PADDLE_2", K_PADDLE_2},
{"PADDLE_3", K_PADDLE_3},
{"PADDLE_4", K_PADDLE_4},
{"BTN_MISC1", K_BTN_MISC1},
{"TOUCHPAD", K_TOUCHPAD},
{"BTN_BACK", K_BTN_BACK},
{"BTN_GUIDE", K_BTN_GUIDE},
{"BTN_START", K_BTN_START},
// virtual keys you get by pressing the corresponding normal joy key
// and the altselector key
{"BTN_A_ALT", K_BTN_A_ALT},
{"BTN_B_ALT", K_BTN_B_ALT},
{"BTN_X_ALT", K_BTN_X_ALT},
{"BTN_Y_ALT", K_BTN_Y_ALT},
{"STICK_LEFT_ALT", K_STICK_LEFT_ALT},
{"STICK_RIGHT_ALT", K_STICK_RIGHT_ALT},
{"SHOULDR_LEFT_ALT", K_SHOULDER_LEFT_ALT},
{"SHOULDR_RIGHT_ALT", K_SHOULDER_RIGHT_ALT},
{"TRIG_LEFT_ALT", K_TRIG_LEFT_ALT},
{"TRIG_RIGHT_ALT", K_TRIG_RIGHT_ALT},
{"DP_UP_ALT", K_DPAD_UP_ALT},
{"DP_DOWN_ALT", K_DPAD_DOWN_ALT},
{"DP_LEFT_ALT", K_DPAD_LEFT_ALT},
{"DP_RIGHT_ALT", K_DPAD_RIGHT_ALT},
{"PADDLE_1_ALT", K_PADDLE_1_ALT},
{"PADDLE_2_ALT", K_PADDLE_2_ALT},
{"PADDLE_3_ALT", K_PADDLE_3_ALT},
{"PADDLE_4_ALT", K_PADDLE_4_ALT},
{"BTN_MISC1_ALT", K_BTN_MISC1_ALT},
{"TOUCHPAD_ALT", K_TOUCHPAD_ALT},
{"BTN_BACK_ALT", K_BTN_BACK_ALT},
{"BTN_GUIDE_ALT", K_BTN_GUIDE_ALT},
{"BTN_START_ALT", K_BTN_START_ALT},
{"JOY_BACK", K_JOY_BACK},
{"SUPER", K_SUPER},
{"COMPOSE", K_COMPOSE},
{"MODE", K_MODE},
@ -267,9 +211,150 @@ keyname_t keynames[] = {
{NULL, 0}
};
static char *gamepadbtns[] =
{
// It is imperative that this list of buttons follow EXACTLY the order they
// appear in QKEYS enum in keyboard.h, which in turn is the same order as
// they appear in SDL_GamepadButton / SDL_GameControllerButton enum.
"BTN_SOUTH",
"BTN_EAST",
"BTN_WEST",
"BTN_NORTH",
"BTN_BACK",
"BTN_GUIDE",
"BTN_START",
"STICK_LEFT",
"STICK_RIGHT",
"SHOULDR_LEFT",
"SHOULDR_RIGHT",
"DP_UP",
"DP_DOWN",
"DP_LEFT",
"DP_RIGHT",
"BTN_MISC1",
"PADDL_RIGHT1",
"PADDL_LEFT1",
"PADDL_RIGHT2",
"PADDL_LEFT2",
"TOUCHPAD",
"BTN_MISC2",
"BTN_MISC3",
"BTN_MISC4",
"BTN_MISC5",
"BTN_MISC6",
"TRIG_LEFT",
"TRIG_RIGHT",
// Same with _ALT buttons ( button + 'alt modifier' pressed )
"BTN_SOUTH_ALT",
"BTN_EAST_ALT",
"BTN_WEST_ALT",
"BTN_NORTH_ALT",
"BTN_BACK_ALT",
"BTN_GUIDE_ALT",
"BTN_START_ALT",
"STICK_LEFT_ALT",
"STICK_RIGHT_ALT",
"SHOULDR_LEFT_ALT",
"SHOULDR_RIGHT_ALT",
"DP_UP_ALT",
"DP_DOWN_ALT",
"DP_LEFT_ALT",
"DP_RIGHT_ALT",
"BTN_MISC1_ALT",
"PADDL_RIGHT1_ALT",
"PADDL_LEFT1_ALT",
"PADDL_RIGHT2_ALT",
"PADDL_LEFT2_ALT",
"TOUCHPAD_ALT",
"BTN_MISC2_ALT",
"BTN_MISC3_ALT",
"BTN_MISC4_ALT",
"BTN_MISC5_ALT",
"BTN_MISC6_ALT",
"TRIG_LEFT_ALT",
"TRIG_RIGHT_ALT"
};
#define NUM_GAMEPAD_BTNS (sizeof gamepadbtns / sizeof gamepadbtns[0])
static char *gpbtns_face[] =
{
// Xbox
"A",
"B",
"X",
"Y",
"VIEW",
"XBOX",
"MENU",
"LS",
"RS",
"LB",
"RB",
// Playstation
"CROSS",
"CIRCLE",
"SQUARE",
"TRIANGLE",
"CREATE",
"PS",
"OPTIONS",
"L3",
"R3",
"L1",
"R1",
// Nintendo Switch
"B",
"A",
"Y",
"X",
"-",
"HOME",
"+",
"L stick",
"R stick",
"L btn",
"R btn",
};
static char *gpbtns_paddles[] =
{
// Xbox
"SHARE",
"P1",
"P3",
"P2",
"P4",
// Playstation
"MIC",
"RB",
"LB",
"Right Fn",
"Left Fn",
// Switch
"CAPTURE",
"Right SR",
"Left SL",
"Right SL",
"Left SR" // JoyCon btn positions suck
};
static char *gpbtns_triggers[] =
{
// Xbox
"LT",
"RT",
// Playstation
"L2",
"R2",
// Switch
"ZL",
"ZR"
};
/* ------------------------------------------------------------------ */
void
static void
CompleteCommand(void)
{
const char *cmd, *s;
@ -300,7 +385,7 @@ CompleteCommand(void)
key_lines[edit_line][key_linepos] = '\0';
}
void
static void
CompleteMapNameCommand(void)
{
const char *s, *cmdArg;
@ -338,7 +423,7 @@ IsInConsole(void)
(cls.state == ca_disconnected || cls.state == ca_connecting));
}
void
static void
Key_Console(int key)
{
char txt[2];
@ -606,7 +691,7 @@ char chat_buffer[MAXCMDLINE];
int chat_bufferlen = 0;
int chat_cursorpos = 0;
void
static void
Key_Message(int key)
{
char last;
@ -734,10 +819,11 @@ Key_Message(int key)
* Single ascii characters return themselves, while
* the K_* names are matched up.
*/
int
static int
Key_StringToKeynum(char *str)
{
keyname_t *kn;
int i;
if (!str || !str[0])
{
@ -757,6 +843,14 @@ Key_StringToKeynum(char *str)
}
}
for (i = 0; i < NUM_GAMEPAD_BTNS; i++)
{
if (!Q_stricmp(str, gamepadbtns[i]))
{
return K_JOY_FIRST_BTN + i;
}
}
return -1;
}
@ -784,6 +878,11 @@ Key_KeynumToString(int keynum)
return tinystr;
}
if (keynum >= K_JOY_FIRST_BTN) // gamepad button
{
return gamepadbtns[keynum - K_JOY_FIRST_BTN];
}
for (kn = keynames; kn->name; kn++)
{
if (keynum == kn->keynum)
@ -795,6 +894,49 @@ Key_KeynumToString(int keynum)
return "<UNKNOWN KEYNUM>";
}
/*
* Same as Key_KeynumToString(), but for joystick/gamepad buttons.
*/
char *
Key_KeynumToString_Joy(int key)
{
extern gamepad_labels_t joy_current_lbls;
const int lbl_style = (int)joy_current_lbls - 1;
if (key < K_JOY_FIRST_BTN)
{
return Key_KeynumToString(key);
}
// Don't print the _ALT buttons (buttons with the alt modifier pressed)
if (key >= K_JOY_FIRST_BTN_ALT)
{
key -= K_JOY_FIRST_BTN_ALT - K_JOY_FIRST_BTN;
}
if (lbl_style < 0) // was SDL
{
goto exit_sdl;
}
// Alter this logic if new gamepad buttons are added in SDL
if (key < K_DPAD_UP) // face & shoulder buttons
{
return gpbtns_face[lbl_style * (K_DPAD_UP - K_BTN_SOUTH) + key - K_BTN_SOUTH];
}
else if (key >= K_TRIG_LEFT) // triggers
{
return gpbtns_triggers[lbl_style * (K_JOY_FIRST_BTN_ALT - K_TRIG_LEFT) + key - K_TRIG_LEFT];
}
else if (key > K_DPAD_RIGHT && key < K_TOUCHPAD) // paddles & misc1
{
return gpbtns_paddles[lbl_style * (K_TOUCHPAD - K_BTN_MISC1) + key - K_BTN_MISC1];
}
exit_sdl:
return gamepadbtns[key - K_JOY_FIRST_BTN];
}
void
Key_SetBinding(int keynum, char *binding)
{
@ -821,7 +963,7 @@ Key_SetBinding(int keynum, char *binding)
keybindings[keynum] = new;
}
void
static void
Key_Unbind_f(void)
{
int b;
@ -843,7 +985,7 @@ Key_Unbind_f(void)
Key_SetBinding(b, "");
}
void
static void
Key_Unbindall_f(void)
{
int i;
@ -861,7 +1003,7 @@ Key_Unbindall_f(void)
* (=> default.cfg is done) */
extern qboolean doneWithDefaultCfg;
void
static void
Key_Bind_f(void)
{
int i, c, b;
@ -884,7 +1026,7 @@ Key_Bind_f(void)
}
/* don't allow binding escape or the special console keys */
if(b == K_ESCAPE || b == '^' || b == '`' || b == '~' || b == K_JOY_BACK)
if(b == K_ESCAPE || b == '^' || b == '`' || b == '~')
{
if(doneWithDefaultCfg)
{
@ -1048,7 +1190,7 @@ Key_ReadConsoleHistory()
fclose(f);
}
void
static void
Key_Bindlist_f(void)
{
int i;
@ -1202,12 +1344,12 @@ Key_Event(int key, qboolean down, qboolean special)
unsigned int time = Sys_Milliseconds();
// evil hack for the joystick key altselector, which turns K_BTN_x into K_BTN_x_ALT
if(joy_altselector_pressed && key >= K_JOY_FIRST_REGULAR && key <= K_JOY_LAST_REGULAR)
if(joy_altselector_pressed && key >= K_JOY_FIRST_BTN && key < K_JOY_FIRST_BTN_ALT)
{
// make sure key is not the altselector itself (which we won't turn into *_ALT)
if(keybindings[key] == NULL || strcmp(keybindings[key], "+joyaltselector") != 0)
{
int altkey = key + (K_JOY_FIRST_REGULAR_ALT - K_JOY_FIRST_REGULAR);
int altkey = key + (K_JOY_FIRST_BTN_ALT - K_JOY_FIRST_BTN);
// allow fallback to binding with non-alt key
if(keybindings[altkey] != NULL || keybindings[key] == NULL)
key = altkey;
@ -1274,7 +1416,7 @@ Key_Event(int key, qboolean down, qboolean special)
}
/* Key is unbound */
if ((key >= K_MOUSE1 && key != K_JOY_BACK) && !keybindings[key] && (cls.key_dest != key_console) &&
if ((key >= K_MOUSE1) && !keybindings[key] && (cls.key_dest != key_console) &&
(cls.state == ca_active))
{
Com_Printf("%s (%d) is unbound, hit F4 to set.\n", Key_KeynumToString(key), key);
@ -1295,47 +1437,43 @@ Key_Event(int key, qboolean down, qboolean special)
- moves one menu level up
- closes the menu
- closes the help computer
- closes the chat window
Fully same logic for K_JOY_BACK */
if (!cls.disable_screen)
- closes the chat window */
if (key == K_ESCAPE && !cls.disable_screen)
{
if (key == K_ESCAPE || key == K_JOY_BACK)
if (!down)
{
if (!down)
{
return;
}
/* Close the help computer */
if (cl.frame.playerstate.stats[STAT_LAYOUTS] &&
(cls.key_dest == key_game))
{
Cbuf_AddText("cmd putaway\n");
return;
}
switch (cls.key_dest)
{
/* Close chat window */
case key_message:
Key_Message(key);
break;
/* Close menu or one layer up */
case key_menu:
M_Keydown(key);
break;
/* Pause game and / or leave console,
break into the menu. */
case key_game:
case key_console:
M_Menu_Main_f();
break;
}
return;
}
/* Close the help computer */
if (cl.frame.playerstate.stats[STAT_LAYOUTS] &&
(cls.key_dest == key_game))
{
Cbuf_AddText("cmd putaway\n");
return;
}
switch (cls.key_dest)
{
/* Close chat window */
case key_message:
Key_Message(key);
break;
/* Close menu or one layer up */
case key_menu:
M_Keydown(key);
break;
/* Pause game and / or leave console,
break into the menu. */
case key_game:
case key_console:
M_Menu_Main_f();
break;
}
return;
}
/* This is one of the most ugly constructs I've
@ -1419,7 +1557,8 @@ Key_Event(int key, qboolean down, qboolean special)
/* FIXME: Better way to do CTRL+<key> actions in the console?
special should be set to true in this case.
*/
if (keydown[K_CTRL] && IsInConsole() &&
if (keydown[K_CTRL] &&
(IsInConsole() || cls.key_dest == key_menu) &&
key >= 'a' && key <= 'z')
{
special = true;

View file

@ -33,6 +33,7 @@ void CL_Changing_f(void);
void CL_Reconnect_f(void);
void CL_Connect_f(void);
void CL_Rcon_f(void);
void CL_Packet_f(void);
void CL_CheckForResend(void);
cvar_t *rcon_client_password;
@ -88,7 +89,7 @@ client_state_t cl;
centity_t cl_entities[MAX_EDICTS];
entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
entity_xstate_t cl_parse_entities[MAX_PARSE_ENTITIES];
/*Evil hack against too many power screen and power
shield impact sounds. For example if the player
@ -156,8 +157,8 @@ CL_Record_f(void)
sizebuf_t buf;
int i;
int len;
entity_state_t *ent;
entity_state_t nullstate;
entity_xstate_t *ent;
entity_xstate_t nullstate;
if (Cmd_Argc() != 2)
{
@ -570,7 +571,8 @@ CL_InitLocal(void)
cl_vwep = Cvar_Get("cl_vwep", "1", CVAR_ARCHIVE);
#ifdef USE_CURL
cl_http_proxy = Cvar_Get("cl_http_proxy", "", 0);
cl_http_verifypeer = Cvar_Get("cl_http_verifypeer", "1", CVAR_ARCHIVE);
cl_http_proxy = Cvar_Get("cl_http_proxy", "", CVAR_ARCHIVE);
cl_http_filelists = Cvar_Get("cl_http_filelists", "1", 0);
cl_http_downloads = Cvar_Get("cl_http_downloads", "1", CVAR_ARCHIVE);
cl_http_max_connections = Cvar_Get("cl_http_max_connections", "4", 0);
@ -599,6 +601,7 @@ CL_InitLocal(void)
Cmd_AddCommand("reconnect", CL_Reconnect_f);
Cmd_AddCommand("rcon", CL_Rcon_f);
Cmd_AddCommand("packet", CL_Packet_f);
Cmd_AddCommand("setenv", CL_Setenv_f);
@ -967,8 +970,6 @@ CL_Shutdown(void)
isdown = true;
CM_ModFreeAll();
#ifdef USE_CURL
CL_HTTP_Cleanup(true);
#endif
@ -982,4 +983,6 @@ CL_Shutdown(void)
S_Shutdown();
IN_Shutdown();
VID_Shutdown();
Mods_NamesFinish();
}

View file

@ -107,7 +107,7 @@ CL_Drop(void)
* We have gotten a challenge from the server, so try and
* connect.
*/
void
static void
CL_SendConnectPacket(void)
{
netadr_t adr;
@ -374,7 +374,7 @@ void
CL_Packet_f(void)
{
char send[2048];
int i, l;
size_t i, l;
char *in, *out;
netadr_t adr;
@ -563,7 +563,7 @@ CL_PingServers_f(void)
/*
* Responses to broadcasts, etc
*/
void
static void
CL_ConnectionlessPacket(void)
{
char *s;

View file

@ -29,7 +29,7 @@
static int bitcounts[32]; /* just for protocol profiling */
static char *svc_strings[256] = {
static const char *svc_strings[256] = {
"svc_bad",
"svc_muzzleflash",
@ -135,7 +135,7 @@ CL_ParseEntityBits(unsigned *bits)
* Can go from either a baseline or a previous packet_entity
*/
static void
CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
CL_ParseDelta(const entity_xstate_t *from, entity_xstate_t *to, int number, int bits)
{
/* set everything to the state we are delta'ing from */
*to = *from;
@ -143,16 +143,35 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
VectorCopy(from->origin, to->old_origin);
to->number = number;
if (cls.serverProtocol != PROTOCOL_VERSION)
{
int i;
/* Always set scale to 1.0f for old clients */
for (i = 0; i < 3; i++)
{
to->scale[i] = 1.0f;
}
}
if (IS_QII97_PROTOCOL(cls.serverProtocol))
{
if (bits & U_MODEL)
{
to->modelindex = MSG_ReadByte(&net_message);
if (to->modelindex == QII97_PLAYER_MODEL)
{
to->modelindex = CUSTOM_PLAYER_MODEL;
}
}
if (bits & U_MODEL2)
{
to->modelindex2 = MSG_ReadByte(&net_message);
if (to->modelindex2 == QII97_PLAYER_MODEL)
{
to->modelindex2 = CUSTOM_PLAYER_MODEL;
}
}
if (bits & U_MODEL3)
@ -202,6 +221,17 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
if ((bits & U_SKIN8) && (bits & U_SKIN16))
{
to->skinnum = MSG_ReadLong(&net_message);
/* Additional scale with skinnum */
if (cls.serverProtocol == PROTOCOL_VERSION)
{
int i;
for (i = 0; i < 3; i++)
{
to->scale[i] = MSG_ReadFloat(&net_message);
}
}
}
else if (bits & U_SKIN8)
{
@ -225,6 +255,31 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
to->effects = MSG_ReadShort(&net_message);
}
/* ReRelease effects */
if (cls.serverProtocol != PROTOCOL_VERSION)
{
to->rr_effects = 0;
to->rr_mesh = 0;
}
else
{
if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
{
to->rr_effects = MSG_ReadLong(&net_message);
to->rr_mesh = MSG_ReadLong(&net_message);
}
else if (bits & U_EFFECTS8)
{
to->rr_effects = MSG_ReadByte(&net_message);
to->rr_mesh = MSG_ReadByte(&net_message);
}
else if (bits & U_EFFECTS16)
{
to->rr_effects = MSG_ReadShort(&net_message);
to->rr_mesh = MSG_ReadShort(&net_message);
}
}
if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16))
{
to->renderfx = MSG_ReadLong(&net_message);
@ -240,17 +295,17 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
if (bits & U_ORIGIN1)
{
to->origin[0] = MSG_ReadCoord(&net_message);
to->origin[0] = MSG_ReadCoord(&net_message, cls.serverProtocol);
}
if (bits & U_ORIGIN2)
{
to->origin[1] = MSG_ReadCoord(&net_message);
to->origin[1] = MSG_ReadCoord(&net_message, cls.serverProtocol);
}
if (bits & U_ORIGIN3)
{
to->origin[2] = MSG_ReadCoord(&net_message);
to->origin[2] = MSG_ReadCoord(&net_message, cls.serverProtocol);
}
if (bits & U_ANGLE1)
@ -270,7 +325,7 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
if (bits & U_OLDORIGIN)
{
MSG_ReadPos(&net_message, to->old_origin);
MSG_ReadPos(&net_message, to->old_origin, cls.serverProtocol);
}
if (bits & U_SOUND)
@ -298,10 +353,10 @@ CL_ParseDelta(entity_state_t *from, entity_state_t *to, int number, int bits)
* the current frame
*/
static void
CL_DeltaEntity(frame_t *frame, int newnum, entity_state_t *old, int bits)
CL_DeltaEntity(frame_t *frame, int newnum, entity_xstate_t *old, int bits)
{
centity_t *ent;
entity_state_t *state;
entity_xstate_t *state;
ent = &cl_entities[newnum];
@ -364,11 +419,10 @@ CL_DeltaEntity(frame_t *frame, int newnum, entity_state_t *old, int bits)
static void
CL_ParsePacketEntities(frame_t *oldframe, frame_t *newframe)
{
entity_xstate_t *oldstate = NULL;
int oldindex, oldnum;
unsigned int newnum;
unsigned bits;
entity_state_t
*oldstate = NULL;
int oldindex, oldnum;
newframe->parse_entities = cl.parse_entities;
newframe->num_entities = 0;
@ -541,7 +595,7 @@ CL_ParsePacketEntities(frame_t *oldframe, frame_t *newframe)
}
static void
CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe, int protocol)
{
int flags, i, statbits;
player_state_t *state;
@ -569,9 +623,18 @@ CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
if (flags & PS_M_ORIGIN)
{
state->pmove.origin[0] = MSG_ReadShort(&net_message);
state->pmove.origin[1] = MSG_ReadShort(&net_message);
state->pmove.origin[2] = MSG_ReadShort(&net_message);
if (IS_QII97_PROTOCOL(protocol))
{
state->pmove.origin[0] = MSG_ReadShort(&net_message);
state->pmove.origin[1] = MSG_ReadShort(&net_message);
state->pmove.origin[2] = MSG_ReadShort(&net_message);
}
else
{
state->pmove.origin[0] = MSG_ReadLong(&net_message);
state->pmove.origin[1] = MSG_ReadLong(&net_message);
state->pmove.origin[2] = MSG_ReadLong(&net_message);
}
}
if (flags & PS_M_VELOCITY)
@ -632,7 +695,7 @@ CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
if (flags & PS_WEAPONINDEX)
{
if (IS_QII97_PROTOCOL(cls.serverProtocol))
if (IS_QII97_PROTOCOL(protocol))
{
state->gunindex = MSG_ReadByte(&net_message);
}
@ -644,7 +707,7 @@ CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
if (flags & PS_WEAPONFRAME)
{
if (IS_QII97_PROTOCOL(cls.serverProtocol))
if (IS_QII97_PROTOCOL(protocol))
{
state->gunframe = MSG_ReadByte(&net_message);
}
@ -691,7 +754,7 @@ CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
if (i == STAT_PICKUP_STRING)
{
state->stats[i] = P_ConvertConfigStringFrom(state->stats[i],
cls.serverProtocol);
protocol);
}
}
}
@ -700,11 +763,13 @@ CL_ParsePlayerstate(frame_t *oldframe, frame_t *newframe)
static void
CL_FireEntityEvents(frame_t *frame)
{
entity_state_t *s1;
int pnum, num;
int pnum;
for (pnum = 0; pnum < frame->num_entities; pnum++)
{
entity_xstate_t *s1;
int num;
num = (frame->parse_entities + pnum) & (MAX_PARSE_ENTITIES - 1);
s1 = &cl_parse_entities[num];
@ -720,8 +785,8 @@ CL_FireEntityEvents(frame_t *frame)
}
}
void
SHOWNET(char *s)
static void
SHOWNET(const char *s)
{
if (cl_shownet->value >= 2)
{
@ -815,7 +880,7 @@ CL_ParseFrame(void)
Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not playerinfo", cmd);
}
CL_ParsePlayerstate(old, &cl.frame);
CL_ParsePlayerstate(old, &cl.frame, cls.serverProtocol);
/* read packet entities */
cmd = MSG_ReadByte(&net_message);
@ -981,10 +1046,10 @@ CL_ParseServerData(void)
static void
CL_ParseBaseline(void)
{
entity_state_t *es;
entity_xstate_t nullstate;
entity_xstate_t *es;
unsigned bits;
int newnum;
entity_state_t nullstate;
memset(&nullstate, 0, sizeof(nullstate));
@ -1151,7 +1216,8 @@ CL_ParseClientinfo(int player)
static void
CL_ParseConfigString(void)
{
int i, length;
size_t length;
int i;
char *s;
char olds[MAX_QPATH];
@ -1304,7 +1370,7 @@ CL_ParseStartSoundPacket(void)
if (flags & SND_POS)
{
/* positioned in space */
MSG_ReadPos(&net_message, pos_v);
MSG_ReadPos(&net_message, pos_v, cls.serverProtocol);
pos = pos_v;
}

View file

@ -81,17 +81,19 @@ void
CL_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs,
vec3_t end, trace_t *tr)
{
int i, x, zd, zu;
trace_t trace;
int headnode;
float *angles;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
vec3_t bmins, bmaxs;
int i;
for (i = 0; i < cl.frame.num_entities; i++)
{
int x, zd, zu;
trace_t trace;
int headnode;
float *angles;
int num;
cmodel_t *cmodel;
vec3_t bmins, bmaxs;
entity_xstate_t *ent;
num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
ent = &cl_parse_entities[num];
@ -184,15 +186,16 @@ int
CL_PMpointcontents(vec3_t point)
{
int i;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
int contents;
contents = CM_PointContents(point, 0);
for (i = 0; i < cl.frame.num_entities; i++)
{
entity_xstate_t *ent;
int num;
cmodel_t *cmodel;
num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
ent = &cl_parse_entities[num];

View file

@ -27,12 +27,12 @@
#include "header/client.h"
float scr_con_current; /* aproaches scr_conlines at scr_conspeed */
float scr_conlines; /* 0.0 to 1.0 lines of console to display */
static float scr_con_current; /* aproaches scr_conlines at scr_conspeed */
static float scr_conlines; /* 0.0 to 1.0 lines of console to display */
qboolean scr_initialized; /* ready to draw */
static qboolean scr_initialized; /* ready to draw */
int scr_draw_loading;
static int scr_draw_loading;
vrect_t scr_vrect; /* position of render window on screen */
@ -59,18 +59,20 @@ typedef struct
int x1, y1, x2, y2;
} dirty_t;
dirty_t scr_dirty, scr_old_dirty[2];
static dirty_t scr_dirty, scr_old_dirty[2];
char crosshair_pic[MAX_QPATH];
int crosshair_width, crosshair_height;
static char crosshair_pic[MAX_QPATH];
static int crosshair_width, crosshair_height;
extern cvar_t *cl_showfps;
extern cvar_t *crosshair_scale;
extern cvar_t *cl_showspeed;
extern float GetPlayerSpeed(float *, float *);
void SCR_TimeRefresh_f(void);
void SCR_Loading_f(void);
static void SCR_TimeRefresh_f(void);
static void SCR_Loading_f(void);
#define CHAR_SIZE 8
/*
* A new packet was just parsed
@ -129,7 +131,7 @@ SCR_DebugGraph(float value, int color)
current++;
}
void
static void
SCR_DrawDebugGraph(void)
{
int a, x, y, w, i, h;
@ -162,11 +164,58 @@ SCR_DrawDebugGraph(void)
}
}
char scr_centerstring[1024];
float scr_centertime_start; /* for slow victory printing */
float scr_centertime_off;
int scr_center_lines;
int scr_erase_center;
static char scr_centerstring[1024];
static float scr_centertime_start; /* for slow victory printing */
static float scr_centertime_off;
static int scr_center_lines;
static int scr_erase_center;
static int
SCR_CopyUtf8(const char *src, char *dst, int limit)
{
int symbols = 0;
while (*src && *src != '\n')
{
size_t size = 1;
int i;
if (symbols >= limit)
{
break;
}
if (!(*src & 0x80))
{
size = 1;
}
else if ((*src & 0xE0) == 0xC0)
{
size = 2;
}
else if ((*src & 0xF0) == 0xE0)
{
size = 3;
}
else if ((*src & 0xF8) == 0xF0)
{
size = 4;
}
for (i = 0; i < size; i++)
{
*dst = *src;
dst ++;
src ++;
}
symbols ++;
}
*dst = 0;
return symbols;
}
/*
* Called for important messages that should stay
@ -176,8 +225,6 @@ void
SCR_CenterPrint(char *str)
{
char *s;
char line[64];
int i, j, l;
Q_strlcpy(scr_centerstring, str, sizeof(scr_centerstring));
scr_centertime_off = scr_centertime->value;
@ -204,29 +251,14 @@ SCR_CenterPrint(char *str)
do
{
/* scan the width of the line */
for (l = 0; l < 40; l++)
{
if ((s[l] == '\n') || !s[l])
{
break;
}
}
char line[161];
int l;
for (i = 0; i < (40 - l) / 2; i++)
{
line[i] = ' ';
}
l = SCR_CopyUtf8(s, line, 40);
memmove(line + (40 - l) / 2, line, strlen(line) + 1);
memset(line, ' ', (40 - l) / 2);
for (j = 0; j < l; j++)
{
line[i++] = s[j];
}
line[i] = '\n';
line[i + 1] = 0;
Com_Printf("%s", line);
Com_Printf("%s\n", line);
while (*s && *s != '\n')
{
@ -246,20 +278,12 @@ SCR_CenterPrint(char *str)
Con_ClearNotify();
}
void
static void
SCR_DrawCenterString(void)
{
char *start;
int l;
int j;
int x, y;
int remaining;
float scale;
const int char_unscaled_width = 8;
const int char_unscaled_height = 8;
/* the finale prints the characters one at a time */
remaining = 9999;
int y;
scr_erase_center = 0;
start = scr_centerstring;
@ -277,31 +301,18 @@ SCR_DrawCenterString(void)
do
{
/* scan the width of the line */
for (l = 0; l < 40; l++)
{
if ((start[l] == '\n') || !start[l])
{
break;
}
}
char message[241]; /* utf string could by 4 bytes per char */
int l, x;
x = ((viddef.width / scale) - (l * char_unscaled_width)) / 2;
SCR_AddDirtyPoint(x, y);
l = SCR_CopyUtf8(start, message, 60);
for (j = 0; j < l; j++, x += char_unscaled_width)
{
Draw_CharScaled(x * scale, y * scale, start[j], scale);
x = ((viddef.width / scale) - (l * CHAR_SIZE)) / 2;
SCR_AddDirtyPoint(x * scale, y * scale);
SCR_AddDirtyPoint((x + l * CHAR_SIZE) * scale, (y + CHAR_SIZE) * scale);
if (!remaining--)
{
return;
}
}
Draw_StringScaled(x * scale, y * scale, scale, false, message);
SCR_AddDirtyPoint(x, y + char_unscaled_height);
y += char_unscaled_height;
y += CHAR_SIZE;
while (*start && *start != '\n')
{
@ -318,7 +329,7 @@ SCR_DrawCenterString(void)
while (1);
}
void
static void
SCR_CheckDrawCenterString(void)
{
scr_centertime_off -= cls.rframetime;
@ -362,16 +373,16 @@ SCR_CalcVrect(void)
/*
* Keybinding command
*/
void
static void
SCR_SizeUp_f(void)
{
Cvar_SetValue("viewsize", (float)scr_viewsize->value + 10);
}
/*
*Keybinding command
* Keybinding command
*/
void
static void
SCR_SizeDown_f(void)
{
Cvar_SetValue("viewsize", (float)scr_viewsize->value - 10);
@ -380,7 +391,7 @@ SCR_SizeDown_f(void)
/*
* Set a specific sky and rotation speed
*/
void
static void
SCR_Sky_f(void)
{
int autorotate = 1;
@ -448,7 +459,7 @@ SCR_Init(void)
scr_initialized = true;
}
void
static void
SCR_DrawNet(void)
{
float scale = SCR_GetMenuScale();
@ -458,10 +469,10 @@ SCR_DrawNet(void)
return;
}
Draw_PicScaled(scr_vrect.x + 64 * scale, scr_vrect.y, "net", scale);
Draw_PicScaledAltText(scr_vrect.x + 64 * scale, scr_vrect.y, "net", scale, "net");
}
void
static void
SCR_DrawPause(void)
{
int w, h;
@ -478,10 +489,11 @@ SCR_DrawPause(void)
}
Draw_GetPicSize(&w, &h, "pause");
Draw_PicScaled((viddef.width - w * scale) / 2, viddef.height / 2 + 8 * scale, "pause", scale);
Draw_PicScaledAltText((viddef.width - w * scale) / 2, viddef.height / 2 + CHAR_SIZE * scale,
"pause", scale, "pause");
}
void
static void
SCR_DrawLoading(void)
{
int w, h;
@ -493,7 +505,8 @@ SCR_DrawLoading(void)
}
Draw_GetPicSize(&w, &h, "loading");
Draw_PicScaled((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2, "loading", scale);
Draw_PicScaledAltText((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2,
"loading", scale, "loading");
}
/*
@ -539,7 +552,7 @@ SCR_RunConsole(void)
}
}
void
static void
SCR_DrawConsole(void)
{
Con_CheckResize();
@ -636,13 +649,13 @@ SCR_EndLoadingPlaque(void)
Con_ClearNotify();
}
void
static void
SCR_Loading_f(void)
{
SCR_BeginLoadingPlaque();
}
void
static void
SCR_TimeRefresh_f(void)
{
int i;
@ -725,7 +738,7 @@ SCR_DirtyScreen(void)
/*
* Clear any parts of the tiled background that were drawn on last frame
*/
void
static void
SCR_TileClear(void)
{
int i;
@ -860,7 +873,7 @@ SCR_TileClear(void)
}
#define STAT_MINUS 10
char *sb_nums[2][11] = {
static char *sb_nums[2][11] = {
{
"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
"num_6", "num_7", "num_8", "num_9", "num_minus"
@ -873,71 +886,27 @@ char *sb_nums[2][11] = {
#define ICON_WIDTH 24
#define ICON_HEIGHT 24
#define CHAR_WIDTH 16
#define CHARACTER_WIDTH 16
#define ICON_SPACE 8
/*
* Allow embedded \n in the string
*/
void
SizeHUDString(char *string, int *w, int *h)
{
int lines, width, current;
lines = 1;
width = 0;
current = 0;
while (*string)
{
if (*string == '\n')
{
lines++;
current = 0;
}
else
{
current++;
if (current > width)
{
width = current;
}
}
string++;
}
*w = width * 8;
*h = lines * 8;
}
void
DrawHUDStringScaled(const char *string, int x, int y, int centerwidth, int xor, float factor)
static void
DrawHUDStringScaled(const char *string, int x, int y, int centerwidth, qboolean alt, float factor)
{
int margin;
char line[1024];
int width;
int i;
margin = x;
while (*string)
{
/* scan out one line of text from the string */
width = 0;
int width;
char line[1024];
while (*string && *string != '\n')
{
line[width++] = *string++;
}
line[width] = 0;
width = SCR_CopyUtf8(string, line, 255);
if (centerwidth)
{
x = margin + (centerwidth - width * 8)*factor / 2;
x = margin + (centerwidth - width * CHAR_SIZE) * factor / 2;
}
else
@ -945,27 +914,22 @@ DrawHUDStringScaled(const char *string, int x, int y, int centerwidth, int xor,
x = margin;
}
for (i = 0; i < width; i++)
Draw_StringScaled(x, y, factor, alt, line);
while (*string && *string != '\n')
{
Draw_CharScaled(x, y, line[i] ^ xor, factor);
x += 8*factor;
string++;
}
if (*string)
{
string++; /* skip the \n */
y += 8*factor;
y += CHAR_SIZE * factor;
}
}
}
void
DrawHUDString(char *string, int x, int y, int centerwidth, int xor)
{
DrawHUDStringScaled(string, x, y, centerwidth, xor, 1.0f);
}
void
static void
SCR_DrawFieldScaled(int x, int y, int color, int width, int value, float factor)
{
char num[16], *ptr;
@ -984,7 +948,7 @@ SCR_DrawFieldScaled(int x, int y, int color, int width, int value, float factor)
}
SCR_AddDirtyPoint(x, y);
SCR_AddDirtyPoint(x + (width * CHAR_WIDTH + 2)*factor, y + factor*24);
SCR_AddDirtyPoint(x + (width * CHARACTER_WIDTH + 2) * factor, y + factor * 24);
Com_sprintf(num, sizeof(num), "%i", value);
l = (int)strlen(num);
@ -994,12 +958,15 @@ SCR_DrawFieldScaled(int x, int y, int color, int width, int value, float factor)
l = width;
}
x += (2 + CHAR_WIDTH * (width - l)) * factor;
x += (2 + CHARACTER_WIDTH * (width - l)) * factor;
ptr = num;
while (*ptr && l)
{
char alttext[] = "?";
alttext[0] = *ptr;
if (*ptr == '-')
{
frame = STAT_MINUS;
@ -1010,19 +977,13 @@ SCR_DrawFieldScaled(int x, int y, int color, int width, int value, float factor)
frame = *ptr - '0';
}
Draw_PicScaled(x, y, sb_nums[color][frame], factor);
x += CHAR_WIDTH*factor;
Draw_PicScaledAltText(x, y, sb_nums[color][frame], factor, alttext);
x += CHARACTER_WIDTH * factor;
ptr++;
l--;
}
}
void
SCR_DrawField(int x, int y, int color, int width, int value)
{
SCR_DrawFieldScaled(x, y, color, width, value, 1.0f);
}
/*
* Allows rendering code to cache all needed sbar graphics
*/
@ -1057,17 +1018,13 @@ SCR_TouchPics(void)
}
}
void
static void
SCR_ExecuteLayoutString(char *s)
{
int x, y;
int value;
const char *token;
int width;
int index;
clientinfo_t *ci;
float scale;
float scale = SCR_GetHUDScale();
scale = SCR_GetHUDScale();
if ((cls.state != ca_active) || !cl.refresh_prepped)
{
@ -1084,6 +1041,8 @@ SCR_ExecuteLayoutString(char *s)
while (s)
{
const char *token;
token = COM_Parse(&s);
if (!strcmp(token, "xl"))
@ -1130,27 +1089,38 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "pic"))
{
int index, value;
/* draw a pic from a stat number */
token = COM_Parse(&s);
index = (int)strtol(token, (char **)NULL, 10);
if ((index < 0) || (index >= MAX_STATS))
{
Com_Error(ERR_DROP, "bad stats index %d (0x%x)", index, index);
Com_DPrintf("%s: bad stats index %d (0x%x) in pic\n",
__func__, index, index);
continue;
}
value = cl.frame.playerstate.stats[index];
if (value >= MAX_IMAGES)
{
Com_Error(ERR_DROP, "Pic >= MAX_IMAGES");
Com_DPrintf("%s: Pic %d >= MAX_IMAGES in pic\n",
__func__, value);
continue;
}
if (cl.configstrings[CS_IMAGES + value][0] != '\0')
{
const char *text;
int w, h;
text = cl.configstrings[CS_IMAGES + value];
Draw_GetPicSize(&w, &h, text);
SCR_AddDirtyPoint(x, y);
SCR_AddDirtyPoint(x + 23*scale, y + 23*scale);
Draw_PicScaled(x, y, cl.configstrings[CS_IMAGES + value], scale);
SCR_AddDirtyPoint(x + (w - 1) * scale, y + (h - 1) * scale);
Draw_PicScaled(x, y, text, scale);
}
continue;
@ -1159,21 +1129,23 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "client"))
{
/* draw a deathmatch client block */
int score, ping, time;
int score, ping, time, value;
clientinfo_t *ci;
token = COM_Parse(&s);
x = viddef.width / 2 - scale*160 + scale*(int)strtol(token, (char **)NULL, 10);
x = viddef.width / 2 - scale * 160 + scale * (int)strtol(token, (char **)NULL, 10);
token = COM_Parse(&s);
y = viddef.height / 2 - scale*120 + scale*(int)strtol(token, (char **)NULL, 10);
y = viddef.height / 2 - scale * 120 + scale * (int)strtol(token, (char **)NULL, 10);
SCR_AddDirtyPoint(x, y);
SCR_AddDirtyPoint(x + scale*159, y + scale*31);
SCR_AddDirtyPoint(x + scale * 159, y + scale * 31);
token = COM_Parse(&s);
value = (int)strtol(token, (char **)NULL, 10);
if ((value >= MAX_CLIENTS) || (value < 0))
{
Com_Error(ERR_DROP, "client >= MAX_CLIENTS");
Com_DPrintf("%s: client >= MAX_CLIENTS in client\n", __func__);
continue;
}
ci = &cl.clientinfo[value];
@ -1187,11 +1159,12 @@ SCR_ExecuteLayoutString(char *s)
token = COM_Parse(&s);
time = (int)strtol(token, (char **)NULL, 10);
DrawAltStringScaled(x + scale*32, y, ci->name, scale);
DrawAltStringScaled(x + scale*32, y + scale*8, "Score: ", scale);
DrawAltStringScaled(x + scale*(32 + 7 * 8), y + scale*8, va("%i", score), scale);
DrawStringScaled(x + scale*32, y + scale*16, va("Ping: %i", ping), scale);
DrawStringScaled(x + scale*32, y + scale*24, va("Time: %i", time), scale);
Draw_StringScaled(x + scale * 32, y, scale, true, ci->name);
Draw_StringScaled(x + scale * 32, y + scale * CHAR_SIZE, scale, true, "Score: ");
Draw_StringScaled(x + scale * (32 + 7 * CHAR_SIZE),
y + scale * CHAR_SIZE, scale, true, va("%i", score));
Draw_StringScaled(x + scale * 32, y + scale * 16, scale, false, va("Ping: %i", ping));
Draw_StringScaled(x + scale * 32, y + scale * 24, scale, false, va("Time: %i", time));
if (!ci->icon)
{
@ -1205,22 +1178,24 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "ctf"))
{
/* draw a ctf client block */
int score, ping;
int score, ping, value;
clientinfo_t *ci;
char block[80];
token = COM_Parse(&s);
x = viddef.width / 2 - scale*160 + scale*(int)strtol(token, (char **)NULL, 10);
x = viddef.width / 2 - scale * 160 + scale*(int)strtol(token, (char **)NULL, 10);
token = COM_Parse(&s);
y = viddef.height / 2 - scale*120 + scale*(int)strtol(token, (char **)NULL, 10);
y = viddef.height / 2 - scale * 120 + scale*(int)strtol(token, (char **)NULL, 10);
SCR_AddDirtyPoint(x, y);
SCR_AddDirtyPoint(x + scale*159, y + scale*31);
SCR_AddDirtyPoint(x + scale * 159, y + scale * 31);
token = COM_Parse(&s);
value = (int)strtol(token, (char **)NULL, 10);
if ((value >= MAX_CLIENTS) || (value < 0))
{
Com_Error(ERR_DROP, "client >= MAX_CLIENTS");
Com_DPrintf("%s: client >= MAX_CLIENTS in client\n", __func__);
continue;
}
ci = &cl.clientinfo[value];
@ -1238,31 +1213,28 @@ SCR_ExecuteLayoutString(char *s)
sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
if (value == cl.playernum)
{
DrawAltStringScaled(x, y, block, scale);
}
else
{
DrawStringScaled(x, y, block, scale);
}
Draw_StringScaled(x, y, scale, value == cl.playernum, token);
continue;
}
if (!strcmp(token, "picn"))
{
int w, h;
/* draw a pic from a name */
token = COM_Parse(&s);
Draw_GetPicSize(&w, &h, token);
SCR_AddDirtyPoint(x, y);
SCR_AddDirtyPoint(x + scale * 23, y + scale * 23);
Draw_PicScaled(x, y, (char *)token, scale);
SCR_AddDirtyPoint(x + scale * (w - 1), y + scale * (h - 1));
Draw_PicScaled(x, y, token, scale);
continue;
}
if (!strcmp(token, "num"))
{
int value, width;
/* draw a number */
token = COM_Parse(&s);
width = (int)strtol(token, (char **)NULL, 10);
@ -1275,7 +1247,7 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "hnum"))
{
/* health number */
int color;
int color, value, width;
width = 3;
value = cl.frame.playerstate.stats[STAT_HEALTH];
@ -1305,7 +1277,7 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "anum"))
{
/* ammo number */
int color;
int color, value, width;
width = 3;
value = cl.frame.playerstate.stats[STAT_AMMO];
@ -1335,7 +1307,7 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "rnum"))
{
/* armor number */
int color;
int color, value, width;
width = 3;
value = cl.frame.playerstate.stats[STAT_ARMOR];
@ -1358,58 +1330,77 @@ SCR_ExecuteLayoutString(char *s)
if (!strcmp(token, "stat_string"))
{
int index;
token = COM_Parse(&s);
index = (int)strtol(token, (char **)NULL, 10);
if ((index < 0) || (index >= MAX_STATS))
{
Com_Error(ERR_DROP, "Bad stat_string index");
Com_DPrintf("%s: bad stats index %d (0x%x) in stat_string\n",
__func__, index, index);
continue;
}
index = cl.frame.playerstate.stats[index];
if ((index < 0) || (index >= MAX_CONFIGSTRINGS))
{
Com_Error(ERR_DROP, "Bad stat_string index");
Com_DPrintf("%s: bad stats index %d (0x%x) in stat_string\n",
__func__, index, index);
continue;
}
DrawStringScaled(x, y, cl.configstrings[index], scale);
Draw_StringScaled(x, y, scale, false, cl.configstrings[index]);
continue;
}
if (!strcmp(token, "cstring"))
{
token = COM_Parse(&s);
DrawHUDStringScaled(token, x, y, 320, 0, scale); // FIXME: or scale 320 here?
DrawHUDStringScaled(token, x, y, 320, false, scale); // FIXME: or scale 320 here?
continue;
}
if (!strcmp(token, "string"))
{
token = COM_Parse(&s);
DrawStringScaled(x, y, token, scale);
Draw_StringScaled(x, y, scale, false, token);
continue;
}
if (!strcmp(token, "cstring2"))
{
token = COM_Parse(&s);
DrawHUDStringScaled(token, x, y, 320, 0x80, scale); // FIXME: or scale 320 here?
DrawHUDStringScaled(token, x, y, 320, true, scale); // FIXME: or scale 320 here?
continue;
}
if (!strcmp(token, "string2"))
{
token = COM_Parse(&s);
DrawAltStringScaled(x, y, token, scale);
Draw_StringScaled(x, y, scale, true, token);
continue;
}
if (!strcmp(token, "if"))
{
int index, value;
/* draw a number */
token = COM_Parse(&s);
value = cl.frame.playerstate.stats[(int)strtol(token, (char **)NULL, 10)];
index = (int)strtol(token, (char **)NULL, 10);
if ((index < 0) || (index >= MAX_STATS))
{
Com_DPrintf("%s: bad stats index %d (0x%x) in if\n",
__func__, index, index);
value = 0;
}
else
{
value = cl.frame.playerstate.stats[index];
}
if (!value)
{
@ -1422,6 +1413,14 @@ SCR_ExecuteLayoutString(char *s)
continue;
}
if (!strcmp(token, "endif") || (token && !token[0]))
{
/* just skip endif and empty line */
continue;
}
Com_DPrintf("%s: Unknown token: %s\n", __func__, token);
}
}
@ -1429,7 +1428,7 @@ SCR_ExecuteLayoutString(char *s)
* The status bar is a small layout program that
* is based on the stats array
*/
void
static void
SCR_DrawStats(void)
{
SCR_ExecuteLayoutString(cl.configstrings[CS_STATUSBAR]);
@ -1437,7 +1436,7 @@ SCR_DrawStats(void)
#define STAT_LAYOUTS 13
void
static void
SCR_DrawLayout(void)
{
if (!cl.frame.playerstate.stats[STAT_LAYOUTS])
@ -1450,7 +1449,7 @@ SCR_DrawLayout(void)
// ----
void
static void
SCR_DrawSpeed(void)
{
if (cl_showspeed->value < 1) //Disabled, do nothing
@ -1463,7 +1462,7 @@ SCR_DrawSpeed(void)
GetPlayerSpeed(&speed, &speedxy);
snprintf(spd_str, sizeof(spd_str), "%6.2f (%6.2f) QU/s", speed, speedxy);
str_len = scale * (strlen(spd_str) * 8 + 2);
str_len = scale * (strlen(spd_str) * CHAR_SIZE + 2);
if (cl_showspeed->value == 1) //Draw speed and xy speed at top right
{
@ -1478,7 +1477,7 @@ SCR_DrawSpeed(void)
yPos = scale * 20;
}
DrawStringScaled(xPos, yPos, spd_str, scale);
Draw_StringScaled(xPos, yPos, scale, false, spd_str);
SCR_AddDirtyPoint(xPos, yPos);
SCR_AddDirtyPoint(viddef.width, yPos);
}
@ -1491,18 +1490,19 @@ SCR_DrawSpeed(void)
}
snprintf(spd_str, sizeof(spd_str), "%6.2f", speedxy);
str_len = scale * (strlen(spd_str) * 8 + 2);
str_len = scale * (strlen(spd_str) * CHAR_SIZE + 2);
yPos = scr_vrect.y + (scr_vrect.height / 2) + (scale * 10);
xPos = scr_vrect.x + (scr_vrect.width / 2) - (str_len / 2);
DrawStringScaled(xPos, yPos, spd_str, scale);
Draw_StringScaled(xPos, yPos, scale, false, spd_str);
SCR_AddDirtyPoint(xPos, yPos);
SCR_AddDirtyPoint(xPos + str_len, yPos);
}
}
void
SCR_Framecounter(void) {
static void
SCR_Framecounter(void)
{
long long newtime;
static int frame;
static int frametimes[60] = {0};
@ -1510,39 +1510,26 @@ SCR_Framecounter(void) {
/* skip statistics without show fps */
if (cl_showfps->value < 1)
{
return;
}
newtime = Sys_Microseconds();
frametimes[frame] = (int)(newtime - oldtime);
oldtime = newtime;
frame++;
if (frame > 59) {
if (frame > 59)
{
frame = 0;
}
float scale = SCR_GetConsoleScale();
if (cl_showfps->value == 1) {
if (cl_showfps->value == 1)
{
// Calculate average of frames.
int avg = 0;
int num = 0;
for (int i = 0; i < 60; i++) {
if (frametimes[i] != 0) {
avg += frametimes[i];
num++;
}
}
char str[10];
snprintf(str, sizeof(str), "%3.2ffps", (1000.0 * 1000.0) / (avg / num));
DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), 0, str, scale);
SCR_AddDirtyPoint(viddef.width - scale*(strlen(str)*8 + 2), 0);
SCR_AddDirtyPoint(viddef.width, 0);
} else if (cl_showfps->value >= 2) {
// Calculate average of frames.
int avg = 0;
int num = 0;
@ -1553,35 +1540,55 @@ SCR_Framecounter(void) {
}
}
snprintf(str, sizeof(str), "%3.2ffps", (1000.0 * 1000.0) / (avg / num));
Draw_StringScaled(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), 0, scale, false, str);
SCR_AddDirtyPoint(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), 0);
SCR_AddDirtyPoint(viddef.width, 0);
}
else if (cl_showfps->value >= 2)
{
// Calculate average of frames.
int avg = 0;
int num = 0;
char str[64];
for (int i = 0; i < 60; i++) {
if (frametimes[i] != 0) {
avg += frametimes[i];
num++;
}
}
// Find lowest and highest
int min = frametimes[0];
int max = frametimes[1];
for (int i = 1; i < 60; i++) {
if ((frametimes[i] > 0) && (min < frametimes[i])) {
for (int i = 1; i < 60; i++)
{
if ((frametimes[i] > 0) && (min < frametimes[i]))
{
min = frametimes[i];
}
if ((frametimes[i] > 0) && (max > frametimes[i])) {
if ((frametimes[i] > 0) && (max > frametimes[i]))
{
max = frametimes[i];
}
}
char str[64];
snprintf(str, sizeof(str), "Min: %7.2ffps, Max: %7.2ffps, Avg: %7.2ffps",
(1000.0 * 1000.0) / min, (1000.0 * 1000.0) / max, (1000.0 * 1000.0) / (avg / num));
DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), 0, str, scale);
SCR_AddDirtyPoint(viddef.width - scale*(strlen(str)*8 + 2), 0);
Draw_StringScaled(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), 0, scale, false, str);
SCR_AddDirtyPoint(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), 0);
SCR_AddDirtyPoint(viddef.width, 0);
if (cl_showfps->value > 2)
{
snprintf(str, sizeof(str), "Max: %5.2fms, Min: %5.2fms, Avg: %5.2fms",
0.001f*min, 0.001f*max, 0.001f*(avg / num));
DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), scale*10, str, scale);
SCR_AddDirtyPoint(viddef.width - scale*(strlen(str)*8 + 2), scale*10);
SCR_AddDirtyPoint(viddef.width, scale+10);
Draw_StringScaled(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), scale * 10, scale, false, str);
SCR_AddDirtyPoint(viddef.width - scale * (strlen(str) * CHAR_SIZE + 2), scale * 10);
SCR_AddDirtyPoint(viddef.width, scale + 10);
}
}
}
@ -1649,7 +1656,8 @@ SCR_UpdateScreen(void)
}
Draw_GetPicSize(&w, &h, "loading");
Draw_PicScaled((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2, "loading", scale);
Draw_PicScaledAltText((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2,
"loading", scale, "loading");
}
/* if a cinematic is supposed to be running,

View file

@ -119,7 +119,6 @@ void
CL_RegisterTEntSounds(void)
{
int i;
char name[MAX_QPATH];
cl_sfx_ric1 = S_RegisterSound("world/ric1.wav");
cl_sfx_ric2 = S_RegisterSound("world/ric2.wav");
@ -139,6 +138,8 @@ CL_RegisterTEntSounds(void)
for (i = 0; i < 4; i++)
{
char name[MAX_QPATH];
Com_sprintf(name, sizeof(name), "player/step%i.wav", i + 1);
cl_sfx_footsteps[i] = S_RegisterSound(name);
}
@ -252,7 +253,7 @@ CL_ParseParticles(void)
int color, count;
vec3_t pos, dir;
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
color = MSG_ReadByte(&net_message);
@ -273,8 +274,8 @@ CL_ParseBeam(struct model_s *model)
ent = MSG_ReadShort(&net_message);
MSG_ReadPos(&net_message, start);
MSG_ReadPos(&net_message, end);
MSG_ReadPos(&net_message, start, cls.serverProtocol);
MSG_ReadPos(&net_message, end, cls.serverProtocol);
/* override any beam with the same entity */
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++)
@ -320,9 +321,9 @@ CL_ParseBeam2(struct model_s *model)
ent = MSG_ReadShort(&net_message);
MSG_ReadPos(&net_message, start);
MSG_ReadPos(&net_message, end);
MSG_ReadPos(&net_message, offset);
MSG_ReadPos(&net_message, start, cls.serverProtocol);
MSG_ReadPos(&net_message, end, cls.serverProtocol);
MSG_ReadPos(&net_message, offset, cls.serverProtocol);
/* override any beam with the same entity */
for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++)
@ -371,8 +372,8 @@ CL_ParsePlayerBeam(struct model_s *model)
ent = MSG_ReadShort(&net_message);
MSG_ReadPos(&net_message, start);
MSG_ReadPos(&net_message, end);
MSG_ReadPos(&net_message, start, cls.serverProtocol);
MSG_ReadPos(&net_message, end, cls.serverProtocol);
/* network optimization */
if (model == cl_mod_heatbeam)
@ -387,7 +388,7 @@ CL_ParsePlayerBeam(struct model_s *model)
}
else
{
MSG_ReadPos(&net_message, offset);
MSG_ReadPos(&net_message, offset, cls.serverProtocol);
}
/* Override any beam with the same entity
@ -438,8 +439,8 @@ CL_ParseLightning(struct model_s *model)
srcEnt = MSG_ReadShort(&net_message);
destEnt = MSG_ReadShort(&net_message);
MSG_ReadPos(&net_message, start);
MSG_ReadPos(&net_message, end);
MSG_ReadPos(&net_message, start, cls.serverProtocol);
MSG_ReadPos(&net_message, end, cls.serverProtocol);
/* override any beam with the same
source AND destination entities */
@ -486,8 +487,8 @@ CL_ParseLaser(int colors)
laser_t *l;
int i;
MSG_ReadPos(&net_message, start);
MSG_ReadPos(&net_message, end);
MSG_ReadPos(&net_message, start, cls.serverProtocol);
MSG_ReadPos(&net_message, end, cls.serverProtocol);
for (i = 0, l = cl_lasers; i < MAX_LASERS; i++, l++)
{
@ -546,7 +547,7 @@ CL_ParseSteam(void)
{
s->id = id;
s->count = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, s->org);
MSG_ReadPos(&net_message, s->org, cls.serverProtocol);
MSG_ReadDir(&net_message, s->dir);
r = MSG_ReadByte(&net_message);
s->basecolor = VID_PaletteColor(r & 0xff);
@ -560,7 +561,7 @@ CL_ParseSteam(void)
else
{
MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
MSG_ReadByte(&net_message);
MSG_ReadShort(&net_message);
@ -571,7 +572,7 @@ CL_ParseSteam(void)
{
/* instant */
cnt = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
r = MSG_ReadByte(&net_message);
magnitude = MSG_ReadShort(&net_message);
@ -604,7 +605,7 @@ CL_ParseWidow(void)
if (free_sustain)
{
s->id = id;
MSG_ReadPos(&net_message, s->org);
MSG_ReadPos(&net_message, s->org, cls.serverProtocol);
s->endtime = cl.time + 2100;
s->think = CL_Widowbeamout;
s->thinkinterval = 1;
@ -613,7 +614,7 @@ CL_ParseWidow(void)
else
{
/* no free sustains */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
}
}
@ -638,7 +639,7 @@ CL_ParseNuke(void)
if (free_sustain)
{
s->id = 21000;
MSG_ReadPos(&net_message, s->org);
MSG_ReadPos(&net_message, s->org, cls.serverProtocol);
s->endtime = cl.time + 1000;
s->think = CL_Nukeblast;
s->thinkinterval = 1;
@ -647,7 +648,7 @@ CL_ParseNuke(void)
else
{
/* no free sustains */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
}
}
@ -664,7 +665,7 @@ static unsigned int splash_color[] = {
void
CL_ParseTEnt(void)
{
int type;
temp_event_t type;
vec3_t pos, pos2, dir;
explosion_t *ex;
int cnt;
@ -678,7 +679,7 @@ CL_ParseTEnt(void)
switch (type)
{
case TE_BLOOD: /* bullet hitting flesh */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_ParticleEffect(pos, dir, 0xff001f9b, 0xff00001b, 60);
break;
@ -686,7 +687,7 @@ CL_ParseTEnt(void)
case TE_GUNSHOT: /* bullet hitting wall */
case TE_SPARKS:
case TE_BULLET_SPARKS:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
if (type == TE_GUNSHOT)
@ -722,7 +723,7 @@ CL_ParseTEnt(void)
case TE_SCREEN_SPARKS:
case TE_SHIELD_SPARKS:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
if (type == TE_SCREEN_SPARKS)
@ -770,7 +771,7 @@ CL_ParseTEnt(void)
break;
case TE_SHOTGUN: /* bullet hitting wall */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_ParticleEffect(pos, dir, 0xff000000, 0xff6b6b6b, 20);
CL_SmokeAndFlash(pos);
@ -778,7 +779,7 @@ CL_ParseTEnt(void)
case TE_SPLASH: /* bullet hitting water */
cnt = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
r = MSG_ReadByte(&net_message);
@ -812,7 +813,7 @@ CL_ParseTEnt(void)
case TE_LASER_SPARKS:
cnt = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
color = MSG_ReadByte(&net_message);
CL_ParticleEffect2(pos, dir,
@ -820,13 +821,13 @@ CL_ParseTEnt(void)
break;
case TE_BLUEHYPERBLASTER:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, dir);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, dir, cls.serverProtocol);
CL_BlasterParticles(pos, dir);
break;
case TE_BLASTER: /* blaster hitting wall */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_BlasterParticles(pos, dir);
@ -864,8 +865,9 @@ CL_ParseTEnt(void)
break;
case TE_RAILTRAIL: /* railgun effect */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos2);
case TE_RAILTRAIL2:
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, pos2, cls.serverProtocol);
CL_RailTrail(pos, pos2);
S_StartSound(pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
break;
@ -873,7 +875,7 @@ CL_ParseTEnt(void)
case TE_EXPLOSION2:
case TE_GRENADE_EXPLOSION:
case TE_GRENADE_EXPLOSION_WATER:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ex = CL_AllocExplosion();
VectorCopy(pos, ex->ent.origin);
ex->type = ex_poly;
@ -901,7 +903,7 @@ CL_ParseTEnt(void)
break;
case TE_PLASMA_EXPLOSION:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ex = CL_AllocExplosion();
VectorCopy(pos, ex->ent.origin);
ex->type = ex_poly;
@ -929,7 +931,7 @@ CL_ParseTEnt(void)
case TE_EXPLOSION1:
case TE_ROCKET_EXPLOSION:
case TE_ROCKET_EXPLOSION_WATER:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ex = CL_AllocExplosion();
VectorCopy(pos, ex->ent.origin);
ex->type = ex_poly;
@ -974,7 +976,7 @@ CL_ParseTEnt(void)
break;
case TE_BFG_EXPLOSION:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ex = CL_AllocExplosion();
VectorCopy(pos, ex->ent.origin);
ex->type = ex_poly;
@ -991,7 +993,7 @@ CL_ParseTEnt(void)
break;
case TE_BFG_BIGEXPLOSION:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_BFGExplosionParticles(pos);
break;
@ -1000,8 +1002,8 @@ CL_ParseTEnt(void)
break;
case TE_BUBBLETRAIL:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos2);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, pos2, cls.serverProtocol);
CL_BubbleTrail(pos, pos2);
break;
@ -1011,7 +1013,7 @@ CL_ParseTEnt(void)
break;
case TE_BOSSTPORT: /* boss teleporting to station */
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_BigTeleportParticles(pos);
S_StartSound(pos, 0, 0, S_RegisterSound(
"misc/bigtele.wav"), 1, ATTN_NONE, 0);
@ -1023,7 +1025,7 @@ CL_ParseTEnt(void)
case TE_WELDING_SPARKS:
cnt = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
color = MSG_ReadByte(&net_message);
CL_ParticleEffect2(pos, dir,
@ -1043,14 +1045,14 @@ CL_ParseTEnt(void)
break;
case TE_GREENBLOOD:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_ParticleEffect2(pos, dir, 0xff0fbfff, 0xff003bb7, 30);
break;
case TE_TUNNEL_SPARKS:
cnt = MSG_ReadByte(&net_message);
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
color = MSG_ReadByte(&net_message);
CL_ParticleEffect3(pos, dir, VID_PaletteColor(color), cnt);
@ -1058,7 +1060,7 @@ CL_ParseTEnt(void)
case TE_BLASTER2:
case TE_FLECHETTE:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
if (type == TE_BLASTER2)
@ -1124,6 +1126,11 @@ CL_ParseTEnt(void)
S_StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
break;
case TE_FLAME:
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_FlameEffects(pos);
break;
case TE_LIGHTNING:
ent = CL_ParseLightning(cl_mod_lightning);
S_StartSound(NULL, ent, CHAN_WEAPON, cl_sfx_lightning,
@ -1131,13 +1138,13 @@ CL_ParseTEnt(void)
break;
case TE_DEBUGTRAIL:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos2);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, pos2, cls.serverProtocol);
CL_DebugTrail(pos, pos2);
break;
case TE_PLAIN_EXPLOSION:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ex = CL_AllocExplosion();
VectorCopy(pos, ex->ent.origin);
@ -1163,14 +1170,14 @@ CL_ParseTEnt(void)
break;
case TE_FLASHLIGHT:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
ent = MSG_ReadShort(&net_message);
CL_Flashlight(ent, pos);
break;
case TE_FORCEWALL:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos2);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, pos2, cls.serverProtocol);
color = MSG_ReadByte(&net_message);
CL_ForceWall(pos, pos2, VID_PaletteColor(color));
break;
@ -1185,7 +1192,7 @@ CL_ParseTEnt(void)
case TE_HEATBEAM_SPARKS:
cnt = 50;
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
r = 8;
magnitude = 60;
@ -1195,7 +1202,7 @@ CL_ParseTEnt(void)
case TE_HEATBEAM_STEAM:
cnt = 20;
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
magnitude = 60;
CL_ParticleSteamEffect(pos, dir, 0xff07abff, 0xff002bab, cnt, magnitude);
@ -1207,14 +1214,14 @@ CL_ParseTEnt(void)
break;
case TE_BUBBLETRAIL2:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos2);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadPos(&net_message, pos2, cls.serverProtocol);
CL_BubbleTrail2(pos, pos2, 8);
S_StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
break;
case TE_MOREBLOOD:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_ParticleEffect(pos, dir, 0xff001f9b, 0xff00001b, 250);
break;
@ -1223,19 +1230,19 @@ CL_ParseTEnt(void)
dir[0] = 0;
dir[1] = 0;
dir[2] = 1;
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_ParticleSmokeEffect(pos, dir, 0xff000000, 0xff6b6b6b, 20, 20);
break;
case TE_ELECTRIC_SPARKS:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
MSG_ReadDir(&net_message, dir);
CL_ParticleEffect(pos, dir, 0xff5b430f, 0xff1f1700, 40);
S_StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
break;
case TE_TRACKER_EXPLOSION:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_ColorFlash(pos, 0, 150, -1, -1, -1);
CL_ColorExplosionParticles(pos, 0xff000000, 0xff0f0f0f);
S_StartSound(pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
@ -1243,7 +1250,7 @@ CL_ParseTEnt(void)
case TE_TELEPORT_EFFECT:
case TE_DBALL_GOAL:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_TeleportParticles(pos);
break;
@ -1256,12 +1263,12 @@ CL_ParseTEnt(void)
break;
case TE_WIDOWSPLASH:
MSG_ReadPos(&net_message, pos);
MSG_ReadPos(&net_message, pos, cls.serverProtocol);
CL_WidowSplash(pos);
break;
default:
Com_Error(ERR_DROP, "CL_ParseTEnt: bad type");
Com_Error(ERR_DROP, "%s: bad type", __func__);
}
}

View file

@ -358,14 +358,13 @@ CL_PrepRefresh(void)
strcpy(name, cl.configstrings[CS_MODELS + i]);
name[37] = 0; /* never go beyond one line */
if (name[0] != '*')
if (developer->value && name[0] != '*')
{
CL_PrintInSameLine(name);
SCR_UpdateScreen();
IN_Update();
}
SCR_UpdateScreen();
IN_Update();
if (name[0] == '#')
{
/* special player weapon model */
@ -395,11 +394,11 @@ CL_PrepRefresh(void)
CL_PrintInSameLine("Images");
SCR_UpdateScreen();
IN_Update();
for (i = 1; i < MAX_IMAGES && cl.configstrings[CS_IMAGES + i][0]; i++)
{
cl.image_precache[i] = Draw_FindPic(cl.configstrings[CS_IMAGES + i]);
IN_Update();
}
CL_PrintInSameLine("Clients");
@ -411,11 +410,14 @@ CL_PrepRefresh(void)
continue;
}
Com_Printf("client %i\r", i);
SCR_UpdateScreen();
IN_Update();
if (developer->value)
{
Com_Printf("Client %i\r", i);
SCR_UpdateScreen();
IN_Update();
}
CL_ParseClientinfo(i);
CL_PrintInSameLine("");
}
CL_LoadClientinfo(&cl.baseclientinfo, "unnamed\\male/grunt");
@ -525,7 +527,7 @@ V_Render3dCrosshair(void)
if(crosshair_3d->value || crosshair_3d_glow->value){
VectorMA(cl.refdef.vieworg,8192,cl.v_forward,end);
VectorMA(cl.refdef.vieworg, 8192, cl.v_forward,end);
crosshair_trace = CL_PMTrace(cl.refdef.vieworg, vec3_origin, vec3_origin, end);
if(crosshair_3d_glow->value){

View file

@ -33,6 +33,7 @@
cvar_t *cl_http_downloads;
cvar_t *cl_http_filelists;
cvar_t *cl_http_verifypeer;
cvar_t *cl_http_proxy;
cvar_t *cl_http_max_connections;
cvar_t *cl_http_show_dw_progress;
@ -81,7 +82,7 @@ static size_t CL_HTTP_Recv(void *ptr, size_t size, size_t nmemb, void *stream)
if (!dl->fileSize)
{
double length = 0;
curl_off_t length = 0;
qcurl_easy_getinfo(dl->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &length);
@ -264,6 +265,9 @@ static void CL_StartHTTPDownload (dlqueue_t *entry, dlhandle_t *dl)
}
// Make sure that the download handle is in empty state.
if (dl->tempBuffer) {
free(dl->tempBuffer);
}
dl->tempBuffer = NULL;
dl->fileSize = 0;
dl->position = 0;
@ -290,6 +294,8 @@ static void CL_StartHTTPDownload (dlqueue_t *entry, dlhandle_t *dl)
qcurl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, CL_HTTP_Recv);
}
qcurl_easy_setopt(dl->curl, CURLOPT_SSL_VERIFYPEER, (long)cl_http_verifypeer->value);
qcurl_easy_setopt(dl->curl, CURLOPT_PROXY_SSL_VERIFYPEER, (long)cl_http_verifypeer->value);
qcurl_easy_setopt(dl->curl, CURLOPT_PROXY, cl_http_proxy->string);
qcurl_easy_setopt(dl->curl, CURLOPT_LOW_SPEED_TIME, (long)cl_http_bw_limit_tmout->value);
qcurl_easy_setopt(dl->curl, CURLOPT_LOW_SPEED_LIMIT, (long)cl_http_bw_limit_rate->value);
@ -477,6 +483,10 @@ static void CL_ParseFileList(dlhandle_t *dl)
return;
}
if (!dl->tempBuffer) {
return;
}
char *list = dl->tempBuffer;
for (;;)
@ -1169,7 +1179,7 @@ qboolean CL_PendingHTTPDownloads(void)
return false;
}
return pendingCount + handleCount;
return ((pendingCount + handleCount) > 0);
}
/*

View file

@ -72,6 +72,7 @@ extern dlquirks_t dlquirks;
extern cvar_t *cl_http_downloads;
extern cvar_t *cl_http_filelists;
extern cvar_t *cl_http_verifypeer;
extern cvar_t *cl_http_proxy;
extern cvar_t *cl_http_max_connections;
extern cvar_t *cl_http_show_dw_progress;

View file

@ -72,9 +72,9 @@ typedef struct
typedef struct
{
entity_state_t baseline; /* delta from this if not from a previous frame */
entity_state_t current;
entity_state_t prev; /* will always be valid, but might just be a copy of current */
entity_xstate_t baseline; /* delta from this if not from a previous frame */
entity_xstate_t current;
entity_xstate_t prev; /* will always be valid, but might just be a copy of current */
int serverframe; /* if not current, this ent isn't in the frame */
@ -331,17 +331,13 @@ typedef struct
extern centity_t cl_entities[MAX_EDICTS];
extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
extern entity_xstate_t cl_parse_entities[MAX_PARSE_ENTITIES];
extern netadr_t net_from;
extern sizebuf_t net_message;
extern qboolean paused_at_load;
void DrawString (int x, int y, const char *s);
void DrawStringScaled(int x, int y, const char *s, float factor);
void DrawAltString (int x, int y, const char *s); /* toggle high bit */
void DrawAltStringScaled(int x, int y, const char *s, float factor);
qboolean CL_CheckOrDownloadFile (const char *filename);
void CL_AddNetgraph (void);
@ -364,7 +360,7 @@ typedef struct cl_sustain
void CL_ParticleSteamEffect2(cl_sustain_t *self);
void CL_TeleporterParticles (entity_state_t *ent);
void CL_TeleporterParticles (const entity_xstate_t *ent);
void CL_ParticleEffect (vec3_t org, vec3_t dir, unsigned int basecolor, unsigned int finalcolor,
int count);
void CL_ParticleEffect2 (vec3_t org, vec3_t dir, unsigned int basecolor, unsigned int finalcolor,
@ -405,7 +401,7 @@ void CL_SmokeTrail (vec3_t start, vec3_t end, unsigned int basecolor, unsigned i
int spacing);
void CL_Flashlight (int ent, vec3_t pos);
void CL_ForceWall (vec3_t start, vec3_t end, int color);
void CL_FlameEffects (centity_t *ent, vec3_t origin);
void CL_FlameEffects (vec3_t origin);
void CL_GenericParticleEffect (vec3_t org, vec3_t dir, unsigned int basecolor, unsigned int finalcolor,
int count, int numcolors, int dirspread, float alphavel);
void CL_BubbleTrail2 (vec3_t start, vec3_t end, int dist);
@ -491,8 +487,18 @@ void CL_BaseMove (usercmd_t *cmd);
void IN_CenterView (void);
typedef enum
{
LBL_SDL = 0,
LBL_XBOX,
LBL_PLAYSTATION,
LBL_SWITCH,
LBL_MAX_COUNT
} gamepad_labels_t;
float CL_KeyState (kbutton_t *key);
char *Key_KeynumToString (int keynum);
char *Key_KeynumToString_Joy (int key);
void CL_WriteDemoMessage (void);
void CL_Stop_f (void);
@ -535,7 +541,7 @@ void CL_DiminishingTrail (vec3_t start, vec3_t end, centity_t *old, int flags);
void CL_FlyEffect (centity_t *ent, vec3_t origin);
void CL_BfgParticles (entity_t *ent);
void CL_AddParticles (void);
void CL_EntityEvent (entity_state_t *ent);
void CL_EntityEvent (entity_xstate_t *ent);
void CL_TrapParticles (entity_t *ent);
void M_Init (void);

View file

@ -208,11 +208,11 @@ enum QKEYS {
// From here on, only gamepad controls must be allowed.
// Otherwise, separate bindings (keyboard / controller) menu options will not work.
K_BTN_A,
K_JOY_FIRST_REGULAR = K_BTN_A,
K_BTN_B,
K_BTN_X,
K_BTN_Y,
K_BTN_SOUTH,
K_JOY_FIRST_BTN = K_BTN_SOUTH,
K_BTN_EAST,
K_BTN_WEST,
K_BTN_NORTH,
K_BTN_BACK,
K_BTN_GUIDE,
K_BTN_START,
@ -225,26 +225,28 @@ enum QKEYS {
K_DPAD_LEFT,
K_DPAD_RIGHT,
K_BTN_MISC1,
K_PADDLE_1,
K_PADDLE_2,
K_PADDLE_3,
K_PADDLE_4,
K_TOUCHPAD, // SDL_CONTROLLER_BUTTON_MAX - 1
K_PADDLE_RIGHT_1,
K_PADDLE_LEFT_1,
K_PADDLE_RIGHT_2,
K_PADDLE_LEFT_2,
K_TOUCHPAD, // SDL_CONTROLLER_BUTTON_MAX - 1, SDL2 limit
K_BTN_MISC2,
K_BTN_MISC3,
K_BTN_MISC4,
K_BTN_MISC5,
K_BTN_MISC6, // SDL_GAMEPAD_BUTTON_COUNT - 1, current SDL3 count
K_TRIG_LEFT, // buttons for triggers (axes)
K_TRIG_RIGHT,
// add other joystick/controller keys before this one
// and adjust it accordingly, also remember to add corresponding _ALT key below!
K_JOY_LAST_REGULAR = K_TRIG_RIGHT,
// Add other gamepad keys before this one, adjust from SDL 2/3 definitions, and
// add the corresponding _ALT key below! Respect the order, must be the same as above.
// Also, verify if cl_keyboard.c needs a refactor on its arrays.
/* Can't be mapped to any action (=> not regular) */
K_JOY_BACK,
K_BTN_A_ALT,
K_JOY_FIRST_REGULAR_ALT = K_BTN_A_ALT,
K_BTN_B_ALT,
K_BTN_X_ALT,
K_BTN_Y_ALT,
K_BTN_SOUTH_ALT,
K_JOY_FIRST_BTN_ALT = K_BTN_SOUTH_ALT,
K_BTN_EAST_ALT,
K_BTN_WEST_ALT,
K_BTN_NORTH_ALT,
K_BTN_BACK_ALT,
K_BTN_GUIDE_ALT,
K_BTN_START_ALT,
@ -257,11 +259,16 @@ enum QKEYS {
K_DPAD_LEFT_ALT,
K_DPAD_RIGHT_ALT,
K_BTN_MISC1_ALT,
K_PADDLE_1_ALT,
K_PADDLE_2_ALT,
K_PADDLE_3_ALT,
K_PADDLE_4_ALT,
K_PADDLE_RIGHT_1_ALT,
K_PADDLE_LEFT_1_ALT,
K_PADDLE_RIGHT_2_ALT,
K_PADDLE_LEFT_2_ALT,
K_TOUCHPAD_ALT,
K_BTN_MISC2_ALT,
K_BTN_MISC3_ALT,
K_BTN_MISC4_ALT,
K_BTN_MISC5_ALT,
K_BTN_MISC6_ALT,
K_TRIG_LEFT_ALT,
K_TRIG_RIGHT_ALT,

View file

@ -43,9 +43,6 @@ void SCR_TouchPics(void);
void SCR_RunConsole(void);
extern float scr_con_current;
extern float scr_conlines; /* lines of console to display */
extern int sb_lines;
extern cvar_t *scr_viewsize;
@ -53,9 +50,6 @@ extern cvar_t *crosshair;
extern vrect_t scr_vrect; /* position of render window */
extern char crosshair_pic[MAX_QPATH];
extern int crosshair_width, crosshair_height;
void SCR_AddDirtyPoint(int x, int y);
void SCR_DirtyScreen(void);

View file

@ -35,6 +35,7 @@
*/
#include <SDL2/SDL.h>
#include <limits.h>
#include "header/input.h"
#include "../header/keyboard.h"
@ -78,7 +79,7 @@ typedef enum
// IN_Update() called at the beginning of a frame to the
// actual movement functions called at a later time.
static float mouse_x, mouse_y;
static unsigned char sdl_back_button = SDL_CONTROLLER_BUTTON_START;
static unsigned char joy_escbutton = SDL_CONTROLLER_BUTTON_START;
static int joystick_left_x, joystick_left_y, joystick_right_x, joystick_right_y;
static float gyro_yaw, gyro_pitch;
static qboolean mlooking;
@ -91,6 +92,12 @@ int sys_frame_time;
// is pressed
qboolean joy_altselector_pressed = false;
// Gamepad labels' style (Xbox, Playstation, etc.) in use, normally set after detection
gamepad_labels_t joy_current_lbls = LBL_SDL;
// Using japanese style for confirm & cancel buttons on gamepad
qboolean japanese_confirm = false;
// Console Variables
cvar_t *freelook;
cvar_t *lookstrafe;
@ -134,6 +141,12 @@ static int last_haptic_effect_size = HAPTIC_EFFECT_LIST_SIZE;
static int last_haptic_effect_pos = 0;
static haptic_effects_cache_t last_haptic_effect[HAPTIC_EFFECT_LIST_SIZE];
// Gamepad labels' style (Xbox, Playstation, etc.) requested by user
static cvar_t *joy_labels;
// Gamepad style for confirm and cancel buttons (traditional or japanese)
static cvar_t *joy_confirm;
// Joystick sensitivity
static cvar_t *joy_yawsensitivity;
static cvar_t *joy_pitchsensitivity;
@ -173,19 +186,20 @@ static cvar_t *gyro_calibration_x;
static cvar_t *gyro_calibration_y;
static cvar_t *gyro_calibration_z;
#if SDL_VERSION_ATLEAST(2, 0, 14) // support for controller sensors (gyro, accelerometer)
// If the used SDL version doesn't support gamepad sensors...
#if !SDL_VERSION_ATLEAST(2, 0, 14)
// ...disable support for reading them.
#define NO_SDL_GYRO
#endif
#ifndef NO_SDL_GYRO // use SDL_CONTROLLERSENSORUPDATE to read gyro
static unsigned int num_samples;
#define NATIVE_SDL_GYRO // uses SDL_CONTROLLERSENSORUPDATE to read gyro
#else // for SDL < 2.0.14, gyro can be read as a "secondary joystick" exposed by dkms-hid-nintendo
#else // gyro can be read as a "secondary joystick" exposed by dkms-hid-nintendo
static unsigned int num_samples[3];
static SDL_Joystick *imu_joystick = NULL; // gyro "joystick"
#define IMU_JOY_AXIS_GYRO_ROLL 3
#define IMU_JOY_AXIS_GYRO_PITCH 4
#define IMU_JOY_AXIS_GYRO_YAW 5
#endif
// To ignore SDL_JOYDEVICEADDED at game init. Allows for hot plugging of game controller afterwards.
@ -505,16 +519,120 @@ IN_TranslateScancodeToQ2Key(SDL_Scancode sc)
static void IN_Controller_Init(qboolean notify_user);
static void IN_Controller_Shutdown(qboolean notify_user);
/*
* Sets the gamepad buttons' style of labels (SDL, Xbox, PS, Switch).
* They are only visible in the gamepad binding options.
* Traditional binding uses SDL style, no matter the gamepad.
*/
static void
IN_GamepadLabels_Changed(void)
{
const int requested = (int)joy_labels->value;
joy_labels->modified = false;
joy_current_lbls = LBL_SDL;
#if SDL_VERSION_ATLEAST(2, 0, 12)
if (requested < 0 && controller) // try to autodetect...
{
switch (SDL_GameControllerGetType(controller))
{
case SDL_CONTROLLER_TYPE_XBOX360:
case SDL_CONTROLLER_TYPE_XBOXONE:
joy_current_lbls = LBL_XBOX;
return;
case SDL_CONTROLLER_TYPE_PS3:
case SDL_CONTROLLER_TYPE_PS4:
#if SDL_VERSION_ATLEAST(2, 0, 14)
case SDL_CONTROLLER_TYPE_PS5:
#endif // SDL_VERSION_ATLEAST(2, 0, 14)
joy_current_lbls = LBL_PLAYSTATION;
return;
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
#if SDL_VERSION_ATLEAST(2, 24, 0)
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
#endif // SDL_VERSION_ATLEAST(2, 24, 0)
joy_current_lbls = LBL_SWITCH;
default:
return;
}
}
else
#endif // SDL_VERSION_ATLEAST(2, 0, 12)
if (requested >= LBL_SDL && requested < LBL_MAX_COUNT)
{
joy_current_lbls = (gamepad_labels_t)requested;
}
}
/*
* Sets which gamepad button works as "confirm", and which
* works as "cancel", in menus.
*/
static void
IN_GamepadConfirm_Changed(void)
{
const int requested = (int)joy_confirm->value;
japanese_confirm = false;
joy_confirm->modified = false;
#if SDL_VERSION_ATLEAST(2, 0, 12)
if (requested < 0 && controller) // try to autodetect...
{
switch (SDL_GameControllerGetType(controller))
{
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
#if SDL_VERSION_ATLEAST(2, 24, 0)
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
#endif // SDL_VERSION_ATLEAST(2, 24, 0)
japanese_confirm = true;
default:
return;
}
}
else
#endif // SDL_VERSION_ATLEAST(2, 0, 12)
if (requested == 1)
{
japanese_confirm = true;
}
}
static void
IN_GyroMode_Changed(void)
{
if (gyro_mode->value < 2)
{
gyro_active = false;
}
else
{
gyro_active = true;
}
gyro_mode->modified = false;
}
static void
IN_VirtualKeyEvent(int keynum, qboolean *state_store, qboolean new_state)
{
if (new_state != *state_store)
{
*state_store = new_state;
Key_Event(keynum, *state_store, true);
}
}
qboolean IN_NumpadIsOn()
{
SDL_Keymod mod = SDL_GetModState();
SDL_Keymod mod = SDL_GetModState();
if ((mod & KMOD_NUM) == KMOD_NUM)
{
return true;
}
if ((mod & KMOD_NUM) == KMOD_NUM)
{
return true;
}
return false;
return false;
}
/* ------------------------------------------------------------------ */
@ -533,6 +651,7 @@ IN_Update(void)
static qboolean left_trigger = false;
static qboolean right_trigger = false;
static qboolean left_stick[4] = {false, false, false, false}; // left, right, up, down virtual keys
static int consoleKeyCode = 0;
@ -733,8 +852,8 @@ IN_Update(void)
qboolean down = (event.type == SDL_CONTROLLERBUTTONDOWN);
unsigned char btn = event.cbutton.button;
// Handle Back Button, to override its original key
Key_Event( (btn == sdl_back_button)? K_JOY_BACK : K_BTN_A + btn,
// Handle Esc button first, to override its original key
Key_Event( (btn == joy_escbutton)? K_ESCAPE : K_JOY_FIRST_BTN + btn,
down, true );
break;
}
@ -746,26 +865,12 @@ IN_Update(void)
switch (event.caxis.axis)
{
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
{
qboolean new_left_trigger = axis_value > 8192;
if (new_left_trigger != left_trigger)
{
left_trigger = new_left_trigger;
Key_Event(K_TRIG_LEFT, left_trigger, true);
}
IN_VirtualKeyEvent(K_TRIG_LEFT, &left_trigger, axis_value > 8192);
break;
}
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
{
qboolean new_right_trigger = axis_value > 8192;
if (new_right_trigger != right_trigger)
{
right_trigger = new_right_trigger;
Key_Event(K_TRIG_RIGHT, right_trigger, true);
}
IN_VirtualKeyEvent(K_TRIG_RIGHT, &right_trigger, axis_value > 8192);
break;
}
}
if (!cl_paused->value && cls.key_dest == key_game)
@ -785,11 +890,29 @@ IN_Update(void)
joystick_right_y = axis_value;
break;
}
break;
}
// Virtual keys to navigate menus with left stick
if (cls.key_dest == key_menu)
{
switch (event.caxis.axis)
{
case SDL_CONTROLLER_AXIS_LEFTX:
IN_VirtualKeyEvent(K_LEFTARROW, &left_stick[0], axis_value < -16896);
IN_VirtualKeyEvent(K_RIGHTARROW, &left_stick[1], axis_value > 16896);
break;
case SDL_CONTROLLER_AXIS_LEFTY:
IN_VirtualKeyEvent(K_UPARROW, &left_stick[2], axis_value < -16896);
IN_VirtualKeyEvent(K_DOWNARROW, &left_stick[3], axis_value > 16896);
break;
}
}
break;
}
#ifdef NATIVE_SDL_GYRO // controller sensors' reading supported (gyro, accelerometer)
#ifndef NO_SDL_GYRO // gamepad sensors' reading is supported (gyro, accelerometer)
case SDL_CONTROLLERSENSORUPDATE:
if (event.csensor.sensor != SDL_SENSOR_GYRO)
{
@ -804,7 +927,7 @@ IN_Update(void)
break;
}
#else // gyro read as "secondary joystick"
#else // gyro read from a "secondary joystick" (usually with name ending in "IMU")
case SDL_JOYAXISMOTION:
if ( !imu_joystick || event.cdevice.which != SDL_JoystickInstanceID(imu_joystick) )
{
@ -831,12 +954,11 @@ IN_Update(void)
break;
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
if (gyro_active && gyro_mode->value &&
!cl_paused->value && cls.key_dest == key_game)
if (gyro_active && !cl_paused->value && cls.key_dest == key_game)
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
if (!gyro_turning_axis->value)
{
gyro_yaw = event.csensor.data[1] - gyro_calibration_y->value; // yaw
@ -864,7 +986,7 @@ IN_Update(void)
gyro_yaw = axis_value - gyro_calibration_z->value;
}
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
}
else
{
@ -956,7 +1078,7 @@ IN_Update(void)
case REASON_GYROCALIBRATION: // finish and save calibration
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
const float inverseSamples = 1.f / num_samples;
Cvar_SetValue("gyro_calibration_x", gyro_accum[0] * inverseSamples);
Cvar_SetValue("gyro_calibration_y", gyro_accum[1] * inverseSamples);
@ -985,6 +1107,19 @@ IN_Update(void)
countdown_reason = REASON_NONE;
}
}
if (joy_labels->modified)
{
IN_GamepadLabels_Changed();
}
if (joy_confirm->modified)
{
IN_GamepadConfirm_Changed();
}
if (gyro_mode->modified)
{
IN_GyroMode_Changed();
}
}
/*
@ -1081,7 +1216,7 @@ IN_TightenInput(float yaw, float pitch)
{
thumbstick_t input = { yaw, pitch };
const float magnitude = IN_StickMagnitude(input);
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
const float threshold = (M_PI / 180.0f) * gyro_tightening->value;
#else
const float threshold = (2560.0f / 180.0f) * gyro_tightening->value;
@ -1177,7 +1312,7 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone)
// Flicking begins now, with a new target
is_flicking = true;
flick_progress = 0.0f;
started_flick = cls.realtime;
started_flick = sys_frame_time;
target_angle = stick_angle;
IN_ResetSmoothSamples();
}
@ -1369,7 +1504,7 @@ IN_Move(usercmd_t *cmd)
//
// For movement this is not needed, as those are absolute values independent of framerate
float joyViewFactor = cls.rframetime/0.01666f;
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
float gyroViewFactor = (1.0f / M_PI) * joyViewFactor;
#else
float gyroViewFactor = (1.0f / 2560.0f) * joyViewFactor; // normalized for Switch gyro
@ -1421,7 +1556,7 @@ IN_Move(usercmd_t *cmd)
// Flick Stick: flick in progress, changing the yaw angle to the target progressively
if (flick_progress < 1.0f)
{
float cur_progress = (float)(cls.realtime - started_flick) / FLICK_TIME;
float cur_progress = (float)(sys_frame_time - started_flick) / FLICK_TIME;
if (cur_progress > 1.0f)
{
@ -1929,7 +2064,7 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
void
StartCalibration(void)
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
num_samples = 0;
#else
num_samples[0] = num_samples[1] = num_samples[2] = 0;
@ -1959,19 +2094,19 @@ IN_Controller_Init(qboolean notify_user)
SDL_Joystick *joystick = NULL;
SDL_bool is_controller = SDL_FALSE;
cvar = Cvar_Get("in_sdlbackbutton", "1", CVAR_ARCHIVE);
cvar = Cvar_Get("joy_escbutton", "0", CVAR_ARCHIVE);
if (cvar)
{
switch ((int)cvar->value)
{
case 0:
sdl_back_button = SDL_CONTROLLER_BUTTON_BACK;
case 1:
joy_escbutton = SDL_CONTROLLER_BUTTON_BACK;
break;
case 2:
sdl_back_button = SDL_CONTROLLER_BUTTON_GUIDE;
joy_escbutton = SDL_CONTROLLER_BUTTON_GUIDE;
break;
default:
sdl_back_button = SDL_CONTROLLER_BUTTON_START;
joy_escbutton = SDL_CONTROLLER_BUTTON_START;
}
}
@ -1995,6 +2130,9 @@ IN_Controller_Init(qboolean notify_user)
#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1" );
#endif
#ifdef SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS // use button positions instead of labels, like SDL3
SDL_SetHint( SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0" );
#endif
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == -1)
{
@ -2036,6 +2174,9 @@ IN_Controller_Init(qboolean notify_user)
for (int i = 0; i < SDL_NumJoysticks(); i++)
{
const char* joystick_name;
size_t name_len;
joystick = SDL_JoystickOpen(i);
if (!joystick)
{
@ -2043,33 +2184,42 @@ IN_Controller_Init(qboolean notify_user)
continue; // try next joystick
}
const char* joystick_name = SDL_JoystickName(joystick);
const int name_len = strlen(joystick_name);
joystick_name = SDL_JoystickName(joystick);
name_len = strlen(joystick_name);
Com_Printf ("Trying joystick %d, '%s'\n", i+1, joystick_name);
// Ugly hack to detect IMU-only devices - works for Switch controllers at least
if (name_len > 4 && !strncmp(joystick_name + name_len - 4, " IMU", 4))
if ( name_len > 6 && strstr(joystick_name + name_len - 6, "IMU") )
{
#ifndef NO_SDL_GYRO
SDL_JoystickClose(joystick);
joystick = NULL;
#ifdef NATIVE_SDL_GYRO
Com_Printf ("Skipping IMU device.\n");
#else // if it's not a Left JoyCon, use it as Gyro
Com_Printf ("IMU device found.\n");
if ( !imu_joystick && name_len > 16 && strncmp(joystick_name + name_len - 16, "Left Joy-Con IMU", 16) != 0 )
qboolean using_imu = !imu_joystick && !( strstr(joystick_name, "Joy-Con") && strstr(joystick_name, "L") );
Com_Printf ("IMU device found... ");
SDL_JoystickClose(joystick);
joystick = NULL;
if (using_imu)
{
imu_joystick = SDL_JoystickOpen(i);
if (imu_joystick)
{
show_gyro = true;
Com_Printf ("Using this device as Gyro sensor.\n");
Com_Printf ("using it as Gyro sensor.\n");
}
else
{
Com_Printf ("Couldn't open IMU: %s.\n", SDL_GetError());
Com_Printf ("\nCouldn't open IMU: %s.\n", SDL_GetError());
}
}
else
{
Com_Printf ("skipping.\n");
}
#endif
continue;
}
@ -2106,7 +2256,7 @@ IN_Controller_Init(qboolean notify_user)
show_gamepad = true;
Com_Printf("Enabled as Game Controller, settings:\n%s\n", SDL_GameControllerMapping(controller));
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
if ( SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO)
&& !SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE) )
@ -2129,7 +2279,7 @@ IN_Controller_Init(qboolean notify_user)
SDL_GameControllerSetLED(controller, 0, 80, 0); // green light
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
@ -2163,11 +2313,15 @@ IN_Controller_Init(qboolean notify_user)
Com_Printf("Controller doesn't support rumble.\n");
}
#ifdef NATIVE_SDL_GYRO // "native" exits when finding a single working controller
#ifndef NO_SDL_GYRO // "native SDL gyro" exits when finding a single working gamepad
break;
#endif
}
}
IN_GamepadLabels_Changed();
IN_GamepadConfirm_Changed();
IN_GyroMode_Changed();
}
/*
@ -2198,11 +2352,13 @@ IN_Init(void)
joy_haptic_distance = Cvar_Get("joy_haptic_distance", "100.0", CVAR_ARCHIVE);
haptic_feedback_filter = Cvar_Get("joy_haptic_filter", default_haptic_filter, CVAR_ARCHIVE);
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "1.0", CVAR_ARCHIVE);
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE);
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "2.5", CVAR_ARCHIVE);
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "2.5", CVAR_ARCHIVE);
joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "1.0", CVAR_ARCHIVE);
joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "1.0", CVAR_ARCHIVE);
joy_labels = Cvar_Get("joy_labels", "-1", CVAR_ARCHIVE);
joy_confirm = Cvar_Get("joy_confirm", "-1", CVAR_ARCHIVE);
joy_layout = Cvar_Get("joy_layout", "0", CVAR_ARCHIVE);
joy_left_expo = Cvar_Get("joy_left_expo", "2.0", CVAR_ARCHIVE);
joy_left_snapaxis = Cvar_Get("joy_left_snapaxis", "0.15", CVAR_ARCHIVE);
@ -2217,16 +2373,11 @@ IN_Init(void)
gyro_calibration_y = Cvar_Get("gyro_calibration_y", "0.0", CVAR_ARCHIVE);
gyro_calibration_z = Cvar_Get("gyro_calibration_z", "0.0", CVAR_ARCHIVE);
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "1.0", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "1.0", CVAR_ARCHIVE);
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "2.5", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "2.5", CVAR_ARCHIVE);
gyro_tightening = Cvar_Get("gyro_tightening", "3.5", CVAR_ARCHIVE);
gyro_turning_axis = Cvar_Get("gyro_turning_axis", "0", CVAR_ARCHIVE);
gyro_mode = Cvar_Get("gyro_mode", "2", CVAR_ARCHIVE);
if ((int)gyro_mode->value == 2)
{
gyro_active = true;
}
windowed_pauseonfocuslost = Cvar_Get("vid_pauseonfocuslost", "0", CVAR_USERINFO | CVAR_ARCHIVE);
windowed_mouse = Cvar_Get("windowed_mouse", "1", CVAR_USERINFO | CVAR_ARCHIVE);
@ -2280,7 +2431,7 @@ IN_Controller_Shutdown(qboolean notify_user)
joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0;
gyro_yaw = gyro_pitch = 0;
#ifndef NATIVE_SDL_GYRO
#ifdef NO_SDL_GYRO
if (imu_joystick)
{
SDL_JoystickClose(imu_joystick);
@ -2331,8 +2482,11 @@ IN_GetClipboardText(char *out, size_t n)
SDL_free(s);
}
/* Copy string s to the clipboard.
Returns 0 on success, 1 otherwise.
*/
int
IN_SetClipboardText(const char *s)
{
return SDL_SetClipboardText(s);
return SDL_SetClipboardText(s) != 0;
}

View file

@ -35,6 +35,7 @@
*/
#include <SDL3/SDL.h>
#include <limits.h>
#include "SDL3/SDL_gamepad.h"
#include "SDL3/SDL_properties.h"
@ -81,7 +82,7 @@ typedef enum
// IN_Update() called at the beginning of a frame to the
// actual movement functions called at a later time.
static float mouse_x, mouse_y;
static unsigned char sdl_back_button = SDL_GAMEPAD_BUTTON_START;
static unsigned char joy_escbutton = SDL_GAMEPAD_BUTTON_START;
static int joystick_left_x, joystick_left_y, joystick_right_x, joystick_right_y;
static float gyro_yaw, gyro_pitch;
static qboolean mlooking;
@ -94,6 +95,12 @@ int sys_frame_time;
// is pressed
qboolean joy_altselector_pressed = false;
// Gamepad labels' style (Xbox, Playstation, etc.) in use, normally set after detection
gamepad_labels_t joy_current_lbls = LBL_SDL;
// Using japanese style for confirm & cancel buttons on gamepad
qboolean japanese_confirm = false;
// Console Variables
cvar_t *freelook;
cvar_t *lookstrafe;
@ -137,6 +144,12 @@ static int last_haptic_effect_size = HAPTIC_EFFECT_LIST_SIZE;
static int last_haptic_effect_pos = 0;
static haptic_effects_cache_t last_haptic_effect[HAPTIC_EFFECT_LIST_SIZE];
// Gamepad labels' style (Xbox, Playstation, etc.) requested by user
static cvar_t *joy_labels;
// Gamepad style for confirm and cancel buttons (traditional or japanese)
static cvar_t *joy_confirm;
// Joystick sensitivity
static cvar_t *joy_yawsensitivity;
static cvar_t *joy_pitchsensitivity;
@ -175,8 +188,17 @@ static float gyro_accum[3];
static cvar_t *gyro_calibration_x;
static cvar_t *gyro_calibration_y;
static cvar_t *gyro_calibration_z;
// If "SDL gyro" is not explicitly disabled, use SDL_EVENT_GAMEPAD_SENSOR_UPDATE to read gyro
#ifndef NO_SDL_GYRO
static unsigned int num_samples;
#define NATIVE_SDL_GYRO // uses SDL_EVENT_GAMEPAD_SENSOR_UPDATE to read gyro
#else // otherwise, gyro can be read as a "secondary joystick" exposed by dkms-hid-nintendo
static unsigned int num_samples[3];
static SDL_Joystick *imu_joystick = NULL; // gyro "joystick"
#define IMU_JOY_AXIS_GYRO_ROLL 3
#define IMU_JOY_AXIS_GYRO_PITCH 4
#define IMU_JOY_AXIS_GYRO_YAW 5
#endif
// To ignore SDL_EVENT_JOYSTICK_ADDED at game init. Allows for hot plugging of gamepad afterwards.
static qboolean first_init = true;
@ -495,16 +517,108 @@ IN_TranslateScancodeToQ2Key(SDL_Scancode sc)
static void IN_Controller_Init(qboolean notify_user);
static void IN_Controller_Shutdown(qboolean notify_user);
/*
* Sets the gamepad buttons' style of labels (SDL, Xbox, PS, Switch).
* They are only visible in the gamepad binding options.
* Traditional binding uses SDL style, no matter the gamepad.
*/
static void
IN_GamepadLabels_Changed(void)
{
const int requested = (int)joy_labels->value;
joy_labels->modified = false;
joy_current_lbls = LBL_SDL;
if (requested < 0 && controller) // try to autodetect...
{
switch (SDL_GetGamepadType(controller))
{
case SDL_GAMEPAD_TYPE_XBOX360:
case SDL_GAMEPAD_TYPE_XBOXONE:
joy_current_lbls = LBL_XBOX;
return;
case SDL_GAMEPAD_TYPE_PS3:
case SDL_GAMEPAD_TYPE_PS4:
case SDL_GAMEPAD_TYPE_PS5:
joy_current_lbls = LBL_PLAYSTATION;
return;
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO:
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
joy_current_lbls = LBL_SWITCH;
default:
return;
}
}
else if (requested >= LBL_SDL && requested < LBL_MAX_COUNT)
{
joy_current_lbls = (gamepad_labels_t)requested;
}
}
/*
* Sets which gamepad button works as "confirm", and which
* works as "cancel", in menus.
*/
static void
IN_GamepadConfirm_Changed(void)
{
const int requested = (int)joy_confirm->value;
japanese_confirm = false;
joy_confirm->modified = false;
if (requested < 0 && controller) // try to autodetect...
{
switch (SDL_GetGamepadType(controller))
{
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO:
case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
japanese_confirm = true;
default:
return;
}
}
else if (requested == 1)
{
japanese_confirm = true;
}
}
static void
IN_GyroMode_Changed(void)
{
if (gyro_mode->value < 2)
{
gyro_active = false;
}
else
{
gyro_active = true;
}
gyro_mode->modified = false;
}
static void
IN_VirtualKeyEvent(int keynum, qboolean *state_store, qboolean new_state)
{
if (new_state != *state_store)
{
*state_store = new_state;
Key_Event(keynum, *state_store, true);
}
}
qboolean IN_NumpadIsOn()
{
SDL_Keymod mod = SDL_GetModState();
SDL_Keymod mod = SDL_GetModState();
if ((mod & SDL_KMOD_NUM) == SDL_KMOD_NUM)
{
return true;
}
if ((mod & SDL_KMOD_NUM) == SDL_KMOD_NUM)
{
return true;
}
return false;
return false;
}
/* ------------------------------------------------------------------ */
@ -523,6 +637,7 @@ IN_Update(void)
static qboolean left_trigger = false;
static qboolean right_trigger = false;
static qboolean left_stick[4] = {false, false, false, false}; // left, right, up, down virtual keys
static int consoleKeyCode = 0;
@ -594,7 +709,7 @@ IN_Update(void)
/* workaround for AZERTY-keyboards, which don't have 1, 2, ..., 9, 0 in first row:
* always map those physical keys (scancodes) to those keycodes anyway
* see also https://bugzilla.libsdl.org/show_bug.cgi?id=3188 */
SDL_Scancode sc = event.key.keysym.scancode;
SDL_Scancode sc = event.key.scancode;
if (sc >= SDL_SCANCODE_1 && sc <= SDL_SCANCODE_0)
{
@ -612,14 +727,14 @@ IN_Update(void)
}
else
{
SDL_Keycode kc = event.key.keysym.sym;
SDL_Keycode kc = event.key.key;
if(sc == SDL_SCANCODE_GRAVE && kc != '\'' && kc != '"')
{
// special case/hack: open the console with the "console key"
// (beneath Esc, left of 1, above Tab)
// but not if the keycode for this is a quote (like on Brazilian
// keyboards) - otherwise you couldn't type them in the console
if((event.key.keysym.mod & (SDL_KMOD_CAPS|SDL_KMOD_SHIFT|SDL_KMOD_ALT|SDL_KMOD_CTRL|SDL_KMOD_GUI)) == 0)
if((event.key.mod & (SDL_KMOD_CAPS|SDL_KMOD_SHIFT|SDL_KMOD_ALT|SDL_KMOD_CTRL|SDL_KMOD_GUI)) == 0)
{
// also, only do this if no modifiers like shift or AltGr or whatever are pressed
// so kc will most likely be the ascii char generated by this and can be ignored
@ -724,8 +839,8 @@ IN_Update(void)
qboolean down = (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
unsigned char btn = event.gbutton.button;
// Handle Back Button, to override its original key
Key_Event( (btn == sdl_back_button)? K_JOY_BACK : K_BTN_A + btn,
// Handle Esc button first, to override its original key
Key_Event( (btn == joy_escbutton)? K_ESCAPE : K_JOY_FIRST_BTN + btn,
down, true );
break;
}
@ -737,26 +852,12 @@ IN_Update(void)
switch (event.gaxis.axis)
{
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER :
{
qboolean new_left_trigger = axis_value > 8192;
if (new_left_trigger != left_trigger)
{
left_trigger = new_left_trigger;
Key_Event(K_TRIG_LEFT, left_trigger, true);
}
IN_VirtualKeyEvent(K_TRIG_LEFT, &left_trigger, axis_value > 8192);
break;
}
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER :
{
qboolean new_right_trigger = axis_value > 8192;
if (new_right_trigger != right_trigger)
{
right_trigger = new_right_trigger;
Key_Event(K_TRIG_RIGHT, right_trigger, true);
}
IN_VirtualKeyEvent(K_TRIG_RIGHT, &right_trigger, axis_value > 8192);
break;
}
}
if (!cl_paused->value && cls.key_dest == key_game)
@ -776,11 +877,29 @@ IN_Update(void)
joystick_right_y = axis_value;
break;
}
break;
}
// Virtual keys to navigate menus with left stick
if (cls.key_dest == key_menu)
{
switch (event.gaxis.axis)
{
case SDL_GAMEPAD_AXIS_LEFTX :
IN_VirtualKeyEvent(K_LEFTARROW, &left_stick[0], axis_value < -16896);
IN_VirtualKeyEvent(K_RIGHTARROW, &left_stick[1], axis_value > 16896);
break;
case SDL_GAMEPAD_AXIS_LEFTY :
IN_VirtualKeyEvent(K_UPARROW, &left_stick[2], axis_value < -16896);
IN_VirtualKeyEvent(K_DOWNARROW, &left_stick[3], axis_value > 16896);
break;
}
}
break;
}
#ifdef NATIVE_SDL_GYRO // controller sensors' reading supported (gyro, accelerometer)
#ifndef NO_SDL_GYRO // gamepad sensors' reading is supported (gyro, accelerometer)
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE :
if (event.gsensor.sensor != SDL_SENSOR_GYRO)
{
@ -795,11 +914,11 @@ IN_Update(void)
break;
}
#else // gyro read as "secondary joystick"
#else // gyro read from a "secondary joystick" (usually with name ending in "IMU")
case SDL_EVENT_JOYSTICK_AXIS_MOTION :
if ( !imu_joystick || event.gdevice.which != SDL_GetJoystickInstanceID(imu_joystick) )
if ( !imu_joystick || event.gdevice.which != SDL_GetJoystickID(imu_joystick) )
{
break; // controller axes handled by SDL_CONTROLLERAXISMOTION
break; // gamepad axes handled by SDL_EVENT_GAMEPAD_AXIS_MOTION
}
int axis_value = event.gaxis.value;
@ -822,12 +941,11 @@ IN_Update(void)
break;
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
if (gyro_active && gyro_mode->value &&
!cl_paused->value && cls.key_dest == key_game)
if (gyro_active && !cl_paused->value && cls.key_dest == key_game)
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
if (!gyro_turning_axis->value)
{
gyro_yaw = event.gsensor.data[1] - gyro_calibration_y->value; // yaw
@ -838,7 +956,7 @@ IN_Update(void)
}
gyro_pitch = event.gsensor.data[0] - gyro_calibration_x->value;
#else // old "joystick" gyro
switch (event.gaxis.axis) // inside "case SDL_JOYAXISMOTION" here
switch (event.gaxis.axis) // inside "case SDL_EVENT_JOYSTICK_AXIS_MOTION" here
{
case IMU_JOY_AXIS_GYRO_PITCH:
gyro_pitch = -(axis_value - gyro_calibration_x->value);
@ -855,7 +973,7 @@ IN_Update(void)
gyro_yaw = axis_value - gyro_calibration_z->value;
}
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
}
else
{
@ -864,7 +982,7 @@ IN_Update(void)
break;
case SDL_EVENT_GAMEPAD_REMOVED :
if (controller && event.gdevice.which == SDL_GetJoystickInstanceID(SDL_GetGamepadJoystick(controller))) {
if (controller && event.gdevice.which == SDL_GetJoystickID(SDL_GetGamepadJoystick(controller))) {
Cvar_SetValue("paused", 1);
IN_Controller_Shutdown(true);
IN_Controller_Init(false);
@ -881,7 +999,7 @@ IN_Update(void)
break;
case SDL_EVENT_JOYSTICK_BATTERY_UPDATED :
if (!controller || event.jbattery.which != SDL_GetJoystickInstanceID(SDL_GetGamepadJoystick(controller)))
if (!controller || event.jbattery.which != SDL_GetJoystickID(SDL_GetGamepadJoystick(controller)))
{
break;
}
@ -945,7 +1063,7 @@ IN_Update(void)
case REASON_GYROCALIBRATION: // finish and save calibration
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
const float inverseSamples = 1.f / num_samples;
Cvar_SetValue("gyro_calibration_x", gyro_accum[0] * inverseSamples);
Cvar_SetValue("gyro_calibration_y", gyro_accum[1] * inverseSamples);
@ -974,6 +1092,20 @@ IN_Update(void)
countdown_reason = REASON_NONE;
}
}
// Gamepad labels' type and "confirm & cancel style" change handling
if (joy_labels->modified)
{
IN_GamepadLabels_Changed();
}
if (joy_confirm->modified)
{
IN_GamepadConfirm_Changed();
}
if (gyro_mode->modified)
{
IN_GyroMode_Changed();
}
}
/*
@ -1070,7 +1202,11 @@ IN_TightenInput(float yaw, float pitch)
{
thumbstick_t input = { yaw, pitch };
const float magnitude = IN_StickMagnitude(input);
#ifndef NO_SDL_GYRO
const float threshold = (M_PI / 180.0f) * gyro_tightening->value;
#else
const float threshold = (2560.0f / 180.0f) * gyro_tightening->value;
#endif
if (magnitude < threshold)
{
@ -1162,7 +1298,7 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone)
// Flicking begins now, with a new target
is_flicking = true;
flick_progress = 0.0f;
started_flick = cls.realtime;
started_flick = sys_frame_time;
target_angle = stick_angle;
IN_ResetSmoothSamples();
}
@ -1354,7 +1490,7 @@ IN_Move(usercmd_t *cmd)
//
// For movement this is not needed, as those are absolute values independent of framerate
float joyViewFactor = cls.rframetime/0.01666f;
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
float gyroViewFactor = (1.0f / M_PI) * joyViewFactor;
#else
float gyroViewFactor = (1.0f / 2560.0f) * joyViewFactor; // normalized for Switch gyro
@ -1406,7 +1542,7 @@ IN_Move(usercmd_t *cmd)
// Flick Stick: flick in progress, changing the yaw angle to the target progressively
if (flick_progress < 1.0f)
{
float cur_progress = (float)(cls.realtime - started_flick) / FLICK_TIME;
float cur_progress = (float)(sys_frame_time - started_flick) / FLICK_TIME;
if (cur_progress > 1.0f)
{
@ -2006,7 +2142,7 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
// Com_Printf("%-29s: vol %5u - %4u ms - dp %.3f l %5.0f h %5.0f\n",
// name, effect_volume, duration, dist_prop, low_freq, hi_freq);
if (SDL_RumbleGamepad(controller, low_freq, hi_freq, duration) == -1)
if (!SDL_RumbleGamepad(controller, low_freq, hi_freq, duration))
{
if (!joystick_haptic)
{
@ -2025,7 +2161,7 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
void
StartCalibration(void)
{
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
num_samples = 0;
#else
num_samples[0] = num_samples[1] = num_samples[2] = 0;
@ -2053,21 +2189,21 @@ IN_Controller_Init(qboolean notify_user)
int nummappings;
char controllerdb[MAX_OSPATH] = {0};
SDL_Joystick *joystick = NULL;
SDL_bool is_controller = SDL_FALSE;
bool is_controller = false;
cvar = Cvar_Get("in_sdlbackbutton", "1", CVAR_ARCHIVE);
cvar = Cvar_Get("joy_escbutton", "0", CVAR_ARCHIVE);
if (cvar)
{
switch ((int)cvar->value)
{
case 0:
sdl_back_button = SDL_GAMEPAD_BUTTON_BACK;
case 1:
joy_escbutton = SDL_GAMEPAD_BUTTON_BACK;
break;
case 2:
sdl_back_button = SDL_GAMEPAD_BUTTON_GUIDE;
joy_escbutton = SDL_GAMEPAD_BUTTON_GUIDE;
break;
default:
sdl_back_button = SDL_GAMEPAD_BUTTON_START;
joy_escbutton = SDL_GAMEPAD_BUTTON_START;
}
}
@ -2084,15 +2220,7 @@ IN_Controller_Init(qboolean notify_user)
if (!SDL_WasInit(SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC))
{
#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE // extended input reports on PS controllers (enables gyro thru bluetooth)
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1" );
#endif
#ifdef SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1" );
#endif
if (SDL_Init(SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC) == -1)
if (!SDL_Init(SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC))
{
Com_Printf ("Couldn't init SDL Gamepad: %s.\n", SDL_GetError());
return;
@ -2126,6 +2254,8 @@ IN_Controller_Init(qboolean notify_user)
show_haptic = true;
}
SDL_free((void *)joysticks);
return;
}
@ -2152,27 +2282,36 @@ IN_Controller_Init(qboolean notify_user)
Com_Printf ("Trying joystick %d, '%s'\n", i+1, joystick_name);
// Ugly hack to detect IMU-only devices - works for Switch controllers at least
if (name_len > 4 && !strncmp(joystick_name + name_len - 4, " IMU", 4))
if ( name_len > 6 && strstr(joystick_name + name_len - 6, "IMU") )
{
#ifndef NO_SDL_GYRO
SDL_CloseJoystick(joystick);
joystick = NULL;
#ifdef NATIVE_SDL_GYRO
Com_Printf ("Skipping IMU device.\n");
#else // if it's not a Left JoyCon, use it as Gyro
Com_Printf ("IMU device found.\n");
if ( !imu_joystick && name_len > 16 && strncmp(joystick_name + name_len - 16, "Left Joy-Con IMU", 16) != 0 )
qboolean using_imu = !imu_joystick && !( strstr(joystick_name, "Joy-Con") && strstr(joystick_name, "L") );
Com_Printf ("IMU device found... ");
SDL_CloseJoystick(joystick);
joystick = NULL;
if (using_imu)
{
imu_joystick = SDL_OpenJoystick(joysticks[i]);
if (imu_joystick)
{
show_gyro = true;
Com_Printf ("Using this device as Gyro sensor.\n");
Com_Printf ("using it as Gyro sensor.\n");
}
else
{
Com_Printf ("Couldn't open IMU: %s.\n", SDL_GetError());
Com_Printf ("\nCouldn't open IMU: %s.\n", SDL_GetError());
}
}
else
{
Com_Printf ("skipping.\n");
}
#endif
continue;
}
@ -2184,9 +2323,9 @@ IN_Controller_Init(qboolean notify_user)
if (!is_controller)
{
char joystick_guid[65] = {0};
SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID(joysticks[i]);
SDL_GUID guid = SDL_GetJoystickGUIDForID(joysticks[i]);
SDL_GetJoystickGUIDString(guid, joystick_guid, 64);
SDL_GUIDToString(guid, joystick_guid, 64);
Com_Printf ("To identify joystick as Gamepad, provide its config by either:\n"
" * Putting 'gamecontrollerdb.txt' file in your game directory.\n"
@ -2210,10 +2349,10 @@ IN_Controller_Init(qboolean notify_user)
Com_Printf("Enabled as Gamepad, settings:\n%s\n",
SDL_GetGamepadMapping(controller));
#ifdef NATIVE_SDL_GYRO
#ifndef NO_SDL_GYRO
if (SDL_GamepadHasSensor(controller, SDL_SENSOR_GYRO)
&& !SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE) )
&& SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, true) )
{
show_gyro = true;
Com_Printf( "Gyro sensor enabled at %.2f Hz\n",
@ -2224,13 +2363,13 @@ IN_Controller_Init(qboolean notify_user)
Com_Printf("Gyro sensor not found.\n");
}
SDL_bool hasLED = SDL_GetBooleanProperty(SDL_GetGamepadProperties(controller), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, SDL_FALSE);
bool hasLED = SDL_GetBooleanProperty(SDL_GetGamepadProperties(controller), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, false);
if (hasLED)
{
SDL_SetGamepadLED(controller, 0, 80, 0); // green light
}
#endif // NATIVE_SDL_GYRO
#endif // !NO_SDL_GYRO
joystick_haptic = SDL_OpenHapticFromJoystick(SDL_GetGamepadJoystick(controller));
@ -2248,7 +2387,7 @@ IN_Controller_Init(qboolean notify_user)
show_haptic = true;
}
SDL_bool hasRumble = SDL_GetBooleanProperty(SDL_GetGamepadProperties(controller), SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, SDL_FALSE);
bool hasRumble = SDL_GetBooleanProperty(SDL_GetGamepadProperties(controller), SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false);
if (hasRumble)
{
show_haptic = true;
@ -2259,13 +2398,16 @@ IN_Controller_Init(qboolean notify_user)
Com_Printf("Gamepad doesn't support rumble.\n");
}
#ifdef NATIVE_SDL_GYRO // "native" exits when finding a single working controller
#ifndef NO_SDL_GYRO // "native SDL gyro" exits when finding a single working gamepad
break;
#endif
}
}
SDL_free((void *)joysticks);
IN_GamepadLabels_Changed();
IN_GamepadConfirm_Changed();
IN_GyroMode_Changed();
}
/*
@ -2296,11 +2438,13 @@ IN_Init(void)
joy_haptic_distance = Cvar_Get("joy_haptic_distance", "100.0", CVAR_ARCHIVE);
haptic_feedback_filter = Cvar_Get("joy_haptic_filter", default_haptic_filter, CVAR_ARCHIVE);
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "1.0", CVAR_ARCHIVE);
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE);
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "2.5", CVAR_ARCHIVE);
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "2.5", CVAR_ARCHIVE);
joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "1.0", CVAR_ARCHIVE);
joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "1.0", CVAR_ARCHIVE);
joy_labels = Cvar_Get("joy_labels", "-1", CVAR_ARCHIVE);
joy_confirm = Cvar_Get("joy_confirm", "-1", CVAR_ARCHIVE);
joy_layout = Cvar_Get("joy_layout", "0", CVAR_ARCHIVE);
joy_left_expo = Cvar_Get("joy_left_expo", "2.0", CVAR_ARCHIVE);
joy_left_snapaxis = Cvar_Get("joy_left_snapaxis", "0.15", CVAR_ARCHIVE);
@ -2315,16 +2459,11 @@ IN_Init(void)
gyro_calibration_y = Cvar_Get("gyro_calibration_y", "0.0", CVAR_ARCHIVE);
gyro_calibration_z = Cvar_Get("gyro_calibration_z", "0.0", CVAR_ARCHIVE);
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "1.0", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "1.0", CVAR_ARCHIVE);
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "2.5", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "2.5", CVAR_ARCHIVE);
gyro_tightening = Cvar_Get("gyro_tightening", "3.5", CVAR_ARCHIVE);
gyro_turning_axis = Cvar_Get("gyro_turning_axis", "0", CVAR_ARCHIVE);
gyro_mode = Cvar_Get("gyro_mode", "2", CVAR_ARCHIVE);
if ((int)gyro_mode->value == 2)
{
gyro_active = true;
}
windowed_pauseonfocuslost = Cvar_Get("vid_pauseonfocuslost", "0", CVAR_USERINFO | CVAR_ARCHIVE);
windowed_mouse = Cvar_Get("windowed_mouse", "1", CVAR_USERINFO | CVAR_ARCHIVE);
@ -2345,8 +2484,6 @@ IN_Init(void)
}
}
SDL_StartTextInput();
IN_Controller_Init(false);
Com_Printf("------------------------------------\n\n");
@ -2386,7 +2523,7 @@ IN_Controller_Shutdown(qboolean notify_user)
joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0;
gyro_yaw = gyro_pitch = 0;
#ifndef NATIVE_SDL_GYRO
#ifdef NO_SDL_GYRO
if (imu_joystick)
{
SDL_CloseJoystick(imu_joystick);
@ -2439,8 +2576,13 @@ IN_GetClipboardText(char *out, size_t n)
SDL_free(s);
}
/* Copy string s to the clipboard.
Returns 0 on success, 1 otherwise.
*/
int
IN_SetClipboardText(const char *s)
{
return SDL_SetClipboardText(s);
bool res = SDL_SetClipboardText(s);
return !res;
}

View file

@ -91,6 +91,7 @@ typedef struct
menucommon_s generic;
char * focuspic;
char * errorpic;
char * alttext;
int width;
int height;
} menubitmap_s;
@ -103,7 +104,6 @@ typedef struct
int cursor;
int length;
int visible_length;
int visible_offset;
} menufield_s;
typedef struct
@ -139,6 +139,7 @@ typedef struct
void M_PushMenu(menuframework_s* menu);
void Field_ResetCursor(menuframework_s *m);
qboolean Field_Key(menufield_s *field, int key);
void Menu_AddItem(menuframework_s *menu, void *item);

View file

@ -257,6 +257,8 @@ M_PushMenu(menuframework_s* menu)
cls.key_dest = key_menu;
}
extern qboolean japanese_confirm;
int
Key_GetMenuKey(int key)
{
@ -297,24 +299,27 @@ Key_GetMenuKey(int key)
case K_KP_ENTER:
case K_ENTER:
case K_BTN_A:
return K_ENTER;
case K_ESCAPE:
case K_JOY_BACK:
case K_BTN_B:
return K_ESCAPE;
case K_BACKSPACE:
case K_DEL:
case K_KP_DEL:
if (IN_NumpadIsOn() == true) { break; }
case K_BTN_Y:
case K_BACKSPACE:
case K_DEL:
case K_BTN_NORTH:
return K_BACKSPACE;
case K_KP_INS:
if (IN_NumpadIsOn() == true) { break; }
case K_INS:
return K_INS;
case K_BTN_SOUTH:
if (japanese_confirm) return K_ESCAPE;
else return K_ENTER;
case K_BTN_EAST:
if (japanese_confirm) return K_ENTER;
else return K_ESCAPE;
}
return key;
@ -328,16 +333,13 @@ Default_MenuKey(menuframework_s *m, int key)
if (m)
{
menucommon_s *item;
menucommon_s *item = Menu_ItemAtCursor(m);
if ((item = Menu_ItemAtCursor(m)) != 0)
if (item && item->type == MTYPE_FIELD)
{
if (item->type == MTYPE_FIELD)
if (Field_Key((menufield_s *)item, key))
{
if (Field_Key((menufield_s *)item, key))
{
return NULL;
}
return NULL;
}
}
}
@ -345,12 +347,19 @@ Default_MenuKey(menuframework_s *m, int key)
switch (menu_key)
{
case K_ESCAPE:
if (m)
{
Field_ResetCursor(m);
}
M_PopMenu();
return menu_out_sound;
case K_UPARROW:
if (m)
{
Field_ResetCursor(m);
m->cursor--;
Menu_AdjustCursor(m, -1);
sound = menu_move_sound;
@ -360,6 +369,8 @@ Default_MenuKey(menuframework_s *m, int key)
case K_DOWNARROW:
if (m)
{
Field_ResetCursor(m);
m->cursor++;
Menu_AdjustCursor(m, 1);
sound = menu_move_sound;
@ -456,7 +467,7 @@ M_DrawCursor(int x, int y, int f)
}
Com_sprintf(cursorname, sizeof(cursorname), "m_cursor%d", f);
Draw_PicScaled(x * scale, y * scale, cursorname, scale);
Draw_PicScaledAltText(x * scale, y * scale, cursorname, scale, "*");
}
static void
@ -659,6 +670,7 @@ InitMainMenu(void)
s_plaque.generic.name = "m_main_plaque";
s_plaque.generic.callback = 0;
s_plaque.focuspic = 0;
s_plaque.alttext = NULL;
s_logo.generic.type = MTYPE_BITMAP;
s_logo.generic.flags = QMF_LEFT_JUSTIFY | QMF_INACTIVE;
@ -667,6 +679,7 @@ InitMainMenu(void)
s_logo.generic.name = "m_main_logo";
s_logo.generic.callback = 0;
s_logo.focuspic = 0;
s_logo.alttext = NULL;
y += 10;
@ -677,6 +690,7 @@ InitMainMenu(void)
s_game.generic.name = "m_main_game";
s_game.generic.callback = GameFunc;
s_game.focuspic = "m_main_game_sel";
s_game.alttext = "Game";
Draw_GetPicSize(&w, &h, ( char * )s_game.generic.name);
y += h + 8;
@ -688,6 +702,7 @@ InitMainMenu(void)
s_multiplayer.generic.name = "m_main_multiplayer";
s_multiplayer.generic.callback = MultiplayerFunc;
s_multiplayer.focuspic = "m_main_multiplayer_sel";
s_multiplayer.alttext = "Multiplayer";
Draw_GetPicSize(&w, &h, ( char * )s_multiplayer.generic.name);
y += h + 8;
@ -699,6 +714,7 @@ InitMainMenu(void)
s_options.generic.name = "m_main_options";
s_options.generic.callback = OptionsFunc;
s_options.focuspic = "m_main_options_sel";
s_options.alttext = "Options";
Draw_GetPicSize(&w, &h, ( char * )s_options.generic.name);
y += h + 8;
@ -710,6 +726,7 @@ InitMainMenu(void)
s_video.generic.name = "m_main_video";
s_video.generic.callback = VideoFunc;
s_video.focuspic = "m_main_video_sel";
s_video.alttext = "Video";
Draw_GetPicSize(&w, &h, ( char * )s_video.generic.name);
y += h + 8;
@ -721,6 +738,7 @@ InitMainMenu(void)
s_quit.generic.name = "m_main_quit";
s_quit.generic.callback = QuitFunc;
s_quit.focuspic = "m_main_quit_sel";
s_quit.alttext = "Quit";
Menu_AddItem(&s_main, (void *)&s_plaque);
Menu_AddItem(&s_main, (void *)&s_logo);
@ -754,7 +772,7 @@ M_Main_Draw(void)
( int )(cls.realtime / 100) % NUM_CURSOR_FRAMES);
}
const char *
static const char *
M_Main_Key(int key)
{
return Default_MenuKey(&s_main, key);
@ -941,14 +959,14 @@ M_UnbindCommand(char *command, int scope)
switch (scope)
{
case KEYS_KEYBOARD_MOUSE:
end = K_JOY_FIRST_REGULAR;
end = K_JOY_FIRST_BTN;
break;
case KEYS_CONTROLLER:
begin = K_JOY_FIRST_REGULAR;
end = K_JOY_LAST_REGULAR + 1;
begin = K_JOY_FIRST_BTN;
end = K_JOY_FIRST_BTN_ALT;
break;
case KEYS_CONTROLLER_ALT:
begin = K_JOY_FIRST_REGULAR_ALT;
begin = K_JOY_FIRST_BTN_ALT;
}
for (j = begin; j < end; j++)
@ -977,14 +995,14 @@ M_FindKeysForCommand(char *command, int *twokeys, int scope)
switch (scope)
{
case KEYS_KEYBOARD_MOUSE:
end = K_JOY_FIRST_REGULAR;
end = K_JOY_FIRST_BTN;
break;
case KEYS_CONTROLLER:
begin = K_JOY_FIRST_REGULAR;
end = K_JOY_LAST_REGULAR + 1;
begin = K_JOY_FIRST_BTN;
end = K_JOY_FIRST_BTN_ALT;
break;
case KEYS_CONTROLLER_ALT:
begin = K_JOY_FIRST_REGULAR_ALT;
begin = K_JOY_FIRST_BTN_ALT;
}
twokeys[0] = twokeys[1] = -1;
@ -1125,7 +1143,7 @@ Keys_MenuKey(int key)
if (menukeyitem_bind)
{
// Any key/button except from the game controller and escape keys
if ((key != K_ESCAPE) && (key != '`') && (key < K_JOY_FIRST_REGULAR))
if ((key != K_ESCAPE) && (key != '`') && (key < K_JOY_FIRST_BTN))
{
char cmd[1024];
@ -1278,7 +1296,7 @@ MultiplayerKeys_MenuKey(int key)
if (menukeyitem_bind)
{
// Any key/button but the escape ones
if ((key != K_ESCAPE) && (key != '`') && (key != K_JOY_BACK))
if ((key != K_ESCAPE) && (key != '`'))
{
char cmd[1024];
@ -1320,6 +1338,30 @@ M_Menu_Multiplayer_Keys_f(void)
* GAME CONTROLLER ( GAMEPAD / JOYSTICK ) BUTTONS MENU
*/
static void
GamepadMenu_StatusPrompt(menuframework_s *m)
{
static char m_gamepadbind_statusbar[64];
int btn_confirm, btn_cancel;
if (japanese_confirm)
{
btn_confirm = K_BTN_EAST;
btn_cancel = K_BTN_SOUTH;
}
else
{
btn_confirm = K_BTN_SOUTH;
btn_cancel = K_BTN_EAST;
}
snprintf(m_gamepadbind_statusbar, 64, "%s assigns, %s clears, %s exits",
Key_KeynumToString_Joy(btn_confirm), Key_KeynumToString_Joy(K_BTN_NORTH),
Key_KeynumToString_Joy(btn_cancel));
Menu_SetStatusBar(m, m_gamepadbind_statusbar);
}
char *controller_bindnames[][2] =
{
{"+attack", "attack"},
@ -1327,12 +1369,20 @@ char *controller_bindnames[][2] =
{"+movedown", "down / crouch"},
{"weapnext", "next weapon"},
{"weapprev", "previous weapon"},
{"cycleweap weapon_chaingun weapon_machinegun weapon_blaster", "long range: quickswitch 1"},
{"cycleweap weapon_supershotgun weapon_shotgun", "close range: quickswitch 2"},
{"cycleweap weapon_rocketlauncher weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"},
{"cycleweap weapon_bfg weapon_railgun weapon_hyperblaster", "special: quickswitch 4"},
{"prefweap weapon_railgun weapon_hyperblaster weapon_chaingun weapon_supershotgun weapon_machinegun weapon_shotgun weapon_blaster", "best safe weapon"},
{"prefweap weapon_bfg weapon_railgun weapon_rocketlauncher weapon_hyperblaster weapon_grenadelauncher weapon_chaingun ammo_grenades weapon_supershotgun", "best unsafe weapon"},
{"cycleweap weapon_plasmabeam weapon_boomer weapon_chaingun weapon_etf_rifle"
" weapon_machinegun weapon_blaster", "long range: quickswitch 1"},
{"cycleweap weapon_supershotgun weapon_shotgun weapon_chainfist",
"close range: quickswitch 2"},
{"cycleweap weapon_phalanx weapon_rocketlauncher weapon_proxlauncher"
" weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"},
{"cycleweap weapon_bfg weapon_disintegrator weapon_railgun weapon_hyperblaster"
" ammo_tesla ammo_trap", "special: quickswitch 4"},
{"prefweap weapon_railgun weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_chaingun"
" weapon_supershotgun weapon_etf_rifle weapon_machinegun weapon_shotgun weapon_blaster",
"best safe weapon"},
{"prefweap weapon_bfg weapon_disintegrator weapon_phalanx weapon_railgun weapon_rocketlauncher"
" weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_grenadelauncher weapon_chaingun"
" weapon_proxlauncher ammo_grenades weapon_supershotgun", "best unsafe weapon"},
{"centerview", "center view"},
{"inven", "inventory"},
{"invuse", "use item"},
@ -1367,7 +1417,7 @@ DrawControllerButtonBindingFunc(void *self)
int x;
const char *name;
name = Key_KeynumToString(keys[0]);
name = Key_KeynumToString_Joy(keys[0]);
Menu_DrawString(a->generic.x + a->generic.parent->x + RCOLUMN_OFFSET * scale,
a->generic.y + a->generic.parent->y, name);
@ -1380,7 +1430,7 @@ DrawControllerButtonBindingFunc(void *self)
a->generic.y + a->generic.parent->y, "or");
Menu_DrawString(a->generic.x + a->generic.parent->x + 48 * scale + (x * scale),
a->generic.y + a->generic.parent->y,
Key_KeynumToString(keys[1]));
Key_KeynumToString_Joy(keys[1]));
}
}
}
@ -1425,7 +1475,7 @@ ControllerButtons_MenuInit(void)
Menu_AddItem(&s_controller_buttons_menu, (void *)&s_controller_buttons_actions[i]);
}
Menu_SetStatusBar(&s_controller_buttons_menu, "BTN_A assigns, BTN_Y clears, BTN_B exits");
GamepadMenu_StatusPrompt(&s_controller_buttons_menu);
Menu_Center(&s_controller_buttons_menu);
}
@ -1444,7 +1494,7 @@ ControllerButtons_MenuKey(int key)
if (menukeyitem_bind)
{
// Only controller buttons allowed
if (key >= K_JOY_FIRST_REGULAR && key != K_JOY_BACK)
if (key >= K_JOY_FIRST_BTN)
{
char cmd[1024];
@ -1453,7 +1503,7 @@ ControllerButtons_MenuKey(int key)
Cbuf_InsertText(cmd);
}
Menu_SetStatusBar(&s_controller_buttons_menu, "BTN_A assigns, BTN_Y clears, BTN_B exits");
GamepadMenu_StatusPrompt(&s_controller_buttons_menu);
menukeyitem_bind = false;
return menu_out_sound;
}
@ -1490,12 +1540,20 @@ char *controller_alt_bindnames[][2] =
{
{"weapnext", "next weapon"},
{"weapprev", "previous weapon"},
{"cycleweap weapon_chaingun weapon_machinegun weapon_blaster", "long range: quickswitch 1"},
{"cycleweap weapon_supershotgun weapon_shotgun", "close range: quickswitch 2"},
{"cycleweap weapon_rocketlauncher weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"},
{"cycleweap weapon_bfg weapon_railgun weapon_hyperblaster", "special: quickswitch 4"},
{"prefweap weapon_railgun weapon_hyperblaster weapon_chaingun weapon_supershotgun weapon_machinegun weapon_shotgun weapon_blaster", "best safe weapon"},
{"prefweap weapon_bfg weapon_railgun weapon_rocketlauncher weapon_hyperblaster weapon_grenadelauncher weapon_chaingun ammo_grenades weapon_supershotgun", "best unsafe weapon"},
{"cycleweap weapon_plasmabeam weapon_boomer weapon_chaingun weapon_etf_rifle"
" weapon_machinegun weapon_blaster", "long range: quickswitch 1"},
{"cycleweap weapon_supershotgun weapon_shotgun weapon_chainfist",
"close range: quickswitch 2"},
{"cycleweap weapon_phalanx weapon_rocketlauncher weapon_proxlauncher"
" weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"},
{"cycleweap weapon_bfg weapon_disintegrator weapon_railgun weapon_hyperblaster"
" ammo_tesla ammo_trap", "special: quickswitch 4"},
{"prefweap weapon_railgun weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_chaingun"
" weapon_supershotgun weapon_etf_rifle weapon_machinegun weapon_shotgun weapon_blaster",
"best safe weapon"},
{"prefweap weapon_bfg weapon_disintegrator weapon_phalanx weapon_railgun weapon_rocketlauncher"
" weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_grenadelauncher weapon_chaingun"
" weapon_proxlauncher ammo_grenades weapon_supershotgun", "best unsafe weapon"},
{"centerview", "center view"},
{"inven", "inventory"},
{"invuse", "use item"},
@ -1530,10 +1588,10 @@ DrawControllerAltButtonBindingFunc(void *self)
}
else
{
int x;
size_t x;
const char *name;
name = Key_KeynumToString(keys[0]);
name = Key_KeynumToString_Joy(keys[0]);
Menu_DrawString(a->generic.x + a->generic.parent->x + RCOLUMN_OFFSET * scale,
a->generic.y + a->generic.parent->y, name);
@ -1546,7 +1604,7 @@ DrawControllerAltButtonBindingFunc(void *self)
a->generic.y + a->generic.parent->y, "or");
Menu_DrawString(a->generic.x + a->generic.parent->x + 48 * scale + (x * scale),
a->generic.y + a->generic.parent->y,
Key_KeynumToString(keys[1]));
Key_KeynumToString_Joy(keys[1]));
}
}
}
@ -1591,7 +1649,7 @@ ControllerAltButtons_MenuInit(void)
Menu_AddItem(&s_controller_alt_buttons_menu, (void *)&s_controller_alt_buttons_actions[i]);
}
Menu_SetStatusBar(&s_controller_alt_buttons_menu, "BTN_A assigns, BTN_Y clears, BTN_B exits");
GamepadMenu_StatusPrompt(&s_controller_alt_buttons_menu);
Menu_Center(&s_controller_alt_buttons_menu);
}
@ -1610,17 +1668,17 @@ ControllerAltButtons_MenuKey(int key)
if (menukeyitem_bind)
{
// Only controller buttons allowed, different from the alt buttons modifier
if (key >= K_JOY_FIRST_REGULAR && key != K_JOY_BACK && (keybindings[key] == NULL || strcmp(keybindings[key], "+joyaltselector") != 0))
if (key >= K_JOY_FIRST_BTN && (keybindings[key] == NULL || strcmp(keybindings[key], "+joyaltselector") != 0))
{
char cmd[1024];
key = key + (K_JOY_FIRST_REGULAR_ALT - K_JOY_FIRST_REGULAR); // change input to its ALT mode
key = key + (K_JOY_FIRST_BTN_ALT - K_JOY_FIRST_BTN); // change input to its ALT mode
Com_sprintf(cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n",
Key_KeynumToString(key), controller_alt_bindnames[item->generic.localdata[0]][0]);
Cbuf_InsertText(cmd);
}
Menu_SetStatusBar(&s_controller_alt_buttons_menu, "BTN_A assigns, BTN_Y clears, BTN_B exits");
GamepadMenu_StatusPrompt(&s_controller_alt_buttons_menu);
menukeyitem_bind = false;
return menu_out_sound;
}
@ -2221,7 +2279,7 @@ CrosshairFunc(void *unused)
}
static void
PauseFocusFunc()
PauseFocusFunc(void *unused)
{
Cvar_SetValue("vid_pauseonfocuslost", (float)s_options_pauseonfocus_box.curvalue);
}
@ -2255,7 +2313,7 @@ ControlsSetMenuItemValues(void)
{
s_options_oggshuffle_box.curvalue = Cvar_VariableValue("ogg_shuffle");
s_options_oggenable_box.curvalue = (Cvar_VariableValue("ogg_enable") != 0);
s_options_quality_list.curvalue = (Cvar_VariableValue("s_loadas8bit") == 0);
s_options_quality_list.curvalue = (Cvar_VariableValue("s_openal") == 0);
s_options_alwaysrun_box.curvalue = (cl_run->value != 0);
s_options_invertmouse_box.curvalue = (m_pitch->value < 0);
s_options_lookstrafe_box.curvalue = (lookstrafe->value != 0);
@ -2340,18 +2398,9 @@ ConsoleFunc(void *unused)
}
static void
UpdateSoundQualityFunc(void *unused)
UpdateSoundBackendFunc(void *unused)
{
if (s_options_quality_list.curvalue == 0)
{
Cvar_SetValue("s_khz", 22);
Cvar_SetValue("s_loadas8bit", false);
}
else
{
Cvar_SetValue("s_khz", 44);
Cvar_SetValue("s_loadas8bit", false);
}
Cvar_Set("s_openal", (s_options_quality_list.curvalue == 0)? "1":"0" );
m_popup_string = "Restarting the sound system. This\n"
"could take up to a minute, so\n"
@ -2387,9 +2436,9 @@ Options_MenuInit(void)
0
};
static const char *quality_items[] =
static const char *sound_items[] =
{
"normal", "high", 0
"openal", "sdl", 0
};
static const char *yesno_names[] =
@ -2457,9 +2506,9 @@ Options_MenuInit(void)
s_options_quality_list.generic.type = MTYPE_SPINCONTROL;
s_options_quality_list.generic.x = 0;
s_options_quality_list.generic.y = (y += 10);
s_options_quality_list.generic.name = "sound quality";
s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
s_options_quality_list.itemnames = quality_items;
s_options_quality_list.generic.name = "sound backend";
s_options_quality_list.generic.callback = UpdateSoundBackendFunc;
s_options_quality_list.itemnames = sound_items;
s_options_sensitivity_slider.generic.type = MTYPE_SLIDER;
s_options_sensitivity_slider.generic.x = 0;
@ -3114,6 +3163,23 @@ static char mods_statusbar[64];
static char **modnames = NULL;
static int nummods;
void
Mods_NamesFinish(void)
{
if (modnames)
{
int i;
for (i = 0; i < nummods; i ++)
{
free(modnames[i]);
}
free(modnames);
modnames = NULL;
}
}
static void
Mods_NamesInit(void)
{
@ -3364,7 +3430,7 @@ ModsFunc(void *unused)
M_Menu_Mods_f();
}
void
static void
Game_MenuInit(void)
{
Mods_NamesInit();
@ -4195,15 +4261,10 @@ RulesChangeFunc(void *self)
s_maxclients_field.generic.statusbar = NULL;
s_startserver_dmoptions_action.generic.statusbar = NULL;
}
/* Ground Zero game modes */
else if (M_IsGame("rogue"))
else if (s_rules_box.curvalue == 2)
{
if (s_rules_box.curvalue == 2)
{
s_maxclients_field.generic.statusbar = NULL;
s_startserver_dmoptions_action.generic.statusbar = NULL;
}
s_maxclients_field.generic.statusbar = NULL;
s_startserver_dmoptions_action.generic.statusbar = NULL;
}
}
@ -4238,16 +4299,12 @@ StartServerActionFunc(void *self)
Cvar_SetValue("singleplayer", 0);
if ((s_rules_box.curvalue < 2) || M_IsGame("rogue"))
{
Cvar_SetValue("deathmatch", (float)!s_rules_box.curvalue);
Cvar_SetValue("coop", (float)s_rules_box.curvalue);
}
else
{
Cvar_SetValue("deathmatch", 1); /* deathmatch is always true for rogue games */
Cvar_SetValue("coop", 0); /* This works for at least the main game and both addons */
}
/* deathmatch is always true for rogue games */
Cvar_SetValue("deathmatch",
(s_rules_box.curvalue == 3 || s_rules_box.curvalue == 0) ? 1 : 0);
/* This works for at least the main game and both addons */
Cvar_SetValue("coop", s_rules_box.curvalue == 1 ? 1 : 0);
Cvar_SetValue("ctf", s_rules_box.curvalue == 3 ? 1 : 0);
spot = NULL;
@ -4315,16 +4372,11 @@ static void
StartServer_MenuInit(void)
{
static const char *dm_coop_names[] =
{
"deathmatch",
"cooperative",
0
};
static const char *dm_coop_names_rogue[] =
{
"deathmatch",
"cooperative",
"tag",
"ctf",
0
};
@ -4379,7 +4431,7 @@ StartServer_MenuInit(void)
char shortname[MAX_TOKEN_CHARS];
char longname[MAX_TOKEN_CHARS];
char scratch[200];
int j, l;
size_t j, l;
strcpy(shortname, COM_Parse(&s));
l = strlen(shortname);
@ -4434,24 +4486,24 @@ StartServer_MenuInit(void)
s_rules_box.generic.y = 20;
s_rules_box.generic.name = "rules";
/* Ground Zero games only available with rogue game */
if (M_IsGame("rogue"))
{
s_rules_box.itemnames = dm_coop_names_rogue;
}
else
{
s_rules_box.itemnames = dm_coop_names;
}
s_rules_box.itemnames = dm_coop_names;
if (Cvar_VariableValue("coop"))
{
s_rules_box.curvalue = 1;
}
else
else if (Cvar_VariableValue("ctf"))
{
s_rules_box.curvalue = 3;
}
else if (Cvar_VariableValue("deathmatch"))
{
s_rules_box.curvalue = 0;
}
else
{
s_rules_box.curvalue = 2;
}
s_rules_box.generic.callback = RulesChangeFunc;
}
@ -5042,7 +5094,7 @@ DMOptions_MenuDraw(void)
Menu_Draw(&s_dmoptions_menu);
}
const char *
static const char *
DMOptions_MenuKey(int key)
{
return Default_MenuKey(&s_dmoptions_menu, key);
@ -5247,6 +5299,7 @@ AddressBook_MenuInit(void)
for (i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++)
{
menufield_s *f;
const cvar_t *adr;
char buffer[20];
@ -5254,23 +5307,26 @@ AddressBook_MenuInit(void)
adr = Cvar_Get(buffer, "", CVAR_ARCHIVE);
s_addressbook_fields[i].generic.type = MTYPE_FIELD;
s_addressbook_fields[i].generic.name = 0;
s_addressbook_fields[i].generic.callback = 0;
s_addressbook_fields[i].generic.x = 0;
s_addressbook_fields[i].generic.y = i * 18 + 0;
s_addressbook_fields[i].generic.localdata[0] = i;
s_addressbook_fields[i].cursor = 0;
s_addressbook_fields[i].length = 60;
s_addressbook_fields[i].visible_length = 30;
f = &s_addressbook_fields[i];
strcpy(s_addressbook_fields[i].buffer, adr->string);
f->generic.type = MTYPE_FIELD;
f->generic.name = 0;
f->generic.callback = 0;
f->generic.x = 0;
f->generic.y = i * 18 + 0;
f->generic.localdata[0] = i;
Menu_AddItem(&s_addressbook_menu, &s_addressbook_fields[i]);
f->length = 60;
f->visible_length = 30;
Q_strlcpy(f->buffer, adr->string, f->length);
f->cursor = strlen(f->buffer);
Menu_AddItem(&s_addressbook_menu, f);
}
}
const char *
static const char *
AddressBook_MenuKey(int key)
{
if (key == K_ESCAPE)
@ -5395,7 +5451,7 @@ IconOfSkinExists(const char* skin, char** pcxfiles, int npcxfiles,
static void
StripExtension(char* path)
{
int length;
size_t length;
length = strlen(path) - 1;
@ -5678,7 +5734,8 @@ HasSkinsInDir(const char *dirname, int *num)
{
char **list_png, **list_pcx, **list_m8;
char **curr = NULL, **list = NULL;
int num_png, num_pcx, num_m8, dirname_size;
int num_png, num_pcx, num_m8;
size_t dirname_size;
*num = 0;
/* dir name size plus one for skip slash */
@ -5970,7 +6027,8 @@ PlayerConfig_ScanDirectories(void)
return result;
}
void ListModels_f(void)
static void
ListModels_f(void)
{
PlayerConfig_ScanDirectories();
@ -6163,11 +6221,12 @@ extern float CalcFov(float fov_x, float w, float h);
static void
PlayerConfig_AnimateModel(entity_t *entity, int count, int curTime)
{
const cvar_t *cl_start_frame, *cl_end_frame;
const cvar_t *cl_start_frame, *cl_end_frame, *cl_mesh_mask;
int startFrame, endFrame;
cl_start_frame = Cvar_Get("cl_model_preview_start", "84", CVAR_ARCHIVE);
cl_end_frame = Cvar_Get("cl_model_preview_end", "94", CVAR_ARCHIVE);
cl_mesh_mask = Cvar_Get("cl_model_mesh_hide", "0", CVAR_ARCHIVE);
startFrame = cl_start_frame->value;
endFrame = cl_end_frame->value;
@ -6179,6 +6238,8 @@ PlayerConfig_AnimateModel(entity_t *entity, int count, int curTime)
{
/* salute male 84..94 frame */
entity[i].frame = (curTime / 100) % (endFrame - startFrame) + startFrame;
/* hide part of meshes */
entity[i].rr_mesh = cl_mesh_mask->value;
}
}
}
@ -6367,7 +6428,8 @@ M_Quit_Draw(void)
float scale = SCR_GetMenuScale();
Draw_GetPicSize(&w, &h, "quit");
Draw_PicScaled((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2, "quit", scale);
Draw_PicScaledAltText((viddef.width - w * scale) / 2, (viddef.height - h * scale) / 2,
"quit", scale, "Quit Y/N?");
}
static void
@ -6409,6 +6471,7 @@ M_Init(void)
Cmd_AddCommand("menu_gyro", M_Menu_Gyro_f);
Cmd_AddCommand("menu_buttons", M_Menu_ControllerButtons_f);
Cmd_AddCommand("menu_altbuttons", M_Menu_ControllerAltButtons_f);
Cmd_AddCommand("menu_sticks", M_Menu_Stick_f);
Cmd_AddCommand("menu_quit", M_Menu_Quit_f);
/* initialize the server address book cvars (adr0, adr1, ...)
@ -6431,6 +6494,12 @@ M_Init(void)
{
m_cursor_width = w;
}
/* No cursor image? */
if (m_cursor_width == 0)
{
m_cursor_width = 8;
}
}
}

View file

@ -29,6 +29,9 @@
#include "../header/client.h"
#include "header/qmenu.h"
void IN_GetClipboardText(char *out, size_t n);
int IN_SetClipboardText(const char *s);
static void Action_Draw(menuaction_s *a);
static void Menu_DrawStatusBar(const char *string);
static void MenuList_Draw(menulist_s *l);
@ -64,7 +67,8 @@ ClampCvar(float min, float max, float value)
Bitmap_Draw
=================
*/
void Bitmap_Draw(menubitmap_s * item)
static void
Bitmap_Draw(menubitmap_s * item)
{
float scale = SCR_GetMenuScale();
int x = 0;
@ -76,11 +80,13 @@ void Bitmap_Draw(menubitmap_s * item)
if (((item->generic.flags & QMF_HIGHLIGHT_IF_FOCUS) &&
(Menu_ItemAtCursor(item->generic.parent) == item)))
{
Draw_PicScaled(x * scale, y * scale, item->focuspic, scale);
Draw_PicScaledAltText(x * scale, y * scale, item->focuspic, scale,
item->alttext);
}
else if (item->generic.name)
{
Draw_PicScaled(x * scale, y * scale, ( char * )item->generic.name, scale);
Draw_PicScaledAltText(x * scale, y * scale, ( char * )item->generic.name, scale,
item->alttext);
}
}
@ -129,19 +135,7 @@ Action_Draw(menuaction_s *a)
}
}
qboolean
Field_DoEnter(menufield_s *f)
{
if (f->generic.callback)
{
f->generic.callback(f);
return true;
}
return false;
}
void
static void
Field_Draw(menufield_s *f)
{
int i, n;
@ -166,7 +160,8 @@ Field_Draw(menufield_s *f)
n = sizeof(tempbuffer);
}
Q_strlcpy(tempbuffer, f->buffer + f->visible_offset, n);
i = (f->cursor > f->visible_length) ? (f->cursor - f->visible_length) : 0;
Q_strlcpy(tempbuffer, f->buffer + i, n);
Draw_CharScaled(x + (16 * scale),
(y - 4) * scale, 18, scale);
@ -191,30 +186,36 @@ Field_Draw(menufield_s *f)
if (Menu_ItemAtCursor(f->generic.parent) == f)
{
int offset;
if (f->visible_offset)
{
offset = f->visible_length;
}
else
{
offset = f->cursor;
}
if (((int)(Sys_Milliseconds() / 250)) & 1)
{
int offset;
if (f->cursor > f->visible_length)
{
offset = f->visible_length;
}
else
{
offset = f->cursor;
}
Draw_CharScaled(
x + (24 * scale) + (offset * (8 * scale)),
y * scale, 11, scale);
}
else
{
Draw_CharScaled(
x + (24 * scale) + (offset * (8 * scale)),
y * scale, ' ', scale);
}
}
}
void
Field_ResetCursor(menuframework_s *m)
{
menucommon_s *item = Menu_ItemAtCursor(m);
if (item && item->type == MTYPE_FIELD)
{
menufield_s *f = (menufield_s *)item;
f->cursor = strlen(f->buffer);
}
}
@ -223,36 +224,97 @@ extern int keydown[];
qboolean
Field_Key(menufield_s *f, int key)
{
if (key > 127)
char txt[256];
if (keydown[K_CTRL])
{
return false;
if (key == 'l')
{
*f->buffer = '\0';
f->cursor = 0;
return true;
}
if (key == 'c' || key == 'x')
{
if (*f->buffer != '\0')
{
if (IN_SetClipboardText(f->buffer))
{
Com_Printf("Copying menu field to clipboard failed.\n");
}
else if (key == 'x')
{
*f->buffer = '\0';
f->cursor = 0;
}
}
return true;
}
if (key == 'v')
{
IN_GetClipboardText(txt, sizeof(txt));
if (*txt != '\0')
{
if ((f->generic.flags & QMF_NUMBERSONLY) && !Q_strisnum(txt))
{
return false;
}
f->cursor += Q_strins(f->buffer, txt, f->cursor, f->length);
}
}
return true;
}
switch (key)
{
case K_KP_LEFTARROW:
case K_LEFTARROW:
case K_BACKSPACE:
if (f->cursor > 0)
{
memmove(&f->buffer[f->cursor - 1],
&f->buffer[f->cursor],
strlen(&f->buffer[f->cursor]) + 1);
f->cursor--;
if (f->visible_offset)
{
f->visible_offset--;
}
}
break;
case K_KP_RIGHTARROW:
case K_RIGHTARROW:
if (f->buffer[f->cursor] != '\0')
{
f->cursor++;
}
break;
case K_BACKSPACE:
if (f->cursor > 0)
{
Q_strdel(f->buffer, f->cursor - 1, 1);
f->cursor--;
}
break;
case K_END:
if (f->buffer[f->cursor] == '\0')
{
f->cursor = 0;
}
else
{
f->cursor = strlen(f->buffer);
}
break;
case K_KP_DEL:
case K_DEL:
memmove(&f->buffer[f->cursor], &f->buffer[f->cursor + 1],
strlen(&f->buffer[f->cursor + 1]) + 1);
if (f->buffer[f->cursor] != '\0')
{
Q_strdel(f->buffer, f->cursor, 1);
}
break;
case K_KP_ENTER:
@ -261,24 +323,21 @@ Field_Key(menufield_s *f, int key)
case K_TAB:
return false;
case K_SPACE:
default:
if (key > 127)
{
return false;
}
if (!isdigit(key) && (f->generic.flags & QMF_NUMBERSONLY))
{
return false;
}
if (f->cursor < f->length)
{
f->buffer[f->cursor++] = key;
f->buffer[f->cursor] = 0;
*txt = key;
*(txt + 1) = '\0';
if (f->cursor > f->visible_length)
{
f->visible_offset++;
}
}
f->cursor += Q_strins(f->buffer, txt, f->cursor, f->length);
}
return true;
@ -469,49 +528,33 @@ Menu_DrawStatusBar(const char *string)
void
Menu_DrawString(int x, int y, const char *string)
{
unsigned i;
float scale = SCR_GetMenuScale();
for (i = 0; i < strlen(string); i++)
{
Draw_CharScaled(x + i * 8 * scale, y * scale, string[i], scale);
}
Draw_StringScaled(x, y * scale, scale, false, string);
}
void
Menu_DrawStringDark(int x, int y, const char *string)
{
unsigned i;
float scale = SCR_GetMenuScale();
for (i = 0; i < strlen(string); i++)
{
Draw_CharScaled(x + i * 8 * scale, y * scale, string[i] + 128, scale);
}
Draw_StringScaled(x, y * scale, scale, true, string);
}
void
Menu_DrawStringR2L(int x, int y, const char *string)
{
unsigned i;
float scale = SCR_GetMenuScale();
for (i = 0; i < strlen(string); i++)
{
Draw_CharScaled(x - i * 8 * scale, y * scale, string[strlen(string) - i - 1], scale);
}
Draw_StringScaled(x - 8 * scale * strlen(string), y * scale, scale, false, string);
}
void
Menu_DrawStringR2LDark(int x, int y, const char *string)
{
unsigned i;
float scale = SCR_GetMenuScale();
for (i = 0; i < strlen(string); i++)
{
Draw_CharScaled(x - i * 8 * scale, y * scale, string[strlen(string) - i - 1] + 128, scale);
}
Draw_StringScaled(x - 8 * scale * strlen(string), y * scale, scale, true, string);
}
void *

View file

@ -445,6 +445,7 @@ VID_MenuInit(void)
"[3840 2160 ]",
"[4096 2160 ]",
"[5120 2880 ]",
"[1600 900 ]",
AUTO_MODE_NAME,
CUSTOM_MODE_NAME,
0

View file

@ -80,8 +80,8 @@ Mod_NumberLeafs(mleaf_t *leafs, mnode_t *node, int *r_leaftovis, int *r_vistolea
static void
Mod_LoadQNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs,
int numleafs, mnode_t **nodes, int *numnodes, const byte *mod_base,
const lump_t *l)
int numleafs, mnode_t **nodes, int *numnodes, vec3_t mins, vec3_t maxs,
const byte *mod_base, const lump_t *l)
{
dqnode_t *in;
mnode_t *out;
@ -101,6 +101,24 @@ Mod_LoadQNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs
*nodes = out;
*numnodes = count;
/* Set initial min/max */
if (count)
{
for (i = 0; i < 3; i++)
{
mins[i] = in->mins[i];
maxs[i] = in->maxs[i];
}
}
else
{
for (i = 0; i < 3; i++)
{
mins[i] = 0;
maxs[i] = 0;
}
}
for (i = 0; i < count; i++, in++, out++)
{
int j, planenum;
@ -109,6 +127,17 @@ Mod_LoadQNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs
{
out->minmaxs[j] = in->mins[j];
out->minmaxs[3 + j] = in->maxs[j];
/* update min/max */
if (mins[j] > in->mins[j])
{
mins[j] = in->mins[j];
}
if (maxs[j] < in->maxs[j])
{
maxs[j] = in->maxs[j];
}
}
planenum = LittleLong(in->planenum) & 0xFFFFFFFF;
@ -156,19 +185,31 @@ Mod_LoadQNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs
void
Mod_LoadQBSPNodes(const char *name, cplane_t *planes, int numplanes, mleaf_t *leafs,
int numleafs, mnode_t **nodes, int *numnodes, const byte *mod_base,
const lump_t *l, int ident)
int numleafs, mnode_t **nodes, int *numnodes, vec3_t mins, vec3_t maxs,
const byte *mod_base, const lump_t *l, int ident)
{
int r_leaftovis[MAX_MAP_LEAFS], r_vistoleaf[MAX_MAP_LEAFS];
int *r_leaftovis, *r_vistoleaf;
int numvisleafs;
r_leaftovis = malloc(numleafs * sizeof(int));
r_vistoleaf = malloc(numleafs * sizeof(int));
if (!r_leaftovis || !r_vistoleaf)
{
Com_Error(ERR_DROP, "%s: Can't allocate %d leaf temporary buf.",
__func__, numleafs);
return;
}
Mod_LoadQNodes(name, planes, numplanes, leafs, numleafs, nodes, numnodes,
mod_base, l);
mins, maxs, mod_base, l);
Mod_SetParent(*nodes, NULL); /* sets nodes and leafs */
numvisleafs = 0;
Mod_NumberLeafs(leafs, *nodes, r_leaftovis, r_vistoleaf, &numvisleafs);
free(r_leaftovis);
free(r_vistoleaf);
}
/*
@ -705,7 +746,7 @@ Mod_LoadQBSPMarksurfaces(const char *name, msurface_t ***marksurfaces, unsigned
void
Mod_LoadQBSPLeafs(const char *name, mleaf_t **leafs, int *numleafs,
msurface_t **marksurfaces, unsigned int nummarksurfaces,
const byte *mod_base, const lump_t *l)
int *numclusters, const byte *mod_base, const lump_t *l)
{
dqleaf_t *in;
mleaf_t *out;
@ -724,6 +765,7 @@ Mod_LoadQBSPLeafs(const char *name, mleaf_t **leafs, int *numleafs,
*leafs = out;
*numleafs = count;
*numclusters = 0;
for (i = 0; i < count; i++, in++, out++)
{
@ -748,6 +790,11 @@ Mod_LoadQBSPLeafs(const char *name, mleaf_t **leafs, int *numleafs,
Com_Error(ERR_DROP, "%s: wrong marksurfaces position in %s",
__func__, name);
}
if (out->cluster >= *numclusters)
{
*numclusters = out->cluster + 1;
}
}
}

View file

@ -26,10 +26,6 @@
#include "../ref_shared.h"
static const float r_avertexnormals[NUMVERTEXNORMALS][3] = {
#include "../constants/anorms.h"
};
static vec4_t *lerpbuff = NULL;
static int lerpbuffnum = 0;
@ -76,31 +72,16 @@ R_VertBufferFree(void)
lerpbuffnum = 0;
}
/* compressed vertex normals used by mdl and md2 model formats */
void
R_ConvertNormalMDL(byte in_normal, signed char *normal)
{
const float *norm;
int n;
norm = r_avertexnormals[in_normal % NUMVERTEXNORMALS];
for (n = 0; n < 3; n ++)
{
normal[n] = norm[n] * 127.f;
}
}
void
R_LerpVerts(qboolean powerUpEffect, int nverts,
const dxtrivertx_t *v, const dxtrivertx_t *ov,
float *lerp, const float move[3],
const float frontv[3], const float backv[3])
const float frontv[3], const float backv[3], const float *scale)
{
int i;
if (powerUpEffect)
{
int i;
for (i = 0; i < nverts; i++, v++, ov++, lerp += 4)
{
int n;
@ -111,18 +92,23 @@ R_LerpVerts(qboolean powerUpEffect, int nverts,
normal = v->normal[n] / 127.f;
lerp[n] = move[n] + ov->v[n] * backv[n] + v->v[n] * frontv[n] +
lerp[n] = scale[n] * (move[n] + ov->v[n] * backv[n] + v->v[n] * frontv[n]) +
normal * POWERSUIT_SCALE;
}
}
}
else
{
int i;
for (i = 0; i < nverts; i++, v++, ov++, lerp += 4)
{
lerp[0] = move[0] + ov->v[0] * backv[0] + v->v[0] * frontv[0];
lerp[1] = move[1] + ov->v[1] * backv[1] + v->v[1] * frontv[1];
lerp[2] = move[2] + ov->v[2] * backv[2] + v->v[2] * frontv[2];
int n;
for (n = 0; n < 3; n++)
{
lerp[n] = scale[n] * (move[n] + ov->v[n] * backv[n] + v->v[n] * frontv[n]);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,8 @@
// include resize implementation
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "../files/stb_truetype.h"
/*
* Add extension to file name
@ -641,6 +643,12 @@ R_LoadImage(const char *name, const char* namewe, const char *ext, imagetype_t t
image = LoadImage_Ext(name, namewe, "png", type, r_retexturing, load_image);
}
/* atd check */
if (!image)
{
image = LoadImage_Ext(name, namewe, "atd", type, r_retexturing, load_image);
}
return image;
}
@ -715,22 +723,25 @@ R_FindPic(const char *name, findimage_t find_image)
const char* ext;
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
strncpy(namewe, name, sizeof(namewe) - 1);
namewe[sizeof(namewe) - 1] = 0;
Q_strlcpy(namewe, name, sizeof(namewe));
}
else
{
int len;
len = strlen(name);
size_t len;
/* Remove the extension */
memset(namewe, 0, MAX_QPATH);
memcpy(namewe, name, len - (strlen(ext) + 1));
namewe[len - (strlen(ext))] = 0;
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
memcpy(namewe, name, len);
namewe[len] = 0;
}
/* Quake 2 */
@ -758,3 +769,150 @@ R_FindPic(const char *name, findimage_t find_image)
return image;
}
unsigned
R_NextUTF8Code(const char **curr)
{
unsigned value = 0, size = 0, i;
value = **curr;
if (!(value & 0x80))
{
size = 1;
}
else if ((value & 0xE0) == 0xC0)
{
size = 2;
value = (value & 0x1F) << 6;
}
else if ((value & 0xF0) == 0xE0)
{
size = 3;
value = (value & 0x0F) << 12;
}
else if ((value & 0xF8) == 0xF0)
{
size = 4;
value = (value & 0x07) << 18;
}
(*curr) ++;
size --;
for (i = 0; (i < size); i++)
{
int c;
c = **curr;
if ((c & 0xC0) != 0x80)
{
break;
}
value |= (c & 0x3F) << ((size - i - 1) * 6);
(*curr) ++;
}
return value;
}
struct image_s *
R_LoadConsoleChars(findimage_t find_image)
{
struct image_s *draw_chars;
/* load console characters */
draw_chars = R_FindPic("conchars", find_image);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic("fonts/conchars", find_image);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic("dkchars", find_image);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}
return draw_chars;
}
void
R_LoadTTFFont(const char *ttffont, int vid_height, float *r_font_size,
int *r_font_height, stbtt_bakedchar **draw_fontcodes,
struct image_s **draw_font, struct image_s **draw_font_alt,
loadimage_t R_LoadPic)
{
char font_name[MAX_QPATH] = {0};
byte *data, *font_mask, *font_data;
int size, i, power_two = 1, texture_size;
snprintf(font_name, sizeof(font_name), "fonts/%s.ttf", ttffont);
size = ri.FS_LoadFile(font_name, (void **)&data);
if (size <= 0)
{
return;
}
*r_font_size = (vid_height / 240.0) * 4.0;
if (*r_font_size < 8)
{
*r_font_size = 8.0;
}
while (power_two < *r_font_size)
{
power_two <<= 1;
}
*r_font_height = 32 * power_two;
texture_size = (*r_font_height) * (*r_font_height);
font_mask = malloc(texture_size);
font_data = malloc(texture_size * 4);
*draw_fontcodes = malloc(MAX_FONTCODE * sizeof(**draw_fontcodes));
stbtt_BakeFontBitmap(data,
0 /* file offset */,
*r_font_size * 1.5 /* symbol size ~ as console font */,
font_mask,
*r_font_height, *r_font_height,
32 /* Start font code */, MAX_FONTCODE,
*draw_fontcodes);
for (i = 0; i < texture_size; i++)
{
font_data[i * 4 + 0] = font_mask[i];
font_data[i * 4 + 1] = font_mask[i];
font_data[i * 4 + 2] = font_mask[i];
font_data[i * 4 + 3] = font_mask[i] > 16 ? 255 : 0;
}
*draw_font = R_LoadPic("***ttf***", font_data,
*r_font_height, *r_font_height, *r_font_height, *r_font_height,
texture_size, it_pic, 32);
for (i = 0; i < texture_size; i++)
{
font_data[i * 4 + 0] = 0x0;
font_data[i * 4 + 1] = font_mask[i];
font_data[i * 4 + 2] = 0x0;
font_data[i * 4 + 3] = font_mask[i] > 16 ? 255 : 0;
}
*draw_font_alt = R_LoadPic("***ttf_alt***", font_data,
*r_font_height, *r_font_height, *r_font_height, *r_font_height,
texture_size, it_pic, 32);
free(font_data);
free(font_mask);
ri.FS_FreeFile((void *)data);
R_Printf(PRINT_ALL, "%s(): Loaded font %s %.0fp.\n", __func__, font_name, *r_font_size);
}

View file

@ -1,4 +1,4 @@
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
@ -48,6 +48,8 @@ LICENSE
RECENT REVISION HISTORY:
2.30 (2024-05-31) avoid erroneous gcc warning
2.29 (2023-05-xx) optimizations
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
2.26 (2020-07-13) many minor fixes
@ -98,7 +100,7 @@ RECENT REVISION HISTORY:
Bug & warning fixes
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
Phil Jordan Dave Moore Roy Eltham
Phil Jordan Henner Zeller Dave Moore Roy Eltham
Hayaki Saito Nathan Reed Won Chun
Luke Graham Johan Duparc Nick Verigakis the Horde3D community
Thomas Ruf Ronny Chevalier github:rlyeh
@ -109,7 +111,7 @@ RECENT REVISION HISTORY:
Cass Everitt Ryamond Barbiero github:grim210
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
Josh Tobin Nia Bickford Matthew Gregan github:poppolopoppo
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
Brad Weinberger Matvey Cherevko github:mosra
@ -371,6 +373,15 @@ RECENT REVISION HISTORY:
#define STBI_VERSION 1
#if defined(__has_attribute)
# if __has_attribute(fallthrough)
# define STBI_FALLTHROUGH __attribute__((fallthrough));
# endif
#endif
#if !defined(STBI_FALLTHROUGH)
# define STBI_FALLTHROUGH
#endif
enum
{
STBI_default = 0, // only used for desired_channels
@ -1072,8 +1083,8 @@ static int stbi__addints_valid(int a, int b)
return a <= INT_MAX - b;
}
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
static int stbi__mul2shorts_valid(short a, short b)
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
static int stbi__mul2shorts_valid(int a, int b)
{
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
@ -1207,7 +1218,7 @@ static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int chan
int img_len = w * h * channels;
stbi__uint16 *enlarged;
enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
enlarged = (stbi__uint16 *) stbi__malloc(((size_t)img_len)*2);
if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
for (i = 0; i < img_len; ++i)
@ -1267,7 +1278,12 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
if (ri.bits_per_channel != 8) {
result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
stbi_uc *converted = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
if (converted == NULL) {
STBI_FREE(result);
return NULL;
}
result = converted;
ri.bits_per_channel = 8;
}
@ -1293,7 +1309,12 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
if (ri.bits_per_channel != 16) {
result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
stbi__uint16 * converted = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
if (converted == NULL) {
STBI_FREE(result);
return NULL;
}
result = converted;
ri.bits_per_channel = 16;
}
@ -1379,7 +1400,12 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req
result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
if (result) {
// need to 'unget' all the characters in the IO buffer
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
if (fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR) != 0) {
// fseek() failed; we can no longer maintain the file cursor position
// guarantee of this function, so return null.
STBI_FREE(result);
return stbi__errpuc("bad file", "fseek() failed; seek position unreliable");
}
}
return result;
}
@ -1392,7 +1418,12 @@ STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp,
result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
if (result) {
// need to 'unget' all the characters in the IO buffer
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
if (fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR) != 0) {
// fseek() failed; we can no longer maintain the file cursor position
// guarantee of this function, so return null.
STBI_FREE(result);
return (stbi__uint16 *) stbi__errpuc("bad file", "fseek() failed; seek position unreliable");
}
}
return result;
}
@ -1446,8 +1477,9 @@ STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int *
stbi__start_mem(&s,buffer,len);
result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
if (stbi__vertically_flip_on_load) {
stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
if (stbi__vertically_flip_on_load && result) {
int channels = req_comp ? req_comp : *comp;
stbi__vertical_flip_slices( result, *x, *y, *z, channels );
}
return result;
@ -1540,12 +1572,13 @@ STBIDEF int stbi_is_hdr (char const *filename)
STBIDEF int stbi_is_hdr_from_file(FILE *f)
{
#ifndef STBI_NO_HDR
long pos = ftell(f);
int res;
long pos = ftell(f);
if (pos < 0) return stbi__err("bad file", "ftell() failed");
stbi__context s;
stbi__start_file(&s,f);
res = stbi__hdr_test(&s);
fseek(f, pos, SEEK_SET);
if (fseek(f, pos, SEEK_SET) != 0) return stbi__err("bad file", "fseek() failed");
return res;
#else
STBI_NOTUSED(f);
@ -1755,6 +1788,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
int i,j;
unsigned char *good;
if (data == NULL) return data;
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
@ -1795,7 +1829,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PNM)
// nothing
#else
static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
@ -1804,7 +1838,7 @@ static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
}
#endif
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PNM)
// nothing
#else
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
@ -2221,8 +2255,8 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc;
if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * dequant[0]);
if ((dc > SHRT_MAX) || (dequant[0] > SHRT_MAX) || !stbi__mul2shorts_valid((short) dc, (short) dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) ((size_t)dc * dequant[0]);
// decode AC components, see JPEG spec
k = 1;
@ -2278,7 +2312,7 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc;
if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
if ((dc > SHRT_MAX) || !stbi__mul2shorts_valid((short) dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * (1 << j->succ_low));
} else {
// refinement scan for DC coefficient
@ -3384,13 +3418,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
return 1;
}
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
{
// some JPEGs have junk at end, skip over it but if we find what looks
// like a valid marker, resume there
while (!stbi__at_eof(j->s)) {
int x = stbi__get8(j->s);
while (x == 255) { // might be a marker
stbi_uc x = stbi__get8(j->s);
while (x == 0xff) { // might be a marker
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
x = stbi__get8(j->s);
if (x != 0x00 && x != 0xff) {
@ -4176,6 +4210,7 @@ typedef struct
{
stbi_uc *zbuffer, *zbuffer_end;
int num_bits;
int hit_zeof_once;
stbi__uint32 code_buffer;
char *zout;
@ -4242,9 +4277,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
int b,s;
if (a->num_bits < 16) {
if (stbi__zeof(a)) {
return -1; /* report error for unexpected end of data. */
if (!a->hit_zeof_once) {
// This is the first time we hit eof, insert 16 extra padding btis
// to allow us to keep going; if we actually consume any of them
// though, that is invalid data. This is caught later.
a->hit_zeof_once = 1;
a->num_bits += 16; // add 16 implicit zero bits
} else {
// We already inserted our extra 16 padding bits and are again
// out, this stream is actually prematurely terminated.
return -1;
}
} else {
stbi__fill_bits(a);
}
stbi__fill_bits(a);
}
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
if (b) {
@ -4309,6 +4355,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
int len,dist;
if (z == 256) {
a->zout = zout;
if (a->hit_zeof_once && a->num_bits < 16) {
// The first time we hit zeof, we inserted 16 extra zero bits into our bit
// buffer so the decoder can just do its speculative decoding. But if we
// actually consumed any of those bits (which is the case when num_bits < 16),
// the stream actually read past the end so it is malformed.
return stbi__err("unexpected end","Corrupt PNG");
}
return 1;
}
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
@ -4320,7 +4373,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
dist = stbi__zdist_base[z];
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
if (zout + len > a->zout_end) {
if (len > a->zout_end - zout) {
if (!stbi__zexpand(a, zout, len)) return 0;
zout = a->zout;
}
@ -4464,6 +4517,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
if (!stbi__parse_zlib_header(a)) return 0;
a->num_bits = 0;
a->code_buffer = 0;
a->hit_zeof_once = 0;
do {
final = stbi__zreceive(a,1);
type = stbi__zreceive(a,2);
@ -4619,9 +4673,8 @@ enum {
STBI__F_up=2,
STBI__F_avg=3,
STBI__F_paeth=4,
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
STBI__F_avg_first,
STBI__F_paeth_first
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
STBI__F_avg_first
};
static stbi_uc first_row_filter[5] =
@ -4630,29 +4683,56 @@ static stbi_uc first_row_filter[5] =
STBI__F_sub,
STBI__F_none,
STBI__F_avg_first,
STBI__F_paeth_first
STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
};
static int stbi__paeth(int a, int b, int c)
{
int p = a + b - c;
int pa = abs(p-a);
int pb = abs(p-b);
int pc = abs(p-c);
if (pa <= pb && pa <= pc) return a;
if (pb <= pc) return b;
return c;
// This formulation looks very different from the reference in the PNG spec, but is
// actually equivalent and has favorable data dependencies and admits straightforward
// generation of branch-free code, which helps performance significantly.
int thresh = c*3 - (a + b);
int lo = a < b ? a : b;
int hi = a < b ? b : a;
int t0 = (hi <= thresh) ? lo : c;
int t1 = (thresh <= lo) ? hi : t0;
return t1;
}
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
// adds an extra all-255 alpha channel
// dest == src is legal
// img_n must be 1 or 3
static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
{
int i;
// must process data backwards since we allow dest==src
if (img_n == 1) {
for (i=x-1; i >= 0; --i) {
dest[i*2+1] = 255;
dest[i*2+0] = src[i];
}
} else {
STBI_ASSERT(img_n == 3);
for (i=x-1; i >= 0; --i) {
dest[i*4+3] = 255;
dest[i*4+2] = src[i*3+2];
dest[i*4+1] = src[i*3+1];
dest[i*4+0] = src[i*3+0];
}
}
}
// create the png data from post-deflated data
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
{
int bytes = (depth == 16? 2 : 1);
int bytes = (depth == 16 ? 2 : 1);
stbi__context *s = a->s;
stbi__uint32 i,j,stride = x*out_n*bytes;
stbi__uint32 img_len, img_width_bytes;
stbi_uc *filter_buf;
int all_ok = 1;
int k;
int img_n = s->img_n; // copy it into a local for later
@ -4664,8 +4744,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory");
// note: error exits here don't need to clean up a->out individually,
// stbi__do_png always does on error.
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
img_len = (img_width_bytes + 1) * y;
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
@ -4673,189 +4756,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
// so just check for raw_len < img_len always.
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
// Allocate two scan lines worth of filter workspace buffer.
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
// Filtering for low-bit-depth images
if (depth < 8) {
filter_bytes = 1;
width = img_width_bytes;
}
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
stbi_uc *prior;
// cur/prior filter buffers alternate
stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
stbi_uc *dest = a->out + stride*j;
int nk = width * filter_bytes;
int filter = *raw++;
if (filter > 4)
return stbi__err("invalid filter","Corrupt PNG");
if (depth < 8) {
if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
filter_bytes = 1;
width = img_width_bytes;
// check filter type
if (filter > 4) {
all_ok = stbi__err("invalid filter","Corrupt PNG");
break;
}
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
// if first row, use special filter that doesn't sample previous row
if (j == 0) filter = first_row_filter[filter];
// handle first byte explicitly
for (k=0; k < filter_bytes; ++k) {
switch (filter) {
case STBI__F_none : cur[k] = raw[k]; break;
case STBI__F_sub : cur[k] = raw[k]; break;
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
case STBI__F_avg_first : cur[k] = raw[k]; break;
case STBI__F_paeth_first: cur[k] = raw[k]; break;
}
// perform actual filtering
switch (filter) {
case STBI__F_none:
memcpy(cur, raw, nk);
break;
case STBI__F_sub:
memcpy(cur, raw, filter_bytes);
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
break;
case STBI__F_up:
for (k = 0; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
break;
case STBI__F_avg:
for (k = 0; k < filter_bytes; ++k)
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
break;
case STBI__F_paeth:
for (k = 0; k < filter_bytes; ++k)
cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
break;
case STBI__F_avg_first:
memcpy(cur, raw, filter_bytes);
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
break;
}
if (depth == 8) {
if (img_n != out_n)
cur[img_n] = 255; // first pixel
raw += img_n;
cur += out_n;
prior += out_n;
} else if (depth == 16) {
if (img_n != out_n) {
cur[filter_bytes] = 255; // first pixel top byte
cur[filter_bytes+1] = 255; // first pixel bottom byte
}
raw += filter_bytes;
cur += output_bytes;
prior += output_bytes;
} else {
raw += 1;
cur += 1;
prior += 1;
}
raw += nk;
// this is a little gross, so that we don't switch per-pixel or per-component
if (depth < 8 || img_n == out_n) {
int nk = (width - 1)*filter_bytes;
#define STBI__CASE(f) \
case f: \
for (k=0; k < nk; ++k)
switch (filter) {
// "none" filter turns into a memcpy here; make that explicit.
case STBI__F_none: memcpy(cur, raw, nk); break;
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
}
#undef STBI__CASE
raw += nk;
} else {
STBI_ASSERT(img_n+1 == out_n);
#define STBI__CASE(f) \
case f: \
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
for (k=0; k < filter_bytes; ++k)
switch (filter) {
STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
}
#undef STBI__CASE
// the loop above sets the high byte of the pixels' alpha, but for
// 16 bit png files we also need the low byte set. we'll do that here.
if (depth == 16) {
cur = a->out + stride*j; // start at the beginning of the row again
for (i=0; i < x; ++i,cur+=output_bytes) {
cur[filter_bytes+1] = 255;
}
}
}
}
// we make a separate pass to expand bits to pixels; for performance,
// this could run two scanlines behind the above code, so it won't
// intefere with filtering but will still be in the cache.
if (depth < 8) {
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
if (depth < 8) {
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
stbi_uc *in = cur;
stbi_uc *out = dest;
stbi_uc inb = 0;
stbi__uint32 nsmp = x*img_n;
// note that the final byte might overshoot and write more data than desired.
// we can allocate enough data that this never writes out of memory, but it
// could also overwrite the next scanline. can it overwrite non-empty data
// on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
// so we need to explicitly clamp the final ones
// expand bits to bytes first
if (depth == 4) {
for (k=x*img_n; k >= 2; k-=2, ++in) {
*cur++ = scale * ((*in >> 4) );
*cur++ = scale * ((*in ) & 0x0f);
for (i=0; i < nsmp; ++i) {
if ((i & 1) == 0) inb = *in++;
*out++ = scale * (inb >> 4);
inb <<= 4;
}
if (k > 0) *cur++ = scale * ((*in >> 4) );
} else if (depth == 2) {
for (k=x*img_n; k >= 4; k-=4, ++in) {
*cur++ = scale * ((*in >> 6) );
*cur++ = scale * ((*in >> 4) & 0x03);
*cur++ = scale * ((*in >> 2) & 0x03);
*cur++ = scale * ((*in ) & 0x03);
for (i=0; i < nsmp; ++i) {
if ((i & 3) == 0) inb = *in++;
*out++ = scale * (inb >> 6);
inb <<= 2;
}
if (k > 0) *cur++ = scale * ((*in >> 6) );
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
} else if (depth == 1) {
for (k=x*img_n; k >= 8; k-=8, ++in) {
*cur++ = scale * ((*in >> 7) );
*cur++ = scale * ((*in >> 6) & 0x01);
*cur++ = scale * ((*in >> 5) & 0x01);
*cur++ = scale * ((*in >> 4) & 0x01);
*cur++ = scale * ((*in >> 3) & 0x01);
*cur++ = scale * ((*in >> 2) & 0x01);
*cur++ = scale * ((*in >> 1) & 0x01);
*cur++ = scale * ((*in ) & 0x01);
} else {
STBI_ASSERT(depth == 1);
for (i=0; i < nsmp; ++i) {
if ((i & 7) == 0) inb = *in++;
*out++ = scale * (inb >> 7);
inb <<= 1;
}
if (k > 0) *cur++ = scale * ((*in >> 7) );
if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
}
if (img_n != out_n) {
int q;
// insert alpha = 255
cur = a->out + stride*j;
// insert alpha=255 values if desired
if (img_n != out_n)
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
} else if (depth == 8) {
if (img_n == out_n)
memcpy(dest, cur, x*img_n);
else
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
} else if (depth == 16) {
// convert the image data from big-endian to platform-native
stbi__uint16 *dest16 = (stbi__uint16*)dest;
stbi__uint32 nsmp = x*img_n;
if (img_n == out_n) {
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
*dest16 = (cur[0] << 8) | cur[1];
} else {
STBI_ASSERT(img_n+1 == out_n);
if (img_n == 1) {
for (q=x-1; q >= 0; --q) {
cur[q*2+1] = 255;
cur[q*2+0] = cur[q];
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
dest16[0] = (cur[0] << 8) | cur[1];
dest16[1] = 0xffff;
}
} else {
STBI_ASSERT(img_n == 3);
for (q=x-1; q >= 0; --q) {
cur[q*4+3] = 255;
cur[q*4+2] = cur[q*3+2];
cur[q*4+1] = cur[q*3+1];
cur[q*4+0] = cur[q*3+0];
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
dest16[0] = (cur[0] << 8) | cur[1];
dest16[1] = (cur[2] << 8) | cur[3];
dest16[2] = (cur[4] << 8) | cur[5];
dest16[3] = 0xffff;
}
}
}
}
} else if (depth == 16) {
// force the image data from big-endian to platform-native.
// this is done in a separate pass due to the decoding relying
// on the data being untouched, but could probably be done
// per-line during decode if care is taken.
stbi_uc *cur = a->out;
stbi__uint16 *cur16 = (stbi__uint16*)cur;
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
*cur16 = (cur[0] << 8) | cur[1];
}
}
STBI_FREE(filter_buf);
if (!all_ok) return 0;
return 1;
}
@ -5161,9 +5192,11 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
if (z->depth == 16) {
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning
tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
} else {
for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
for (k = 0; k < s->img_n && k < 3; ++k)
tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
}
}
break;
@ -5555,7 +5588,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz == 12) {
if (info.bpp < 24)
psize = (info.offset - info.extra_read - 24) / 3;
psize = (info.offset - info.extra_read - info.hsz) / 3;
} else {
if (info.bpp < 16)
psize = (info.offset - info.extra_read - info.hsz) >> 2;
@ -5742,7 +5775,7 @@ static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
switch(bits_per_pixel) {
case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha;
// fallthrough
STBI_FALLTHROUGH;
case 15: if(is_rgb16) *is_rgb16 = 1;
return STBI_rgb;
case 24: // fallthrough
@ -5933,7 +5966,10 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
for (i=0; i < tga_height; ++i) {
int row = tga_inverted ? tga_height -i - 1 : i;
stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
stbi__getn(s, tga_row, tga_width * tga_comp);
if(!stbi__getn(s, tga_row, tga_width * tga_comp)) {
STBI_FREE(tga_data);
return stbi__errpuc("bad palette", "Corrupt TGA");
}
}
} else {
// do I need to load a palette?
@ -6527,7 +6563,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c
if (!stbi__pic_load_core(s,x,y,comp, result)) {
STBI_FREE(result);
result=0;
return 0;
}
*px = x;
*py = y;
@ -6990,9 +7026,20 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
stride = g.w * g.h * 4;
if (out) {
if (stride == 0) {
void *ret = stbi__load_gif_main_outofmem(&g, out, delays);
return ret;
}
if (!stbi__mul2sizes_valid(layers, stride)) {
void *ret = stbi__load_gif_main_outofmem(&g, out, delays);
return ret;
}
void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
if (!tmp)
return stbi__load_gif_main_outofmem(&g, out, delays);
if (!tmp) {
void *ret = stbi__load_gif_main_outofmem(&g, out, delays);
if (delays && *delays) *delays = 0;
return ret;
}
else {
out = (stbi_uc*) tmp;
out_size = layers * stride;
@ -7006,9 +7053,16 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
delays_size = layers * sizeof(int);
}
} else {
if (!stbi__mul2sizes_valid(layers, stride)) {
void *ret = stbi__load_gif_main_outofmem(&g, out, delays);
return ret;
}
out = (stbi_uc*)stbi__malloc( layers * stride );
if (!out)
return stbi__load_gif_main_outofmem(&g, out, delays);
if (!out) {
void *ret = stbi__load_gif_main_outofmem(&g, out, delays);
if (delays && *delays) *delays = 0;
return ret;
}
out_size = layers * stride;
if (delays) {
*delays = (int*) stbi__malloc( layers * sizeof(int) );
@ -7019,7 +7073,7 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y,
}
memcpy( out + ((layers - 1) * stride), u, stride );
if (layers >= 2) {
two_back = out - 2 * stride;
two_back = out + (layers - 2) * stride;
}
if (delays) {
@ -7144,10 +7198,10 @@ static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
if (req_comp == 4) output[3] = 1;
} else {
switch (req_comp) {
case 4: output[3] = 1; /* fallthrough */
case 4: output[3] = 1; STBI_FALLTHROUGH;
case 3: output[0] = output[1] = output[2] = 0;
break;
case 2: output[1] = 1; /* fallthrough */
case 2: output[1] = 1; STBI_FALLTHROUGH;
case 1: output[0] = 0;
break;
}
@ -7218,7 +7272,10 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
for (i=0; i < width; ++i) {
stbi_uc rgbe[4];
main_decode_loop:
stbi__getn(s, rgbe, 4);
if (!stbi__getn(s, rgbe, 4)) {
STBI_FREE(hdr_data);
return stbi__errpf("invalid decoded scanline length", "corrupt HDR");
}
stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
}
}
@ -7702,9 +7759,10 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
int r;
stbi__context s;
long pos = ftell(f);
if (pos < 0) return stbi__err("bad file", "ftell() failed");
stbi__start_file(&s, f);
r = stbi__info_main(&s,x,y,comp);
fseek(f,pos,SEEK_SET);
if (fseek(f, pos, SEEK_SET) != 0) return stbi__err("bad file", "fseek() failed");
return r;
}
@ -7723,9 +7781,10 @@ STBIDEF int stbi_is_16_bit_from_file(FILE *f)
int r;
stbi__context s;
long pos = ftell(f);
if (pos < 0) return stbi__err("bad file", "ftell() failed");
stbi__start_file(&s, f);
r = stbi__is_16_main(&s);
fseek(f,pos,SEEK_SET);
if (fseek(f, pos, SEEK_SET) != 0) return stbi__err("bad file", "fseek() failed");
return r;
}
#endif // !STBI_NO_STDIO

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,7 @@ int cur_lm_copy; // which lightmap copy to use (when lightmapcopies=on)
static GLushort vtx_ptr, idx_ptr; // pointers for array positions in gl_buf
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
extern void R_SetPerspective(GLdouble fovy);
void
R_ResetGLBuffer(void)
@ -50,7 +50,6 @@ R_ApplyGLBuffer(void)
// Properties of batched draws here
GLint vtx_size;
qboolean texture, mtex, alpha, color, alias, texenv_set;
float fovy, dist;
if (vtx_ptr == 0 || idx_ptr == 0)
{
@ -107,9 +106,7 @@ R_ApplyGLBuffer(void)
glScalef(-1, 1, 1);
}
fovy = (r_gunfov->value < 0) ? r_newrefdef.fov_y : r_gunfov->value;
dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f;
R_MYgluPerspective(fovy, (float)r_newrefdef.width / r_newrefdef.height, 4, dist);
R_SetPerspective( (r_gunfov->value < 0) ? r_newrefdef.fov_y : r_gunfov->value );
glMatrixMode(GL_MODELVIEW);

View file

@ -25,37 +25,38 @@
*/
#include "header/local.h"
#include "../files/stb_truetype.h"
image_t *draw_chars;
static float gl_font_size = 8.0;
static int gl_font_height = 128;
image_t *draw_chars = NULL;
static image_t *draw_font = NULL;
static image_t *draw_font_alt = NULL;
static stbtt_bakedchar *draw_fontcodes = NULL;
extern qboolean scrap_dirty;
void Scrap_Upload(void);
extern unsigned r_rawpalette[256];
void R_LoadTTFFont(const char *ttffont, int vid_height, float *r_font_size,
int *r_font_height, stbtt_bakedchar **draw_fontcodes,
struct image_s **draw_font, struct image_s **draw_font_alt,
loadimage_t R_LoadPic);
void
Draw_InitLocal(void)
{
/* load console characters */
draw_chars = R_FindPic("conchars", (findimage_t)R_FindImage);
R_LoadTTFFont(r_ttffont->string, vid.height, &gl_font_size, &gl_font_height,
&draw_fontcodes, &draw_font, &draw_font_alt, R_LoadPic);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic ("fonts/conchars", (findimage_t)R_FindImage);
}
draw_chars = R_LoadConsoleChars((findimage_t)R_FindImage);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic ("dkchars", (findimage_t)R_FindImage);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}
void
RDraw_FreeLocal(void)
{
free(draw_fontcodes);
}
/*
@ -88,7 +89,7 @@ RDraw_CharScaled(int x, int y, int num, float scale)
fcol = col * 0.0625;
size = 0.0625;
scaledSize = 8*scale;
scaledSize = 8 * scale;
R_UpdateGLBuffer(buf_2d, draw_chars->texnum, 0, 0, 1);
@ -96,6 +97,64 @@ RDraw_CharScaled(int x, int y, int num, float scale)
fcol, frow, fcol + size, frow + size);
}
void
RDraw_StringScaled(int x, int y, float scale, qboolean alt, const char *message)
{
while (*message)
{
unsigned value = R_NextUTF8Code(&message);
if (draw_fontcodes && (draw_font || draw_font_alt))
{
float font_scale;
font_scale = gl_font_size / 8.0;
if (value >= 32 && value < MAX_FONTCODE)
{
float xf = 0, yf = 0, xdiff;
stbtt_aligned_quad q;
stbtt_GetBakedQuad(draw_fontcodes, gl_font_height, gl_font_height,
value - 32, &xf, &yf, &q, 1);
xdiff = (8 - xf / font_scale) / 2;
if (xdiff < 0)
{
xdiff = 0;
}
R_UpdateGLBuffer(buf_2d, alt ? draw_font_alt->texnum : draw_font->texnum, 0, 0, 1);
R_Buffer2DQuad(
(float)(x + (xdiff + q.x0 / font_scale) * scale),
(float)(y + q.y0 * scale / font_scale + 8 * scale),
x + (xdiff + q.x1 / font_scale) * scale,
y + q.y1 * scale / font_scale + 8 * scale,
q.s0, q.t0, q.s1, q.t1);
x += Q_max(8, xf / font_scale) * scale;
}
else
{
x += 8 * scale;
}
}
else
{
int xor;
xor = alt ? 0x80 : 0;
if (value > ' ' && value < 128)
{
RDraw_CharScaled(x, y, value ^ xor, scale);
}
x += 8 * scale;
}
}
}
image_t *
RDraw_FindPic(const char *name)
{
@ -165,7 +224,7 @@ RDraw_StretchPic(int x, int y, int w, int h, const char *pic)
}
void
RDraw_PicScaled(int x, int y, const char *pic, float factor)
RDraw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext)
{
image_t *gl;
@ -173,6 +232,13 @@ RDraw_PicScaled(int x, int y, const char *pic, float factor)
if (!gl)
{
if (alttext && alttext[0])
{
/* Show alttext if provided */
RDraw_StringScaled(x, y, factor, false, alttext);
return;
}
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
return;
}

View file

@ -471,7 +471,7 @@ R_ImageList_f(void)
/*
* Fill background pixels so mipmapping doesn't have haloes
*/
void
static void
R_FloodFillSkin(byte *skin, int skinwidth, int skinheight)
{
byte fillcolor = *skin; /* assume this is the pixel to fill */
@ -537,7 +537,7 @@ R_FloodFillSkin(byte *skin, int skinwidth, int skinheight)
* texture to increase the
* lighting range
*/
void
static void
R_LightScaleTexture(unsigned *in, int inwidth,
int inheight, qboolean only_gamma)
{
@ -578,7 +578,7 @@ R_LightScaleTexture(unsigned *in, int inwidth,
/*
* Operates in place, quartering the size of the texture
*/
void
static void
R_MipMap(byte *in, int width, int height)
{
int i, j;
@ -603,7 +603,7 @@ R_MipMap(byte *in, int width, int height)
/*
* Returns has_alpha
*/
void
static void
R_BuildPalettedTexture(unsigned char *paletted_texture, unsigned char *scaled,
int scaled_width, int scaled_height)
{
@ -625,7 +625,7 @@ R_BuildPalettedTexture(unsigned char *paletted_texture, unsigned char *scaled,
}
}
qboolean
static qboolean
R_Upload32Native(unsigned *data, int width, int height, qboolean mipmap)
{
// This is for GL 2.x so no palettes, no scaling, no messing around with the data here. :)
@ -661,7 +661,7 @@ R_Upload32Native(unsigned *data, int width, int height, qboolean mipmap)
}
qboolean
static qboolean
R_Upload32Soft(unsigned *data, int width, int height, qboolean mipmap)
{
int samples;
@ -1139,42 +1139,41 @@ R_LoadPic(const char *name, byte *pic, int width, int realwidth,
* Finds or loads the given image or null
*/
image_t *
R_FindImage(const char *name, imagetype_t type)
R_FindImage(const char *originname, imagetype_t type)
{
image_t *image;
int i, len;
char *ptr;
char namewe[256];
char namewe[256], name[256] = {0};
const char* ext;
image_t *image;
size_t len;
int i;
if (!name)
if (!originname)
{
return NULL;
}
Q_strlcpy(name, originname, sizeof(name));
/* fix backslashes */
Q_replacebackslash(name);
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
/* Remove the extension */
memset(namewe, 0, 256);
memcpy(namewe, name, len - (strlen(ext) + 1));
if (len < 5)
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
memcpy(namewe, name, len);
namewe[len] = 0;
/* look for it */
for (i = 0, image = gltextures; i < numgltextures; i++, image++)

View file

@ -101,6 +101,7 @@ cvar_t *gl_shadows;
cvar_t *gl1_stencilshadow;
cvar_t *r_mode;
cvar_t *r_fixsurfsky;
cvar_t *r_ttffont;
cvar_t *r_customwidth;
cvar_t *r_customheight;
@ -144,6 +145,7 @@ cvar_t *gl1_stereo_separation;
cvar_t *gl1_stereo_anaglyph_colors;
cvar_t *gl1_stereo_convergence;
static cvar_t *gl1_waterwarp;
refimport_t ri;
@ -151,6 +153,7 @@ void LM_FreeLightmapBuffers(void);
void Scrap_Free(void);
void Scrap_Init(void);
extern void R_SetDefaultState(void);
extern void R_ResetGLBuffer(void);
void
@ -635,6 +638,19 @@ R_PolyBlend(void)
glColor4f(1, 1, 1, 1);
}
static void
R_ResetClearColor(void)
{
if (gl1_discardfb->value == 1 && !r_clear->value)
{
glClearColor(0, 0, 0, 0.5);
}
else
{
glClearColor(1, 0, 0.5, 0.5);
}
}
static void
R_SetupFrame(void)
{
@ -712,25 +728,41 @@ R_SetupFrame(void)
vid.height - r_newrefdef.height - r_newrefdef.y,
r_newrefdef.width, r_newrefdef.height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5);
R_ResetClearColor();
glDisable(GL_SCISSOR_TEST);
}
}
void
R_MYgluPerspective(GLdouble fovy, GLdouble aspect,
GLdouble zNear, GLdouble zFar)
R_SetPerspective(GLdouble fovy)
{
// gluPerspective style parameters
static const GLdouble zNear = 4;
const GLdouble zFar = (r_farsee->value) ? 8192.0f : 4096.0f;
const GLdouble aspectratio = (GLdouble)r_newrefdef.width / r_newrefdef.height;
GLdouble xmin, xmax, ymin, ymax;
// traditional gluPerspective calculations - https://youtu.be/YqSNGcF5nvM?t=644
ymax = zNear * tan(fovy * M_PI / 360.0);
xmax = ymax * aspectratio;
if ((r_newrefdef.rdflags & RDF_UNDERWATER) && gl1_waterwarp->value)
{
const GLdouble warp = sin(r_newrefdef.time * 1.5) * 0.03 * gl1_waterwarp->value;
ymax *= 1.0 - warp;
xmax *= 1.0 + warp;
}
ymin = -ymax;
xmin = -xmax;
xmin = ymin * aspect;
xmax = ymax * aspect;
xmin += - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear;
xmax += - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear;
if (gl_state.camera_separation)
{
const GLdouble separation = - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear;
xmin += separation;
xmax += separation;
}
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}
@ -738,7 +770,6 @@ R_MYgluPerspective(GLdouble fovy, GLdouble aspect,
void
R_SetupGL(void)
{
float screenaspect;
int x, x2, y2, y, w, h;
/* set up viewport */
@ -768,18 +799,10 @@ R_SetupGL(void)
glViewport(x, y2, w, h);
/* set up projection matrix */
screenaspect = (float)r_newrefdef.width / r_newrefdef.height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (r_farsee->value == 0)
{
R_MYgluPerspective(r_newrefdef.fov_y, screenaspect, 4, 4096);
}
else
{
R_MYgluPerspective(r_newrefdef.fov_y, screenaspect, 4, 8192);
}
R_SetPerspective(r_newrefdef.fov_y);
glCullFace(GL_FRONT);
@ -814,53 +837,72 @@ R_SetupGL(void)
void
R_Clear(void)
{
// Check whether the stencil buffer needs clearing, and do so if need be.
GLbitfield stencilFlags = 0;
if (gl_state.stereo_mode >= STEREO_MODE_ROW_INTERLEAVED && gl_state.stereo_mode <= STEREO_MODE_PIXEL_INTERLEAVED) {
glClearStencil(GL_FALSE);
stencilFlags |= GL_STENCIL_BUFFER_BIT;
// Define which buffers need clearing
GLbitfield clearFlags = 0;
GLenum depthFunc = GL_LEQUAL;
// This breaks stereo modes, but we'll leave that responsibility to the user
if (r_clear->value)
{
clearFlags |= GL_COLOR_BUFFER_BIT;
}
// No stencil shadows allowed when using certain stereo modes, otherwise "wallhack" happens
if (gl_state.stereo_mode >= STEREO_MODE_ROW_INTERLEAVED && gl_state.stereo_mode <= STEREO_MODE_PIXEL_INTERLEAVED)
{
glClearStencil(0);
clearFlags |= GL_STENCIL_BUFFER_BIT;
}
else if (gl_shadows->value && gl_state.stencil && gl1_stencilshadow->value)
{
glClearStencil(1);
clearFlags |= GL_STENCIL_BUFFER_BIT;
}
if (gl1_ztrick->value)
{
static int trickframe;
if (r_clear->value)
{
glClear(GL_COLOR_BUFFER_BIT | stencilFlags);
}
trickframe++;
if (trickframe & 1)
{
gldepthmin = 0;
gldepthmax = 0.49999;
glDepthFunc(GL_LEQUAL);
}
else
{
gldepthmin = 1;
gldepthmax = 0.5;
glDepthFunc(GL_GEQUAL);
depthFunc = GL_GEQUAL;
}
}
else
{
if (r_clear->value)
{
glClear(GL_COLOR_BUFFER_BIT | stencilFlags | GL_DEPTH_BUFFER_BIT);
}
else
{
glClear(GL_DEPTH_BUFFER_BIT | stencilFlags);
}
clearFlags |= GL_DEPTH_BUFFER_BIT;
gldepthmin = 0;
gldepthmax = 1;
glDepthFunc(GL_LEQUAL);
}
switch ((int)gl1_discardfb->value)
{
case 1:
if (gl_state.stereo_mode == STEREO_MODE_NONE)
{
clearFlags |= GL_COLOR_BUFFER_BIT;
}
case 2:
clearFlags |= GL_STENCIL_BUFFER_BIT;
default:
break;
}
if (clearFlags)
{
glClear(clearFlags);
}
glDepthFunc(depthFunc);
glDepthRange(gldepthmin, gldepthmax);
if (gl_zfix->value)
@ -874,13 +916,6 @@ R_Clear(void)
glPolygonOffset(-0.05, -1);
}
}
/* stencilbuffer shadows */
if (gl_shadows->value && gl_state.stencil && gl1_stencilshadow->value)
{
glClearStencil(GL_TRUE);
glClear(GL_STENCIL_BUFFER_BIT);
}
}
void
@ -932,7 +967,6 @@ R_SetGL2D(void)
static void
R_RenderView(const refdef_t *fd)
{
#ifndef YQ2_GL1_GLES
if ((gl_state.stereo_mode != STEREO_MODE_NONE) && gl_state.camera_separation) {
qboolean drawing_left_eye = gl_state.camera_separation < 0;
@ -982,6 +1016,13 @@ R_RenderView(const refdef_t *fd)
qboolean flip_eyes = true;
int client_x, client_y;
GLshort screen[] = {
0, 0,
(GLshort)vid.width, 0,
(GLshort)vid.width, (GLshort)vid.height,
0, (GLshort)vid.height
};
//GLimp_GetClientAreaOffset(&client_x, &client_y);
client_x = 0;
client_y = 0;
@ -989,47 +1030,53 @@ R_RenderView(const refdef_t *fd)
R_SetGL2D();
glEnable(GL_STENCIL_TEST);
glStencilMask(GL_TRUE);
glStencilMask(1);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
glStencilFunc(GL_NEVER, 0, 1);
glBegin(GL_QUADS);
{
glVertex2i(0, 0);
glVertex2i(vid.width, 0);
glVertex2i(vid.width, vid.height);
glVertex2i(0, vid.height);
}
glEnd();
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_SHORT, 0, screen);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
glStencilFunc(GL_NEVER, 1, 1);
glBegin(GL_LINES);
if (gl_state.stereo_mode == STEREO_MODE_ROW_INTERLEAVED || gl_state.stereo_mode == STEREO_MODE_PIXEL_INTERLEAVED)
{
if (gl_state.stereo_mode == STEREO_MODE_ROW_INTERLEAVED || gl_state.stereo_mode == STEREO_MODE_PIXEL_INTERLEAVED) {
int y;
for (y = 0; y <= vid.height; y += 2) {
glVertex2f(0, y - 0.5f);
glVertex2f(vid.width, y - 0.5f);
}
flip_eyes ^= (client_y & 1);
}
if (gl_state.stereo_mode == STEREO_MODE_COLUMN_INTERLEAVED || gl_state.stereo_mode == STEREO_MODE_PIXEL_INTERLEAVED) {
int x;
for (x = 0; x <= vid.width; x += 2) {
glVertex2f(x - 0.5f, 0);
glVertex2f(x - 0.5f, vid.height);
}
flip_eyes ^= (client_x & 1);
for (int y = 0; y <= vid.height; y += 2)
{
gl_buf.vtx[gl_buf.vt ] = 0;
gl_buf.vtx[gl_buf.vt + 1] = y - 0.5f;
gl_buf.vtx[gl_buf.vt + 2] = vid.width;
gl_buf.vtx[gl_buf.vt + 3] = y - 0.5f;
gl_buf.vt += 4;
}
flip_eyes ^= (client_y & 1);
}
glEnd();
glStencilMask(GL_FALSE);
if (gl_state.stereo_mode == STEREO_MODE_COLUMN_INTERLEAVED || gl_state.stereo_mode == STEREO_MODE_PIXEL_INTERLEAVED)
{
for (int x = 0; x <= vid.width; x += 2)
{
gl_buf.vtx[gl_buf.vt ] = x - 0.5f;
gl_buf.vtx[gl_buf.vt + 1] = 0;
gl_buf.vtx[gl_buf.vt + 2] = x - 0.5f;
gl_buf.vtx[gl_buf.vt + 3] = vid.height;
gl_buf.vt += 4;
}
flip_eyes ^= (client_x & 1);
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, gl_buf.vtx);
glDrawArrays(GL_LINES, 0, gl_buf.vt / 2);
glDisableClientState(GL_VERTEX_ARRAY);
gl_buf.vt = 0;
glStencilMask(0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, drawing_left_eye ^ flip_eyes, 1);
@ -1040,7 +1087,6 @@ R_RenderView(const refdef_t *fd)
break;
}
}
#endif
if (r_norefresh->value)
{
@ -1182,9 +1228,9 @@ RI_RenderFrame(refdef_t *fd)
}
#ifdef YQ2_GL1_GLES
#define DEFAULT_LMCOPIES "1"
#define GLES1_ENABLED_ONLY "1"
#else
#define DEFAULT_LMCOPIES "0"
#define GLES1_ENABLED_ONLY "0"
#endif
void
@ -1235,6 +1281,8 @@ R_Register(void)
gl_polyblend = ri.Cvar_Get("gl_polyblend", "1", 0);
r_flashblend = ri.Cvar_Get("r_flashblend", "0", 0);
r_fixsurfsky = ri.Cvar_Get("r_fixsurfsky", "0", CVAR_ARCHIVE);
/* font should looks good with 8 pixels size */
r_ttffont = ri.Cvar_Get("r_ttffont", "RussoOne-Regular", CVAR_ARCHIVE);
gl_texturemode = ri.Cvar_Get("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE);
gl1_texturealphamode = ri.Cvar_Get("gl1_texturealphamode", "default", CVAR_ARCHIVE);
@ -1245,10 +1293,8 @@ R_Register(void)
gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE);
gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE);
gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE);
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", DEFAULT_LMCOPIES, CVAR_ARCHIVE);
#ifdef YQ2_GL1_GLES
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", "1", CVAR_ARCHIVE);
#endif
gl1_lightmapcopies = ri.Cvar_Get("gl1_lightmapcopies", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
gl1_discardfb = ri.Cvar_Get("gl1_discardfb", GLES1_ENABLED_ONLY, CVAR_ARCHIVE);
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE);
@ -1280,13 +1326,15 @@ R_Register(void)
gl1_stereo_anaglyph_colors = ri.Cvar_Get( "gl1_stereo_anaglyph_colors", "rc", CVAR_ARCHIVE );
gl1_stereo_convergence = ri.Cvar_Get( "gl1_stereo_convergence", "1", CVAR_ARCHIVE );
gl1_waterwarp = ri.Cvar_Get( "gl1_waterwarp", "1.0", CVAR_ARCHIVE );
ri.Cmd_AddCommand("imagelist", R_ImageList_f);
ri.Cmd_AddCommand("screenshot", R_ScreenShot);
ri.Cmd_AddCommand("modellist", Mod_Modellist_f);
ri.Cmd_AddCommand("gl_strings", R_Strings);
}
#undef DEFAULT_LMCOPIES
#undef GLES1_ENABLED_ONLY
/*
* Changes the video mode
@ -1689,28 +1737,28 @@ RI_Init(void)
// ----
/* Discard framebuffer: Available only on GLES1, enables the use of a "performance hint"
* to the graphic driver, to get rid of the contents of the depth and stencil buffers.
/* Discard framebuffer: Enables the use of a "performance hint" to the graphic
* driver in GLES1, to get rid of the contents of the different framebuffers.
* Useful for some GPUs that may attempt to keep them and/or write them back to
* external/uniform memory, actions that are useless for Quake 2 rendering path.
* https://registry.khronos.org/OpenGL/extensions/EXT/EXT_discard_framebuffer.txt
* This extension is used by 'gl1_discardfb', and regardless of its existence,
* that cvar will enable glClear at the start of each frame, helping mobile GPUs.
*/
gl_config.discardfb = false;
#ifdef YQ2_GL1_GLES
R_Printf(PRINT_ALL, " - Discard framebuffer: ");
if (strstr(gl_config.extensions_string, "GL_EXT_discard_framebuffer"))
{
qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *))
RI_GetProcAddress ("glDiscardFramebufferEXT");
qglDiscardFramebufferEXT = (void (APIENTRY *)(GLenum, GLsizei, const GLenum *))
RI_GetProcAddress ("glDiscardFramebufferEXT");
}
if (gl1_discardfb->value)
{
if (qglDiscardFramebufferEXT)
if (qglDiscardFramebufferEXT) // enough to verify availability
{
gl_config.discardfb = true;
R_Printf(PRINT_ALL, "Okay\n");
}
else
@ -1740,6 +1788,7 @@ RI_Init(void)
// ----
R_ResetClearColor();
R_SetDefaultState();
R_VertBufferInit();
@ -1766,6 +1815,7 @@ RI_Shutdown(void)
Mod_FreeAll();
R_ShutdownImages();
RDraw_FreeLocal();
R_VertBufferFree();
@ -1789,17 +1839,17 @@ RI_BeginFrame(float camera_separation)
gl_state.camera_separation = camera_separation;
// force a vid_restart if gl1_stereo has been modified.
if ( gl_state.stereo_mode != gl1_stereo->value ) {
if ( gl_state.stereo_mode != gl1_stereo->value )
{
// If we've gone from one mode to another with the same special buffer requirements there's no need to restart.
if ( GL_GetSpecialBufferModeForStereoMode( gl_state.stereo_mode ) == GL_GetSpecialBufferModeForStereoMode( gl1_stereo->value ) ) {
if ( GL_GetSpecialBufferModeForStereoMode( gl_state.stereo_mode ) == GL_GetSpecialBufferModeForStereoMode( gl1_stereo->value ) )
{
gl_state.stereo_mode = gl1_stereo->value;
}
else
{
R_Printf(PRINT_ALL, "stereo supermode changed, restarting video!\n");
cvar_t *ref;
ref = ri.Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
ref->modified = true;
ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n");
}
}
@ -1894,12 +1944,12 @@ RI_BeginFrame(float camera_separation)
gl1_particle_square->modified = false;
}
#ifndef YQ2_GL1_GLES
/* draw buffer stuff */
if (gl_drawbuffer->modified)
{
gl_drawbuffer->modified = false;
#ifndef YQ2_GL1_GLES
if ((gl_state.camera_separation == 0) || gl_state.stereo_mode != STEREO_MODE_OPENGL)
{
if (Q_stricmp(gl_drawbuffer->string, "GL_FRONT") == 0)
@ -1911,8 +1961,8 @@ RI_BeginFrame(float camera_separation)
glDrawBuffer(GL_BACK);
}
}
}
#endif
}
/* texturemode stuff */
if (gl_texturemode->modified || (gl_config.anisotropic && gl_anisotropic->modified)
@ -1982,7 +2032,7 @@ RI_SetPalette(const unsigned char *palette)
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 0, 0.5, 0.5);
R_ResetClearColor();
}
void
@ -2119,6 +2169,7 @@ GetRefAPI(refimport_t imp)
refexport.DrawPicScaled = RDraw_PicScaled;
refexport.DrawStretchPic = RDraw_StretchPic;
refexport.DrawCharScaled = RDraw_CharScaled;
refexport.DrawStringScaled = RDraw_StringScaled;
refexport.DrawTileClear = RDraw_TileClear;
refexport.DrawFill = RDraw_Fill;
refexport.DrawFadeScreen = RDraw_FadeScreen;
@ -2171,6 +2222,15 @@ Com_Printf(const char *msg, ...)
va_end(argptr);
}
void
Com_DPrintf(const char *msg, ...)
{
va_list argptr;
va_start(argptr, msg);
ri.Com_VPrintf(PRINT_DEVELOPER, msg, argptr);
va_end(argptr);
}
void
Com_Error(int code, const char *fmt, ...)
{

View file

@ -174,13 +174,18 @@ R_DrawAliasFrameLerp(entity_t *currententity, dmdx_t *paliashdr, float backlerp,
lerp = s_lerped[0];
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, lerp,
move, frontv, backv);
move, frontv, backv, currententity->scale);
num_mesh_nodes = paliashdr->num_meshes;
mesh_nodes = (dmdxmesh_t *)((char*)paliashdr + paliashdr->ofs_meshes);
for (i = 0; i < num_mesh_nodes; i++)
{
if (currententity->rr_mesh & (1 << i))
{
continue;
}
R_DrawAliasDrawCommands(currententity,
order + mesh_nodes[i].ofs_glcmds,
order + Q_min(paliashdr->num_glcmds,
@ -237,6 +242,10 @@ static void
R_DrawAliasShadow(entity_t *currententity, dmdx_t *paliashdr, int posenum,
vec4_t *s_lerped, vec3_t shadevector)
{
// Don't do stencil test on unsupported stereo modes
const qboolean stencilt = ( gl_state.stencil && gl1_stencilshadow->value &&
( gl_state.stereo_mode < STEREO_MODE_ROW_INTERLEAVED
|| gl_state.stereo_mode > STEREO_MODE_PIXEL_INTERLEAVED ) );
int *order, i, num_mesh_nodes;
float height = 0, lheight;
dmdxmesh_t *mesh_nodes;
@ -248,7 +257,7 @@ R_DrawAliasShadow(entity_t *currententity, dmdx_t *paliashdr, int posenum,
R_UpdateGLBuffer(buf_shadow, 0, 0, 0, 1);
/* stencilbuffer shadows */
if (gl_state.stencil && gl1_stencilshadow->value)
if (stencilt)
{
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 2);
@ -270,7 +279,7 @@ R_DrawAliasShadow(entity_t *currententity, dmdx_t *paliashdr, int posenum,
R_ApplyGLBuffer();
/* stencilbuffer shadows */
if (gl_state.stencil && gl1_stencilshadow->value)
if (stencilt)
{
glDisable(GL_STENCIL_TEST);
}
@ -334,6 +343,15 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
}
}
for (i = 0; i < 3; i++)
{
/* fix scale */
if (!currententity->scale[i])
{
currententity->scale[i] = 1.0f;
}
}
paliashdr = (dmdx_t *)currentmodel->extradata;
/* get lighting information */

View file

@ -169,7 +169,6 @@ R_Strings(void)
void
R_SetDefaultState(void)
{
glClearColor(1, 0, 0.5, 0.5);
glDisable(GL_MULTISAMPLE);
glCullFace(GL_FRONT);
glEnable(GL_TEXTURE_2D);

View file

@ -26,7 +26,8 @@
#include "header/local.h"
static YQ2_ALIGNAS_TYPE(int) byte mod_novis[MAX_MAP_LEAFS / 8];
static byte *mod_novis = NULL;
static size_t mod_novis_len = 0;
static model_t mod_known[MAX_MOD_KNOWN];
static int mod_numknown = 0;
@ -65,15 +66,34 @@ Mod_HasFreeSpace(void)
const byte *
Mod_ClusterPVS(int cluster, const model_t *model)
{
if ((cluster == -1) || !model->vis)
if (!mod_novis)
{
Com_Error(ERR_DROP, "%s: incrorrect init of PVS/PHS", __func__);
}
if (!model->vis)
{
Mod_DecompressVis(NULL, mod_novis, NULL,
(model->numclusters + 7) >> 3);
return mod_novis;
}
return Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS],
if (cluster == -1)
{
memset(mod_novis, 0, (model->numclusters + 7) >> 3);
return mod_novis;
}
if (cluster < 0 || cluster >= model->numvisibility)
{
Com_Error(ERR_DROP, "%s: bad cluster", __func__);
}
Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS], mod_novis,
(byte *)model->vis + model->numvisibility,
(model->vis->numclusters + 7) >> 3);
(model->numclusters + 7) >> 3);
return mod_novis;
}
void
@ -117,7 +137,8 @@ void
Mod_Init(void)
{
mod_max = 0;
memset(mod_novis, 0xff, sizeof(mod_novis));
mod_novis = NULL;
mod_novis_len = 0;
}
static void
@ -362,33 +383,28 @@ Mod_LoadBrushModel(model_t *mod, const void *buffer, int modfilelen)
Mod_LoadVisibility(mod->name, &mod->vis, &mod->numvisibility, mod_base,
&header->lumps[LUMP_VISIBILITY]);
Mod_LoadQBSPLeafs(mod->name, &mod->leafs, &mod->numleafs,
mod->marksurfaces, mod->nummarksurfaces, mod_base,
&header->lumps[LUMP_LEAFS]);
mod->marksurfaces, mod->nummarksurfaces, &mod->numclusters,
mod_base, &header->lumps[LUMP_LEAFS]);
Mod_LoadQBSPNodes(mod->name, mod->planes, mod->numplanes, mod->leafs,
mod->numleafs, &mod->nodes, &mod->numnodes, mod_base,
&header->lumps[LUMP_NODES], header->ident);
mod->numleafs, &mod->nodes, &mod->numnodes, mod->mins, mod->maxs,
mod_base, &header->lumps[LUMP_NODES], header->ident);
Mod_LoadSubmodels(mod, mod_base, &header->lumps[LUMP_MODELS]);
mod->numframes = 2; /* regular and alternate animation */
}
/* Temporary solution, need to use load file dirrectly */
static int
Mod_ReadFile(const char *path, void **buffer)
{
char *data;
int size;
size = ri.FS_LoadFile(path, (void **)&data);
if (size <= 0)
if (mod->vis && mod->numclusters != mod->vis->numclusters)
{
return size;
Com_Error(ERR_DROP, "%s: Map %s has incorrect number of clusters %d != %d",
__func__, mod->name, mod->numclusters, mod->vis->numclusters);
}
*buffer = malloc(size);
memcpy(*buffer, data, size);
ri.FS_FreeFile((void *)data);
return size;
if ((mod->numleafs > mod_novis_len) || !mod_novis)
{
/* reallocate buffers for PVS/PHS buffers*/
mod_novis_len = (mod->numleafs + 63) & ~63;
mod_novis = realloc(mod_novis, mod_novis_len / 8);
Com_Printf("Allocated " YQ2_COM_PRIdS " bit leafs of PVS/PHS buffer\n",
mod_novis_len);
}
}
/*
@ -397,9 +413,10 @@ Mod_ReadFile(const char *path, void **buffer)
static model_t *
Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
{
char filename[256] = {0}, *tag;
int i, modfilelen;
model_t *mod;
void *buf;
int i, modfilelen;
if (!name[0])
{
@ -455,8 +472,18 @@ Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
strcpy(mod->name, name);
/* Anachronox has tags in model path*/
Q_strlcpy(filename, name, sizeof(filename));
tag = strstr(filename, ".mda!");
if (tag)
{
tag += 4; /* strlen(.mda) */
*tag = 0;
tag ++;
}
/* load the file */
modfilelen = ri.Mod_LoadFile(mod->name, &buf);
modfilelen = ri.Mod_LoadFile(filename, &buf);
if (!buf)
{
@ -478,32 +505,14 @@ Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
/* call the apropriate loader */
switch (LittleLong(*(unsigned *)buf))
{
case MDAHEADER:
/* fall through */
case SDEFHEADER:
/* fall through */
case MDXHEADER:
/* fall through */
case DKMHEADER:
/* fall through */
case RAVENFMHEADER:
/* fall through */
case IDALIASHEADER:
/* fall through */
case IDMDLHEADER:
/* fall through */
case ID3HEADER:
/* fall through */
case MDR_IDENT:
/* fall through */
case IDMD5HEADER:
/* fall through */
case IDSPRITEHEADER:
{
mod->extradata = Mod_LoadModel(mod->name, buf, modfilelen,
mod->mins, mod->maxs,
(struct image_s ***)&mod->skins, &mod->numskins,
(findimage_t)R_FindImage, (loadimage_t)R_LoadPic, Mod_ReadFile,
(findimage_t)R_FindImage, (loadimage_t)R_LoadPic,
&(mod->type));
if (!mod->extradata)
{
@ -555,6 +564,13 @@ Mod_Free(model_t *mod)
}
Hunk_Free(mod->extradata);
if (mod->type == mod_alias || mod->type == mod_sprite)
{
/* skins are allocated separately */
free(mod->skins);
}
memset(mod, 0, sizeof(*mod));
}
@ -570,6 +586,14 @@ Mod_FreeAll(void)
Mod_Free(&mod_known[i]);
}
}
/* Free PVS buffer */
if (mod_novis)
{
free(mod_novis);
mod_novis = NULL;
}
mod_novis_len = 0;
}
/*

View file

@ -38,6 +38,8 @@ static SDL_GLContext context = NULL;
qboolean IsHighDPIaware = false;
static qboolean vsyncActive = false;
extern cvar_t *gl1_discardfb;
// ----
/*
@ -47,13 +49,26 @@ void
RI_EndFrame(void)
{
R_ApplyGLBuffer(); // to draw buffered 2D text
#ifdef YQ2_GL1_GLES
if (gl_config.discardfb)
static const GLenum attachments[3] = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT};
if (qglDiscardFramebufferEXT)
{
static const GLenum attachments[] = { GL_DEPTH_EXT, GL_STENCIL_EXT };
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments);
switch ((int)gl1_discardfb->value)
{
case 1:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 3, &attachments[0]);
break;
case 2:
qglDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, &attachments[1]);
break;
default:
break;
}
}
#endif
SDL_GL_SwapWindow(window);
}
@ -89,7 +104,11 @@ int RI_PrepareForWindow(void)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
#ifdef USE_SDL3
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8))
#else
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0)
#endif
{
gl_state.stencil = true;
}
@ -111,7 +130,11 @@ int RI_PrepareForWindow(void)
msaa_samples = gl_msaa_samples->value;
#ifdef USE_SDL3
if (!SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1))
#else
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) < 0)
#endif
{
R_Printf(PRINT_ALL, "MSAA is unsupported: %s\n", SDL_GetError());
@ -120,7 +143,11 @@ int RI_PrepareForWindow(void)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
}
#ifdef USE_SDL3
else if (!SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples))
#else
else if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples) < 0)
#endif
{
R_Printf(PRINT_ALL, "MSAA %ix is unsupported: %s\n", msaa_samples, SDL_GetError());
@ -157,7 +184,11 @@ void RI_SetVsync(void)
vsync = -1;
}
#ifdef USE_SDL3
if (!SDL_GL_SetSwapInterval(vsync))
#else
if (SDL_GL_SetSwapInterval(vsync) == -1)
#endif
{
if (vsync == -1)
{
@ -170,7 +201,7 @@ void RI_SetVsync(void)
#ifdef USE_SDL3
int vsyncState;
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
if (!SDL_GL_GetSwapInterval(&vsyncState))
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
@ -239,7 +270,7 @@ int RI_InitContext(void* win)
#ifdef YQ2_GL1_GLES
// Load GL pointers through GLAD and check context.
if( !gladLoadGLES1Loader(SDL_GL_GetProcAddress))
if( !gladLoadGLES1Loader( (void * (*)(const char *)) SDL_GL_GetProcAddress ) )
{
R_Printf(PRINT_ALL, "RI_InitContext(): ERROR: loading OpenGL ES function pointers failed!\n");
return false;
@ -282,7 +313,11 @@ int RI_InitContext(void* win)
if (gl_msaa_samples->value)
{
#ifdef USE_SDL3
if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples))
#else
if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0)
#endif
{
ri.Cvar_SetValue("r_msaa_samples", msaa_samples);
}
@ -296,7 +331,11 @@ int RI_InitContext(void* win)
if (gl_state.stencil)
{
#ifdef USE_SDL3
if (!SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) || stencil_bits < 8)
#else
if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) < 0 || stencil_bits < 8)
#endif
{
gl_state.stencil = false;
}
@ -350,7 +389,11 @@ RI_ShutdownContext(void)
{
if(context)
{
#ifdef USE_SDL3
SDL_GL_DestroyContext(context);
#else
SDL_GL_DeleteContext(context);
#endif
context = NULL;
}
}
@ -364,12 +407,11 @@ RI_ShutdownContext(void)
int RI_GetSDLVersion()
{
#ifdef USE_SDL3
SDL_Version ver;
int version = SDL_GetVersion();
return SDL_VERSIONNUM_MAJOR(version);
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
return ver.major;
#endif
}

View file

@ -376,7 +376,7 @@ R_BlendLightmaps(const model_t *currentmodel)
}
static void
R_RenderBrushPoly(const entity_t *currententity, msurface_t *fa)
R_RenderBrushPoly(msurface_t *fa)
{
qboolean is_dynamic = false;
int maps;
@ -517,12 +517,12 @@ R_DrawAlphaSurfaces(void)
}
static void
R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf)
R_RenderLightmappedPoly(msurface_t *surf)
{
int i;
int nv = surf->polys->numverts;
mvtx_t* vert;
const int nv = surf->polys->numverts;
float sscroll, tscroll;
mvtx_t* vert;
int i;
c_brush_polys++;
vert = surf->polys->verts;
@ -728,7 +728,7 @@ dynamic_surf:
}
static void
R_DrawTextureChains(const entity_t *currententity)
R_DrawTextureChains(void)
{
int i;
msurface_t *s;
@ -757,7 +757,7 @@ R_DrawTextureChains(const entity_t *currententity)
for ( ; s; s = s->texturechain)
{
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1);
R_RenderBrushPoly(currententity, s);
R_RenderBrushPoly(s);
}
image->texturechain = NULL;
@ -780,7 +780,7 @@ R_DrawTextureChains(const entity_t *currententity)
if (!(s->flags & SURF_DRAWTURB))
{
R_UpdateGLBuffer(buf_mtex, image->texnum, s->lightmaptexturenum, 0, 1);
R_RenderLightmappedPoly(currententity, s);
R_RenderLightmappedPoly(s);
}
}
}
@ -800,7 +800,7 @@ R_DrawTextureChains(const entity_t *currententity)
if (s->flags & SURF_DRAWTURB)
{
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1);
R_RenderBrushPoly(currententity, s);
R_RenderBrushPoly(s);
}
}
@ -862,12 +862,12 @@ R_DrawInlineBModel(const entity_t *currententity, const model_t *currentmodel)
{
// Dynamic lighting already generated in R_GetBrushesLighting()
R_UpdateGLBuffer(buf_mtex, image->texnum, psurf->lightmaptexturenum, 0, 1);
R_RenderLightmappedPoly(currententity, psurf);
R_RenderLightmappedPoly(psurf);
}
else
{
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, psurf->flags, 1);
R_RenderBrushPoly(currententity, psurf);
R_RenderBrushPoly(psurf);
}
}
}
@ -1090,6 +1090,11 @@ R_RecursiveWorldNode(entity_t *currententity, mnode_t *node)
r_alpha_surfaces = surf;
r_alpha_surfaces->texinfo->image = R_TextureAnimation(currententity, surf->texinfo);
}
else if (surf->texinfo->flags & SURF_NODRAW)
{
/* Surface should be skipped */
continue;
}
else
{
/* the polygon is visible, so add it to the texture sorted chain */
@ -1223,7 +1228,7 @@ R_DrawWorld(void)
R_RecursiveWorldNode(&ent, r_worldmodel->nodes);
R_GetBrushesLighting();
R_RegenAllLightmaps();
R_DrawTextureChains(&ent);
R_DrawTextureChains();
R_BlendLightmaps(r_worldmodel);
R_DrawSkyBox();
R_DrawTriangleOutlines();
@ -1237,7 +1242,7 @@ void
R_MarkLeaves(void)
{
const byte *vis;
YQ2_ALIGNAS_TYPE(int) byte fatvis[MAX_MAP_LEAFS / 8];
byte *fatvis = NULL;
mnode_t *node;
int i;
mleaf_t *leaf;
@ -1284,6 +1289,7 @@ R_MarkLeaves(void)
{
int c;
fatvis = malloc(((r_worldmodel->numleafs + 31) / 32) * sizeof(int));
memcpy(fatvis, vis, (r_worldmodel->numleafs + 7) / 8);
vis = Mod_ClusterPVS(r_viewcluster2, r_worldmodel);
c = (r_worldmodel->numleafs + 31) / 32;
@ -1326,4 +1332,10 @@ R_MarkLeaves(void)
while (node);
}
}
/* clean combined buffer */
if (fatvis)
{
free(fatvis);
}
}

View file

@ -51,8 +51,8 @@
#define TEXNUM_LIGHTMAPS 1024
#define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS * MAX_LIGHTMAP_COPIES)
#define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS)
#define BLOCK_WIDTH 256 // default values; now defined in glstate_t
#define BLOCK_HEIGHT 256
#define BLOCK_WIDTH 1024 // default values; now defined in glstate_t
#define BLOCK_HEIGHT 1024
#define MAX_TEXTURE_UNITS 2
#define GL_LIGHTMAP_FORMAT GL_RGBA
@ -127,8 +127,6 @@ typedef struct // 832k aprox.
#include "model.h"
void R_SetDefaultState(void);
extern glbuffer_t gl_buf;
extern float gldepthmin, gldepthmax;
@ -168,6 +166,7 @@ extern cvar_t *r_fullbright;
extern cvar_t *r_novis;
extern cvar_t *r_lerpmodels;
extern cvar_t *r_fixsurfsky;
extern cvar_t *r_ttffont;
extern cvar_t *r_lightlevel;
extern cvar_t *gl1_overbrightbits;
@ -287,6 +286,7 @@ void R_SetTexturePalette(const unsigned palette[256]);
void R_InitImages(void);
void R_ShutdownImages(void);
void RDraw_FreeLocal(void);
void R_FreeUnusedImages(void);
qboolean R_ImageHasFreeSpace(void);
@ -397,7 +397,6 @@ typedef struct
qboolean pointparameters;
qboolean multitexture;
qboolean lightmapcopies; // many copies of same lightmap, for embedded
qboolean discardfb;
// ----
@ -487,9 +486,10 @@ int RI_GetSDLVersion();
/* g11_draw */
extern image_t * RDraw_FindPic(const char *name);
extern void RDraw_GetPicSize(int *w, int *h, const char *pic);
extern void RDraw_PicScaled(int x, int y, const char *pic, float factor);
extern void RDraw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext);
extern void RDraw_StretchPic(int x, int y, int w, int h, const char *pic);
extern void RDraw_CharScaled(int x, int y, int num, float scale);
extern void RDraw_StringScaled(int x, int y, float scale, qboolean alt, const char *message);
extern void RDraw_TileClear(int x, int y, int w, int h, const char *pic);
extern void RDraw_Fill(int x, int y, int w, int h, int c);
extern void RDraw_FadeScreen(void);

View file

@ -84,6 +84,7 @@ typedef struct model_s
msurface_t **marksurfaces;
int numvisibility;
int numclusters;
dvis_t *vis;
byte *lightdata;

View file

@ -26,36 +26,31 @@
*/
#include "header/local.h"
#include "../files/stb_truetype.h"
unsigned d_8to24table[256];
gl3image_t *draw_chars;
static float gl3_font_size = 8.0;
static int gl3_font_height = 128;
gl3image_t *draw_chars = NULL;
static gl3image_t *draw_font = NULL;
static gl3image_t *draw_font_alt = NULL;
static stbtt_bakedchar *draw_fontcodes = NULL;
static GLuint vbo2D = 0, vao2D = 0, vao2Dcolor = 0; // vao2D is for textured rendering, vao2Dcolor for color-only
void R_LoadTTFFont(const char *ttffont, int vid_height, float *r_font_size,
int *r_font_height, stbtt_bakedchar **draw_fontcodes,
struct image_s **draw_font, struct image_s **draw_font_alt,
loadimage_t R_LoadPic);
void
GL3_Draw_InitLocal(void)
{
/* load console characters */
draw_chars = R_FindPic("conchars", (findimage_t)GL3_FindImage);
R_LoadTTFFont(r_ttffont->string, vid.height, &gl3_font_size, &gl3_font_height,
&draw_fontcodes, &draw_font, &draw_font_alt, (loadimage_t)GL3_LoadPic);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic ("fonts/conchars", (findimage_t)GL3_FindImage);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic ("dkchars", (findimage_t)GL3_FindImage);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}
draw_chars = R_LoadConsoleChars((findimage_t)GL3_FindImage);
// set up attribute layout for 2D textured rendering
glGenVertexArrays(1, &vao2D);
@ -98,6 +93,7 @@ GL3_Draw_ShutdownLocal(void)
vao2D = 0;
glDeleteVertexArrays(1, &vao2Dcolor);
vao2Dcolor = 0;
free(draw_fontcodes);
}
// bind the texture before calling this
@ -173,6 +169,64 @@ GL3_Draw_CharScaled(int x, int y, int num, float scale)
drawTexturedRectangle(x, y, scaledSize, scaledSize, fcol, frow, fcol+size, frow+size);
}
void
GL3_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message)
{
while (*message)
{
unsigned value = R_NextUTF8Code(&message);
if (draw_fontcodes && (draw_font || draw_font_alt))
{
float font_scale;
font_scale = gl3_font_size / 8.0;
if (value >= 32 && value < MAX_FONTCODE)
{
float xf = 0, yf = 0, xdiff;
stbtt_aligned_quad q;
stbtt_GetBakedQuad(draw_fontcodes, gl3_font_height, gl3_font_height,
value - 32, &xf, &yf, &q, 1);
xdiff = (8 - xf / font_scale) / 2;
if (xdiff < 0)
{
xdiff = 0;
}
GL3_UseProgram(gl3state.si2D.shaderProgram);
GL3_Bind(alt ? draw_font_alt->texnum : draw_font->texnum);
drawTexturedRectangle(
(float)(x + (xdiff + q.x0 / font_scale) * scale),
(float)(y + q.y0 * scale / font_scale + 8 * scale),
(q.x1 - q.x0) * scale / font_scale,
(q.y1 - q.y0) * scale / font_scale,
q.s0, q.t0, q.s1, q.t1);
x += Q_max(8, xf / font_scale) * scale;
}
else
{
x += 8 * scale;
}
}
else
{
int xor;
xor = alt ? 0x80 : 0;
if (value > ' ' && value < 128)
{
GL3_Draw_CharScaled(x, y, value ^ xor, scale);
}
x += 8 * scale;
}
}
}
gl3image_t *
GL3_Draw_FindPic(const char *name)
{
@ -214,11 +268,20 @@ GL3_Draw_StretchPic(int x, int y, int w, int h, const char *pic)
}
void
GL3_Draw_PicScaled(int x, int y, const char *pic, float factor)
GL3_Draw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext)
{
gl3image_t *gl = R_FindPic(pic, (findimage_t)GL3_FindImage);
gl3image_t *gl;
gl = R_FindPic(pic, (findimage_t)GL3_FindImage);
if (!gl)
{
if (alttext && alttext[0])
{
/* Show alttext if provided */
GL3_Draw_StringScaled(x, y, factor, false, alttext);
return;
}
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
return;
}

View file

@ -186,7 +186,7 @@ GL3_BindLightmap(int lightmapnum)
/*
* Returns has_alpha
*/
qboolean
static qboolean
GL3_Upload32(unsigned *data, int width, int height, qboolean mipmap)
{
qboolean res;
@ -237,7 +237,7 @@ GL3_Upload32(unsigned *data, int width, int height, qboolean mipmap)
/*
* Returns has_alpha
*/
qboolean
static qboolean
GL3_Upload8(byte *data, int width, int height, qboolean mipmap, qboolean is_sky)
{
int s = width * height;
@ -609,42 +609,41 @@ GL3_LoadPic(char *name, byte *pic, int width, int realwidth,
* Finds or loads the given image or NULL
*/
gl3image_t *
GL3_FindImage(const char *name, imagetype_t type)
GL3_FindImage(const char *originname, imagetype_t type)
{
char namewe[256], name[256] = {0};
gl3image_t *image;
int i, len;
char *ptr;
char namewe[256];
const char* ext;
size_t len;
int i;
if (!name)
if (!originname)
{
return NULL;
}
Q_strlcpy(name, originname, sizeof(name));
/* fix backslashes */
Q_replacebackslash(name);
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
/* Remove the extension */
memset(namewe, 0, 256);
memcpy(namewe, name, len - (strlen(ext) + 1));
if (len < 5)
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
memcpy(namewe, name, len);
namewe[len] = 0;
/* look for it */
for (i = 0, image = gl3textures; i < numgl3textures; i++, image++)

View file

@ -130,6 +130,7 @@ cvar_t *gl_shadows;
cvar_t *gl3_debugcontext;
cvar_t *gl3_usebigvbo;
cvar_t *r_fixsurfsky;
cvar_t *r_ttffont;
cvar_t *r_palettedtexture;
cvar_t *r_validation;
cvar_t *gl3_usefbo;
@ -232,6 +233,8 @@ GL3_Register(void)
r_drawentities = ri.Cvar_Get("r_drawentities", "1", 0);
r_drawworld = ri.Cvar_Get("r_drawworld", "1", 0);
r_fullbright = ri.Cvar_Get("r_fullbright", "0", 0);
/* font should looks good with 8 pixels size */
r_ttffont = ri.Cvar_Get("r_ttffont", "RussoOne-Regular", CVAR_ARCHIVE);
r_fixsurfsky = ri.Cvar_Get("r_fixsurfsky", "0", CVAR_ARCHIVE);
r_palettedtexture = ri.Cvar_Get("r_palettedtexture", "0", 0);
r_validation = ri.Cvar_Get("r_validation", "0", CVAR_ARCHIVE);
@ -366,12 +369,16 @@ SetMode_impl(int *pwidth, int *pheight, int mode, int fullscreen)
R_Printf(PRINT_ALL, " %dx%d (vid_fullscreen %i)\n", *pwidth, *pheight, fullscreen);
if (!ri.GLimp_InitGraphics(fullscreen, pwidth, pheight))
{
return rserr_invalid_mode;
}
if (mode == -2 || fullscreen)
{
GL3_BindVBO(0);
}
/* This is totaly obscure: For some strange reasons the renderer
maintains two(!) repesentations of the resolution. One comes
from the client and is saved in gl3_newrefdef. The other one
@ -526,19 +533,6 @@ GL3_Init(void)
R_Printf(PRINT_ALL, "\nOpenGL setting:\n");
GL3_Strings();
/*
if (gl_config.major_version < 3)
{
// if (gl_config.major_version == 3 && gl_config.minor_version < 2)
{
QGL_Shutdown();
R_Printf(PRINT_ALL, "Support for OpenGL 3.2 is not available\n");
return false;
}
}
*/
R_Printf(PRINT_ALL, "\n\nProbing for OpenGL extensions:\n");
@ -2018,6 +2012,7 @@ GetRefAPI(refimport_t imp)
re.DrawStretchPic = GL3_Draw_StretchPic;
re.DrawCharScaled = GL3_Draw_CharScaled;
re.DrawStringScaled = GL3_Draw_StringScaled;
re.DrawTileClear = GL3_Draw_TileClear;
re.DrawFill = GL3_Draw_Fill;
re.DrawFadeScreen = GL3_Draw_FadeScreen;
@ -2070,6 +2065,15 @@ Com_Printf(const char *msg, ...)
va_end(argptr);
}
void
Com_DPrintf(const char *msg, ...)
{
va_list argptr;
va_start(argptr, msg);
ri.Com_VPrintf(PRINT_DEVELOPER, msg, argptr);
va_end(argptr);
}
void
Com_Error(int code, const char *fmt, ...)
{

View file

@ -289,7 +289,8 @@ DrawAliasFrameLerp(dmdx_t *paliashdr, entity_t* entity, vec3_t shadelight,
lerp = s_lerped[0];
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, lerp, move, frontv, backv);
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, lerp,
move, frontv, backv, entity->scale);
YQ2_STATIC_ASSERT(sizeof(gl3_alias_vtx_t) == 9 * sizeof(GLfloat), "invalid gl3_alias_vtx_t size");
@ -298,6 +299,11 @@ DrawAliasFrameLerp(dmdx_t *paliashdr, entity_t* entity, vec3_t shadelight,
for (i = 0; i < num_mesh_nodes; i++)
{
if (entity->rr_mesh & (1 << i))
{
continue;
}
DrawAliasFrameLerpCommands(paliashdr, entity, shadelight,
order + mesh_nodes[i].ofs_glcmds,
order + Q_min(paliashdr->num_glcmds,
@ -469,7 +475,8 @@ DrawAliasShadow(gl3_shadowinfo_t* shadowInfo)
// false: don't extrude vertices for powerup - this means the powerup shell
// is not seen in the shadow, only the underlying model..
R_LerpVerts(false, paliashdr->num_xyz, verts, ov, s_lerped[0], move, frontv, backv);
R_LerpVerts(false, paliashdr->num_xyz, verts, ov, s_lerped[0],
move, frontv, backv, entity->scale);
}
lheight = entity->origin[2] - shadowInfo->lightspot[2];
@ -546,6 +553,15 @@ GL3_DrawAliasModel(entity_t *entity)
}
}
for (i = 0; i < 3; i++)
{
/* fix scale */
if (!entity->scale[i])
{
entity->scale[i] = 1.0f;
}
}
gl3model_t* model = entity->model;
paliashdr = (dmdx_t *)model->extradata;

View file

@ -27,7 +27,8 @@
#include "header/local.h"
static YQ2_ALIGNAS_TYPE(int) byte mod_novis[MAX_MAP_LEAFS / 8];
static byte *mod_novis = NULL;
static size_t mod_novis_len = 0;
static gl3model_t mod_known[MAX_MOD_KNOWN];
static int mod_numknown = 0;
@ -66,15 +67,34 @@ Mod_HasFreeSpace(void)
const byte *
GL3_Mod_ClusterPVS(int cluster, const gl3model_t *model)
{
if ((cluster == -1) || !model->vis)
if (!mod_novis)
{
Com_Error(ERR_DROP, "%s: incrorrect init of PVS/PHS", __func__);
}
if (!model->vis)
{
Mod_DecompressVis(NULL, mod_novis, NULL,
(model->numclusters + 7) >> 3);
return mod_novis;
}
return Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS],
if (cluster == -1)
{
memset(mod_novis, 0, (model->numclusters + 7) >> 3);
return mod_novis;
}
if (cluster < 0 || cluster >= model->numvisibility)
{
Com_Error(ERR_DROP, "%s: bad cluster", __func__);
}
Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS], mod_novis,
(byte *)model->vis + model->numvisibility,
(model->vis->numclusters + 7) >> 3);
(model->numclusters + 7) >> 3);
return mod_novis;
}
void
@ -118,7 +138,8 @@ void
GL3_Mod_Init(void)
{
mod_max = 0;
memset(mod_novis, 0xff, sizeof(mod_novis));
mod_novis = NULL;
mod_novis_len = 0;
}
static void
@ -363,33 +384,28 @@ Mod_LoadBrushModel(gl3model_t *mod, const void *buffer, int modfilelen)
Mod_LoadVisibility(mod->name, &mod->vis, &mod->numvisibility, mod_base,
&header->lumps[LUMP_VISIBILITY]);
Mod_LoadQBSPLeafs(mod->name, &mod->leafs, &mod->numleafs,
mod->marksurfaces, mod->nummarksurfaces, mod_base,
&header->lumps[LUMP_LEAFS]);
mod->marksurfaces, mod->nummarksurfaces, &mod->numclusters,
mod_base, &header->lumps[LUMP_LEAFS]);
Mod_LoadQBSPNodes(mod->name, mod->planes, mod->numplanes, mod->leafs,
mod->numleafs, &mod->nodes, &mod->numnodes, mod_base,
&header->lumps[LUMP_NODES], header->ident);
mod->numleafs, &mod->nodes, &mod->numnodes, mod->mins, mod->maxs,
mod_base, &header->lumps[LUMP_NODES], header->ident);
Mod_LoadSubmodels(mod, mod_base, &header->lumps[LUMP_MODELS]);
mod->numframes = 2; /* regular and alternate animation */
}
/* Temporary solution, need to use load file dirrectly */
static int
Mod_ReadFile(const char *path, void **buffer)
{
char *data;
int size;
size = ri.FS_LoadFile(path, (void **)&data);
if (size <= 0)
if (mod->vis && mod->numclusters != mod->vis->numclusters)
{
return size;
Com_Error(ERR_DROP, "%s: Map %s has incorrect number of clusters %d != %d",
__func__, mod->name, mod->numclusters, mod->vis->numclusters);
}
*buffer = malloc(size);
memcpy(*buffer, data, size);
ri.FS_FreeFile((void *)data);
return size;
if ((mod->numleafs > mod_novis_len) || !mod_novis)
{
/* reallocate buffers for PVS/PHS buffers*/
mod_novis_len = (mod->numleafs + 63) & ~63;
mod_novis = realloc(mod_novis, mod_novis_len / 8);
Com_Printf("Allocated " YQ2_COM_PRIdS " bit leafs of PVS/PHS buffer\n",
mod_novis_len);
}
}
/*
@ -398,9 +414,10 @@ Mod_ReadFile(const char *path, void **buffer)
static gl3model_t *
Mod_ForName(const char *name, gl3model_t *parent_model, qboolean crash)
{
char filename[256] = {0}, *tag;
int i, modfilelen;
gl3model_t *mod;
void *buf;
int i, modfilelen;
if (!name[0])
{
@ -456,8 +473,18 @@ Mod_ForName(const char *name, gl3model_t *parent_model, qboolean crash)
strcpy(mod->name, name);
/* Anachronox has tags in model path*/
Q_strlcpy(filename, name, sizeof(filename));
tag = strstr(filename, ".mda!");
if (tag)
{
tag += 4; /* strlen(.mda) */
*tag = 0;
tag ++;
}
/* load the file */
modfilelen = ri.Mod_LoadFile(mod->name, &buf);
modfilelen = ri.Mod_LoadFile(filename, &buf);
if (!buf)
{
@ -479,32 +506,14 @@ Mod_ForName(const char *name, gl3model_t *parent_model, qboolean crash)
/* call the apropriate loader */
switch (LittleLong(*(unsigned *)buf))
{
case MDAHEADER:
/* fall through */
case SDEFHEADER:
/* fall through */
case MDXHEADER:
/* fall through */
case DKMHEADER:
/* fall through */
case RAVENFMHEADER:
/* fall through */
case IDALIASHEADER:
/* fall through */
case IDMDLHEADER:
/* fall through */
case ID3HEADER:
/* fall through */
case MDR_IDENT:
/* fall through */
case IDMD5HEADER:
/* fall through */
case IDSPRITEHEADER:
{
mod->extradata = Mod_LoadModel(mod->name, buf, modfilelen,
mod->mins, mod->maxs,
(struct image_s ***)&mod->skins, &mod->numskins,
(findimage_t)GL3_FindImage, (loadimage_t)GL3_LoadPic, Mod_ReadFile,
(findimage_t)GL3_FindImage, (loadimage_t)GL3_LoadPic,
&(mod->type));
if (!mod->extradata)
{
@ -556,6 +565,13 @@ Mod_Free(gl3model_t *mod)
}
Hunk_Free(mod->extradata);
if (mod->type == mod_alias || mod->type == mod_sprite)
{
/* skins are allocated separately */
free(mod->skins);
}
memset(mod, 0, sizeof(*mod));
}
@ -571,6 +587,14 @@ GL3_Mod_FreeAll(void)
Mod_Free(&mod_known[i]);
}
}
/* Free PVS buffer */
if (mod_novis)
{
free(mod_novis);
mod_novis = NULL;
}
mod_novis_len = 0;
}
/*

View file

@ -53,7 +53,7 @@ enum {
*/
static void APIENTRY
DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
const GLchar *message, const void *userParam)
{
const char* sourceStr = "Source: Unknown";
const char* typeStr = "Type: Unknown";
@ -155,7 +155,11 @@ void GL3_SetVsync(void)
vsync = -1;
}
#ifdef USE_SDL3
if (!SDL_GL_SetSwapInterval(vsync))
#else
if (SDL_GL_SetSwapInterval(vsync) == -1)
#endif
{
if (vsync == -1)
{
@ -168,15 +172,15 @@ void GL3_SetVsync(void)
#ifdef USE_SDL3
int vsyncState;
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
if (!SDL_GL_GetSwapInterval(&vsyncState))
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
#else
vsyncActive = SDL_GL_GetSwapInterval() != 0;
#endif
@ -204,7 +208,11 @@ int GL3_PrepareForWindow(void)
while (1)
{
#ifdef USE_SDL3
if (!SDL_GL_LoadLibrary(libgl))
#else
if (SDL_GL_LoadLibrary(libgl) < 0)
#endif
{
if (libgl == NULL)
{
@ -236,7 +244,11 @@ int GL3_PrepareForWindow(void)
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifdef USE_SDL3
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8))
#else
if (SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8) == 0)
#endif
{
gl3config.stencil = true;
}
@ -287,7 +299,11 @@ int GL3_PrepareForWindow(void)
{
msaa_samples = gl_msaa_samples->value;
#ifdef USE_SDL3
if (!SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1))
#else
if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) < 0)
#endif
{
R_Printf(PRINT_ALL, "MSAA is unsupported: %s\n", SDL_GetError());
@ -296,7 +312,11 @@ int GL3_PrepareForWindow(void)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
}
#ifdef USE_SDL3
else if (!SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples))
#else
else if (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa_samples) < 0)
#endif
{
R_Printf(PRINT_ALL, "MSAA %ix is unsupported: %s\n", msaa_samples, SDL_GetError());
@ -350,7 +370,11 @@ int GL3_InitContext(void* win)
if (gl_msaa_samples->value)
{
#ifdef USE_SDL3
if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples))
#else
if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0)
#endif
{
ri.Cvar_SetValue("r_msaa_samples", msaa_samples);
}
@ -361,7 +385,11 @@ int GL3_InitContext(void* win)
if (gl3config.stencil)
{
#ifdef USE_SDL3
if (!SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) || stencil_bits < 8)
#else
if (SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits) < 0 || stencil_bits < 8)
#endif
{
gl3config.stencil = false;
}
@ -435,7 +463,7 @@ int GL3_InitContext(void* win)
}
// Window title - set here so we can display renderer name in it.
char title[40] = {0};
char title[64] = {0};
#ifdef YQ2_GL3_GLES3
snprintf(title, sizeof(title), "Yamagi Quake II %s - OpenGL ES 3.0", YQ2VERSION);
#else
@ -477,7 +505,11 @@ void GL3_ShutdownContext()
{
if(context)
{
#ifdef USE_SDL3
SDL_GL_DestroyContext(context);
#else
SDL_GL_DeleteContext(context);
#endif
context = NULL;
}
}
@ -491,12 +523,11 @@ void GL3_ShutdownContext()
int GL3_GetSDLVersion()
{
#ifdef USE_SDL3
SDL_Version ver;
int version = SDL_GetVersion();
return SDL_VERSIONNUM_MAJOR(version);
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
return ver.major;
#endif
}

View file

@ -729,6 +729,11 @@ RecursiveWorldNode(entity_t *currententity, mnode_t *node)
gl3_alpha_surfaces = surf;
gl3_alpha_surfaces->texinfo->image = R_TextureAnimation(currententity, surf->texinfo);
}
else if (surf->texinfo->flags & SURF_NODRAW)
{
/* Surface should be skipped */
continue;
}
else
{
// calling RenderLightmappedPoly() here probably isn't optimal, rendering everything
@ -792,11 +797,10 @@ void
GL3_MarkLeaves(void)
{
const byte *vis;
YQ2_ALIGNAS_TYPE(int) byte fatvis[MAX_MAP_LEAFS / 8];
byte *fatvis = NULL;
mnode_t *node;
int i, c;
int i;
mleaf_t *leaf;
int cluster;
if ((gl3_oldviewcluster == gl3_viewcluster) &&
(gl3_oldviewcluster2 == gl3_viewcluster2) &&
@ -838,6 +842,9 @@ GL3_MarkLeaves(void)
/* may have to combine two clusters because of solid water boundaries */
if (gl3_viewcluster2 != gl3_viewcluster)
{
int c;
fatvis = malloc(((gl3_worldmodel->numleafs + 31) / 32) * sizeof(int));
memcpy(fatvis, vis, (gl3_worldmodel->numleafs + 7) / 8);
vis = GL3_Mod_ClusterPVS(gl3_viewcluster2, gl3_worldmodel);
c = (gl3_worldmodel->numleafs + 31) / 32;
@ -854,6 +861,8 @@ GL3_MarkLeaves(void)
i < gl3_worldmodel->numleafs;
i++, leaf++)
{
int cluster;
cluster = leaf->cluster;
if (cluster == -1)
@ -878,5 +887,10 @@ GL3_MarkLeaves(void)
while (node);
}
}
}
/* clean combined buffer */
if (fatvis)
{
free(fatvis);
}
}

View file

@ -190,8 +190,8 @@ enum {
// width and height used to be 128, so now we should be able to get the same lightmap data
// that used 32 lightmaps before into one, so 4 lightmaps should be enough
BLOCK_WIDTH = 1024,
BLOCK_HEIGHT = 512,
MAX_LIGHTMAPS = 8,
BLOCK_HEIGHT = 1024,
MAX_LIGHTMAPS = 16,
MAX_LIGHTMAPS_PER_SURFACE = MAXLIGHTMAPS // 4
};
@ -417,15 +417,17 @@ extern void GL3_Draw_ShutdownLocal(void);
extern gl3image_t * GL3_Draw_FindPic(const char *name);
extern void GL3_Draw_GetPicSize(int *w, int *h, const char *pic);
extern void GL3_Draw_PicScaled(int x, int y, const char *pic, float factor);
extern void GL3_Draw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext);
extern void GL3_Draw_StretchPic(int x, int y, int w, int h, const char *pic);
extern void GL3_Draw_CharScaled(int x, int y, int num, float scale);
extern void GL3_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message);
extern void GL3_Draw_TileClear(int x, int y, int w, int h, const char *pic);
extern void GL3_DrawFrameBufferObject(int x, int y, int w, int h, GLuint fboTexture, const float v_blend[4]);
extern void GL3_Draw_Fill(int x, int y, int w, int h, int c);
extern void GL3_Draw_FadeScreen(void);
extern void GL3_Draw_Flash(const float color[4], float x, float y, float w, float h);
extern void GL3_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits);
extern void GL3_Draw_FreeLocal(void);
// gl3_image.c
@ -550,6 +552,7 @@ extern cvar_t *r_modulate;
extern cvar_t *gl_lightmap;
extern cvar_t *gl_shadows;
extern cvar_t *r_fixsurfsky;
extern cvar_t *r_ttffont;
extern cvar_t *r_palettedtexture;
extern cvar_t *r_validation;

View file

@ -95,6 +95,7 @@ typedef struct model_s
msurface_t **marksurfaces;
int numvisibility;
int numclusters;
dvis_t *vis;
byte *lightdata;

View file

@ -26,36 +26,31 @@
*/
#include "header/local.h"
#include "../files/stb_truetype.h"
unsigned d_8to24table[256];
gl4image_t *draw_chars;
static float gl4_font_size = 8.0;
static int gl4_font_height = 128;
gl4image_t *draw_chars = NULL;
static gl4image_t *draw_font = NULL;
static gl4image_t *draw_font_alt = NULL;
static stbtt_bakedchar *draw_fontcodes = NULL;
static GLuint vbo2D = 0, vao2D = 0, vao2Dcolor = 0; // vao2D is for textured rendering, vao2Dcolor for color-only
void R_LoadTTFFont(const char *ttffont, int vid_height, float *r_font_size,
int *r_font_height, stbtt_bakedchar **draw_fontcodes,
struct image_s **draw_font, struct image_s **draw_font_alt,
loadimage_t R_LoadPic);
void
GL4_Draw_InitLocal(void)
{
/* load console characters */
draw_chars = R_FindPic("conchars", (findimage_t)GL4_FindImage);
R_LoadTTFFont(r_ttffont->string, vid.height, &gl4_font_size, &gl4_font_height,
&draw_fontcodes, &draw_font, &draw_font_alt, (loadimage_t)GL4_LoadPic);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic ("fonts/conchars", (findimage_t)GL4_FindImage);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic ("dkchars", (findimage_t)GL4_FindImage);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars.pcx",
__func__);
}
draw_chars = R_LoadConsoleChars((findimage_t)GL4_FindImage);
// set up attribute layout for 2D textured rendering
glGenVertexArrays(1, &vao2D);
@ -98,6 +93,7 @@ GL4_Draw_ShutdownLocal(void)
vao2D = 0;
glDeleteVertexArrays(1, &vao2Dcolor);
vao2Dcolor = 0;
free(draw_fontcodes);
}
// bind the texture before calling this
@ -173,6 +169,64 @@ GL4_Draw_CharScaled(int x, int y, int num, float scale)
drawTexturedRectangle(x, y, scaledSize, scaledSize, fcol, frow, fcol+size, frow+size);
}
void
GL4_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message)
{
while (*message)
{
unsigned value = R_NextUTF8Code(&message);
if (draw_fontcodes && (draw_font || draw_font_alt))
{
float font_scale;
font_scale = gl4_font_size / 8.0;
if (value >= 32 && value < MAX_FONTCODE)
{
float xf = 0, yf = 0, xdiff;
stbtt_aligned_quad q;
stbtt_GetBakedQuad(draw_fontcodes, gl4_font_height, gl4_font_height,
value - 32, &xf, &yf, &q, 1);
xdiff = (8 - xf / font_scale) / 2;
if (xdiff < 0)
{
xdiff = 0;
}
GL4_UseProgram(gl4state.si2D.shaderProgram);
GL4_Bind(alt ? draw_font_alt->texnum : draw_font->texnum);
drawTexturedRectangle(
(float)(x + (xdiff + q.x0 / font_scale) * scale),
(float)(y + q.y0 * scale / font_scale + 8 * scale),
(q.x1 - q.x0) * scale / font_scale,
(q.y1 - q.y0) * scale / font_scale,
q.s0, q.t0, q.s1, q.t1);
x += Q_max(8, xf / font_scale) * scale;
}
else
{
x += 8 * scale;
}
}
else
{
int xor;
xor = alt ? 0x80 : 0;
if (value > ' ' && value < 128)
{
GL4_Draw_CharScaled(x, y, value ^ xor, scale);
}
x += 8 * scale;
}
}
}
gl4image_t *
GL4_Draw_FindPic(const char *name)
{
@ -214,11 +268,18 @@ GL4_Draw_StretchPic(int x, int y, int w, int h, const char *pic)
}
void
GL4_Draw_PicScaled(int x, int y, const char *pic, float factor)
GL4_Draw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext)
{
gl4image_t *gl = R_FindPic(pic, (findimage_t)GL4_FindImage);
if (!gl)
{
if (alttext && alttext[0])
{
/* Show alttext if provided */
GL4_Draw_StringScaled(x, y, factor, false, alttext);
return;
}
R_Printf(PRINT_ALL, "Can't find pic: %s\n", pic);
return;
}

View file

@ -610,42 +610,40 @@ GL4_LoadPic(char *name, byte *pic, int width, int realwidth,
* Finds or loads the given image or NULL
*/
gl4image_t *
GL4_FindImage(const char *name, imagetype_t type)
GL4_FindImage(const char *originname, imagetype_t type)
{
char namewe[256], name[256] = {0};
gl4image_t *image;
int i, len;
char *ptr;
char namewe[256];
const char* ext;
int i, len;
if (!name)
if (!originname)
{
return NULL;
}
Q_strlcpy(name, originname, sizeof(name));
/* fix backslashes */
Q_replacebackslash(name);
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
/* Remove the extension */
memset(namewe, 0, 256);
memcpy(namewe, name, len - (strlen(ext) + 1));
if (len < 5)
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
memcpy(namewe, name, len);
namewe[len] = 0;
/* look for it */
for (i = 0, image = gl4textures; i < numgl4textures; i++, image++)

View file

@ -126,6 +126,7 @@ cvar_t *gl_shadows;
cvar_t *gl4_debugcontext;
cvar_t *gl4_usebigvbo;
cvar_t *r_fixsurfsky;
cvar_t *r_ttffont;
cvar_t *r_palettedtexture;
cvar_t *r_validation;
cvar_t *gl4_usefbo;
@ -228,6 +229,8 @@ GL4_Register(void)
r_drawentities = ri.Cvar_Get("r_drawentities", "1", 0);
r_drawworld = ri.Cvar_Get("r_drawworld", "1", 0);
r_fullbright = ri.Cvar_Get("r_fullbright", "0", 0);
/* font should looks good with 8 pixels size */
r_ttffont = ri.Cvar_Get("r_ttffont", "RussoOne-Regular", CVAR_ARCHIVE);
r_fixsurfsky = ri.Cvar_Get("r_fixsurfsky", "0", CVAR_ARCHIVE);
r_palettedtexture = ri.Cvar_Get("r_palettedtexture", "0", 0);
r_validation = ri.Cvar_Get("r_validation", "0", CVAR_ARCHIVE);
@ -362,12 +365,16 @@ SetMode_impl(int *pwidth, int *pheight, int mode, int fullscreen)
R_Printf(PRINT_ALL, " %dx%d (vid_fullscreen %i)\n", *pwidth, *pheight, fullscreen);
if (!ri.GLimp_InitGraphics(fullscreen, pwidth, pheight))
{
return rserr_invalid_mode;
}
if (mode == -2 || fullscreen)
{
GL4_BindVBO(0);
}
/* This is totaly obscure: For some strange reasons the renderer
maintains two(!) repesentations of the resolution. One comes
from the client and is saved in gl4_newrefdef. The other one
@ -1590,9 +1597,6 @@ GL4_RenderView(refdef_t *fd)
GL4_DrawAlphaSurfaces();
// simple gamma correction
glEnable(GL_FRAMEBUFFER_SRGB);
// Note: R_Flash() is now GL4_Draw_Flash() and called from GL4_RenderFrame()
if (r_speeds->value)
@ -1938,6 +1942,7 @@ GetRefAPI(refimport_t imp)
re.DrawStretchPic = GL4_Draw_StretchPic;
re.DrawCharScaled = GL4_Draw_CharScaled;
re.DrawStringScaled = GL4_Draw_StringScaled;
re.DrawTileClear = GL4_Draw_TileClear;
re.DrawFill = GL4_Draw_Fill;
re.DrawFadeScreen = GL4_Draw_FadeScreen;
@ -1990,6 +1995,15 @@ Com_Printf(const char *msg, ...)
va_end(argptr);
}
void
Com_DPrintf(const char *msg, ...)
{
va_list argptr;
va_start(argptr, msg);
ri.Com_VPrintf(PRINT_DEVELOPER, msg, argptr);
va_end(argptr);
}
void
Com_Error(int code, const char *fmt, ...)
{

View file

@ -289,7 +289,8 @@ DrawAliasFrameLerp(dmdx_t *paliashdr, entity_t* entity, vec3_t shadelight,
lerp = s_lerped[0];
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, lerp, move, frontv, backv);
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, lerp,
move, frontv, backv, entity->scale);
YQ2_STATIC_ASSERT(sizeof(gl4_alias_vtx_t) == 9 * sizeof(GLfloat), "invalid gl4_alias_vtx_t size");
@ -298,6 +299,11 @@ DrawAliasFrameLerp(dmdx_t *paliashdr, entity_t* entity, vec3_t shadelight,
for (i = 0; i < num_mesh_nodes; i++)
{
if (entity->rr_mesh & (1 << i))
{
continue;
}
DrawAliasFrameLerpCommands(paliashdr, entity, shadelight,
order + mesh_nodes[i].ofs_glcmds,
order + Q_min(paliashdr->num_glcmds,
@ -469,7 +475,8 @@ DrawAliasShadow(gl4_shadowinfo_t* shadowInfo)
// false: don't extrude vertices for powerup - this means the powerup shell
// is not seen in the shadow, only the underlying model..
R_LerpVerts(false, paliashdr->num_xyz, verts, ov, s_lerped[0], move, frontv, backv);
R_LerpVerts(false, paliashdr->num_xyz, verts, ov, s_lerped[0],
move, frontv, backv, entity->scale);
}
lheight = entity->origin[2] - shadowInfo->lightspot[2];
@ -546,6 +553,15 @@ GL4_DrawAliasModel(entity_t *entity)
}
}
for (i = 0; i < 3; i++)
{
/* fix scale */
if (!entity->scale[i])
{
entity->scale[i] = 1.0f;
}
}
gl4model_t* model = entity->model;
paliashdr = (dmdx_t *)model->extradata;

View file

@ -27,7 +27,8 @@
#include "header/local.h"
YQ2_ALIGNAS_TYPE(int) static byte mod_novis[MAX_MAP_LEAFS / 8];
static byte *mod_novis = NULL;
static size_t mod_novis_len = 0;
static gl4model_t mod_known[MAX_MOD_KNOWN];
static int mod_numknown = 0;
@ -66,15 +67,34 @@ Mod_HasFreeSpace(void)
const byte *
GL4_Mod_ClusterPVS(int cluster, const gl4model_t *model)
{
if ((cluster == -1) || !model->vis)
if (!mod_novis)
{
Com_Error(ERR_DROP, "%s: incrorrect init of PVS/PHS", __func__);
}
if (!model->vis)
{
Mod_DecompressVis(NULL, mod_novis, NULL,
(model->numclusters + 7) >> 3);
return mod_novis;
}
return Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS],
if (cluster == -1)
{
memset(mod_novis, 0, (model->numclusters + 7) >> 3);
return mod_novis;
}
if (cluster < 0 || cluster >= model->numvisibility)
{
Com_Error(ERR_DROP, "%s: bad cluster", __func__);
}
Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS], mod_novis,
(byte *)model->vis + model->numvisibility,
(model->vis->numclusters + 7) >> 3);
(model->numclusters + 7) >> 3);
return mod_novis;
}
void
@ -118,7 +138,8 @@ void
GL4_Mod_Init(void)
{
mod_max = 0;
memset(mod_novis, 0xff, sizeof(mod_novis));
mod_novis = NULL;
mod_novis_len = 0;
}
static void
@ -363,33 +384,28 @@ Mod_LoadBrushModel(gl4model_t *mod, const void *buffer, int modfilelen)
Mod_LoadVisibility(mod->name, &mod->vis, &mod->numvisibility, mod_base,
&header->lumps[LUMP_VISIBILITY]);
Mod_LoadQBSPLeafs(mod->name, &mod->leafs, &mod->numleafs,
mod->marksurfaces, mod->nummarksurfaces, mod_base,
&header->lumps[LUMP_LEAFS]);
mod->marksurfaces, mod->nummarksurfaces, &mod->numclusters,
mod_base, &header->lumps[LUMP_LEAFS]);
Mod_LoadQBSPNodes(mod->name, mod->planes, mod->numplanes, mod->leafs,
mod->numleafs, &mod->nodes, &mod->numnodes, mod_base,
&header->lumps[LUMP_NODES], header->ident);
mod->numleafs, &mod->nodes, &mod->numnodes, mod->mins, mod->maxs,
mod_base, &header->lumps[LUMP_NODES], header->ident);
Mod_LoadSubmodels(mod, mod_base, &header->lumps[LUMP_MODELS]);
mod->numframes = 2; /* regular and alternate animation */
}
/* Temporary solution, need to use load file dirrectly */
static int
Mod_ReadFile(const char *path, void **buffer)
{
char *data;
int size;
size = ri.FS_LoadFile(path, (void **)&data);
if (size <= 0)
if (mod->vis && mod->numclusters != mod->vis->numclusters)
{
return size;
Com_Error(ERR_DROP, "%s: Map %s has incorrect number of clusters %d != %d",
__func__, mod->name, mod->numclusters, mod->vis->numclusters);
}
*buffer = malloc(size);
memcpy(*buffer, data, size);
ri.FS_FreeFile((void *)data);
return size;
if ((mod->numleafs > mod_novis_len) || !mod_novis)
{
/* reallocate buffers for PVS/PHS buffers*/
mod_novis_len = (mod->numleafs + 63) & ~63;
mod_novis = realloc(mod_novis, mod_novis_len / 8);
Com_Printf("Allocated " YQ2_COM_PRIdS " bit leafs of PVS/PHS buffer\n",
mod_novis_len);
}
}
/*
@ -398,9 +414,10 @@ Mod_ReadFile(const char *path, void **buffer)
static gl4model_t *
Mod_ForName(const char *name, gl4model_t *parent_model, qboolean crash)
{
char filename[256] = {0}, *tag;
int i, modfilelen;
gl4model_t *mod;
void *buf;
int i, modfilelen;
if (!name[0])
{
@ -456,8 +473,18 @@ Mod_ForName(const char *name, gl4model_t *parent_model, qboolean crash)
strcpy(mod->name, name);
/* Anachronox has tags in model path*/
Q_strlcpy(filename, name, sizeof(filename));
tag = strstr(filename, ".mda!");
if (tag)
{
tag += 4; /* strlen(.mda) */
*tag = 0;
tag ++;
}
/* load the file */
modfilelen = ri.Mod_LoadFile(mod->name, &buf);
modfilelen = ri.Mod_LoadFile(filename, &buf);
if (!buf)
{
@ -479,32 +506,14 @@ Mod_ForName(const char *name, gl4model_t *parent_model, qboolean crash)
/* call the apropriate loader */
switch (LittleLong(*(unsigned *)buf))
{
case MDAHEADER:
/* fall through */
case SDEFHEADER:
/* fall through */
case MDXHEADER:
/* fall through */
case DKMHEADER:
/* fall through */
case RAVENFMHEADER:
/* fall through */
case IDALIASHEADER:
/* fall through */
case IDMDLHEADER:
/* fall through */
case ID3HEADER:
/* fall through */
case MDR_IDENT:
/* fall through */
case IDMD5HEADER:
/* fall through */
case IDSPRITEHEADER:
{
mod->extradata = Mod_LoadModel(mod->name, buf, modfilelen,
mod->mins, mod->maxs,
(struct image_s ***)&mod->skins, &mod->numskins,
(findimage_t)GL4_FindImage, (loadimage_t)GL4_LoadPic, Mod_ReadFile,
(findimage_t)GL4_FindImage, (loadimage_t)GL4_LoadPic,
&(mod->type));
if (!mod->extradata)
{
@ -556,6 +565,13 @@ Mod_Free(gl4model_t *mod)
}
Hunk_Free(mod->extradata);
if (mod->type == mod_alias || mod->type == mod_sprite)
{
/* skins are allocated separately */
free(mod->skins);
}
memset(mod, 0, sizeof(*mod));
}
@ -571,6 +587,14 @@ GL4_Mod_FreeAll(void)
Mod_Free(&mod_known[i]);
}
}
/* Free PVS buffer */
if (mod_novis)
{
free(mod_novis);
mod_novis = NULL;
}
mod_novis_len = 0;
}
/*

View file

@ -53,7 +53,7 @@ enum {
*/
static void APIENTRY
DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
const GLchar *message, const void *userParam)
{
const char* sourceStr = "Source: Unknown";
const char* typeStr = "Type: Unknown";
@ -155,15 +155,15 @@ void GL4_SetVsync(void)
#ifdef USE_SDL3
int vsyncState;
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
#else
vsyncActive = SDL_GL_GetSwapInterval() != 0;
#endif
@ -439,9 +439,9 @@ void GL4_ShutdownContext()
if(context)
{
#ifdef USE_SDL3
SDL_GL_DestroyContext(context);
SDL_GL_DestroyContext(context);
#else
SDL_GL_DeleteContext(context);
SDL_GL_DeleteContext(context);
#endif
context = NULL;
}

View file

@ -726,6 +726,11 @@ RecursiveWorldNode(entity_t *currententity, mnode_t *node)
gl4_alpha_surfaces = surf;
gl4_alpha_surfaces->texinfo->image = R_TextureAnimation(currententity, surf->texinfo);
}
else if (surf->texinfo->flags & SURF_NODRAW)
{
/* Surface should be skipped */
continue;
}
else
{
// calling RenderLightmappedPoly() here probably isn't optimal, rendering everything
@ -789,11 +794,10 @@ void
GL4_MarkLeaves(void)
{
const byte *vis;
YQ2_ALIGNAS_TYPE(int) byte fatvis[MAX_MAP_LEAFS / 8];
byte *fatvis = NULL;
mnode_t *node;
int i, c;
int i;
mleaf_t *leaf;
int cluster;
if ((gl4_oldviewcluster == gl4_viewcluster) &&
(gl4_oldviewcluster2 == gl4_viewcluster2) &&
@ -835,6 +839,9 @@ GL4_MarkLeaves(void)
/* may have to combine two clusters because of solid water boundaries */
if (gl4_viewcluster2 != gl4_viewcluster)
{
int c;
fatvis = malloc(((gl4_worldmodel->numleafs + 31) / 32) * sizeof(int));
memcpy(fatvis, vis, (gl4_worldmodel->numleafs + 7) / 8);
vis = GL4_Mod_ClusterPVS(gl4_viewcluster2, gl4_worldmodel);
c = (gl4_worldmodel->numleafs + 31) / 32;
@ -851,6 +858,8 @@ GL4_MarkLeaves(void)
i < gl4_worldmodel->numleafs;
i++, leaf++)
{
int cluster;
cluster = leaf->cluster;
if (cluster == -1)
@ -875,5 +884,10 @@ GL4_MarkLeaves(void)
while (node);
}
}
}
/* clean combined buffer */
if (fatvis)
{
free(fatvis);
}
}

View file

@ -180,8 +180,8 @@ enum {
// width and height used to be 128, so now we should be able to get the same lightmap data
// that used 32 lightmaps before into one, so 4 lightmaps should be enough
BLOCK_WIDTH = 1024,
BLOCK_HEIGHT = 512,
MAX_LIGHTMAPS = 8,
BLOCK_HEIGHT = 1024,
MAX_LIGHTMAPS = 16,
MAX_LIGHTMAPS_PER_SURFACE = MAXLIGHTMAPS // 4
};
@ -407,9 +407,10 @@ extern void GL4_Draw_ShutdownLocal(void);
extern gl4image_t * GL4_Draw_FindPic(const char *name);
extern void GL4_Draw_GetPicSize(int *w, int *h, const char *pic);
extern void GL4_Draw_PicScaled(int x, int y, const char *pic, float factor);
extern void GL4_Draw_PicScaled(int x, int y, const char *pic, float factor, const char *alttext);
extern void GL4_Draw_StretchPic(int x, int y, int w, int h, const char *pic);
extern void GL4_Draw_CharScaled(int x, int y, int num, float scale);
extern void GL4_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message);
extern void GL4_Draw_TileClear(int x, int y, int w, int h, const char *pic);
extern void GL4_DrawFrameBufferObject(int x, int y, int w, int h, GLuint fboTexture, const float v_blend[4]);
extern void GL4_Draw_Fill(int x, int y, int w, int h, int c);
@ -540,6 +541,7 @@ extern cvar_t *r_modulate;
extern cvar_t *gl_lightmap;
extern cvar_t *gl_shadows;
extern cvar_t *r_fixsurfsky;
extern cvar_t *r_ttffont;
extern cvar_t *r_palettedtexture;
extern cvar_t *r_validation;

View file

@ -95,6 +95,7 @@ typedef struct model_s
msurface_t **marksurfaces;
int numvisibility;
int numclusters;
dvis_t *vis;
byte *lightdata;

View file

@ -90,6 +90,7 @@ typedef enum
#define MAX_MOD_KNOWN (MAX_MODELS * 2)
#define MAX_TEXTURES (MAX_IMAGES * 4)
#define MAX_FONTCODE 0x500
extern void R_Printf(int level, const char* msg, ...) PRINTF_ATTR(2, 3);
@ -110,10 +111,6 @@ extern void SmoothColorImage(unsigned *dst, size_t size, size_t rstep);
extern void scale2x(const byte *src, byte *dst, int width, int height);
extern void scale3x(const byte *src, byte *dst, int width, int height);
extern float Mod_RadiusFromBounds(const vec3_t mins, const vec3_t maxs);
extern const byte* Mod_DecompressVis(const byte *in, const byte* numvisibility,
int row);
/* Shared models struct */
enum {
@ -318,29 +315,29 @@ typedef struct
} bspxlightgrid_t;
/* Shared models func */
typedef int (*readfile_t)(const char *path, void **buffer);
typedef struct image_s* (*findimage_t)(const char *name, imagetype_t type);
extern void *Mod_LoadModel(const char *mod_name, const void *buffer, int modfilelen,
vec3_t mins, vec3_t maxs, struct image_s ***skins, int *numskins,
findimage_t find_image, loadimage_t load_image, readfile_t read_file,
modtype_t *type);
findimage_t find_image, loadimage_t load_image, modtype_t *type);
extern int Mod_ReLoadSkins(const char *name, struct image_s **skins, findimage_t find_image,
loadimage_t load_image, void *extradata, modtype_t type);
extern struct image_s *GetSkyImage(const char *skyname, const char* surfname,
qboolean palettedtexture, findimage_t find_image);
extern struct image_s *GetTexImage(const char *name, findimage_t find_image);
extern struct image_s *R_FindPic(const char *name, findimage_t find_image);
extern struct image_s *R_LoadConsoleChars(findimage_t find_image);
extern unsigned R_NextUTF8Code(const char **curr);
extern struct image_s *R_LoadImage(const char *name, const char* namewe, const char *ext,
imagetype_t type, int r_retexturing, loadimage_t load_image);
extern void Mod_LoadQBSPMarksurfaces(const char *name, msurface_t ***marksurfaces,
unsigned int *nummarksurfaces, msurface_t *surfaces, int numsurfaces,
const byte *mod_base, const lump_t *lMod_LoadQBSPMarksurfaces);
extern void Mod_LoadQBSPNodes(const char *name, cplane_t *planes, int numplanes,
mleaf_t *leafs, int numleafs, mnode_t **nodes, int *numnodes,
mleaf_t *leafs, int numleafs, mnode_t **nodes, int *numnodes, vec3_t mins, vec3_t maxs,
const byte *mod_base, const lump_t *l, int ident);
extern void Mod_LoadQBSPLeafs(const char *name, mleaf_t **leafs, int *numleafs,
msurface_t **marksurfaces, unsigned int nummarksurfaces,
const byte *mod_base, const lump_t *l);
int *numclusters, const byte *mod_base, const lump_t *l);
extern void Mod_LoadQBSPEdges(const char *name, medge_t **edges, int *numedges,
const byte *mod_base, const lump_t *l);
extern void Mod_LoadVertexes(const char *name, mvertex_t **vertexes, int *numvertexes,
@ -382,7 +379,7 @@ extern qboolean R_CullAliasMeshModel(dmdx_t *paliashdr, cplane_t *frustum,
extern void R_LerpVerts(qboolean powerUpEffect, int nverts,
const dxtrivertx_t *v, const dxtrivertx_t *ov,
float *lerp, const float move[3],
const float frontv[3], const float backv[3]);
const float frontv[3], const float backv[3], const float *scale);
extern void R_ConvertNormalMDL(byte in_normal, signed char *normal);
extern vec4_t *R_VertBufferRealloc(int num);
extern void R_VertBufferInit(void);

View file

@ -553,7 +553,8 @@ void RE_EndRegistration (void);
struct image_s *RE_Draw_FindPic (const char *name);
void RE_Draw_GetPicSize (int *w, int *h, const char *name);
void RE_Draw_PicScaled (int x, int y, const char *name, float scale);
void RE_Draw_PicScaled (int x, int y, const char *name, float scale, const char *alttext);
void RE_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message);
void RE_Draw_StretchPic (int x, int y, int w, int h, const char *name);
void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int bits);
void RE_Draw_CharScaled (int x, int y, int c, float scale);

View file

@ -108,6 +108,7 @@ typedef struct model_s
msurface_t **marksurfaces;
int numvisibility;
int numclusters;
dvis_t *vis;
byte *lightdata;

View file

@ -457,7 +457,7 @@ R_AliasPreparePoints(const entity_t *currententity, finalvert_t *verts, const fi
RF_SHELL_HALF_DAM));
R_LerpVerts(colorOnly, s_pmdl->num_xyz, r_thisframe->verts, r_lastframe->verts,
s_lerped[0], r_lerp_move, r_lerp_frontv, r_lerp_backv);
s_lerped[0], r_lerp_move, r_lerp_frontv, r_lerp_backv, currententity->scale);
R_AliasTransformFinalVerts(s_pmdl->num_xyz,
verts, /* destination for transformed verts */
@ -476,6 +476,11 @@ R_AliasPreparePoints(const entity_t *currententity, finalvert_t *verts, const fi
const dtriangle_t *ptri;
int num_tris;
if (currententity->rr_mesh & (1 << i))
{
continue;
}
num_tris = Q_min(s_pmdl->num_tris - mesh_nodes[i].ofs_tris, mesh_nodes[i].num_tris);
ptri = (dtriangle_t *)((byte *)s_pmdl + s_pmdl->ofs_tris) + mesh_nodes[i].ofs_tris;
@ -795,17 +800,21 @@ R_AliasDrawModel
void
R_AliasDrawModel(entity_t *currententity, const model_t *currentmodel)
{
int i;
s_pmdl = (dmdx_t *)currentmodel->extradata;
if ( r_lerpmodels->value == 0 )
{
currententity->backlerp = 0;
}
float oldAliasxscale = aliasxscale;
float oldAliasyscale = aliasyscale;
if ( currententity->flags & RF_WEAPONMODEL )
if (currententity->flags & RF_WEAPONMODEL)
{
if ( r_lefthand->value == 2.0F )
if (r_lefthand->value == 2.0F)
{
return;
}
@ -821,6 +830,15 @@ R_AliasDrawModel(entity_t *currententity, const model_t *currentmodel)
aliasxscale = -aliasxscale;
}
for (i = 0; i < 3; i++)
{
/* fix scale */
if (!currententity->scale[i])
{
currententity->scale[i] = 1.0f;
}
}
/*
** we have to set our frame pointers and transformations before
** doing any real work

View file

@ -322,7 +322,7 @@ R_DrawSolidClippedSubmodelPolygons(entity_t *currententity, const model_t *curre
numsurfaces = currentmodel->nummodelsurfaces;
pedges = currentmodel->edges;
for (i=0 ; i<numsurfaces ; i++, psurf++)
for (i = 0; i < numsurfaces; i++, psurf++)
{
cplane_t *pplane;
bedge_t *pbedge;
@ -337,7 +337,9 @@ R_DrawSolidClippedSubmodelPolygons(entity_t *currententity, const model_t *curre
// draw the polygon
if (( !(psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
((psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
continue;
}
// FIXME: use bounding-box-based frustum clipping info?
@ -349,7 +351,7 @@ R_DrawSolidClippedSubmodelPolygons(entity_t *currententity, const model_t *curre
pbedge = &bedges[numbedges];
numbedges += psurf->numedges;
for (j=0 ; j<psurf->numedges ; j++)
for (j = 0; j < psurf->numedges; j++)
{
int lindex;

View file

@ -47,24 +47,7 @@ Draw_InitLocal
void
Draw_InitLocal (void)
{
draw_chars = R_FindPic ("conchars", (findimage_t)R_FindImage);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic ("fonts/conchars", (findimage_t)R_FindImage);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic ("dkchars", (findimage_t)R_FindImage);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars", __func__);
}
draw_chars = R_LoadConsoleChars((findimage_t)R_FindImage);
}
/*
@ -385,25 +368,47 @@ RE_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *d
RE_Draw_StretchPicImplementation (x, y, w, h, &pic);
if (r_retexturing->value)
if (image_scaled != (byte *)data)
{
free(image_scaled);
}
}
void
RE_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message)
{
int xor;
xor = alt ? 0x80 : 0;
while (*message)
{
RE_Draw_CharScaled(x * scale, y * scale, *message ^ xor, scale);
x += 8 * scale;
message ++;
}
}
/*
=============
Draw_Pic
=============
*/
void
RE_Draw_PicScaled(int x, int y, const char *name, float scale)
RE_Draw_PicScaled(int x, int y, const char *name, float scale, const char *alttext)
{
const image_t *pic;
pic = R_FindPic (name, (findimage_t)R_FindImage);
if (!pic)
{
if (alttext && alttext[0])
{
/* Show alttext if provided */
RE_Draw_StringScaled(x, y, scale, false, alttext);
return;
}
R_Printf(PRINT_ALL, "Can't find pic: %s\n", name);
return;
}

View file

@ -548,48 +548,47 @@ Finds or loads the given image or NULL
===============
*/
image_t *
R_FindImage(const char *name, imagetype_t type)
R_FindImage(const char *originname, imagetype_t type)
{
image_t *image;
int i, len;
char *ptr;
char namewe[256];
char namewe[256], name[256] = {0};
const char* ext;
image_t *image;
size_t len;
int i;
if (!name)
if (!originname)
{
return NULL;
}
Q_strlcpy(name, originname, sizeof(name));
/* just return white image if show lightmap only */
if ((type == it_wall || type == it_skin) && r_lightmap->value)
{
return r_whitetexture_mip;
}
/* fix backslashes */
Q_replacebackslash(name);
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
/* Remove the extension */
memset(namewe, 0, 256);
memcpy(namewe, name, len - (strlen(ext) + 1));
if (len < 5)
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
memcpy(namewe, name, len);
namewe[len] = 0;
// look for it
for (i=0, image=r_images ; i<numr_images ; i++,image++)

View file

@ -1780,8 +1780,7 @@ RE_IsVsyncActive(void)
static int RE_PrepareForWindow(void)
{
int flags = SDL_SWSURFACE;
return flags;
return 0;
}
/*
@ -1809,17 +1808,18 @@ GetRefAPI(refimport_t imp)
// Need to communicate the SDL major version to the client.
#ifdef USE_SDL3
SDL_Version ver;
int version = SDL_VERSIONNUM_MAJOR(SDL_GetVersion());
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
int version = ver.major;
#endif
memset(&refexport, 0, sizeof(refexport_t));
ri = imp;
refexport.api_version = API_VERSION;
refexport.framework_version = ver.major;
refexport.framework_version = version;
refexport.BeginRegistration = RE_BeginRegistration;
refexport.RegisterModel = RE_RegisterModel;
@ -1835,6 +1835,7 @@ GetRefAPI(refimport_t imp)
refexport.DrawPicScaled = RE_Draw_PicScaled;
refexport.DrawStretchPic = RE_Draw_StretchPic;
refexport.DrawCharScaled = RE_Draw_CharScaled;
refexport.DrawStringScaled = RE_Draw_StringScaled;
refexport.DrawTileClear = RE_Draw_TileClear;
refexport.DrawFill = RE_Draw_Fill;
refexport.DrawFadeScreen = RE_Draw_FadeScreen;
@ -1854,9 +1855,9 @@ GetRefAPI(refimport_t imp)
refexport.EndWorldRenderpass = RE_EndWorldRenderpass;
refexport.EndFrame = RE_EndFrame;
// Tell the client that we're unsing the
// Tell the client that we're unsing the
// new renderer restart API.
ri.Vid_RequestRestart(RESTART_NO);
ri.Vid_RequestRestart(RESTART_NO);
Swap_Init ();
@ -1905,19 +1906,32 @@ RE_InitContext(void *win)
if (r_vsync->value)
{
#ifdef USE_SDL3
renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_PRESENTVSYNC);
renderer = SDL_CreateRenderer(window, NULL);
SDL_SetRenderVSync(renderer, 1);
#else
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(!renderer)
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE | SDL_RENDERER_PRESENTVSYNC);
}
#endif
}
else
{
#ifdef USE_SDL3
renderer = SDL_CreateRenderer(window, NULL, 0);
renderer = SDL_CreateRenderer(window, NULL);
#else
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if(!renderer)
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
}
#endif
}
if(!renderer) {
Com_Printf("Can't create renderer: %s\n", SDL_GetError());
return false;
}
/* Select the color for drawing. It is set to black here. */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
@ -1963,7 +1977,10 @@ RE_InitContext(void *win)
#endif
SDL_TEXTUREACCESS_STREAMING,
vid_buffer_width, vid_buffer_height);
if(!texture) {
Com_Printf("Can't create texture: %s\n", SDL_GetError());
return false;
}
R_InitGraphics(vid_buffer_width, vid_buffer_height);
SWimp_CreateRender(vid_buffer_width, vid_buffer_height);
@ -2178,7 +2195,7 @@ RE_BufferDifferenceStart(int vmin, int vmax)
return (pixel_t*)back_buffer - swap_frames[0];
}
static int
static size_t
RE_BufferDifferenceEnd(int vmin, int vmax)
{
int *front_buffer, *back_buffer;
@ -2205,7 +2222,11 @@ RE_CleanFrame(void)
memset(swap_buffers, 0,
vid_buffer_height * vid_buffer_width * sizeof(pixel_t) * 2);
#ifdef USE_SDL3
if (!SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch))
#else
if (SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch))
#endif
{
Com_Printf("Can't lock texture: %s\n", SDL_GetError());
return;
@ -2237,7 +2258,11 @@ RE_FlushFrame(int vmin, int vmax)
return;
}
#ifdef USE_SDL3
if (!SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch))
#else
if (SDL_LockTexture(texture, NULL, (void**)&pixels, &pitch))
#endif
{
Com_Printf("Can't lock texture: %s\n", SDL_GetError());
return;
@ -2317,7 +2342,11 @@ RE_Draw_StretchDirectRaw(int x, int y, int w, int h, int cols, int rows, const b
}
/* Full screen update should be faster */
#ifdef USE_SDL3
if (!SDL_LockTexture(texture_rgba, NULL, (void**)&pixels, &pitch))
#else
if (SDL_LockTexture(texture_rgba, NULL, (void**)&pixels, &pitch))
#endif
{
Com_Printf("Can't lock texture: %s\n", SDL_GetError());
return;
@ -2353,16 +2382,28 @@ RE_Draw_StretchDirectRaw(int x, int y, int w, int h, int cols, int rows, const b
if (cols == vid_buffer_width && rows == vid_buffer_height)
{
#ifdef USE_SDL3
SDL_RenderTexture(renderer, texture_rgba, NULL, NULL);
#else
SDL_RenderCopy(renderer, texture_rgba, NULL, NULL);
#endif
}
else
{
#ifdef USE_SDL3
SDL_FRect srcrect;
#else
SDL_Rect srcrect;
#endif
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = cols;
srcrect.h = rows;
#ifdef USE_SDL3
SDL_RenderTexture(renderer, texture_rgba, &srcrect, NULL);
#else
SDL_RenderCopy(renderer, texture_rgba, &srcrect, NULL);
#endif
}
SDL_RenderPresent(renderer);
@ -2630,6 +2671,15 @@ Com_Printf(const char *msg, ...)
va_end(argptr);
}
void
Com_DPrintf(const char *msg, ...)
{
va_list argptr;
va_start(argptr, msg);
ri.Com_VPrintf(PRINT_DEVELOPER, msg, argptr);
va_end(argptr);
}
void
Com_Error(int code, const char *fmt, ...)
{

View file

@ -30,7 +30,8 @@
#include <limits.h>
#include "header/local.h"
static YQ2_ALIGNAS_TYPE(int) byte mod_novis[MAX_MAP_LEAFS / 8];
static byte *mod_novis = NULL;
static size_t mod_novis_len = 0;
static model_t mod_known[MAX_MOD_KNOWN];
static int mod_numknown = 0;
@ -69,15 +70,34 @@ Mod_HasFreeSpace(void)
const byte *
Mod_ClusterPVS(int cluster, const model_t *model)
{
if ((cluster == -1) || !model->vis)
if (!mod_novis)
{
Com_Error(ERR_DROP, "%s: incrorrect init of PVS/PHS", __func__);
}
if (!model->vis)
{
Mod_DecompressVis(NULL, mod_novis, NULL,
(model->numclusters + 7) >> 3);
return mod_novis;
}
return Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS],
if (cluster == -1)
{
memset(mod_novis, 0, (model->numclusters + 7) >> 3);
return mod_novis;
}
if (cluster < 0 || cluster >= model->numvisibility)
{
Com_Error(ERR_DROP, "%s: bad cluster", __func__);
}
Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS], mod_novis,
(byte *)model->vis + model->numvisibility,
(model->vis->numclusters + 7) >> 3);
(model->numclusters + 7) >> 3);
return mod_novis;
}
void
@ -121,7 +141,8 @@ void
Mod_Init(void)
{
mod_max = 0;
memset(mod_novis, 0xff, sizeof(mod_novis));
mod_novis = NULL;
mod_novis_len = 0;
}
static void
@ -320,7 +341,7 @@ Mod_LoadBrushModel(model_t *mod, const void *buffer, int modfilelen)
header = (dheader_t *)mod_base;
/* check for BSPX extensions */
bspx_header = Mod_LoadBSPX(modfilelen, (byte*)mod_base);
bspx_header = Mod_LoadBSPX(modfilelen, mod_base);
// calculate the needed hunksize from the lumps
hunkSize = Mod_CalcNonModelLumpHunkSize(mod_base, header);
@ -368,35 +389,30 @@ Mod_LoadBrushModel(model_t *mod, const void *buffer, int modfilelen)
Mod_LoadVisibility(mod->name, &mod->vis, &mod->numvisibility, mod_base,
&header->lumps[LUMP_VISIBILITY]);
Mod_LoadQBSPLeafs(mod->name, &mod->leafs, &mod->numleafs,
mod->marksurfaces, mod->nummarksurfaces, mod_base,
&header->lumps[LUMP_LEAFS]);
mod->marksurfaces, mod->nummarksurfaces, &mod->numclusters,
mod_base, &header->lumps[LUMP_LEAFS]);
Mod_LoadQBSPNodes(mod->name, mod->planes, mod->numplanes, mod->leafs,
mod->numleafs, &mod->nodes, &mod->numnodes, mod_base,
&header->lumps[LUMP_NODES], header->ident);
mod->numleafs, &mod->nodes, &mod->numnodes, mod->mins, mod->maxs,
mod_base, &header->lumps[LUMP_NODES], header->ident);
Mod_LoadSubmodels(mod, mod_base, &header->lumps[LUMP_MODELS]);
mod->numframes = 2; /* regular and alternate animation */
R_InitSkyBox(mod);
}
/* Temporary solution, need to use load file dirrectly */
static int
Mod_ReadFile(const char *path, void **buffer)
{
char *data;
int size;
size = ri.FS_LoadFile(path, (void **)&data);
if (size <= 0)
if (mod->vis && mod->numclusters != mod->vis->numclusters)
{
return size;
Com_Error(ERR_DROP, "%s: Map %s has incorrect number of clusters %d != %d",
__func__, mod->name, mod->numclusters, mod->vis->numclusters);
}
*buffer = malloc(size);
memcpy(*buffer, data, size);
ri.FS_FreeFile((void *)data);
if ((mod->numleafs > mod_novis_len) || !mod_novis)
{
/* reallocate buffers for PVS/PHS buffers*/
mod_novis_len = (mod->numleafs + 63) & ~63;
mod_novis = realloc(mod_novis, mod_novis_len / 8);
Com_Printf("Allocated " YQ2_COM_PRIdS " bit leafs of PVS/PHS buffer\n",
mod_novis_len);
}
return size;
R_InitSkyBox(mod);
}
/*
@ -405,9 +421,10 @@ Mod_ReadFile(const char *path, void **buffer)
static model_t *
Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
{
char filename[256] = {0}, *tag;
int i, modfilelen;
model_t *mod;
void *buf;
int i, modfilelen;
if (!name[0])
{
@ -463,8 +480,18 @@ Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
strcpy(mod->name, name);
/* Anachronox has tags in model path*/
Q_strlcpy(filename, name, sizeof(filename));
tag = strstr(filename, ".mda!");
if (tag)
{
tag += 4; /* strlen(.mda) */
*tag = 0;
tag ++;
}
/* load the file */
modfilelen = ri.Mod_LoadFile(mod->name, &buf);
modfilelen = ri.Mod_LoadFile(filename, &buf);
if (!buf)
{
@ -486,32 +513,14 @@ Mod_ForName(const char *name, model_t *parent_model, qboolean crash)
/* call the apropriate loader */
switch (LittleLong(*(unsigned *)buf))
{
case MDAHEADER:
/* fall through */
case SDEFHEADER:
/* fall through */
case MDXHEADER:
/* fall through */
case DKMHEADER:
/* fall through */
case RAVENFMHEADER:
/* fall through */
case IDALIASHEADER:
/* fall through */
case IDMDLHEADER:
/* fall through */
case ID3HEADER:
/* fall through */
case MDR_IDENT:
/* fall through */
case IDMD5HEADER:
/* fall through */
case IDSPRITEHEADER:
{
mod->extradata = Mod_LoadModel(mod->name, buf, modfilelen,
mod->mins, mod->maxs,
(struct image_s ***)&mod->skins, &mod->numskins,
(findimage_t)R_FindImage, (loadimage_t)R_LoadPic, Mod_ReadFile,
(findimage_t)R_FindImage, (loadimage_t)R_LoadPic,
&(mod->type));
if (!mod->extradata)
{
@ -563,6 +572,13 @@ Mod_Free(model_t *mod)
}
Hunk_Free(mod->extradata);
if (mod->type == mod_alias || mod->type == mod_sprite)
{
/* skins are allocated separately */
free(mod->skins);
}
memset(mod, 0, sizeof(*mod));
}
@ -578,6 +594,14 @@ Mod_FreeAll(void)
Mod_Free(&mod_known[i]);
}
}
/* Free PVS buffer */
if (mod_novis)
{
free(mod_novis);
mod_novis = NULL;
}
mod_novis_len = 0;
}
/*

View file

@ -536,6 +536,12 @@ R_RenderFace (entity_t *currententity, const model_t *currentmodel, msurface_t *
return;
}
if (fa->texinfo->flags & SURF_NODRAW)
{
/* Surface should be skipped */
return;
}
// sky surfaces encountered in the world will cause the
// environment box surfaces to be emited
if ( fa->texinfo->flags & SURF_SKY )

View file

@ -42,7 +42,7 @@ surfcache_t *sc_base;
/*
* Color light apply is not required
*/
static qboolean
static int
R_GreyscaledLight(const light3_t light)
{
light3_t light_masked;
@ -108,6 +108,8 @@ R_DrawSurfaceBlock_Light (pixel_t *prowdest, pixel_t *psource, size_t size,
for (b=(size-1); b>=0; b--)
{
pixel_t pix;
int j;
pix = psource[b];
prowdest[b] = R_ApplyLight(pix, light);

View file

@ -149,6 +149,7 @@ extern cvar_t *r_2D_unfiltered;
extern cvar_t *r_videos_unfiltered;
extern cvar_t *vk_pixel_size;
extern cvar_t *r_fixsurfsky;
extern cvar_t *r_ttffont;
extern cvar_t *vid_fullscreen;
extern cvar_t *vid_gamma;
@ -193,6 +194,7 @@ void R_RenderDlights(void);
void R_DrawAlphaSurfaces(void);
void RE_InitParticleTexture(void);
void Draw_InitLocal(void);
void Draw_FreeLocal(void);
void R_RotateForEntity(entity_t *e, float *mvMatrix);
void R_MarkLeaves(void);
@ -206,9 +208,10 @@ void R_DrawSkyBox(void);
struct image_s *RE_Draw_FindPic (const char *name);
void RE_Draw_GetPicSize (int *w, int *h, const char *name);
void RE_Draw_PicScaled (int x, int y, const char *name, float scale);
void RE_Draw_PicScaled (int x, int y, const char *name, float scale, const char *alttext);
void RE_Draw_StretchPic (int x, int y, int w, int h, const char *name);
void RE_Draw_CharScaled (int x, int y, int num, float scale);
void RE_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message);
void RE_Draw_TileClear (int x, int y, int w, int h, const char *name);
void RE_Draw_Fill (int x, int y, int w, int h, int c);
void RE_Draw_FadeScreen (void);
@ -275,8 +278,8 @@ typedef struct
#define MAX_LIGHTMAPS 256
#define DYNLIGHTMAP_OFFSET MAX_LIGHTMAPS
#define BLOCK_WIDTH 256
#define BLOCK_HEIGHT 256
#define BLOCK_WIDTH 1024
#define BLOCK_HEIGHT 1024
typedef struct
{

View file

@ -104,6 +104,7 @@ typedef struct model_s
msurface_t **marksurfaces;
int numvisibility;
int numclusters;
dvis_t *vis;
byte *lightdata;

View file

@ -340,7 +340,7 @@ void QVk_Draw2DCallsRender(void);
void QVk_DrawColorRect(float x, float y, float w, float h,
float r, float g, float b, float a, qvkrenderpasstype_t rpType);
void QVk_DrawTexRect(float x, float y, float w, float h,
float u, float v, float us, float vs, qvktexture_t *texture);
float u, float v, float us, float vs, const qvktexture_t *texture);
void QVk_BindPipeline(qvkpipeline_t *pipeline);
void QVk_SubmitStagingBuffers(void);
void Qvk_MemoryBarrier(VkCommandBuffer cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);

View file

@ -279,7 +279,7 @@ static float draw2dcolor_calls[16 * MAXDRAWCALLS] = {0};
static float draw2dcolor_r, draw2dcolor_g, draw2dcolor_b, draw2dcolor_a;
static qvkrenderpasstype_t draw2dcolor_rpType;
static calltype_t draw2dcolor_calltype;
static qvktexture_t *draw2dcolor_texture = NULL;
static const qvktexture_t *draw2dcolor_texture = NULL;
VkFormat QVk_FindDepthFormat()
{
@ -1696,7 +1696,8 @@ void QVk_GetDrawableSize(int *width, int *height)
#endif
}
void QVk_WaitAndShutdownAll (void)
void
QVk_WaitAndShutdownAll(void)
{
if (!vk_initialized)
{
@ -1711,6 +1712,7 @@ void QVk_WaitAndShutdownAll (void)
Mod_FreeAll();
Mod_FreeModelsKnown();
Vk_ShutdownImages();
Draw_FreeLocal();
Mesh_Free();
R_VertBufferFree();
QVk_Shutdown();
@ -2253,7 +2255,9 @@ VkResult QVk_EndFrame(qboolean force)
{
// continue only if QVk_BeginFrame() had been previously issued
if (!vk_frameStarted)
{
return VK_SUCCESS;
}
QVk_Draw2DCallsRender();
@ -2592,7 +2596,7 @@ uint8_t *QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer
stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer];
if (size > stagingBuffer->resource.size)
{
R_Printf(PRINT_ALL, "%s: %d: Resize stanging buffer %" YQ2_COM_PRIu64 "-> %" YQ2_COM_PRIu64 "\n",
R_Printf(PRINT_ALL, "%s: %d: Resize stanging buffer " YQ2_COM_PRIdS "-> " YQ2_COM_PRIdS "\n",
__func__, vk_activeStagingBuffer, stagingBuffer->resource.size, size);
DestroyStagingBuffer(stagingBuffer);
@ -2814,7 +2818,7 @@ QVk_DrawColorRect(float x, float y, float w, float h, float r, float g, float b,
void QVk_DrawTexRect(float x, float y, float w, float h,
float u, float v, float us, float vs, qvktexture_t *texture)
float u, float v, float us, float vs, const qvktexture_t *texture)
{
float *last;

View file

@ -21,63 +21,64 @@
*/
#include "header/local.h"
#include "../files/stb_truetype.h"
static image_t *draw_chars;
static int vk_rawTexture_height = 0;
static int vk_rawTexture_width = 0;
static float vk_font_size = 8.0;
static int vk_font_height = 128;
static image_t *draw_chars = NULL;
static image_t *draw_font = NULL;
static image_t *draw_font_alt = NULL;
static stbtt_bakedchar *draw_fontcodes = NULL;
/*
===============
Draw_InitLocal
===============
*/
void Draw_InitLocal (void)
void R_LoadTTFFont(const char *ttffont, int vid_height, float *r_font_size,
int *r_font_height, stbtt_bakedchar **draw_fontcodes,
struct image_s **draw_font, struct image_s **draw_font_alt,
loadimage_t R_LoadPic);
void
Draw_InitLocal(void)
{
draw_chars = R_FindPic ("conchars", (findimage_t)Vk_FindImage);
R_LoadTTFFont(r_ttffont->string, vid.height, &vk_font_size, &vk_font_height,
&draw_fontcodes, &draw_font, &draw_font_alt, Vk_LoadPic);
/* Anachronox */
if (!draw_chars)
{
draw_chars = R_FindPic ("fonts/conchars", (findimage_t)Vk_FindImage);
}
/* Daikatana */
if (!draw_chars)
{
draw_chars = R_FindPic ("dkchars", (findimage_t)Vk_FindImage);
}
if (!draw_chars)
{
Com_Error(ERR_FATAL, "%s: Couldn't load pics/conchars",
__func__);
}
draw_chars = R_LoadConsoleChars((findimage_t)Vk_FindImage);
}
void
Draw_FreeLocal(void)
{
free(draw_fontcodes);
}
/*
================
RE_Draw_CharScaled
Draws one 8*8 graphics character with 0 being transparent.
It can be clipped to the top of the screen to allow the console to be
smoothly scrolled off.
================
*/
void RE_Draw_CharScaled (int x, int y, int num, float scale)
* Draws one 8*8 graphics character with 0 being transparent.
* It can be clipped to the top of the screen to allow the console to be
* smoothly scrolled off.
*/
void
RE_Draw_CharScaled(int x, int y, int num, float scale)
{
int row, col;
float frow, fcol, size;
int row, col;
float frow, fcol, size, scaledSize;
if (!vk_frameStarted)
{
return;
}
num &= 255;
if ((num & 127) == 32)
return; // space
{
return; /* space */
}
if (y <= -8)
return; // totally off screen
{
return; /* totally off screen */
}
row = num >> 4;
col = num & 15;
@ -86,17 +87,76 @@ void RE_Draw_CharScaled (int x, int y, int num, float scale)
fcol = col * 0.0625;
size = 0.0625;
scaledSize = 8 * scale;
QVk_DrawTexRect((float)x / vid.width, (float)y / vid.height,
8.f * scale / vid.width, 8.f * scale / vid.height,
scaledSize / vid.width, scaledSize / vid.height,
fcol, frow, size, size, &draw_chars->vk_texture);
}
void
RE_Draw_StringScaled(int x, int y, float scale, qboolean alt, const char *message)
{
while (*message)
{
unsigned value = R_NextUTF8Code(&message);
if (draw_fontcodes && (draw_font || draw_font_alt))
{
float font_scale;
font_scale = vk_font_size / 8.0;
if (value >= 32 && value < MAX_FONTCODE)
{
float xf = 0, yf = 0, xdiff;
stbtt_aligned_quad q;
stbtt_GetBakedQuad(draw_fontcodes, vk_font_height, vk_font_height,
value - 32, &xf, &yf, &q, 1);
xdiff = (8 - xf / font_scale) / 2;
if (xdiff < 0)
{
xdiff = 0;
}
QVk_DrawTexRect((float)(x + (xdiff + q.x0 / font_scale) * scale) / vid.width,
(float)(y + q.y0 * scale / font_scale + 8 * scale) / vid.height,
(q.x1 - q.x0) * scale / font_scale / vid.width,
(q.y1 - q.y0) * scale / font_scale / vid.height,
q.s0, q.t0, q.s1 - q.s0, q.t1 - q.t0,
alt ? &draw_font_alt->vk_texture : &draw_font->vk_texture);
x += Q_max(8, xf / font_scale) * scale;
}
else
{
x += 8 * scale;
}
}
else
{
int xor;
xor = alt ? 0x80 : 0;
if (value > ' ' && value < 128)
{
RE_Draw_CharScaled(x, y, value ^ xor, scale);
}
x += 8 * scale;
}
}
}
/*
=============
RE_Draw_FindPic
=============
*/
image_t *RE_Draw_FindPic (const char *name)
image_t *
RE_Draw_FindPic(const char *name)
{
return R_FindPic(name, (findimage_t)Vk_FindImage);
}
@ -106,9 +166,10 @@ image_t *RE_Draw_FindPic (const char *name)
RE_Draw_GetPicSize
=============
*/
void RE_Draw_GetPicSize (int *w, int *h, const char *name)
void
RE_Draw_GetPicSize(int *w, int *h, const char *name)
{
image_t *image;
const image_t *image;
image = R_FindPic(name, (findimage_t)Vk_FindImage);
if (!image)
@ -126,12 +187,15 @@ void RE_Draw_GetPicSize (int *w, int *h, const char *name)
RE_Draw_StretchPic
=============
*/
void RE_Draw_StretchPic (int x, int y, int w, int h, const char *name)
void
RE_Draw_StretchPic(int x, int y, int w, int h, const char *name)
{
image_t *vk;
if (!vk_frameStarted)
{
return;
}
vk = R_FindPic(name, (findimage_t)Vk_FindImage);
if (!vk)
@ -151,37 +215,46 @@ void RE_Draw_StretchPic (int x, int y, int w, int h, const char *name)
RE_Draw_PicScaled
=============
*/
void RE_Draw_PicScaled (int x, int y, const char *name, float scale)
void
RE_Draw_PicScaled(int x, int y, const char *name, float scale, const char *alttext)
{
image_t *vk;
vk = R_FindPic(name, (findimage_t)Vk_FindImage);
if (!vk)
{
if (alttext && alttext[0])
{
/* Show alttext if provided */
RE_Draw_StringScaled(x, y, scale, false, alttext);
return;
}
R_Printf(PRINT_ALL, "%s(): Can't find pic: %s\n", __func__, name);
return;
}
RE_Draw_StretchPic(x, y, vk->width*scale, vk->height*scale, name);
RE_Draw_StretchPic(x, y, vk->width * scale, vk->height * scale, name);
}
/*
=============
RE_Draw_TileClear
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void RE_Draw_TileClear (int x, int y, int w, int h, const char *name)
* This repeats a 64*64 tile graphic to fill
* the screen around a sized down
* refresh window.
*/
void
RE_Draw_TileClear(int x, int y, int w, int h, const char *name)
{
image_t *image;
const image_t *image;
float divisor;
if (!vk_frameStarted)
{
return;
}
image = R_FindPic(name, (findimage_t)Vk_FindImage);
if (!image)
{
R_Printf(PRINT_ALL, "%s(): Can't find pic: %s\n", __func__, name);
@ -219,27 +292,27 @@ void RE_Draw_TileClear (int x, int y, int w, int h, const char *name)
}
/*
=============
RE_Draw_Fill
Fills a box of pixels with a single color
=============
*/
void RE_Draw_Fill (int x, int y, int w, int h, int c)
* Fills a box of pixels with a single color
*/
void
RE_Draw_Fill(int x, int y, int w, int h, int c)
{
union
{
unsigned c;
byte v[4];
unsigned c;
byte v[4];
} color;
if (!vk_frameStarted)
{
return;
}
if ((unsigned)c > 255)
{
Com_Error(ERR_FATAL, "%s: bad color", __func__);
}
color.c = d_8to24table[c];
@ -261,10 +334,13 @@ RE_Draw_FadeScreen
================
*/
void RE_Draw_FadeScreen (void)
void
RE_Draw_FadeScreen(void)
{
if (!vk_frameStarted)
{
return;
}
QVk_DrawColorRect(
0.0f, 0.0f, 1.0f, 1.0f,
@ -281,20 +357,20 @@ void RE_Draw_FadeScreen (void)
RE_Draw_StretchRaw
=============
*/
static int vk_rawTexture_height;
static int vk_rawTexture_width;
void RE_Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int bits)
void
RE_Draw_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int bits)
{
int i, j;
int i, j;
unsigned *dest;
byte *source;
byte *image_scaled = NULL;
unsigned *raw_image32;
if (!vk_frameStarted)
{
return;
}
if (bits == 32)
{

View file

@ -1187,41 +1187,40 @@ Finds or loads the given image or NULL
===============
*/
image_t *
Vk_FindImage(const char *name, imagetype_t type)
Vk_FindImage(const char *originname, imagetype_t type)
{
image_t *image;
int i, len;
char *ptr;
char namewe[256];
char namewe[256], name[256] = {0};
const char* ext;
image_t *image;
int i, len;
if (!name)
if (!originname)
{
return NULL;
}
Q_strlcpy(name, originname, sizeof(name));
/* fix backslashes */
Q_replacebackslash(name);
ext = COM_FileExtension(name);
if(!ext[0])
if (!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
if (len < 5)
/* Remove the extension */
len = (ext - name) - 1;
if ((len < 1) || (len > sizeof(namewe) - 1))
{
Com_DPrintf("%s: Bad filename %s\n", __func__, name);
return NULL;
}
/* Remove the extension */
memset(namewe, 0, sizeof(namewe));
memcpy(namewe, name, len - (strlen(ext) + 1));
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
memcpy(namewe, name, len);
namewe[len] = 0;
/* look for it */
for (i=0, image=vktextures ; i<numvktextures ; i++,image++)

View file

@ -139,6 +139,7 @@ cvar_t *r_lerp_list;
cvar_t *r_2D_unfiltered;
cvar_t *r_videos_unfiltered;
cvar_t *r_fixsurfsky;
cvar_t *r_ttffont;
cvar_t *vid_fullscreen;
cvar_t *vid_gamma;
@ -1207,6 +1208,8 @@ R_Register(void)
/* don't bilerp videos */
r_videos_unfiltered = ri.Cvar_Get("r_videos_unfiltered", "0", CVAR_ARCHIVE);
r_fixsurfsky = ri.Cvar_Get("r_fixsurfsky", "0", CVAR_ARCHIVE);
/* font should looks good with 8 pixels size */
r_ttffont = ri.Cvar_Get("r_ttffont", "RussoOne-Regular", CVAR_ARCHIVE);
// clamp vk_msaa to accepted range so that video menu doesn't crash on us
if (vk_msaa->value < 0)
@ -1716,6 +1719,20 @@ static int RE_PrepareForWindow(void)
return SDL_WINDOW_VULKAN;
}
static int
RE_GetSDLVersion(void)
{
#ifdef USE_SDL3
int version = SDL_GetVersion();
return SDL_VERSIONNUM_MAJOR(version);
#else
SDL_version ver;
SDL_VERSION(&ver);
return ver.major;
#endif
}
/*
===============
GetRefAPI
@ -1726,18 +1743,10 @@ GetRefAPI(refimport_t imp)
{
refexport_t refexport = {0};
// Need to communicate the SDL major version to the client.
#ifdef USE_SDL3
SDL_Version ver;
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
ri = imp;
refexport.api_version = API_VERSION;
refexport.framework_version = ver.major;
refexport.framework_version = RE_GetSDLVersion();
refexport.BeginRegistration = RE_BeginRegistration;
refexport.RegisterModel = RE_RegisterModel;
@ -1752,6 +1761,7 @@ GetRefAPI(refimport_t imp)
refexport.DrawPicScaled = RE_Draw_PicScaled;
refexport.DrawStretchPic = RE_Draw_StretchPic;
refexport.DrawCharScaled = RE_Draw_CharScaled;
refexport.DrawStringScaled = RE_Draw_StringScaled;
refexport.DrawTileClear = RE_Draw_TileClear;
refexport.DrawFill = RE_Draw_Fill;
refexport.DrawFadeScreen= RE_Draw_FadeScreen;
@ -1814,6 +1824,15 @@ Com_Printf(const char *msg, ...)
va_end(argptr);
}
void
Com_DPrintf(const char *msg, ...)
{
va_list argptr;
va_start(argptr, msg);
ri.Com_VPrintf(PRINT_DEVELOPER, msg, argptr);
va_end(argptr);
}
void
Com_Error(int code, const char *fmt, ...)
{

View file

@ -359,7 +359,7 @@ Vk_DrawAliasFrameLerp(entity_t *currententity, dmdx_t *paliashdr, float backlerp
}
R_LerpVerts(colorOnly, paliashdr->num_xyz, verts, ov, (float*)s_lerped,
move, frontv, backv);
move, frontv, backv, currententity->scale);
VkDescriptorSet descriptorSets[] = {
skin->vk_texture.descriptorSet,
@ -383,6 +383,11 @@ Vk_DrawAliasFrameLerp(entity_t *currententity, dmdx_t *paliashdr, float backlerp
for (i = 0; i < num_mesh_nodes; i++)
{
if (currententity->rr_mesh & (1 << i))
{
continue;
}
Vk_DrawAliasFrameLerpCommands(
order + mesh_nodes[i].ofs_glcmds,
order + Q_min(paliashdr->num_glcmds,
@ -527,6 +532,15 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
}
}
for (i = 0; i < 3; i++)
{
/* fix scale */
if (!currententity->scale[i])
{
currententity->scale[i] = 1.0f;
}
}
paliashdr = (dmdx_t *)currentmodel->extradata;
/* get lighting information */

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