summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-11 15:34:30 -0500
committerFranklin Wei <git@fwei.tk>2019-07-19 22:37:40 -0400
commit5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4 (patch)
tree84406e21639529a185556a33e5de7f43cffc277b
parentb70fecf21ddc21877ec1ae7888d9c18a979e37ad (diff)
downloadrockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.tar.gz
rockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.zip
Quake!
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/SUBDIRS6
-rw-r--r--apps/plugins/lib/stdio_compat.h2
-rw-r--r--apps/plugins/quake.c31
-rw-r--r--apps/plugins/sdl/SOURCES.quake77
-rw-r--r--apps/plugins/sdl/include/SDL_config_rockbox.h17
-rw-r--r--apps/plugins/sdl/include/SDL_platform.h1
-rw-r--r--apps/plugins/sdl/main.c11
-rw-r--r--apps/plugins/sdl/progs/quake/Makefile.linuxi3861242
-rw-r--r--apps/plugins/sdl/progs/quake/adivtab.h1077
-rw-r--r--apps/plugins/sdl/progs/quake/anorm_dots.h37
-rw-r--r--apps/plugins/sdl/progs/quake/anorms.h181
-rw-r--r--apps/plugins/sdl/progs/quake/asm_draw.h151
-rw-r--r--apps/plugins/sdl/progs/quake/asm_i386.h97
-rw-r--r--apps/plugins/sdl/progs/quake/block16.h142
-rw-r--r--apps/plugins/sdl/progs/quake/block8.h143
-rw-r--r--apps/plugins/sdl/progs/quake/bspfile.h324
-rw-r--r--apps/plugins/sdl/progs/quake/cd_linux.c416
-rw-r--r--apps/plugins/sdl/progs/quake/cd_null.c55
-rw-r--r--apps/plugins/sdl/progs/quake/cd_sdl.c223
-rw-r--r--apps/plugins/sdl/progs/quake/cdaudio.h27
-rw-r--r--apps/plugins/sdl/progs/quake/chase.c92
-rw-r--r--apps/plugins/sdl/progs/quake/cl_demo.c367
-rw-r--r--apps/plugins/sdl/progs/quake/cl_input.c448
-rw-r--r--apps/plugins/sdl/progs/quake/cl_main.c757
-rw-r--r--apps/plugins/sdl/progs/quake/cl_parse.c963
-rw-r--r--apps/plugins/sdl/progs/quake/cl_tent.c394
-rw-r--r--apps/plugins/sdl/progs/quake/clean.bat18
-rw-r--r--apps/plugins/sdl/progs/quake/client.h376
-rw-r--r--apps/plugins/sdl/progs/quake/cmd.c721
-rw-r--r--apps/plugins/sdl/progs/quake/cmd.h123
-rw-r--r--apps/plugins/sdl/progs/quake/common.c1856
-rw-r--r--apps/plugins/sdl/progs/quake/common.h184
-rw-r--r--apps/plugins/sdl/progs/quake/conproc.h37
-rw-r--r--apps/plugins/sdl/progs/quake/console.c644
-rw-r--r--apps/plugins/sdl/progs/quake/console.h46
-rw-r--r--apps/plugins/sdl/progs/quake/crc.c81
-rw-r--r--apps/plugins/sdl/progs/quake/crc.h24
-rw-r--r--apps/plugins/sdl/progs/quake/cvar.c224
-rw-r--r--apps/plugins/sdl/progs/quake/cvar.h97
-rw-r--r--apps/plugins/sdl/progs/quake/d_copy.S149
-rw-r--r--apps/plugins/sdl/progs/quake/d_edge.c331
-rw-r--r--apps/plugins/sdl/progs/quake/d_fill.c88
-rw-r--r--apps/plugins/sdl/progs/quake/d_iface.h231
-rw-r--r--apps/plugins/sdl/progs/quake/d_ifacea.h98
-rw-r--r--apps/plugins/sdl/progs/quake/d_init.c173
-rw-r--r--apps/plugins/sdl/progs/quake/d_local.h111
-rw-r--r--apps/plugins/sdl/progs/quake/d_modech.c107
-rw-r--r--apps/plugins/sdl/progs/quake/d_part.c207
-rw-r--r--apps/plugins/sdl/progs/quake/d_polyse.c1111
-rw-r--r--apps/plugins/sdl/progs/quake/d_scan.c449
-rw-r--r--apps/plugins/sdl/progs/quake/d_sky.c138
-rw-r--r--apps/plugins/sdl/progs/quake/d_sprite.c442
-rw-r--r--apps/plugins/sdl/progs/quake/d_surf.c335
-rw-r--r--apps/plugins/sdl/progs/quake/d_vars.c50
-rw-r--r--apps/plugins/sdl/progs/quake/d_zpoint.c47
-rw-r--r--apps/plugins/sdl/progs/quake/dosasm.S77
-rw-r--r--apps/plugins/sdl/progs/quake/dosisms.h100
-rw-r--r--apps/plugins/sdl/progs/quake/draw.c890
-rw-r--r--apps/plugins/sdl/progs/quake/draw.h40
-rw-r--r--apps/plugins/sdl/progs/quake/gl_vidlinux.c866
-rw-r--r--apps/plugins/sdl/progs/quake/gl_vidlinuxglx.c997
-rw-r--r--apps/plugins/sdl/progs/quake/host.c977
-rw-r--r--apps/plugins/sdl/progs/quake/host_cmd.c1931
-rw-r--r--apps/plugins/sdl/progs/quake/in_null.c39
-rw-r--r--apps/plugins/sdl/progs/quake/input.h34
-rw-r--r--apps/plugins/sdl/progs/quake/keys.c804
-rw-r--r--apps/plugins/sdl/progs/quake/keys.h134
-rw-r--r--apps/plugins/sdl/progs/quake/mathlib.c550
-rw-r--r--apps/plugins/sdl/progs/quake/mathlib.h154
-rw-r--r--apps/plugins/sdl/progs/quake/menu.c3234
-rw-r--r--apps/plugins/sdl/progs/quake/menu.h38
-rw-r--r--apps/plugins/sdl/progs/quake/model.c1874
-rw-r--r--apps/plugins/sdl/progs/quake/model.h383
-rw-r--r--apps/plugins/sdl/progs/quake/modelgen.h137
-rw-r--r--apps/plugins/sdl/progs/quake/mpdosock.h797
-rw-r--r--apps/plugins/sdl/progs/quake/net.h337
-rw-r--r--apps/plugins/sdl/progs/quake/net_bsd.c93
-rw-r--r--apps/plugins/sdl/progs/quake/net_bw.h39
-rw-r--r--apps/plugins/sdl/progs/quake/net_dgrm.c1390
-rw-r--r--apps/plugins/sdl/progs/quake/net_dgrm.h34
-rw-r--r--apps/plugins/sdl/progs/quake/net_loop.c245
-rw-r--r--apps/plugins/sdl/progs/quake/net_loop.h33
-rw-r--r--apps/plugins/sdl/progs/quake/net_main.c997
-rw-r--r--apps/plugins/sdl/progs/quake/net_none.c46
-rw-r--r--apps/plugins/sdl/progs/quake/net_udp.c415
-rw-r--r--apps/plugins/sdl/progs/quake/net_udp.h39
-rw-r--r--apps/plugins/sdl/progs/quake/net_vcr.c167
-rw-r--r--apps/plugins/sdl/progs/quake/net_vcr.h37
-rw-r--r--apps/plugins/sdl/progs/quake/net_wso.c0
-rw-r--r--apps/plugins/sdl/progs/quake/nonintel.c64
-rw-r--r--apps/plugins/sdl/progs/quake/pr_cmds.c1936
-rw-r--r--apps/plugins/sdl/progs/quake/pr_comp.h180
-rw-r--r--apps/plugins/sdl/progs/quake/pr_edict.c1113
-rw-r--r--apps/plugins/sdl/progs/quake/pr_exec.c668
-rw-r--r--apps/plugins/sdl/progs/quake/progdefs.h24
-rw-r--r--apps/plugins/sdl/progs/quake/progdefs.q1143
-rw-r--r--apps/plugins/sdl/progs/quake/progdefs.q2158
-rw-r--r--apps/plugins/sdl/progs/quake/progs.h134
-rw-r--r--apps/plugins/sdl/progs/quake/protocol.h167
-rw-r--r--apps/plugins/sdl/progs/quake/quakeasm.h280
-rw-r--r--apps/plugins/sdl/progs/quake/quakedef.h333
-rw-r--r--apps/plugins/sdl/progs/quake/quakesound.h177
-rw-r--r--apps/plugins/sdl/progs/quake/r_aclip.c350
-rw-r--r--apps/plugins/sdl/progs/quake/r_alias.c753
-rw-r--r--apps/plugins/sdl/progs/quake/r_bsp.c675
-rw-r--r--apps/plugins/sdl/progs/quake/r_draw.c908
-rw-r--r--apps/plugins/sdl/progs/quake/r_edge.c775
-rw-r--r--apps/plugins/sdl/progs/quake/r_efrag.c276
-rw-r--r--apps/plugins/sdl/progs/quake/r_light.c260
-rw-r--r--apps/plugins/sdl/progs/quake/r_local.h316
-rw-r--r--apps/plugins/sdl/progs/quake/r_main.c1089
-rw-r--r--apps/plugins/sdl/progs/quake/r_misc.c523
-rw-r--r--apps/plugins/sdl/progs/quake/r_part.c802
-rw-r--r--apps/plugins/sdl/progs/quake/r_shared.h157
-rw-r--r--apps/plugins/sdl/progs/quake/r_sky.c280
-rw-r--r--apps/plugins/sdl/progs/quake/r_sprite.c401
-rw-r--r--apps/plugins/sdl/progs/quake/r_surf.c678
-rw-r--r--apps/plugins/sdl/progs/quake/r_vars.c39
-rw-r--r--apps/plugins/sdl/progs/quake/r_varsa.S64
-rw-r--r--apps/plugins/sdl/progs/quake/render.h158
-rw-r--r--apps/plugins/sdl/progs/quake/resource.h20
-rw-r--r--apps/plugins/sdl/progs/quake/sbar.c1323
-rw-r--r--apps/plugins/sdl/progs/quake/sbar.h39
-rw-r--r--apps/plugins/sdl/progs/quake/screen.c994
-rw-r--r--apps/plugins/sdl/progs/quake/screen.h57
-rw-r--r--apps/plugins/sdl/progs/quake/server.h258
-rw-r--r--apps/plugins/sdl/progs/quake/snd_dma.c1021
-rw-r--r--apps/plugins/sdl/progs/quake/snd_linux.c269
-rw-r--r--apps/plugins/sdl/progs/quake/snd_mem.c341
-rw-r--r--apps/plugins/sdl/progs/quake/snd_mix.c132
-rw-r--r--apps/plugins/sdl/progs/quake/snd_mix_arm.S129
-rw-r--r--apps/plugins/sdl/progs/quake/snd_mix_generic.c69
-rw-r--r--apps/plugins/sdl/progs/quake/snd_mix_generic_annotated.s191
-rw-r--r--apps/plugins/sdl/progs/quake/snd_null.c97
-rw-r--r--apps/plugins/sdl/progs/quake/snd_sdl.c113
-rw-r--r--apps/plugins/sdl/progs/quake/spritegn.h114
-rw-r--r--apps/plugins/sdl/progs/quake/sv_main.c1209
-rw-r--r--apps/plugins/sdl/progs/quake/sv_move.c427
-rw-r--r--apps/plugins/sdl/progs/quake/sv_phys.c1617
-rw-r--r--apps/plugins/sdl/progs/quake/sv_user.c629
-rw-r--r--apps/plugins/sdl/progs/quake/sys.h74
-rw-r--r--apps/plugins/sdl/progs/quake/sys_linux.c457
-rw-r--r--apps/plugins/sdl/progs/quake/sys_null.c232
-rw-r--r--apps/plugins/sdl/progs/quake/sys_sdl.c436
-rw-r--r--apps/plugins/sdl/progs/quake/vgamodes.h599
-rw-r--r--apps/plugins/sdl/progs/quake/vid.h85
-rw-r--r--apps/plugins/sdl/progs/quake/vid_null.c87
-rw-r--r--apps/plugins/sdl/progs/quake/vid_sdl.c389
-rw-r--r--apps/plugins/sdl/progs/quake/vid_svgalib.c1003
-rw-r--r--apps/plugins/sdl/progs/quake/vid_vga.c478
-rw-r--r--apps/plugins/sdl/progs/quake/view.c1113
-rw-r--r--apps/plugins/sdl/progs/quake/view.h35
-rw-r--r--apps/plugins/sdl/progs/quake/wad.c158
-rw-r--r--apps/plugins/sdl/progs/quake/wad.h75
-rw-r--r--apps/plugins/sdl/progs/quake/winquake.h115
-rw-r--r--apps/plugins/sdl/progs/quake/world.c962
-rw-r--r--apps/plugins/sdl/progs/quake/world.h78
-rw-r--r--apps/plugins/sdl/progs/quake/zone.c935
-rw-r--r--apps/plugins/sdl/progs/quake/zone.h131
-rw-r--r--apps/plugins/sdl/sdl.make40
-rw-r--r--apps/plugins/sdl/src/audio/SDL_audio.c1
-rw-r--r--apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c19
-rw-r--r--apps/plugins/sdl/src/thread/rockbox/SDL_systhread.c4
-rw-r--r--apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c1
-rw-r--r--apps/plugins/sdl/src/video/rockbox/SDL_rockboxvideo.c2
-rw-r--r--apps/plugins/sdl/wrappers.c122
-rw-r--r--docs/CREDITS1
-rw-r--r--manual/plugins/main.tex2
-rw-r--r--manual/plugins/quake.tex15
171 files changed, 64268 insertions, 20 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index a0527c87e2..ad99f3959f 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -80,6 +80,7 @@ gif,viewers
80pong,games 80pong,games
81ppm,viewers 81ppm,viewers
82properties,viewers 82properties,viewers
83quake,games
83random_folder_advance_config,apps 84random_folder_advance_config,apps
84remote_control,apps 85remote_control,apps
85resistor,apps 86resistor,apps
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 0ff6eb9c76..c3e56af254 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -78,6 +78,7 @@ iriverify.c
78 (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) 78 (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE))
79#if (PLUGIN_BUFFER_SIZE > 0x14000) && defined(CPU_ARM) 79#if (PLUGIN_BUFFER_SIZE > 0x14000) && defined(CPU_ARM)
80duke3d.c 80duke3d.c
81quake.c
81wolf3d.c 82wolf3d.c
82#endif 83#endif
83#endif 84#endif
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index 04c3d763b2..93cf8297b5 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -16,11 +16,11 @@ clock
16 (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE)) 16 (!defined(LCD_STRIDEFORMAT) || (LCD_STRIDEFORMAT != VERTICAL_STRIDE))
17xworld 17xworld
18 18
19/* for duke, etc. */ 19/* for duke3d, wolf3d and quake */
20#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && (PLUGIN_BUFFER_SIZE > 0x14000) && \ 20#if (PLUGIN_BUFFER_SIZE > 0x14000) && (CONFIG_PLATFORM & PLATFORM_NATIVE) && defined(CPU_ARM)
21 defined(CPU_ARM)
22sdl 21sdl
23#endif 22#endif
23
24puzzles 24puzzles
25#endif 25#endif
26 26
diff --git a/apps/plugins/lib/stdio_compat.h b/apps/plugins/lib/stdio_compat.h
index b9056fae04..bce21ea203 100644
--- a/apps/plugins/lib/stdio_compat.h
+++ b/apps/plugins/lib/stdio_compat.h
@@ -50,6 +50,8 @@
50#undef stderr 50#undef stderr
51#define stderr _stderr_ 51#define stderr _stderr_
52 52
53#define getc fgetc
54
53typedef struct { 55typedef struct {
54 int fd; 56 int fd;
55 int unget_char; 57 int unget_char;
diff --git a/apps/plugins/quake.c b/apps/plugins/quake.c
new file mode 100644
index 0000000000..d3abd43cc8
--- /dev/null
+++ b/apps/plugins/quake.c
@@ -0,0 +1,31 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2017 Franklin Wei
11 *
12 * Duke3D stub loader.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "plugin.h"
24
25#include "lib/overlay.h"
26
27/* this is the plugin entry point */
28enum plugin_status plugin_start(const void* parameter)
29{
30 return run_overlay(parameter, PLUGIN_GAMES_DIR "/quake.ovl", "Quake!");
31}
diff --git a/apps/plugins/sdl/SOURCES.quake b/apps/plugins/sdl/SOURCES.quake
new file mode 100644
index 0000000000..10a53a38a5
--- /dev/null
+++ b/apps/plugins/sdl/SOURCES.quake
@@ -0,0 +1,77 @@
1progs/quake/cd_null.c
2progs/quake/chase.c
3progs/quake/cl_demo.c
4progs/quake/cl_input.c
5progs/quake/cl_main.c
6progs/quake/cl_parse.c
7progs/quake/cl_tent.c
8progs/quake/cmd.c
9progs/quake/common.c
10progs/quake/console.c
11progs/quake/crc.c
12progs/quake/cvar.c
13progs/quake/d_edge.c
14progs/quake/d_fill.c
15progs/quake/d_init.c
16progs/quake/d_modech.c
17progs/quake/d_part.c
18progs/quake/d_polyse.c
19progs/quake/draw.c
20progs/quake/d_scan.c
21progs/quake/d_sky.c
22progs/quake/d_sprite.c
23progs/quake/d_surf.c
24progs/quake/d_vars.c
25progs/quake/d_zpoint.c
26progs/quake/host.c
27progs/quake/host_cmd.c
28progs/quake/keys.c
29progs/quake/mathlib.c
30progs/quake/menu.c
31progs/quake/model.c
32progs/quake/net_loop.c
33progs/quake/net_main.c
34progs/quake/net_none.c
35progs/quake/net_vcr.c
36progs/quake/nonintel.c
37progs/quake/pr_cmds.c
38progs/quake/pr_edict.c
39progs/quake/pr_exec.c
40progs/quake/r_aclip.c
41progs/quake/r_alias.c
42progs/quake/r_bsp.c
43progs/quake/r_draw.c
44progs/quake/r_edge.c
45progs/quake/r_efrag.c
46progs/quake/r_light.c
47progs/quake/r_main.c
48progs/quake/r_misc.c
49progs/quake/r_part.c
50progs/quake/r_sky.c
51progs/quake/r_sprite.c
52progs/quake/r_surf.c
53progs/quake/r_vars.c
54progs/quake/sbar.c
55progs/quake/screen.c
56progs/quake/snd_dma.c
57progs/quake/snd_mem.c
58progs/quake/snd_mix.c
59
60#ifdef __ARM_ARCH__5TEJ__
61progs/quake/snd_mix_arm.S
62#endif
63
64/* we still need generic no matter what */
65progs/quake/snd_mix_generic.c
66
67progs/quake/snd_sdl.c
68progs/quake/sv_main.c
69progs/quake/sv_move.c
70progs/quake/sv_phys.c
71progs/quake/sv_user.c
72progs/quake/sys_sdl.c
73progs/quake/vid_sdl.c
74progs/quake/view.c
75progs/quake/wad.c
76progs/quake/world.c
77progs/quake/zone.c
diff --git a/apps/plugins/sdl/include/SDL_config_rockbox.h b/apps/plugins/sdl/include/SDL_config_rockbox.h
index e268a73a8b..2b7f9a6793 100644
--- a/apps/plugins/sdl/include/SDL_config_rockbox.h
+++ b/apps/plugins/sdl/include/SDL_config_rockbox.h
@@ -38,7 +38,8 @@
38 38
39//#define COMBINED_SDL 39//#define COMBINED_SDL
40 40
41/* games will use this sample rate */ 41/* "recommended" sample rate for Rockbox. Games should use this by
42 * default unless necessary to do otherwise. */
42#ifdef SIMULATOR 43#ifdef SIMULATOR
43#define RB_SAMPR SAMPR_44 44#define RB_SAMPR SAMPR_44
44#else 45#else
@@ -57,6 +58,7 @@
57/* woot */ 58/* woot */
58#define SDL_AUDIO_DRIVER_ROCKBOX 1 59#define SDL_AUDIO_DRIVER_ROCKBOX 1
59#define SDL_THREAD_ROCKBOX 1 60#define SDL_THREAD_ROCKBOX 1
61#undef SDL_THREAD_PTHREAD
60#define SDL_TIMER_ROCKBOX 1 62#define SDL_TIMER_ROCKBOX 1
61#define SDL_VIDEO_DRIVER_ROCKBOX 1 63#define SDL_VIDEO_DRIVER_ROCKBOX 1
62 64
@@ -78,6 +80,10 @@
78#define HAVE_FREE 1 80#define HAVE_FREE 1
79#define HAVE_REALLOC 1 81#define HAVE_REALLOC 1
80#define HAVE_QSORT 1 82#define HAVE_QSORT 1
83#define HAVE_STRLEN 1
84#define HAVE_STRLCPY 1
85#define HAVE_STRCMP 1
86#define HAVE_STRNCMP 1
81 87
82#undef strdup 88#undef strdup
83 89
@@ -116,6 +122,7 @@
116#define floor floor_wrapper 122#define floor floor_wrapper
117#define fmod fmod_wrapper 123#define fmod fmod_wrapper
118#define free tlsf_free 124#define free tlsf_free
125#define fscanf fscanf_wrapper
119#define getchar() rb->sleep(2*HZ) 126#define getchar() rb->sleep(2*HZ)
120#define getenv SDL_getenv 127#define getenv SDL_getenv
121#define log rb_log 128#define log rb_log
@@ -146,6 +153,7 @@
146#define strcpy strcpy_wrapper 153#define strcpy strcpy_wrapper
147#define strdup strdup_wrapper 154#define strdup strdup_wrapper
148#define strerror(x) "error" 155#define strerror(x) "error"
156#define strlcpy rb->strlcpy
149#define strlen rb->strlen 157#define strlen rb->strlen
150#define strncasecmp rb->strncasecmp 158#define strncasecmp rb->strncasecmp
151#define strncat rb->strlcat /* hack */ 159#define strncat rb->strlcat /* hack */
@@ -163,8 +171,12 @@
163#define vsnprintf rb->vsnprintf 171#define vsnprintf rb->vsnprintf
164#define vsprintf vsprintf_wrapper 172#define vsprintf vsprintf_wrapper
165 173
174// use Rockbox's string routines
175#define SDL_memcpy memcpy
176#define SDL_memcmp memcmp
177
166#define M_PI 3.14159265358979323846 178#define M_PI 3.14159265358979323846
167#define EOF 0xff 179#define EOF (-1)
168 180
169#define LOAD_XPM 181#define LOAD_XPM
170#define MID_MUSIC 182#define MID_MUSIC
@@ -194,6 +206,7 @@ int vprintf(const char *fmt, va_list ap);
194void fatal(char *fmt, ...); 206void fatal(char *fmt, ...);
195void rb_exit(int rc); 207void rb_exit(int rc);
196void rbsdl_atexit(void (*)(void)); 208void rbsdl_atexit(void (*)(void));
209float atof_wrapper (char *str);
197 210
198/* speed */ 211/* speed */
199static inline uint16_t readLE16(void *addr) 212static inline uint16_t readLE16(void *addr)
diff --git a/apps/plugins/sdl/include/SDL_platform.h b/apps/plugins/sdl/include/SDL_platform.h
index 22c320118b..40df082205 100644
--- a/apps/plugins/sdl/include/SDL_platform.h
+++ b/apps/plugins/sdl/include/SDL_platform.h
@@ -108,6 +108,7 @@
108#endif 108#endif
109#if defined(ROCKBOX) 109#if defined(ROCKBOX)
110#undef __ROCKBOX__ 110#undef __ROCKBOX__
111#undef __LINUX__ /* maybe sim */
111#define __ROCKBOX__ 1 112#define __ROCKBOX__ 1
112#endif 113#endif
113 114
diff --git a/apps/plugins/sdl/main.c b/apps/plugins/sdl/main.c
index 478debc1ad..cefc1565d0 100644
--- a/apps/plugins/sdl/main.c
+++ b/apps/plugins/sdl/main.c
@@ -72,7 +72,7 @@ void cleanup(void)
72} 72}
73 73
74/* 256KB */ 74/* 256KB */
75static long main_stack[1024 * 1024 / 4]; 75static long main_stack[1024 * 1024 / 2];
76int (*main_fn)(int argc, char *argv[]); 76int (*main_fn)(int argc, char *argv[]);
77int prog_idx; 77int prog_idx;
78static void main_thread(void) 78static void main_thread(void)
@@ -176,7 +176,7 @@ enum plugin_status plugin_start(const void *param)
176#if defined(CPU_ARM) && !defined(SIMULATOR) 176#if defined(CPU_ARM) && !defined(SIMULATOR)
177 /* (don't) set alignment trap. Will generate a data abort 177 /* (don't) set alignment trap. Will generate a data abort
178 * exception on ARM. */ 178 * exception on ARM. */
179 //set_cr(get_cr() | CR_A); 179 set_cr(get_cr() | CR_A);
180#endif 180#endif
181 181
182#if 0 182#if 0
@@ -222,8 +222,11 @@ enum plugin_status plugin_start(const void *param)
222#undef rb_atexit 222#undef rb_atexit
223 rb_atexit(cleanup); 223 rb_atexit(cleanup);
224 224
225 /* make a new thread to use a bigger stack than otherwise accessible */ 225 /* make a new thread to use a bigger stack and higher priority than otherwise accessible */
226 sdl_thread_id = rb->create_thread(main_thread, main_stack, sizeof(main_stack), 0, "sdl_main" IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); 226 sdl_thread_id = rb->create_thread(main_thread, main_stack,
227 sizeof(main_stack), 0, "sdl_main"
228 IF_PRIO(, PRIORITY_USER_INTERFACE) // we need other threads still
229 IF_COP(, CPU));
227 rb->thread_wait(sdl_thread_id); 230 rb->thread_wait(sdl_thread_id);
228 231
229 rb->sleep(HZ); /* wait a second in case there's an error message on screen */ 232 rb->sleep(HZ); /* wait a second in case there's an error message on screen */
diff --git a/apps/plugins/sdl/progs/quake/Makefile.linuxi386 b/apps/plugins/sdl/progs/quake/Makefile.linuxi386
new file mode 100644
index 0000000000..e0750d1e78
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/Makefile.linuxi386
@@ -0,0 +1,1242 @@
1#
2# Quake Makefile for Linux 2.0
3#
4# Aug '98 by Zoid <zoid@idsoftware.com>
5#
6# ELF only
7#
8
9BASEVERSION=1.09
10VERSION=$(BASEVERSION)$(GLIBC)
11
12# RPM release number
13RPM_RELEASE=5
14
15ifneq (,$(findstring libc6,$(shell if [ -e /lib/libc.so.6 ];then echo libc6;fi)))
16GLIBC=-glibc
17else
18GLIBC=
19endif
20
21ifneq (,$(findstring alpha,$(shell uname -m)))
22ARCH=axp
23else
24ARCH=i386
25endif
26NOARCH=noarch
27
28#MOUNT_DIR=/grog/Projects/WinQuake
29MOUNT_DIR := $(shell pwd)
30MASTER_DIR=/grog/Projects/QuakeMaster
31MESA_DIR=/usr/local/src/Mesa-2.6
32TDFXGL_DIR = /home/zoid/3dfxgl
33
34BUILD_DEBUG_DIR=debug$(ARCH)$(GLIBC)
35BUILD_RELEASE_DIR=release$(ARCH)$(GLIBC)
36
37#EGCS=/usr/local/egcs-1.1.2/bin/gcc
38#CC=$(EGCS)
39
40BASE_CFLAGS=-Dstricmp=strcasecmp
41RELEASE_CFLAGS=$(BASE_CFLAGS) -g -mpentiumpro -O6 -ffast-math -funroll-loops \
42 -fomit-frame-pointer -fexpensive-optimizations
43DEBUG_CFLAGS=$(BASE_CFLAGS) -g
44LDFLAGS=-lm
45SVGALDFLAGS=-lvga
46XLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext -lXxf86dga
47XCFLAGS=-DX11
48
49MESAGLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib -L$(MESA_DIR)/lib -lMesaGL -lglide2x -lX11 -lXext -ldl
50TDFXGLLDFLAGS=-L$(TDFXGL_DIR)/release$(ARCH)$(GLIBC) -l3dfxgl -lglide2x -ldl
51GLLDFLAGS=-L/usr/X11/lib -L/usr/local/lib -lGL -lX11 -lXext -ldl -lXxf86dga -lXxf86vm -lm
52GLCFLAGS=-DGLQUAKE -I$(MESA_DIR)/include -I/usr/include/glide
53
54DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
55DO_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) -o $@ -c $<
56DO_GL_CC=$(CC) $(CFLAGS) $(GLCFLAGS) -o $@ -c $<
57DO_GL_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(GLCFLAGS) -o $@ -c $<
58DO_X11_CC=$(CC) $(CFLAGS) $(XCFLAGS) -o $@ -c $<
59DO_X11_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(XCFLAGS) -o $@ -c $<
60DO_O_CC=$(CC) -O $(CFLAGS) -o $@ -c $<
61#DO_AS=$(CC) $(CFLAGS) -DELF -x assembler-with-cpp -o $@ -c $<
62DO_AS=$(CC) $(CFLAGS) -DELF -o $@ -c $<
63DO_GL_AS=$(CC) $(CFLAGS) $(GLCFLAGS) -DELF -x assembler-with-cpp -o $@ -c $<
64
65#############################################################################
66# SETUP AND BUILD
67#############################################################################
68
69TARGETS=$(BUILDDIR)/bin/quake.x11\
70 $(BUILDDIR)/bin/squake \
71 $(BUILDDIR)/bin/glquake \
72 $(BUILDDIR)/bin/glquake.glx \
73 $(BUILDDIR)/bin/glquake.3dfxgl \
74 # $(BUILDDIR)/bin/unixded
75
76build_debug:
77 @-mkdir $(BUILD_DEBUG_DIR) \
78 $(BUILD_DEBUG_DIR)/bin \
79 $(BUILD_DEBUG_DIR)/glquake \
80 $(BUILD_DEBUG_DIR)/squake \
81 $(BUILD_DEBUG_DIR)/unixded \
82 $(BUILD_DEBUG_DIR)/x11
83 $(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
84
85build_release:
86 @-mkdir $(BUILD_RELEASE_DIR) \
87 $(BUILD_RELEASE_DIR)/bin \
88 $(BUILD_RELEASE_DIR)/glquake \
89 $(BUILD_RELEASE_DIR)/squake \
90 $(BUILD_RELEASE_DIR)/unixded \
91 $(BUILD_RELEASE_DIR)/x11
92 $(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
93
94all: build_debug build_release
95
96targets: $(TARGETS)
97
98#############################################################################
99# SVGALIB Quake
100#############################################################################
101
102SQUAKE_OBJS = \
103 $(BUILDDIR)/squake/cl_demo.o \
104 $(BUILDDIR)/squake/cl_input.o \
105 $(BUILDDIR)/squake/cl_main.o \
106 $(BUILDDIR)/squake/cl_parse.o \
107 $(BUILDDIR)/squake/cl_tent.o \
108 $(BUILDDIR)/squake/chase.o \
109 $(BUILDDIR)/squake/cmd.o \
110 $(BUILDDIR)/squake/common.o \
111 $(BUILDDIR)/squake/console.o \
112 $(BUILDDIR)/squake/crc.o \
113 $(BUILDDIR)/squake/cvar.o \
114 $(BUILDDIR)/squake/draw.o \
115 $(BUILDDIR)/squake/d_edge.o \
116 $(BUILDDIR)/squake/d_fill.o \
117 $(BUILDDIR)/squake/d_init.o \
118 $(BUILDDIR)/squake/d_modech.o \
119 $(BUILDDIR)/squake/d_part.o \
120 $(BUILDDIR)/squake/d_polyse.o \
121 $(BUILDDIR)/squake/d_scan.o \
122 $(BUILDDIR)/squake/d_sky.o \
123 $(BUILDDIR)/squake/d_sprite.o \
124 $(BUILDDIR)/squake/d_surf.o \
125 $(BUILDDIR)/squake/d_vars.o \
126 $(BUILDDIR)/squake/d_zpoint.o \
127 $(BUILDDIR)/squake/host.o \
128 $(BUILDDIR)/squake/host_cmd.o \
129 $(BUILDDIR)/squake/keys.o \
130 $(BUILDDIR)/squake/menu.o \
131 $(BUILDDIR)/squake/mathlib.o \
132 $(BUILDDIR)/squake/model.o \
133 $(BUILDDIR)/squake/net_dgrm.o \
134 $(BUILDDIR)/squake/net_loop.o \
135 $(BUILDDIR)/squake/net_main.o \
136 $(BUILDDIR)/squake/net_vcr.o \
137 $(BUILDDIR)/squake/net_udp.o \
138 $(BUILDDIR)/squake/net_bsd.o \
139 $(BUILDDIR)/squake/nonintel.o \
140 $(BUILDDIR)/squake/pr_cmds.o \
141 $(BUILDDIR)/squake/pr_edict.o \
142 $(BUILDDIR)/squake/pr_exec.o \
143 $(BUILDDIR)/squake/r_aclip.o \
144 $(BUILDDIR)/squake/r_alias.o \
145 $(BUILDDIR)/squake/r_bsp.o \
146 $(BUILDDIR)/squake/r_light.o \
147 $(BUILDDIR)/squake/r_draw.o \
148 $(BUILDDIR)/squake/r_efrag.o \
149 $(BUILDDIR)/squake/r_edge.o \
150 $(BUILDDIR)/squake/r_misc.o \
151 $(BUILDDIR)/squake/r_main.o \
152 $(BUILDDIR)/squake/r_sky.o \
153 $(BUILDDIR)/squake/r_sprite.o \
154 $(BUILDDIR)/squake/r_surf.o \
155 $(BUILDDIR)/squake/r_part.o \
156 $(BUILDDIR)/squake/r_vars.o \
157 $(BUILDDIR)/squake/screen.o \
158 $(BUILDDIR)/squake/sbar.o \
159 $(BUILDDIR)/squake/sv_main.o \
160 $(BUILDDIR)/squake/sv_phys.o \
161 $(BUILDDIR)/squake/sv_move.o \
162 $(BUILDDIR)/squake/sv_user.o \
163 $(BUILDDIR)/squake/zone.o \
164 $(BUILDDIR)/squake/view.o \
165 $(BUILDDIR)/squake/wad.o \
166 $(BUILDDIR)/squake/world.o \
167 $(BUILDDIR)/squake/cd_linux.o \
168 $(BUILDDIR)/squake/sys_linux.o \
169 $(BUILDDIR)/squake/vid_svgalib.o \
170 $(BUILDDIR)/squake/snd_dma.o \
171 $(BUILDDIR)/squake/snd_mem.o \
172 $(BUILDDIR)/squake/snd_mix.o \
173 $(BUILDDIR)/squake/snd_linux.o \
174 \
175 $(BUILDDIR)/squake/d_copy.o \
176 $(BUILDDIR)/squake/d_draw.o \
177 $(BUILDDIR)/squake/d_draw16.o \
178 $(BUILDDIR)/squake/d_parta.o \
179 $(BUILDDIR)/squake/d_polysa.o \
180 $(BUILDDIR)/squake/d_scana.o \
181 $(BUILDDIR)/squake/d_spr8.o \
182 $(BUILDDIR)/squake/d_varsa.o \
183 $(BUILDDIR)/squake/math.o \
184 $(BUILDDIR)/squake/r_aliasa.o \
185 $(BUILDDIR)/squake/r_drawa.o \
186 $(BUILDDIR)/squake/r_edgea.o \
187 $(BUILDDIR)/squake/r_varsa.o \
188 $(BUILDDIR)/squake/surf16.o \
189 $(BUILDDIR)/squake/surf8.o \
190 $(BUILDDIR)/squake/worlda.o \
191 $(BUILDDIR)/squake/r_aclipa.o \
192 $(BUILDDIR)/squake/snd_mixa.o \
193 $(BUILDDIR)/squake/sys_dosa.o
194
195$(BUILDDIR)/bin/squake : $(SQUAKE_OBJS)
196 $(CC) $(CFLAGS) -o $@ $(SQUAKE_OBJS) $(SVGALDFLAGS) $(LDFLAGS)
197
198####
199
200$(BUILDDIR)/squake/cl_demo.o : $(MOUNT_DIR)/cl_demo.c
201 $(DO_CC)
202
203$(BUILDDIR)/squake/cl_input.o : $(MOUNT_DIR)/cl_input.c
204 $(DO_CC)
205
206$(BUILDDIR)/squake/cl_main.o : $(MOUNT_DIR)/cl_main.c
207 $(DO_CC)
208
209$(BUILDDIR)/squake/cl_parse.o : $(MOUNT_DIR)/cl_parse.c
210 $(DO_CC)
211
212$(BUILDDIR)/squake/cl_tent.o : $(MOUNT_DIR)/cl_tent.c
213 $(DO_CC)
214
215$(BUILDDIR)/squake/chase.o : $(MOUNT_DIR)/chase.c
216 $(DO_CC)
217
218$(BUILDDIR)/squake/cmd.o : $(MOUNT_DIR)/cmd.c
219 $(DO_CC)
220
221$(BUILDDIR)/squake/common.o : $(MOUNT_DIR)/common.c
222 $(DO_DEBUG_CC)
223
224$(BUILDDIR)/squake/console.o : $(MOUNT_DIR)/console.c
225 $(DO_CC)
226
227$(BUILDDIR)/squake/crc.o : $(MOUNT_DIR)/crc.c
228 $(DO_CC)
229
230$(BUILDDIR)/squake/cvar.o : $(MOUNT_DIR)/cvar.c
231 $(DO_CC)
232
233$(BUILDDIR)/squake/draw.o : $(MOUNT_DIR)/draw.c
234 $(DO_CC)
235
236$(BUILDDIR)/squake/d_edge.o : $(MOUNT_DIR)/d_edge.c
237 $(DO_CC)
238
239$(BUILDDIR)/squake/d_fill.o : $(MOUNT_DIR)/d_fill.c
240 $(DO_CC)
241
242$(BUILDDIR)/squake/d_init.o : $(MOUNT_DIR)/d_init.c
243 $(DO_CC)
244
245$(BUILDDIR)/squake/d_modech.o : $(MOUNT_DIR)/d_modech.c
246 $(DO_CC)
247
248$(BUILDDIR)/squake/d_part.o : $(MOUNT_DIR)/d_part.c
249 $(DO_CC)
250
251$(BUILDDIR)/squake/d_polyse.o : $(MOUNT_DIR)/d_polyse.c
252 $(DO_CC)
253
254$(BUILDDIR)/squake/d_scan.o : $(MOUNT_DIR)/d_scan.c
255 $(DO_CC)
256
257$(BUILDDIR)/squake/d_sky.o : $(MOUNT_DIR)/d_sky.c
258 $(DO_CC)
259
260$(BUILDDIR)/squake/d_sprite.o : $(MOUNT_DIR)/d_sprite.c
261 $(DO_CC)
262
263$(BUILDDIR)/squake/d_surf.o : $(MOUNT_DIR)/d_surf.c
264 $(DO_CC)
265
266$(BUILDDIR)/squake/d_vars.o : $(MOUNT_DIR)/d_vars.c
267 $(DO_CC)
268
269$(BUILDDIR)/squake/d_zpoint.o : $(MOUNT_DIR)/d_zpoint.c
270 $(DO_CC)
271
272$(BUILDDIR)/squake/host.o : $(MOUNT_DIR)/host.c
273 $(DO_CC)
274
275$(BUILDDIR)/squake/host_cmd.o : $(MOUNT_DIR)/host_cmd.c
276 $(DO_CC)
277
278$(BUILDDIR)/squake/keys.o : $(MOUNT_DIR)/keys.c
279 $(DO_CC)
280
281$(BUILDDIR)/squake/menu.o : $(MOUNT_DIR)/menu.c
282 $(DO_CC)
283
284$(BUILDDIR)/squake/mathlib.o : $(MOUNT_DIR)/mathlib.c
285 $(DO_CC)
286
287$(BUILDDIR)/squake/model.o : $(MOUNT_DIR)/model.c
288 $(DO_CC)
289
290$(BUILDDIR)/squake/net_dgrm.o : $(MOUNT_DIR)/net_dgrm.c
291 $(DO_CC)
292
293$(BUILDDIR)/squake/net_loop.o : $(MOUNT_DIR)/net_loop.c
294 $(DO_CC)
295
296$(BUILDDIR)/squake/net_main.o : $(MOUNT_DIR)/net_main.c
297 $(DO_CC)
298
299$(BUILDDIR)/squake/net_vcr.o : $(MOUNT_DIR)/net_vcr.c
300 $(DO_CC)
301
302$(BUILDDIR)/squake/net_udp.o : $(MOUNT_DIR)/net_udp.c
303 $(DO_CC)
304
305$(BUILDDIR)/squake/net_bsd.o : $(MOUNT_DIR)/net_bsd.c
306 $(DO_CC)
307
308$(BUILDDIR)/squake/nonintel.o : $(MOUNT_DIR)/nonintel.c
309 $(DO_CC)
310
311$(BUILDDIR)/squake/pr_cmds.o : $(MOUNT_DIR)/pr_cmds.c
312 $(DO_CC)
313
314$(BUILDDIR)/squake/pr_edict.o : $(MOUNT_DIR)/pr_edict.c
315 $(DO_CC)
316
317$(BUILDDIR)/squake/pr_exec.o : $(MOUNT_DIR)/pr_exec.c
318 $(DO_CC)
319
320$(BUILDDIR)/squake/r_aclip.o : $(MOUNT_DIR)/r_aclip.c
321 $(DO_CC)
322
323$(BUILDDIR)/squake/r_alias.o : $(MOUNT_DIR)/r_alias.c
324 $(DO_CC)
325
326$(BUILDDIR)/squake/r_bsp.o : $(MOUNT_DIR)/r_bsp.c
327 $(DO_CC)
328
329$(BUILDDIR)/squake/r_light.o : $(MOUNT_DIR)/r_light.c
330 $(DO_CC)
331
332$(BUILDDIR)/squake/r_draw.o : $(MOUNT_DIR)/r_draw.c
333 $(DO_CC)
334
335$(BUILDDIR)/squake/r_efrag.o : $(MOUNT_DIR)/r_efrag.c
336 $(DO_CC)
337
338$(BUILDDIR)/squake/r_edge.o : $(MOUNT_DIR)/r_edge.c
339 $(DO_CC)
340
341$(BUILDDIR)/squake/r_misc.o : $(MOUNT_DIR)/r_misc.c
342 $(DO_CC)
343
344$(BUILDDIR)/squake/r_main.o : $(MOUNT_DIR)/r_main.c
345 $(DO_CC)
346
347$(BUILDDIR)/squake/r_sky.o : $(MOUNT_DIR)/r_sky.c
348 $(DO_CC)
349
350$(BUILDDIR)/squake/r_sprite.o : $(MOUNT_DIR)/r_sprite.c
351 $(DO_CC)
352
353$(BUILDDIR)/squake/r_surf.o : $(MOUNT_DIR)/r_surf.c
354 $(DO_CC)
355
356$(BUILDDIR)/squake/r_part.o : $(MOUNT_DIR)/r_part.c
357 $(DO_CC)
358
359$(BUILDDIR)/squake/r_vars.o : $(MOUNT_DIR)/r_vars.c
360 $(DO_CC)
361
362$(BUILDDIR)/squake/screen.o : $(MOUNT_DIR)/screen.c
363 $(DO_CC)
364
365$(BUILDDIR)/squake/sbar.o : $(MOUNT_DIR)/sbar.c
366 $(DO_CC)
367
368$(BUILDDIR)/squake/sv_main.o : $(MOUNT_DIR)/sv_main.c
369 $(DO_CC)
370
371$(BUILDDIR)/squake/sv_phys.o : $(MOUNT_DIR)/sv_phys.c
372 $(DO_CC)
373
374$(BUILDDIR)/squake/sv_move.o : $(MOUNT_DIR)/sv_move.c
375 $(DO_CC)
376
377$(BUILDDIR)/squake/sv_user.o : $(MOUNT_DIR)/sv_user.c
378 $(DO_CC)
379
380$(BUILDDIR)/squake/zone.o : $(MOUNT_DIR)/zone.c
381 $(DO_CC)
382
383$(BUILDDIR)/squake/view.o : $(MOUNT_DIR)/view.c
384 $(DO_CC)
385
386$(BUILDDIR)/squake/wad.o : $(MOUNT_DIR)/wad.c
387 $(DO_CC)
388
389$(BUILDDIR)/squake/world.o : $(MOUNT_DIR)/world.c
390 $(DO_CC)
391
392$(BUILDDIR)/squake/cd_linux.o : $(MOUNT_DIR)/cd_linux.c
393 $(DO_CC)
394
395$(BUILDDIR)/squake/sys_linux.o :$(MOUNT_DIR)/sys_linux.c
396 $(DO_CC)
397
398$(BUILDDIR)/squake/vid_svgalib.o:$(MOUNT_DIR)/vid_svgalib.c
399 $(DO_O_CC)
400
401$(BUILDDIR)/squake/snd_dma.o : $(MOUNT_DIR)/snd_dma.c
402 $(DO_CC)
403
404$(BUILDDIR)/squake/snd_mem.o : $(MOUNT_DIR)/snd_mem.c
405 $(DO_CC)
406
407$(BUILDDIR)/squake/snd_mix.o : $(MOUNT_DIR)/snd_mix.c
408 $(DO_CC)
409
410$(BUILDDIR)/squake/snd_linux.o :$(MOUNT_DIR)/snd_linux.c
411 $(DO_CC)
412
413#####
414
415$(BUILDDIR)/squake/d_copy.o : $(MOUNT_DIR)/d_copy.S
416 $(DO_AS)
417
418$(BUILDDIR)/squake/d_draw.o : $(MOUNT_DIR)/d_draw.S
419 $(DO_AS)
420
421$(BUILDDIR)/squake/d_draw16.o : $(MOUNT_DIR)/d_draw16.S
422 $(DO_AS)
423
424$(BUILDDIR)/squake/d_parta.o : $(MOUNT_DIR)/d_parta.S
425 $(DO_AS)
426
427$(BUILDDIR)/squake/d_polysa.o : $(MOUNT_DIR)/d_polysa.S
428 $(DO_AS)
429
430$(BUILDDIR)/squake/d_scana.o : $(MOUNT_DIR)/d_scana.S
431 $(DO_AS)
432
433$(BUILDDIR)/squake/d_spr8.o : $(MOUNT_DIR)/d_spr8.S
434 $(DO_AS)
435
436$(BUILDDIR)/squake/d_varsa.o : $(MOUNT_DIR)/d_varsa.S
437 $(DO_AS)
438
439$(BUILDDIR)/squake/math.o : $(MOUNT_DIR)/math.S
440 $(DO_AS)
441
442$(BUILDDIR)/squake/r_aliasa.o : $(MOUNT_DIR)/r_aliasa.S
443 $(DO_AS)
444
445$(BUILDDIR)/squake/r_drawa.o : $(MOUNT_DIR)/r_drawa.S
446 $(DO_AS)
447
448$(BUILDDIR)/squake/r_edgea.o : $(MOUNT_DIR)/r_edgea.S
449 $(DO_AS)
450
451$(BUILDDIR)/squake/r_varsa.o : $(MOUNT_DIR)/r_varsa.S
452 $(DO_AS)
453
454$(BUILDDIR)/squake/surf16.o : $(MOUNT_DIR)/surf16.S
455 $(DO_AS)
456
457$(BUILDDIR)/squake/surf8.o : $(MOUNT_DIR)/surf8.S
458 $(DO_AS)
459
460$(BUILDDIR)/squake/worlda.o : $(MOUNT_DIR)/worlda.S
461 $(DO_AS)
462
463$(BUILDDIR)/squake/r_aclipa.o : $(MOUNT_DIR)/r_aclipa.S
464 $(DO_AS)
465
466$(BUILDDIR)/squake/snd_mixa.o : $(MOUNT_DIR)/snd_mixa.S
467 $(DO_AS)
468
469$(BUILDDIR)/squake/sys_dosa.o : $(MOUNT_DIR)/sys_dosa.S
470 $(DO_AS)
471
472#############################################################################
473# X11 Quake
474#############################################################################
475
476X11_OBJS = \
477 $(BUILDDIR)/x11/cl_demo.o \
478 $(BUILDDIR)/x11/cl_input.o \
479 $(BUILDDIR)/x11/cl_main.o \
480 $(BUILDDIR)/x11/cl_parse.o \
481 $(BUILDDIR)/x11/cl_tent.o \
482 $(BUILDDIR)/x11/chase.o \
483 $(BUILDDIR)/x11/cmd.o \
484 $(BUILDDIR)/x11/common.o \
485 $(BUILDDIR)/x11/console.o \
486 $(BUILDDIR)/x11/crc.o \
487 $(BUILDDIR)/x11/cvar.o \
488 $(BUILDDIR)/x11/draw.o \
489 $(BUILDDIR)/x11/d_edge.o \
490 $(BUILDDIR)/x11/d_fill.o \
491 $(BUILDDIR)/x11/d_init.o \
492 $(BUILDDIR)/x11/d_modech.o \
493 $(BUILDDIR)/x11/d_part.o \
494 $(BUILDDIR)/x11/d_polyse.o \
495 $(BUILDDIR)/x11/d_scan.o \
496 $(BUILDDIR)/x11/d_sky.o \
497 $(BUILDDIR)/x11/d_sprite.o \
498 $(BUILDDIR)/x11/d_surf.o \
499 $(BUILDDIR)/x11/d_vars.o \
500 $(BUILDDIR)/x11/d_zpoint.o \
501 $(BUILDDIR)/x11/host.o \
502 $(BUILDDIR)/x11/host_cmd.o \
503 $(BUILDDIR)/x11/keys.o \
504 $(BUILDDIR)/x11/menu.o \
505 $(BUILDDIR)/x11/mathlib.o \
506 $(BUILDDIR)/x11/model.o \
507 $(BUILDDIR)/x11/net_dgrm.o \
508 $(BUILDDIR)/x11/net_loop.o \
509 $(BUILDDIR)/x11/net_main.o \
510 $(BUILDDIR)/x11/net_vcr.o \
511 $(BUILDDIR)/x11/net_udp.o \
512 $(BUILDDIR)/x11/net_bsd.o \
513 $(BUILDDIR)/x11/nonintel.o \
514 $(BUILDDIR)/x11/pr_cmds.o \
515 $(BUILDDIR)/x11/pr_edict.o \
516 $(BUILDDIR)/x11/pr_exec.o \
517 $(BUILDDIR)/x11/r_aclip.o \
518 $(BUILDDIR)/x11/r_alias.o \
519 $(BUILDDIR)/x11/r_bsp.o \
520 $(BUILDDIR)/x11/r_light.o \
521 $(BUILDDIR)/x11/r_draw.o \
522 $(BUILDDIR)/x11/r_efrag.o \
523 $(BUILDDIR)/x11/r_edge.o \
524 $(BUILDDIR)/x11/r_misc.o \
525 $(BUILDDIR)/x11/r_main.o \
526 $(BUILDDIR)/x11/r_sky.o \
527 $(BUILDDIR)/x11/r_sprite.o \
528 $(BUILDDIR)/x11/r_surf.o \
529 $(BUILDDIR)/x11/r_part.o \
530 $(BUILDDIR)/x11/r_vars.o \
531 $(BUILDDIR)/x11/screen.o \
532 $(BUILDDIR)/x11/sbar.o \
533 $(BUILDDIR)/x11/sv_main.o \
534 $(BUILDDIR)/x11/sv_phys.o \
535 $(BUILDDIR)/x11/sv_move.o \
536 $(BUILDDIR)/x11/sv_user.o \
537 $(BUILDDIR)/x11/zone.o \
538 $(BUILDDIR)/x11/view.o \
539 $(BUILDDIR)/x11/wad.o \
540 $(BUILDDIR)/x11/world.o \
541 $(BUILDDIR)/x11/cd_linux.o \
542 $(BUILDDIR)/x11/sys_linux.o \
543 $(BUILDDIR)/x11/vid_x.o \
544 $(BUILDDIR)/x11/snd_dma.o \
545 $(BUILDDIR)/x11/snd_mem.o \
546 $(BUILDDIR)/x11/snd_mix.o \
547 $(BUILDDIR)/x11/snd_linux.o \
548 \
549 $(BUILDDIR)/x11/d_draw.o \
550 $(BUILDDIR)/x11/d_draw16.o \
551 $(BUILDDIR)/x11/d_parta.o \
552 $(BUILDDIR)/x11/d_polysa.o \
553 $(BUILDDIR)/x11/d_scana.o \
554 $(BUILDDIR)/x11/d_spr8.o \
555 $(BUILDDIR)/x11/d_varsa.o \
556 $(BUILDDIR)/x11/math.o \
557 $(BUILDDIR)/x11/r_aliasa.o \
558 $(BUILDDIR)/x11/r_drawa.o \
559 $(BUILDDIR)/x11/r_edgea.o \
560 $(BUILDDIR)/x11/r_varsa.o \
561 $(BUILDDIR)/x11/surf16.o \
562 $(BUILDDIR)/x11/surf8.o \
563 $(BUILDDIR)/x11/worlda.o \
564 $(BUILDDIR)/x11/r_aclipa.o \
565 $(BUILDDIR)/x11/snd_mixa.o \
566 $(BUILDDIR)/x11/sys_dosa.o
567
568$(BUILDDIR)/bin/quake.x11 : $(X11_OBJS)
569 $(CC) $(CFLAGS) -o $@ $(X11_OBJS) $(XLDFLAGS) $(LDFLAGS)
570
571####
572
573$(BUILDDIR)/x11/cl_demo.o : $(MOUNT_DIR)/cl_demo.c
574 $(DO_X11_CC)
575
576$(BUILDDIR)/x11/cl_input.o : $(MOUNT_DIR)/cl_input.c
577 $(DO_X11_CC)
578
579$(BUILDDIR)/x11/cl_main.o : $(MOUNT_DIR)/cl_main.c
580 $(DO_X11_CC)
581
582$(BUILDDIR)/x11/cl_parse.o : $(MOUNT_DIR)/cl_parse.c
583 $(DO_X11_CC)
584
585$(BUILDDIR)/x11/cl_tent.o : $(MOUNT_DIR)/cl_tent.c
586 $(DO_X11_CC)
587
588$(BUILDDIR)/x11/chase.o : $(MOUNT_DIR)/chase.c
589 $(DO_X11_CC)
590
591$(BUILDDIR)/x11/cmd.o : $(MOUNT_DIR)/cmd.c
592 $(DO_X11_CC)
593
594$(BUILDDIR)/x11/common.o : $(MOUNT_DIR)/common.c
595 $(DO_X11_DEBUG_CC)
596
597$(BUILDDIR)/x11/console.o : $(MOUNT_DIR)/console.c
598 $(DO_X11_CC)
599
600$(BUILDDIR)/x11/crc.o : $(MOUNT_DIR)/crc.c
601 $(DO_X11_CC)
602
603$(BUILDDIR)/x11/cvar.o : $(MOUNT_DIR)/cvar.c
604 $(DO_X11_CC)
605
606$(BUILDDIR)/x11/draw.o : $(MOUNT_DIR)/draw.c
607 $(DO_X11_CC)
608
609$(BUILDDIR)/x11/d_edge.o : $(MOUNT_DIR)/d_edge.c
610 $(DO_X11_CC)
611
612$(BUILDDIR)/x11/d_fill.o : $(MOUNT_DIR)/d_fill.c
613 $(DO_X11_CC)
614
615$(BUILDDIR)/x11/d_init.o : $(MOUNT_DIR)/d_init.c
616 $(DO_X11_CC)
617
618$(BUILDDIR)/x11/d_modech.o : $(MOUNT_DIR)/d_modech.c
619 $(DO_X11_CC)
620
621$(BUILDDIR)/x11/d_part.o : $(MOUNT_DIR)/d_part.c
622 $(DO_X11_CC)
623
624$(BUILDDIR)/x11/d_polyse.o : $(MOUNT_DIR)/d_polyse.c
625 $(DO_X11_CC)
626
627$(BUILDDIR)/x11/d_scan.o : $(MOUNT_DIR)/d_scan.c
628 $(DO_X11_CC)
629
630$(BUILDDIR)/x11/d_sky.o : $(MOUNT_DIR)/d_sky.c
631 $(DO_X11_CC)
632
633$(BUILDDIR)/x11/d_sprite.o : $(MOUNT_DIR)/d_sprite.c
634 $(DO_X11_CC)
635
636$(BUILDDIR)/x11/d_surf.o : $(MOUNT_DIR)/d_surf.c
637 $(DO_X11_CC)
638
639$(BUILDDIR)/x11/d_vars.o : $(MOUNT_DIR)/d_vars.c
640 $(DO_X11_CC)
641
642$(BUILDDIR)/x11/d_zpoint.o : $(MOUNT_DIR)/d_zpoint.c
643 $(DO_X11_CC)
644
645$(BUILDDIR)/x11/host.o : $(MOUNT_DIR)/host.c
646 $(DO_X11_CC)
647
648$(BUILDDIR)/x11/host_cmd.o : $(MOUNT_DIR)/host_cmd.c
649 $(DO_X11_CC)
650
651$(BUILDDIR)/x11/keys.o : $(MOUNT_DIR)/keys.c
652 $(DO_X11_CC)
653
654$(BUILDDIR)/x11/menu.o : $(MOUNT_DIR)/menu.c
655 $(DO_X11_CC)
656
657$(BUILDDIR)/x11/mathlib.o : $(MOUNT_DIR)/mathlib.c
658 $(DO_X11_CC)
659
660$(BUILDDIR)/x11/model.o : $(MOUNT_DIR)/model.c
661 $(DO_X11_CC)
662
663$(BUILDDIR)/x11/net_dgrm.o : $(MOUNT_DIR)/net_dgrm.c
664 $(DO_X11_CC)
665
666$(BUILDDIR)/x11/net_loop.o : $(MOUNT_DIR)/net_loop.c
667 $(DO_X11_CC)
668
669$(BUILDDIR)/x11/net_main.o : $(MOUNT_DIR)/net_main.c
670 $(DO_X11_CC)
671
672$(BUILDDIR)/x11/net_vcr.o : $(MOUNT_DIR)/net_vcr.c
673 $(DO_X11_CC)
674
675$(BUILDDIR)/x11/net_udp.o : $(MOUNT_DIR)/net_udp.c
676 $(DO_X11_CC)
677
678$(BUILDDIR)/x11/net_bsd.o : $(MOUNT_DIR)/net_bsd.c
679 $(DO_X11_CC)
680
681$(BUILDDIR)/x11/nonintel.o : $(MOUNT_DIR)/nonintel.c
682 $(DO_X11_CC)
683
684$(BUILDDIR)/x11/pr_cmds.o : $(MOUNT_DIR)/pr_cmds.c
685 $(DO_X11_CC)
686
687$(BUILDDIR)/x11/pr_edict.o : $(MOUNT_DIR)/pr_edict.c
688 $(DO_X11_CC)
689
690$(BUILDDIR)/x11/pr_exec.o : $(MOUNT_DIR)/pr_exec.c
691 $(DO_X11_CC)
692
693$(BUILDDIR)/x11/r_aclip.o : $(MOUNT_DIR)/r_aclip.c
694 $(DO_X11_CC)
695
696$(BUILDDIR)/x11/r_alias.o : $(MOUNT_DIR)/r_alias.c
697 $(DO_X11_CC)
698
699$(BUILDDIR)/x11/r_bsp.o : $(MOUNT_DIR)/r_bsp.c
700 $(DO_X11_CC)
701
702$(BUILDDIR)/x11/r_light.o : $(MOUNT_DIR)/r_light.c
703 $(DO_X11_CC)
704
705$(BUILDDIR)/x11/r_draw.o : $(MOUNT_DIR)/r_draw.c
706 $(DO_X11_CC)
707
708$(BUILDDIR)/x11/r_efrag.o : $(MOUNT_DIR)/r_efrag.c
709 $(DO_X11_CC)
710
711$(BUILDDIR)/x11/r_edge.o : $(MOUNT_DIR)/r_edge.c
712 $(DO_X11_CC)
713
714$(BUILDDIR)/x11/r_misc.o : $(MOUNT_DIR)/r_misc.c
715 $(DO_X11_CC)
716
717$(BUILDDIR)/x11/r_main.o : $(MOUNT_DIR)/r_main.c
718 $(DO_X11_CC)
719
720$(BUILDDIR)/x11/r_sky.o : $(MOUNT_DIR)/r_sky.c
721 $(DO_X11_CC)
722
723$(BUILDDIR)/x11/r_sprite.o : $(MOUNT_DIR)/r_sprite.c
724 $(DO_X11_CC)
725
726$(BUILDDIR)/x11/r_surf.o : $(MOUNT_DIR)/r_surf.c
727 $(DO_X11_CC)
728
729$(BUILDDIR)/x11/r_part.o : $(MOUNT_DIR)/r_part.c
730 $(DO_X11_CC)
731
732$(BUILDDIR)/x11/r_vars.o : $(MOUNT_DIR)/r_vars.c
733 $(DO_X11_CC)
734
735$(BUILDDIR)/x11/screen.o : $(MOUNT_DIR)/screen.c
736 $(DO_X11_CC)
737
738$(BUILDDIR)/x11/sbar.o : $(MOUNT_DIR)/sbar.c
739 $(DO_X11_CC)
740
741$(BUILDDIR)/x11/sv_main.o : $(MOUNT_DIR)/sv_main.c
742 $(DO_X11_CC)
743
744$(BUILDDIR)/x11/sv_phys.o : $(MOUNT_DIR)/sv_phys.c
745 $(DO_X11_CC)
746
747$(BUILDDIR)/x11/sv_move.o : $(MOUNT_DIR)/sv_move.c
748 $(DO_X11_CC)
749
750$(BUILDDIR)/x11/sv_user.o : $(MOUNT_DIR)/sv_user.c
751 $(DO_X11_CC)
752
753$(BUILDDIR)/x11/zone.o : $(MOUNT_DIR)/zone.c
754 $(DO_X11_CC)
755
756$(BUILDDIR)/x11/view.o : $(MOUNT_DIR)/view.c
757 $(DO_X11_CC)
758
759$(BUILDDIR)/x11/wad.o : $(MOUNT_DIR)/wad.c
760 $(DO_X11_CC)
761
762$(BUILDDIR)/x11/world.o : $(MOUNT_DIR)/world.c
763 $(DO_X11_CC)
764
765$(BUILDDIR)/x11/cd_linux.o : $(MOUNT_DIR)/cd_linux.c
766 $(DO_X11_CC)
767
768$(BUILDDIR)/x11/sys_linux.o :$(MOUNT_DIR)/sys_linux.c
769 $(DO_X11_CC)
770
771$(BUILDDIR)/x11/vid_x.o: $(MOUNT_DIR)/vid_x.c
772 $(DO_O_CC)
773
774$(BUILDDIR)/x11/snd_dma.o : $(MOUNT_DIR)/snd_dma.c
775 $(DO_X11_CC)
776
777$(BUILDDIR)/x11/snd_mem.o : $(MOUNT_DIR)/snd_mem.c
778 $(DO_X11_CC)
779
780$(BUILDDIR)/x11/snd_mix.o : $(MOUNT_DIR)/snd_mix.c
781 $(DO_X11_CC)
782
783$(BUILDDIR)/x11/snd_linux.o :$(MOUNT_DIR)/snd_linux.c
784 $(DO_X11_CC)
785
786#####
787
788$(BUILDDIR)/x11/d_copy.o : $(MOUNT_DIR)/d_copy.S
789 $(DO_AS)
790
791$(BUILDDIR)/x11/d_draw.o : $(MOUNT_DIR)/d_draw.S
792 $(DO_AS)
793
794$(BUILDDIR)/x11/d_draw16.o : $(MOUNT_DIR)/d_draw16.S
795 $(DO_AS)
796
797$(BUILDDIR)/x11/d_parta.o : $(MOUNT_DIR)/d_parta.S
798 $(DO_AS)
799
800$(BUILDDIR)/x11/d_polysa.o : $(MOUNT_DIR)/d_polysa.S
801 $(DO_AS)
802
803$(BUILDDIR)/x11/d_scana.o : $(MOUNT_DIR)/d_scana.S
804 $(DO_AS)
805
806$(BUILDDIR)/x11/d_spr8.o : $(MOUNT_DIR)/d_spr8.S
807 $(DO_AS)
808
809$(BUILDDIR)/x11/d_varsa.o : $(MOUNT_DIR)/d_varsa.S
810 $(DO_AS)
811
812$(BUILDDIR)/x11/math.o : $(MOUNT_DIR)/math.S
813 $(DO_AS)
814
815$(BUILDDIR)/x11/r_aliasa.o : $(MOUNT_DIR)/r_aliasa.S
816 $(DO_AS)
817
818$(BUILDDIR)/x11/r_drawa.o : $(MOUNT_DIR)/r_drawa.S
819 $(DO_AS)
820
821$(BUILDDIR)/x11/r_edgea.o : $(MOUNT_DIR)/r_edgea.S
822 $(DO_AS)
823
824$(BUILDDIR)/x11/r_varsa.o : $(MOUNT_DIR)/r_varsa.S
825 $(DO_AS)
826
827$(BUILDDIR)/x11/surf16.o : $(MOUNT_DIR)/surf16.S
828 $(DO_AS)
829
830$(BUILDDIR)/x11/surf8.o : $(MOUNT_DIR)/surf8.S
831 $(DO_AS)
832
833$(BUILDDIR)/x11/worlda.o : $(MOUNT_DIR)/worlda.S
834 $(DO_AS)
835
836$(BUILDDIR)/x11/r_aclipa.o : $(MOUNT_DIR)/r_aclipa.S
837 $(DO_AS)
838
839$(BUILDDIR)/x11/snd_mixa.o : $(MOUNT_DIR)/snd_mixa.S
840 $(DO_AS)
841
842$(BUILDDIR)/x11/sys_dosa.o : $(MOUNT_DIR)/sys_dosa.S
843 $(DO_AS)
844
845#############################################################################
846# GLQuake
847#############################################################################
848
849GLQUAKE_OBJS= \
850 $(BUILDDIR)/glquake/cl_demo.o \
851 $(BUILDDIR)/glquake/cl_input.o \
852 $(BUILDDIR)/glquake/cl_main.o \
853 $(BUILDDIR)/glquake/cl_parse.o \
854 $(BUILDDIR)/glquake/cl_tent.o \
855 $(BUILDDIR)/glquake/chase.o \
856 $(BUILDDIR)/glquake/cmd.o \
857 $(BUILDDIR)/glquake/common.o \
858 $(BUILDDIR)/glquake/console.o \
859 $(BUILDDIR)/glquake/crc.o \
860 $(BUILDDIR)/glquake/cvar.o \
861 \
862 $(BUILDDIR)/glquake/gl_draw.o \
863 $(BUILDDIR)/glquake/gl_mesh.o \
864 $(BUILDDIR)/glquake/gl_model.o \
865 $(BUILDDIR)/glquake/gl_refrag.o \
866 $(BUILDDIR)/glquake/gl_rlight.o \
867 $(BUILDDIR)/glquake/gl_rmain.o \
868 $(BUILDDIR)/glquake/gl_rmisc.o \
869 $(BUILDDIR)/glquake/gl_rsurf.o \
870 $(BUILDDIR)/glquake/gl_screen.o \
871 $(BUILDDIR)/glquake/gl_test.o \
872 $(BUILDDIR)/glquake/gl_warp.o \
873 \
874 $(BUILDDIR)/glquake/host.o \
875 $(BUILDDIR)/glquake/host_cmd.o \
876 $(BUILDDIR)/glquake/keys.o \
877 $(BUILDDIR)/glquake/menu.o \
878 $(BUILDDIR)/glquake/mathlib.o \
879 $(BUILDDIR)/glquake/net_dgrm.o \
880 $(BUILDDIR)/glquake/net_loop.o \
881 $(BUILDDIR)/glquake/net_main.o \
882 $(BUILDDIR)/glquake/net_vcr.o \
883 $(BUILDDIR)/glquake/net_udp.o \
884 $(BUILDDIR)/glquake/net_bsd.o \
885 $(BUILDDIR)/glquake/pr_cmds.o \
886 $(BUILDDIR)/glquake/pr_edict.o \
887 $(BUILDDIR)/glquake/pr_exec.o \
888 $(BUILDDIR)/glquake/r_part.o \
889 $(BUILDDIR)/glquake/sbar.o \
890 $(BUILDDIR)/glquake/sv_main.o \
891 $(BUILDDIR)/glquake/sv_phys.o \
892 $(BUILDDIR)/glquake/sv_move.o \
893 $(BUILDDIR)/glquake/sv_user.o \
894 $(BUILDDIR)/glquake/zone.o \
895 $(BUILDDIR)/glquake/view.o \
896 $(BUILDDIR)/glquake/wad.o \
897 $(BUILDDIR)/glquake/world.o \
898 $(BUILDDIR)/glquake/cd_linux.o \
899 $(BUILDDIR)/glquake/sys_linux.o \
900 $(BUILDDIR)/glquake/snd_dma.o \
901 $(BUILDDIR)/glquake/snd_mem.o \
902 $(BUILDDIR)/glquake/snd_mix.o \
903 $(BUILDDIR)/glquake/snd_linux.o \
904 \
905 $(BUILDDIR)/glquake/math.o \
906 $(BUILDDIR)/glquake/worlda.o \
907 $(BUILDDIR)/glquake/snd_mixa.o \
908 $(BUILDDIR)/glquake/sys_dosa.o
909
910GLSVGA_OBJS=$(BUILDDIR)/glquake/gl_vidlinux.o
911
912GLX_OBJS=$(BUILDDIR)/glquake/gl_vidlinuxglx.o
913
914$(BUILDDIR)/bin/glquake : $(GLQUAKE_OBJS) $(GLSVGA_OBJS)
915 $(CC) $(CFLAGS) -o $@ $(GLQUAKE_OBJS) $(GLSVGA_OBJS) $(MESAGLLDFLAGS) $(SVGALDFLAGS) $(LDFLAGS)
916
917$(BUILDDIR)/bin/glquake.glx : $(GLQUAKE_OBJS) $(GLX_OBJS)
918 $(CC) $(CFLAGS) -o $@ $(GLQUAKE_OBJS) $(GLX_OBJS) $(GLLDFLAGS) $(LDFLAGS)
919
920$(BUILDDIR)/bin/glquake.3dfxgl : $(GLQUAKE_OBJS) $(GLSVGA_OBJS)
921 $(CC) $(CFLAGS) -o $@ $(GLQUAKE_OBJS) $(GLSVGA_OBJS) $(TDFXGLLDFLAGS) $(SVGALDFLAGS) $(LDFLAGS)
922
923$(BUILDDIR)/glquake/cl_demo.o : $(MOUNT_DIR)/cl_demo.c
924 $(DO_GL_CC)
925
926$(BUILDDIR)/glquake/cl_input.o : $(MOUNT_DIR)/cl_input.c
927 $(DO_GL_CC)
928
929$(BUILDDIR)/glquake/cl_main.o : $(MOUNT_DIR)/cl_main.c
930 $(DO_GL_CC)
931
932$(BUILDDIR)/glquake/cl_parse.o : $(MOUNT_DIR)/cl_parse.c
933 $(DO_GL_CC)
934
935$(BUILDDIR)/glquake/cl_tent.o : $(MOUNT_DIR)/cl_tent.c
936 $(DO_GL_CC)
937
938$(BUILDDIR)/glquake/chase.o : $(MOUNT_DIR)/chase.c
939 $(DO_GL_CC)
940
941$(BUILDDIR)/glquake/cmd.o : $(MOUNT_DIR)/cmd.c
942 $(DO_GL_CC)
943
944$(BUILDDIR)/glquake/common.o : $(MOUNT_DIR)/common.c
945 $(DO_GL_DEBUG_CC)
946
947$(BUILDDIR)/glquake/console.o : $(MOUNT_DIR)/console.c
948 $(DO_GL_CC)
949
950$(BUILDDIR)/glquake/crc.o : $(MOUNT_DIR)/crc.c
951 $(DO_GL_CC)
952
953$(BUILDDIR)/glquake/cvar.o : $(MOUNT_DIR)/cvar.c
954 $(DO_GL_CC)
955
956$(BUILDDIR)/glquake/gl_draw.o : $(MOUNT_DIR)/gl_draw.c
957 $(DO_GL_CC)
958
959$(BUILDDIR)/glquake/gl_mesh.o : $(MOUNT_DIR)/gl_mesh.c
960 $(DO_GL_CC)
961
962$(BUILDDIR)/glquake/gl_model.o : $(MOUNT_DIR)/gl_model.c
963 $(DO_GL_CC)
964
965$(BUILDDIR)/glquake/gl_refrag.o : $(MOUNT_DIR)/gl_refrag.c
966 $(DO_GL_CC)
967
968$(BUILDDIR)/glquake/gl_rlight.o : $(MOUNT_DIR)/gl_rlight.c
969 $(DO_GL_CC)
970
971$(BUILDDIR)/glquake/gl_rmain.o : $(MOUNT_DIR)/gl_rmain.c
972 $(DO_GL_CC)
973
974$(BUILDDIR)/glquake/gl_rmisc.o : $(MOUNT_DIR)/gl_rmisc.c
975 $(DO_GL_CC)
976
977$(BUILDDIR)/glquake/gl_rsurf.o : $(MOUNT_DIR)/gl_rsurf.c
978 $(DO_GL_CC)
979
980$(BUILDDIR)/glquake/gl_screen.o : $(MOUNT_DIR)/gl_screen.c
981 $(DO_GL_CC)
982
983$(BUILDDIR)/glquake/gl_test.o : $(MOUNT_DIR)/gl_test.c
984 $(DO_GL_CC)
985
986$(BUILDDIR)/glquake/gl_vidlinux.o : $(MOUNT_DIR)/gl_vidlinux.c
987 $(DO_GL_CC)
988
989$(BUILDDIR)/glquake/gl_vidlinuxglx.o : $(MOUNT_DIR)/gl_vidlinuxglx.c
990 $(DO_GL_CC)
991
992$(BUILDDIR)/glquake/gl_warp.o : $(MOUNT_DIR)/gl_warp.c
993 $(DO_GL_CC)
994
995$(BUILDDIR)/glquake/host.o : $(MOUNT_DIR)/host.c
996 $(DO_GL_CC)
997
998$(BUILDDIR)/glquake/host_cmd.o : $(MOUNT_DIR)/host_cmd.c
999 $(DO_GL_CC)
1000
1001$(BUILDDIR)/glquake/keys.o : $(MOUNT_DIR)/keys.c
1002 $(DO_GL_CC)
1003
1004$(BUILDDIR)/glquake/menu.o : $(MOUNT_DIR)/menu.c
1005 $(DO_GL_CC)
1006
1007$(BUILDDIR)/glquake/mathlib.o : $(MOUNT_DIR)/mathlib.c
1008 $(DO_GL_CC)
1009
1010$(BUILDDIR)/glquake/net_dgrm.o : $(MOUNT_DIR)/net_dgrm.c
1011 $(DO_GL_CC)
1012
1013$(BUILDDIR)/glquake/net_loop.o : $(MOUNT_DIR)/net_loop.c
1014 $(DO_GL_CC)
1015
1016$(BUILDDIR)/glquake/net_main.o : $(MOUNT_DIR)/net_main.c
1017 $(DO_GL_CC)
1018
1019$(BUILDDIR)/glquake/net_vcr.o : $(MOUNT_DIR)/net_vcr.c
1020 $(DO_GL_CC)
1021
1022$(BUILDDIR)/glquake/net_udp.o : $(MOUNT_DIR)/net_udp.c
1023 $(DO_GL_CC)
1024
1025$(BUILDDIR)/glquake/net_bsd.o : $(MOUNT_DIR)/net_bsd.c
1026 $(DO_GL_CC)
1027
1028$(BUILDDIR)/glquake/pr_cmds.o : $(MOUNT_DIR)/pr_cmds.c
1029 $(DO_GL_CC)
1030
1031$(BUILDDIR)/glquake/pr_edict.o : $(MOUNT_DIR)/pr_edict.c
1032 $(DO_GL_CC)
1033
1034$(BUILDDIR)/glquake/pr_exec.o : $(MOUNT_DIR)/pr_exec.c
1035 $(DO_GL_CC)
1036
1037$(BUILDDIR)/glquake/r_part.o : $(MOUNT_DIR)/r_part.c
1038 $(DO_GL_CC)
1039
1040$(BUILDDIR)/glquake/sbar.o : $(MOUNT_DIR)/sbar.c
1041 $(DO_GL_CC)
1042
1043$(BUILDDIR)/glquake/sv_main.o : $(MOUNT_DIR)/sv_main.c
1044 $(DO_GL_CC)
1045
1046$(BUILDDIR)/glquake/sv_phys.o : $(MOUNT_DIR)/sv_phys.c
1047 $(DO_GL_CC)
1048
1049$(BUILDDIR)/glquake/sv_move.o : $(MOUNT_DIR)/sv_move.c
1050 $(DO_GL_CC)
1051
1052$(BUILDDIR)/glquake/sv_user.o : $(MOUNT_DIR)/sv_user.c
1053 $(DO_GL_CC)
1054
1055$(BUILDDIR)/glquake/zone.o : $(MOUNT_DIR)/zone.c
1056 $(DO_GL_CC)
1057
1058$(BUILDDIR)/glquake/view.o : $(MOUNT_DIR)/view.c
1059 $(DO_GL_CC)
1060
1061$(BUILDDIR)/glquake/wad.o : $(MOUNT_DIR)/wad.c
1062 $(DO_GL_CC)
1063
1064$(BUILDDIR)/glquake/world.o : $(MOUNT_DIR)/world.c
1065 $(DO_GL_CC)
1066
1067$(BUILDDIR)/glquake/cd_linux.o : $(MOUNT_DIR)/cd_linux.c
1068 $(DO_GL_CC)
1069
1070$(BUILDDIR)/glquake/sys_linux.o : $(MOUNT_DIR)/sys_linux.c
1071 $(DO_GL_CC)
1072
1073$(BUILDDIR)/glquake/snd_dma.o : $(MOUNT_DIR)/snd_dma.c
1074 $(DO_GL_CC)
1075
1076$(BUILDDIR)/glquake/snd_mem.o : $(MOUNT_DIR)/snd_mem.c
1077 $(DO_GL_CC)
1078
1079$(BUILDDIR)/glquake/snd_mix.o : $(MOUNT_DIR)/snd_mix.c
1080 $(DO_GL_CC)
1081
1082$(BUILDDIR)/glquake/snd_linux.o : $(MOUNT_DIR)/snd_linux.c
1083 $(DO_GL_CC)
1084
1085$(BUILDDIR)/glquake/math.o : $(MOUNT_DIR)/math.S
1086 $(DO_GL_AS)
1087
1088$(BUILDDIR)/glquake/worlda.o : $(MOUNT_DIR)/worlda.S
1089 $(DO_GL_AS)
1090
1091$(BUILDDIR)/glquake/snd_mixa.o : $(MOUNT_DIR)/snd_mixa.S
1092 $(DO_GL_AS)
1093
1094$(BUILDDIR)/glquake/sys_dosa.o : $(MOUNT_DIR)/sys_dosa.S
1095 $(DO_GL_AS)
1096
1097#############################################################################
1098# RPM
1099#############################################################################
1100
1101# Make RPMs. You need to be root to make this work
1102RPMROOT=/usr/src/redhat
1103RPM = rpm
1104RPMFLAGS = -bb
1105INSTALLDIR = /usr/local/games/quake
1106TMPDIR = /var/tmp
1107RPMDIR = $(TMPDIR)/quake-$(VERSION)
1108BASERPMDIR = $(TMPDIR)/quake-$(BASEVERSION)
1109
1110rpm: rpm-quake rpm-quake-data rpm-hipnotic rpm-rogue
1111
1112rpm-quake: quake.spec \
1113 $(BUILD_RELEASE_DIR)/bin/squake \
1114 $(BUILD_RELEASE_DIR)/bin/quake.x11 \
1115 $(BUILD_RELEASE_DIR)/bin/glquake \
1116 $(BUILD_RELEASE_DIR)/bin/glquake.glx \
1117 $(BUILD_RELEASE_DIR)/bin/glquake.3dfxgl
1118 touch $(RPMROOT)/SOURCES/quake-$(VERSION).tar.gz
1119 if [ ! -d RPMS ];then mkdir RPMS;fi
1120 cp $(MOUNT_DIR)/quake.gif $(RPMROOT)/SOURCES/quake.gif
1121
1122 # basic binaries rpm
1123 -mkdirhier $(RPMDIR)/$(INSTALLDIR)
1124 cp $(MOUNT_DIR)/docs/README $(RPMDIR)/$(INSTALLDIR)/.
1125 cp $(BUILD_RELEASE_DIR)/bin/squake $(RPMDIR)/$(INSTALLDIR)/squake
1126 strip $(RPMDIR)/$(INSTALLDIR)/squake
1127 cp $(BUILD_RELEASE_DIR)/bin/quake.x11 $(RPMDIR)/$(INSTALLDIR)/quake.x11
1128 strip $(RPMDIR)/$(INSTALLDIR)/quake.x11
1129 cp $(BUILD_RELEASE_DIR)/bin/glquake $(RPMDIR)/$(INSTALLDIR)/glquake
1130 strip $(RPMDIR)/$(INSTALLDIR)/glquake
1131 cp $(BUILD_RELEASE_DIR)/bin/glquake.glx $(RPMDIR)/$(INSTALLDIR)/glquake.glx
1132 strip $(RPMDIR)/$(INSTALLDIR)/glquake.glx
1133 cp $(BUILD_RELEASE_DIR)/bin/glquake.3dfxgl $(RPMDIR)/$(INSTALLDIR)/glquake.3dfxgl
1134 strip $(RPMDIR)/$(INSTALLDIR)/glquake.3dfxgl
1135 -mkdirhier $(RPMDIR)/usr/lib
1136 cp $(TDFXGL_DIR)/release$(ARCH)$(GLIBC)/lib3dfxgl.so $(RPMDIR)/usr/lib/lib3dfxgl.so
1137 cp $(MESA_DIR)/lib/libMesaGL.so.2.6 $(RPMDIR)/usr/lib/libMesaGL.so.2.6
1138
1139 cp quake.spec $(RPMROOT)/SPECS/.
1140 cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) quake.spec
1141 rm -rf $(RPMDIR)
1142 rm -f $(RPMROOT)/SOURCES/quake-$(VERSION).tar.gz
1143
1144 mv $(RPMROOT)/RPMS/$(ARCH)/quake-$(VERSION)-$(RPM_RELEASE).$(ARCH).rpm RPMS/.
1145
1146QUAKEDATADIR=$(TMPDIR)/quake-data-$(BASEVERSION)
1147rpm-quake-data: quake-data.spec
1148 # data rpm
1149 touch $(RPMROOT)/SOURCES/quake-$(BASEVERSION)-data.tar.gz
1150
1151 -mkdirhier $(QUAKEDATADIR)/$(INSTALLDIR)/id1
1152 cp $(MASTER_DIR)/id1/pak0.pak $(QUAKEDATADIR)/$(INSTALLDIR)/id1/.
1153 cp $(MASTER_DIR)/id1/pak1.pak $(QUAKEDATADIR)/$(INSTALLDIR)/id1/.
1154 cp $(MOUNT_DIR)/docs/README $(QUAKEDATADIR)/$(INSTALLDIR)/.
1155 cp $(MOUNT_DIR)/data/comexp.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1156 cp $(MOUNT_DIR)/data/help.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1157 cp $(MOUNT_DIR)/data/licinfo.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1158 cp $(MOUNT_DIR)/data/manual.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1159 cp $(MOUNT_DIR)/data/readme.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1160 cp $(MOUNT_DIR)/data/rlicnse.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1161 cp $(MOUNT_DIR)/data/slicnse.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1162 cp $(MOUNT_DIR)/data/techinfo.txt $(QUAKEDATADIR)/$(INSTALLDIR)/.
1163 cp quake-data.spec $(RPMROOT)/SPECS/.
1164 cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) quake-data.spec
1165 rm -rf $(QUAKEDATADIR)
1166 rm -f $(RPMROOT)/SOURCES/quake-$(BASEVERSION)-data.tar.gz
1167
1168 mv $(RPMROOT)/RPMS/$(NOARCH)/quake-data-$(BASEVERSION)-$(RPM_RELEASE).$(NOARCH).rpm RPMS/.
1169
1170RPMHIPNOTICDIR=$(TMPDIR)/quake-hipnotic-$(BASEVERSION)
1171rpm-hipnotic: quake-hipnotic.spec
1172 touch $(RPMROOT)/SOURCES/quake-hipnotic-$(BASEVERSION).tar.gz
1173 if [ ! -d RPMS ];then mkdir RPMS;fi
1174 cp $(MOUNT_DIR)/quake.gif $(RPMROOT)/SOURCES/quake.gif
1175 -mkdirhier $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs
1176 cp $(MASTER_DIR)/hipnotic/pak0.pak $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/.
1177 cp $(MASTER_DIR)/hipnotic/config.cfg $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/.
1178 cp $(MASTER_DIR)/hipnotic/docs/manual.doc $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1179 cp $(MASTER_DIR)/hipnotic/docs/manual.htm $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1180 cp $(MASTER_DIR)/hipnotic/docs/manual.txt $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1181 cp $(MASTER_DIR)/hipnotic/docs/readme.doc $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1182 cp $(MASTER_DIR)/hipnotic/docs/readme.htm $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1183 cp $(MASTER_DIR)/hipnotic/docs/readme.txt $(RPMHIPNOTICDIR)/$(INSTALLDIR)/hipnotic/docs/.
1184 cp quake-hipnotic.spec $(RPMROOT)/SPECS/.
1185 cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) quake-hipnotic.spec
1186 rm -rf $(RPMHIPNOTICDIR)
1187 rm -f $(RPMROOT)/SOURCES/quake-hipnotic-$(BASEVERSION).tar.gz
1188
1189 mv $(RPMROOT)/RPMS/$(NOARCH)/quake-hipnotic-$(BASEVERSION)-$(RPM_RELEASE).$(NOARCH).rpm RPMS/.
1190
1191RPMROGUEDIR=$(TMPDIR)/quake-rogue-$(BASEVERSION)
1192rpm-rogue: quake-rogue.spec
1193 touch $(RPMROOT)/SOURCES/quake-rogue-$(BASEVERSION).tar.gz
1194 if [ ! -d RPMS ];then mkdir RPMS;fi
1195 cp $(MOUNT_DIR)/quake.gif $(RPMROOT)/SOURCES/quake.gif
1196 -mkdirhier $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs
1197 cp $(MASTER_DIR)/rogue/pak0.pak $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/.
1198 cp $(MASTER_DIR)/rogue/docs/manual.doc $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1199 cp $(MASTER_DIR)/rogue/docs/manual.htm $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1200 cp $(MASTER_DIR)/rogue/docs/manual.txt $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1201 cp $(MASTER_DIR)/rogue/docs/readme.doc $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1202 cp $(MASTER_DIR)/rogue/docs/readme.htm $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1203 cp $(MASTER_DIR)/rogue/docs/readme.txt $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1204 cp $(MASTER_DIR)/rogue/docs/ctf.doc $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1205 cp $(MASTER_DIR)/rogue/docs/ctf.htm $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1206 cp $(MASTER_DIR)/rogue/docs/ctf.txt $(RPMROGUEDIR)/$(INSTALLDIR)/rogue/docs/.
1207 cp quake-rogue.spec $(RPMROOT)/SPECS/.
1208 cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) quake-rogue.spec
1209 rm -rf $(RPMROGUEDIR)
1210 rm -f $(RPMROOT)/SOURCES/quake-rogue-$(BASEVERSION).tar.gz
1211
1212 mv $(RPMROOT)/RPMS/$(NOARCH)/quake-rogue-$(BASEVERSION)-$(RPM_RELEASE).$(NOARCH).rpm RPMS/.
1213
1214quake.spec : $(MOUNT_DIR)/quake.spec.sh
1215 sh $< $(VERSION) $(RPM_RELEASE) $(INSTALLDIR) > $@
1216
1217quake-data.spec : $(MOUNT_DIR)/quake-data.spec.sh
1218 sh $< $(BASEVERSION) $(RPM_RELEASE) $(INSTALLDIR) > $@
1219
1220quake-hipnotic.spec : $(MOUNT_DIR)/quake-hipnotic.spec.sh
1221 sh $< $(BASEVERSION) $(RPM_RELEASE) $(INSTALLDIR) > $@
1222
1223quake-rogue.spec : $(MOUNT_DIR)/quake-rogue.spec.sh
1224 sh $< $(BASEVERSION) $(RPM_RELEASE) $(INSTALLDIR) > $@
1225
1226#############################################################################
1227# MISC
1228#############################################################################
1229
1230clean: clean-debug clean-release
1231 rm -f squake.spec glquake.spec quake.x11.spec
1232
1233clean-debug:
1234 $(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
1235
1236clean-release:
1237 $(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
1238
1239clean2:
1240 -rm -f $(SQUAKE_OBJS) $(X11_OBJS) $(GLQUAKE_OBJS) $(GLSVGA_OBJS) \
1241 $(GLX_OBJS)
1242
diff --git a/apps/plugins/sdl/progs/quake/adivtab.h b/apps/plugins/sdl/progs/quake/adivtab.h
new file mode 100644
index 0000000000..238df5c052
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/adivtab.h
@@ -0,0 +1,1077 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// table of quotients and remainders for [-15...16] / [-15...16]
21
22// numerator = -15
23{1, 0},
24{1, -1},
25{1, -2},
26{1, -3},
27{1, -4},
28{1, -5},
29{1, -6},
30{1, -7},
31{2, -1},
32{2, -3},
33{3, 0},
34{3, -3},
35{5, 0},
36{7, -1},
37{15, 0},
38{0, 0},
39{-15, 0},
40{-8, 1},
41{-5, 0},
42{-4, 1},
43{-3, 0},
44{-3, 3},
45{-3, 6},
46{-2, 1},
47{-2, 3},
48{-2, 5},
49{-2, 7},
50{-2, 9},
51{-2, 11},
52{-2, 13},
53{-1, 0},
54{-1, 1},
55// numerator = -14
56{0, -14},
57{1, 0},
58{1, -1},
59{1, -2},
60{1, -3},
61{1, -4},
62{1, -5},
63{1, -6},
64{2, 0},
65{2, -2},
66{2, -4},
67{3, -2},
68{4, -2},
69{7, 0},
70{14, 0},
71{0, 0},
72{-14, 0},
73{-7, 0},
74{-5, 1},
75{-4, 2},
76{-3, 1},
77{-3, 4},
78{-2, 0},
79{-2, 2},
80{-2, 4},
81{-2, 6},
82{-2, 8},
83{-2, 10},
84{-2, 12},
85{-1, 0},
86{-1, 1},
87{-1, 2},
88// numerator = -13
89{0, -13},
90{0, -13},
91{1, 0},
92{1, -1},
93{1, -2},
94{1, -3},
95{1, -4},
96{1, -5},
97{1, -6},
98{2, -1},
99{2, -3},
100{3, -1},
101{4, -1},
102{6, -1},
103{13, 0},
104{0, 0},
105{-13, 0},
106{-7, 1},
107{-5, 2},
108{-4, 3},
109{-3, 2},
110{-3, 5},
111{-2, 1},
112{-2, 3},
113{-2, 5},
114{-2, 7},
115{-2, 9},
116{-2, 11},
117{-1, 0},
118{-1, 1},
119{-1, 2},
120{-1, 3},
121// numerator = -12
122{0, -12},
123{0, -12},
124{0, -12},
125{1, 0},
126{1, -1},
127{1, -2},
128{1, -3},
129{1, -4},
130{1, -5},
131{2, 0},
132{2, -2},
133{3, 0},
134{4, 0},
135{6, 0},
136{12, 0},
137{0, 0},
138{-12, 0},
139{-6, 0},
140{-4, 0},
141{-3, 0},
142{-3, 3},
143{-2, 0},
144{-2, 2},
145{-2, 4},
146{-2, 6},
147{-2, 8},
148{-2, 10},
149{-1, 0},
150{-1, 1},
151{-1, 2},
152{-1, 3},
153{-1, 4},
154// numerator = -11
155{0, -11},
156{0, -11},
157{0, -11},
158{0, -11},
159{1, 0},
160{1, -1},
161{1, -2},
162{1, -3},
163{1, -4},
164{1, -5},
165{2, -1},
166{2, -3},
167{3, -2},
168{5, -1},
169{11, 0},
170{0, 0},
171{-11, 0},
172{-6, 1},
173{-4, 1},
174{-3, 1},
175{-3, 4},
176{-2, 1},
177{-2, 3},
178{-2, 5},
179{-2, 7},
180{-2, 9},
181{-1, 0},
182{-1, 1},
183{-1, 2},
184{-1, 3},
185{-1, 4},
186{-1, 5},
187// numerator = -10
188{0, -10},
189{0, -10},
190{0, -10},
191{0, -10},
192{0, -10},
193{1, 0},
194{1, -1},
195{1, -2},
196{1, -3},
197{1, -4},
198{2, 0},
199{2, -2},
200{3, -1},
201{5, 0},
202{10, 0},
203{0, 0},
204{-10, 0},
205{-5, 0},
206{-4, 2},
207{-3, 2},
208{-2, 0},
209{-2, 2},
210{-2, 4},
211{-2, 6},
212{-2, 8},
213{-1, 0},
214{-1, 1},
215{-1, 2},
216{-1, 3},
217{-1, 4},
218{-1, 5},
219{-1, 6},
220// numerator = -9
221{0, -9},
222{0, -9},
223{0, -9},
224{0, -9},
225{0, -9},
226{0, -9},
227{1, 0},
228{1, -1},
229{1, -2},
230{1, -3},
231{1, -4},
232{2, -1},
233{3, 0},
234{4, -1},
235{9, 0},
236{0, 0},
237{-9, 0},
238{-5, 1},
239{-3, 0},
240{-3, 3},
241{-2, 1},
242{-2, 3},
243{-2, 5},
244{-2, 7},
245{-1, 0},
246{-1, 1},
247{-1, 2},
248{-1, 3},
249{-1, 4},
250{-1, 5},
251{-1, 6},
252{-1, 7},
253// numerator = -8
254{0, -8},
255{0, -8},
256{0, -8},
257{0, -8},
258{0, -8},
259{0, -8},
260{0, -8},
261{1, 0},
262{1, -1},
263{1, -2},
264{1, -3},
265{2, 0},
266{2, -2},
267{4, 0},
268{8, 0},
269{0, 0},
270{-8, 0},
271{-4, 0},
272{-3, 1},
273{-2, 0},
274{-2, 2},
275{-2, 4},
276{-2, 6},
277{-1, 0},
278{-1, 1},
279{-1, 2},
280{-1, 3},
281{-1, 4},
282{-1, 5},
283{-1, 6},
284{-1, 7},
285{-1, 8},
286// numerator = -7
287{0, -7},
288{0, -7},
289{0, -7},
290{0, -7},
291{0, -7},
292{0, -7},
293{0, -7},
294{0, -7},
295{1, 0},
296{1, -1},
297{1, -2},
298{1, -3},
299{2, -1},
300{3, -1},
301{7, 0},
302{0, 0},
303{-7, 0},
304{-4, 1},
305{-3, 2},
306{-2, 1},
307{-2, 3},
308{-2, 5},
309{-1, 0},
310{-1, 1},
311{-1, 2},
312{-1, 3},
313{-1, 4},
314{-1, 5},
315{-1, 6},
316{-1, 7},
317{-1, 8},
318{-1, 9},
319// numerator = -6
320{0, -6},
321{0, -6},
322{0, -6},
323{0, -6},
324{0, -6},
325{0, -6},
326{0, -6},
327{0, -6},
328{0, -6},
329{1, 0},
330{1, -1},
331{1, -2},
332{2, 0},
333{3, 0},
334{6, 0},
335{0, 0},
336{-6, 0},
337{-3, 0},
338{-2, 0},
339{-2, 2},
340{-2, 4},
341{-1, 0},
342{-1, 1},
343{-1, 2},
344{-1, 3},
345{-1, 4},
346{-1, 5},
347{-1, 6},
348{-1, 7},
349{-1, 8},
350{-1, 9},
351{-1, 10},
352// numerator = -5
353{0, -5},
354{0, -5},
355{0, -5},
356{0, -5},
357{0, -5},
358{0, -5},
359{0, -5},
360{0, -5},
361{0, -5},
362{0, -5},
363{1, 0},
364{1, -1},
365{1, -2},
366{2, -1},
367{5, 0},
368{0, 0},
369{-5, 0},
370{-3, 1},
371{-2, 1},
372{-2, 3},
373{-1, 0},
374{-1, 1},
375{-1, 2},
376{-1, 3},
377{-1, 4},
378{-1, 5},
379{-1, 6},
380{-1, 7},
381{-1, 8},
382{-1, 9},
383{-1, 10},
384{-1, 11},
385// numerator = -4
386{0, -4},
387{0, -4},
388{0, -4},
389{0, -4},
390{0, -4},
391{0, -4},
392{0, -4},
393{0, -4},
394{0, -4},
395{0, -4},
396{0, -4},
397{1, 0},
398{1, -1},
399{2, 0},
400{4, 0},
401{0, 0},
402{-4, 0},
403{-2, 0},
404{-2, 2},
405{-1, 0},
406{-1, 1},
407{-1, 2},
408{-1, 3},
409{-1, 4},
410{-1, 5},
411{-1, 6},
412{-1, 7},
413{-1, 8},
414{-1, 9},
415{-1, 10},
416{-1, 11},
417{-1, 12},
418// numerator = -3
419{0, -3},
420{0, -3},
421{0, -3},
422{0, -3},
423{0, -3},
424{0, -3},
425{0, -3},
426{0, -3},
427{0, -3},
428{0, -3},
429{0, -3},
430{0, -3},
431{1, 0},
432{1, -1},
433{3, 0},
434{0, 0},
435{-3, 0},
436{-2, 1},
437{-1, 0},
438{-1, 1},
439{-1, 2},
440{-1, 3},
441{-1, 4},
442{-1, 5},
443{-1, 6},
444{-1, 7},
445{-1, 8},
446{-1, 9},
447{-1, 10},
448{-1, 11},
449{-1, 12},
450{-1, 13},
451// numerator = -2
452{0, -2},
453{0, -2},
454{0, -2},
455{0, -2},
456{0, -2},
457{0, -2},
458{0, -2},
459{0, -2},
460{0, -2},
461{0, -2},
462{0, -2},
463{0, -2},
464{0, -2},
465{1, 0},
466{2, 0},
467{0, 0},
468{-2, 0},
469{-1, 0},
470{-1, 1},
471{-1, 2},
472{-1, 3},
473{-1, 4},
474{-1, 5},
475{-1, 6},
476{-1, 7},
477{-1, 8},
478{-1, 9},
479{-1, 10},
480{-1, 11},
481{-1, 12},
482{-1, 13},
483{-1, 14},
484// numerator = -1
485{0, -1},
486{0, -1},
487{0, -1},
488{0, -1},
489{0, -1},
490{0, -1},
491{0, -1},
492{0, -1},
493{0, -1},
494{0, -1},
495{0, -1},
496{0, -1},
497{0, -1},
498{0, -1},
499{1, 0},
500{0, 0},
501{-1, 0},
502{-1, 1},
503{-1, 2},
504{-1, 3},
505{-1, 4},
506{-1, 5},
507{-1, 6},
508{-1, 7},
509{-1, 8},
510{-1, 9},
511{-1, 10},
512{-1, 11},
513{-1, 12},
514{-1, 13},
515{-1, 14},
516{-1, 15},
517// numerator = 0
518{0, 0},
519{0, 0},
520{0, 0},
521{0, 0},
522{0, 0},
523{0, 0},
524{0, 0},
525{0, 0},
526{0, 0},
527{0, 0},
528{0, 0},
529{0, 0},
530{0, 0},
531{0, 0},
532{0, 0},
533{0, 0},
534{0, 0},
535{0, 0},
536{0, 0},
537{0, 0},
538{0, 0},
539{0, 0},
540{0, 0},
541{0, 0},
542{0, 0},
543{0, 0},
544{0, 0},
545{0, 0},
546{0, 0},
547{0, 0},
548{0, 0},
549{0, 0},
550// numerator = 1
551{-1, -14},
552{-1, -13},
553{-1, -12},
554{-1, -11},
555{-1, -10},
556{-1, -9},
557{-1, -8},
558{-1, -7},
559{-1, -6},
560{-1, -5},
561{-1, -4},
562{-1, -3},
563{-1, -2},
564{-1, -1},
565{-1, 0},
566{0, 0},
567{1, 0},
568{0, 1},
569{0, 1},
570{0, 1},
571{0, 1},
572{0, 1},
573{0, 1},
574{0, 1},
575{0, 1},
576{0, 1},
577{0, 1},
578{0, 1},
579{0, 1},
580{0, 1},
581{0, 1},
582{0, 1},
583// numerator = 2
584{-1, -13},
585{-1, -12},
586{-1, -11},
587{-1, -10},
588{-1, -9},
589{-1, -8},
590{-1, -7},
591{-1, -6},
592{-1, -5},
593{-1, -4},
594{-1, -3},
595{-1, -2},
596{-1, -1},
597{-1, 0},
598{-2, 0},
599{0, 0},
600{2, 0},
601{1, 0},
602{0, 2},
603{0, 2},
604{0, 2},
605{0, 2},
606{0, 2},
607{0, 2},
608{0, 2},
609{0, 2},
610{0, 2},
611{0, 2},
612{0, 2},
613{0, 2},
614{0, 2},
615{0, 2},
616// numerator = 3
617{-1, -12},
618{-1, -11},
619{-1, -10},
620{-1, -9},
621{-1, -8},
622{-1, -7},
623{-1, -6},
624{-1, -5},
625{-1, -4},
626{-1, -3},
627{-1, -2},
628{-1, -1},
629{-1, 0},
630{-2, -1},
631{-3, 0},
632{0, 0},
633{3, 0},
634{1, 1},
635{1, 0},
636{0, 3},
637{0, 3},
638{0, 3},
639{0, 3},
640{0, 3},
641{0, 3},
642{0, 3},
643{0, 3},
644{0, 3},
645{0, 3},
646{0, 3},
647{0, 3},
648{0, 3},
649// numerator = 4
650{-1, -11},
651{-1, -10},
652{-1, -9},
653{-1, -8},
654{-1, -7},
655{-1, -6},
656{-1, -5},
657{-1, -4},
658{-1, -3},
659{-1, -2},
660{-1, -1},
661{-1, 0},
662{-2, -2},
663{-2, 0},
664{-4, 0},
665{0, 0},
666{4, 0},
667{2, 0},
668{1, 1},
669{1, 0},
670{0, 4},
671{0, 4},
672{0, 4},
673{0, 4},
674{0, 4},
675{0, 4},
676{0, 4},
677{0, 4},
678{0, 4},
679{0, 4},
680{0, 4},
681{0, 4},
682// numerator = 5
683{-1, -10},
684{-1, -9},
685{-1, -8},
686{-1, -7},
687{-1, -6},
688{-1, -5},
689{-1, -4},
690{-1, -3},
691{-1, -2},
692{-1, -1},
693{-1, 0},
694{-2, -3},
695{-2, -1},
696{-3, -1},
697{-5, 0},
698{0, 0},
699{5, 0},
700{2, 1},
701{1, 2},
702{1, 1},
703{1, 0},
704{0, 5},
705{0, 5},
706{0, 5},
707{0, 5},
708{0, 5},
709{0, 5},
710{0, 5},
711{0, 5},
712{0, 5},
713{0, 5},
714{0, 5},
715// numerator = 6
716{-1, -9},
717{-1, -8},
718{-1, -7},
719{-1, -6},
720{-1, -5},
721{-1, -4},
722{-1, -3},
723{-1, -2},
724{-1, -1},
725{-1, 0},
726{-2, -4},
727{-2, -2},
728{-2, 0},
729{-3, 0},
730{-6, 0},
731{0, 0},
732{6, 0},
733{3, 0},
734{2, 0},
735{1, 2},
736{1, 1},
737{1, 0},
738{0, 6},
739{0, 6},
740{0, 6},
741{0, 6},
742{0, 6},
743{0, 6},
744{0, 6},
745{0, 6},
746{0, 6},
747{0, 6},
748// numerator = 7
749{-1, -8},
750{-1, -7},
751{-1, -6},
752{-1, -5},
753{-1, -4},
754{-1, -3},
755{-1, -2},
756{-1, -1},
757{-1, 0},
758{-2, -5},
759{-2, -3},
760{-2, -1},
761{-3, -2},
762{-4, -1},
763{-7, 0},
764{0, 0},
765{7, 0},
766{3, 1},
767{2, 1},
768{1, 3},
769{1, 2},
770{1, 1},
771{1, 0},
772{0, 7},
773{0, 7},
774{0, 7},
775{0, 7},
776{0, 7},
777{0, 7},
778{0, 7},
779{0, 7},
780{0, 7},
781// numerator = 8
782{-1, -7},
783{-1, -6},
784{-1, -5},
785{-1, -4},
786{-1, -3},
787{-1, -2},
788{-1, -1},
789{-1, 0},
790{-2, -6},
791{-2, -4},
792{-2, -2},
793{-2, 0},
794{-3, -1},
795{-4, 0},
796{-8, 0},
797{0, 0},
798{8, 0},
799{4, 0},
800{2, 2},
801{2, 0},
802{1, 3},
803{1, 2},
804{1, 1},
805{1, 0},
806{0, 8},
807{0, 8},
808{0, 8},
809{0, 8},
810{0, 8},
811{0, 8},
812{0, 8},
813{0, 8},
814// numerator = 9
815{-1, -6},
816{-1, -5},
817{-1, -4},
818{-1, -3},
819{-1, -2},
820{-1, -1},
821{-1, 0},
822{-2, -7},
823{-2, -5},
824{-2, -3},
825{-2, -1},
826{-3, -3},
827{-3, 0},
828{-5, -1},
829{-9, 0},
830{0, 0},
831{9, 0},
832{4, 1},
833{3, 0},
834{2, 1},
835{1, 4},
836{1, 3},
837{1, 2},
838{1, 1},
839{1, 0},
840{0, 9},
841{0, 9},
842{0, 9},
843{0, 9},
844{0, 9},
845{0, 9},
846{0, 9},
847// numerator = 10
848{-1, -5},
849{-1, -4},
850{-1, -3},
851{-1, -2},
852{-1, -1},
853{-1, 0},
854{-2, -8},
855{-2, -6},
856{-2, -4},
857{-2, -2},
858{-2, 0},
859{-3, -2},
860{-4, -2},
861{-5, 0},
862{-10, 0},
863{0, 0},
864{10, 0},
865{5, 0},
866{3, 1},
867{2, 2},
868{2, 0},
869{1, 4},
870{1, 3},
871{1, 2},
872{1, 1},
873{1, 0},
874{0, 10},
875{0, 10},
876{0, 10},
877{0, 10},
878{0, 10},
879{0, 10},
880// numerator = 11
881{-1, -4},
882{-1, -3},
883{-1, -2},
884{-1, -1},
885{-1, 0},
886{-2, -9},
887{-2, -7},
888{-2, -5},
889{-2, -3},
890{-2, -1},
891{-3, -4},
892{-3, -1},
893{-4, -1},
894{-6, -1},
895{-11, 0},
896{0, 0},
897{11, 0},
898{5, 1},
899{3, 2},
900{2, 3},
901{2, 1},
902{1, 5},
903{1, 4},
904{1, 3},
905{1, 2},
906{1, 1},
907{1, 0},
908{0, 11},
909{0, 11},
910{0, 11},
911{0, 11},
912{0, 11},
913// numerator = 12
914{-1, -3},
915{-1, -2},
916{-1, -1},
917{-1, 0},
918{-2, -10},
919{-2, -8},
920{-2, -6},
921{-2, -4},
922{-2, -2},
923{-2, 0},
924{-3, -3},
925{-3, 0},
926{-4, 0},
927{-6, 0},
928{-12, 0},
929{0, 0},
930{12, 0},
931{6, 0},
932{4, 0},
933{3, 0},
934{2, 2},
935{2, 0},
936{1, 5},
937{1, 4},
938{1, 3},
939{1, 2},
940{1, 1},
941{1, 0},
942{0, 12},
943{0, 12},
944{0, 12},
945{0, 12},
946// numerator = 13
947{-1, -2},
948{-1, -1},
949{-1, 0},
950{-2, -11},
951{-2, -9},
952{-2, -7},
953{-2, -5},
954{-2, -3},
955{-2, -1},
956{-3, -5},
957{-3, -2},
958{-4, -3},
959{-5, -2},
960{-7, -1},
961{-13, 0},
962{0, 0},
963{13, 0},
964{6, 1},
965{4, 1},
966{3, 1},
967{2, 3},
968{2, 1},
969{1, 6},
970{1, 5},
971{1, 4},
972{1, 3},
973{1, 2},
974{1, 1},
975{1, 0},
976{0, 13},
977{0, 13},
978{0, 13},
979// numerator = 14
980{-1, -1},
981{-1, 0},
982{-2, -12},
983{-2, -10},
984{-2, -8},
985{-2, -6},
986{-2, -4},
987{-2, -2},
988{-2, 0},
989{-3, -4},
990{-3, -1},
991{-4, -2},
992{-5, -1},
993{-7, 0},
994{-14, 0},
995{0, 0},
996{14, 0},
997{7, 0},
998{4, 2},
999{3, 2},
1000{2, 4},
1001{2, 2},
1002{2, 0},
1003{1, 6},
1004{1, 5},
1005{1, 4},
1006{1, 3},
1007{1, 2},
1008{1, 1},
1009{1, 0},
1010{0, 14},
1011{0, 14},
1012// numerator = 15
1013{-1, 0},
1014{-2, -13},
1015{-2, -11},
1016{-2, -9},
1017{-2, -7},
1018{-2, -5},
1019{-2, -3},
1020{-2, -1},
1021{-3, -6},
1022{-3, -3},
1023{-3, 0},
1024{-4, -1},
1025{-5, 0},
1026{-8, -1},
1027{-15, 0},
1028{0, 0},
1029{15, 0},
1030{7, 1},
1031{5, 0},
1032{3, 3},
1033{3, 0},
1034{2, 3},
1035{2, 1},
1036{1, 7},
1037{1, 6},
1038{1, 5},
1039{1, 4},
1040{1, 3},
1041{1, 2},
1042{1, 1},
1043{1, 0},
1044{0, 15},
1045// numerator = 16
1046{-2, -14},
1047{-2, -12},
1048{-2, -10},
1049{-2, -8},
1050{-2, -6},
1051{-2, -4},
1052{-2, -2},
1053{-2, 0},
1054{-3, -5},
1055{-3, -2},
1056{-4, -4},
1057{-4, 0},
1058{-6, -2},
1059{-8, 0},
1060{-16, 0},
1061{0, 0},
1062{16, 0},
1063{8, 0},
1064{5, 1},
1065{4, 0},
1066{3, 1},
1067{2, 4},
1068{2, 2},
1069{2, 0},
1070{1, 7},
1071{1, 6},
1072{1, 5},
1073{1, 4},
1074{1, 3},
1075{1, 2},
1076{1, 1},
1077{1, 0},
diff --git a/apps/plugins/sdl/progs/quake/anorm_dots.h b/apps/plugins/sdl/progs/quake/anorm_dots.h
new file mode 100644
index 0000000000..2845fa20ee
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/anorm_dots.h
@@ -0,0 +1,37 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20{
21{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
22{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
23{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
24{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
25{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
26{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
27{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
28{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
29{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
30{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
31{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
32{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
33{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
34{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
35{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},
36{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}
37}
diff --git a/apps/plugins/sdl/progs/quake/anorms.h b/apps/plugins/sdl/progs/quake/anorms.h
new file mode 100644
index 0000000000..11a9007e88
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/anorms.h
@@ -0,0 +1,181 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20{-0.525731, 0.000000, 0.850651},
21{-0.442863, 0.238856, 0.864188},
22{-0.295242, 0.000000, 0.955423},
23{-0.309017, 0.500000, 0.809017},
24{-0.162460, 0.262866, 0.951056},
25{0.000000, 0.000000, 1.000000},
26{0.000000, 0.850651, 0.525731},
27{-0.147621, 0.716567, 0.681718},
28{0.147621, 0.716567, 0.681718},
29{0.000000, 0.525731, 0.850651},
30{0.309017, 0.500000, 0.809017},
31{0.525731, 0.000000, 0.850651},
32{0.295242, 0.000000, 0.955423},
33{0.442863, 0.238856, 0.864188},
34{0.162460, 0.262866, 0.951056},
35{-0.681718, 0.147621, 0.716567},
36{-0.809017, 0.309017, 0.500000},
37{-0.587785, 0.425325, 0.688191},
38{-0.850651, 0.525731, 0.000000},
39{-0.864188, 0.442863, 0.238856},
40{-0.716567, 0.681718, 0.147621},
41{-0.688191, 0.587785, 0.425325},
42{-0.500000, 0.809017, 0.309017},
43{-0.238856, 0.864188, 0.442863},
44{-0.425325, 0.688191, 0.587785},
45{-0.716567, 0.681718, -0.147621},
46{-0.500000, 0.809017, -0.309017},
47{-0.525731, 0.850651, 0.000000},
48{0.000000, 0.850651, -0.525731},
49{-0.238856, 0.864188, -0.442863},
50{0.000000, 0.955423, -0.295242},
51{-0.262866, 0.951056, -0.162460},
52{0.000000, 1.000000, 0.000000},
53{0.000000, 0.955423, 0.295242},
54{-0.262866, 0.951056, 0.162460},
55{0.238856, 0.864188, 0.442863},
56{0.262866, 0.951056, 0.162460},
57{0.500000, 0.809017, 0.309017},
58{0.238856, 0.864188, -0.442863},
59{0.262866, 0.951056, -0.162460},
60{0.500000, 0.809017, -0.309017},
61{0.850651, 0.525731, 0.000000},
62{0.716567, 0.681718, 0.147621},
63{0.716567, 0.681718, -0.147621},
64{0.525731, 0.850651, 0.000000},
65{0.425325, 0.688191, 0.587785},
66{0.864188, 0.442863, 0.238856},
67{0.688191, 0.587785, 0.425325},
68{0.809017, 0.309017, 0.500000},
69{0.681718, 0.147621, 0.716567},
70{0.587785, 0.425325, 0.688191},
71{0.955423, 0.295242, 0.000000},
72{1.000000, 0.000000, 0.000000},
73{0.951056, 0.162460, 0.262866},
74{0.850651, -0.525731, 0.000000},
75{0.955423, -0.295242, 0.000000},
76{0.864188, -0.442863, 0.238856},
77{0.951056, -0.162460, 0.262866},
78{0.809017, -0.309017, 0.500000},
79{0.681718, -0.147621, 0.716567},
80{0.850651, 0.000000, 0.525731},
81{0.864188, 0.442863, -0.238856},
82{0.809017, 0.309017, -0.500000},
83{0.951056, 0.162460, -0.262866},
84{0.525731, 0.000000, -0.850651},
85{0.681718, 0.147621, -0.716567},
86{0.681718, -0.147621, -0.716567},
87{0.850651, 0.000000, -0.525731},
88{0.809017, -0.309017, -0.500000},
89{0.864188, -0.442863, -0.238856},
90{0.951056, -0.162460, -0.262866},
91{0.147621, 0.716567, -0.681718},
92{0.309017, 0.500000, -0.809017},
93{0.425325, 0.688191, -0.587785},
94{0.442863, 0.238856, -0.864188},
95{0.587785, 0.425325, -0.688191},
96{0.688191, 0.587785, -0.425325},
97{-0.147621, 0.716567, -0.681718},
98{-0.309017, 0.500000, -0.809017},
99{0.000000, 0.525731, -0.850651},
100{-0.525731, 0.000000, -0.850651},
101{-0.442863, 0.238856, -0.864188},
102{-0.295242, 0.000000, -0.955423},
103{-0.162460, 0.262866, -0.951056},
104{0.000000, 0.000000, -1.000000},
105{0.295242, 0.000000, -0.955423},
106{0.162460, 0.262866, -0.951056},
107{-0.442863, -0.238856, -0.864188},
108{-0.309017, -0.500000, -0.809017},
109{-0.162460, -0.262866, -0.951056},
110{0.000000, -0.850651, -0.525731},
111{-0.147621, -0.716567, -0.681718},
112{0.147621, -0.716567, -0.681718},
113{0.000000, -0.525731, -0.850651},
114{0.309017, -0.500000, -0.809017},
115{0.442863, -0.238856, -0.864188},
116{0.162460, -0.262866, -0.951056},
117{0.238856, -0.864188, -0.442863},
118{0.500000, -0.809017, -0.309017},
119{0.425325, -0.688191, -0.587785},
120{0.716567, -0.681718, -0.147621},
121{0.688191, -0.587785, -0.425325},
122{0.587785, -0.425325, -0.688191},
123{0.000000, -0.955423, -0.295242},
124{0.000000, -1.000000, 0.000000},
125{0.262866, -0.951056, -0.162460},
126{0.000000, -0.850651, 0.525731},
127{0.000000, -0.955423, 0.295242},
128{0.238856, -0.864188, 0.442863},
129{0.262866, -0.951056, 0.162460},
130{0.500000, -0.809017, 0.309017},
131{0.716567, -0.681718, 0.147621},
132{0.525731, -0.850651, 0.000000},
133{-0.238856, -0.864188, -0.442863},
134{-0.500000, -0.809017, -0.309017},
135{-0.262866, -0.951056, -0.162460},
136{-0.850651, -0.525731, 0.000000},
137{-0.716567, -0.681718, -0.147621},
138{-0.716567, -0.681718, 0.147621},
139{-0.525731, -0.850651, 0.000000},
140{-0.500000, -0.809017, 0.309017},
141{-0.238856, -0.864188, 0.442863},
142{-0.262866, -0.951056, 0.162460},
143{-0.864188, -0.442863, 0.238856},
144{-0.809017, -0.309017, 0.500000},
145{-0.688191, -0.587785, 0.425325},
146{-0.681718, -0.147621, 0.716567},
147{-0.442863, -0.238856, 0.864188},
148{-0.587785, -0.425325, 0.688191},
149{-0.309017, -0.500000, 0.809017},
150{-0.147621, -0.716567, 0.681718},
151{-0.425325, -0.688191, 0.587785},
152{-0.162460, -0.262866, 0.951056},
153{0.442863, -0.238856, 0.864188},
154{0.162460, -0.262866, 0.951056},
155{0.309017, -0.500000, 0.809017},
156{0.147621, -0.716567, 0.681718},
157{0.000000, -0.525731, 0.850651},
158{0.425325, -0.688191, 0.587785},
159{0.587785, -0.425325, 0.688191},
160{0.688191, -0.587785, 0.425325},
161{-0.955423, 0.295242, 0.000000},
162{-0.951056, 0.162460, 0.262866},
163{-1.000000, 0.000000, 0.000000},
164{-0.850651, 0.000000, 0.525731},
165{-0.955423, -0.295242, 0.000000},
166{-0.951056, -0.162460, 0.262866},
167{-0.864188, 0.442863, -0.238856},
168{-0.951056, 0.162460, -0.262866},
169{-0.809017, 0.309017, -0.500000},
170{-0.864188, -0.442863, -0.238856},
171{-0.951056, -0.162460, -0.262866},
172{-0.809017, -0.309017, -0.500000},
173{-0.681718, 0.147621, -0.716567},
174{-0.681718, -0.147621, -0.716567},
175{-0.850651, 0.000000, -0.525731},
176{-0.688191, 0.587785, -0.425325},
177{-0.587785, 0.425325, -0.688191},
178{-0.425325, 0.688191, -0.587785},
179{-0.425325, -0.688191, -0.587785},
180{-0.587785, -0.425325, -0.688191},
181{-0.688191, -0.587785, -0.425325},
diff --git a/apps/plugins/sdl/progs/quake/asm_draw.h b/apps/plugins/sdl/progs/quake/asm_draw.h
new file mode 100644
index 0000000000..5534ab63c7
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/asm_draw.h
@@ -0,0 +1,151 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// asm_draw.h
22//
23// Include file for asm drawing routines.
24//
25
26//
27// !!! note that this file must match the corresponding C structures at all
28// times !!!
29//
30
31// !!! if this is changed, it must be changed in r_local.h too !!!
32#define NEAR_CLIP 0.01
33
34// !!! if this is changed, it must be changed in r_local.h too !!!
35#define CYCLE 128
36
37// espan_t structure
38// !!! if this is changed, it must be changed in r_shared.h too !!!
39#define espan_t_u 0
40#define espan_t_v 4
41#define espan_t_count 8
42#define espan_t_pnext 12
43#define espan_t_size 16
44
45// sspan_t structure
46// !!! if this is changed, it must be changed in d_local.h too !!!
47#define sspan_t_u 0
48#define sspan_t_v 4
49#define sspan_t_count 8
50#define sspan_t_size 12
51
52// spanpackage_t structure
53// !!! if this is changed, it must be changed in d_polyset.c too !!!
54#define spanpackage_t_pdest 0
55#define spanpackage_t_pz 4
56#define spanpackage_t_count 8
57#define spanpackage_t_ptex 12
58#define spanpackage_t_sfrac 16
59#define spanpackage_t_tfrac 20
60#define spanpackage_t_light 24
61#define spanpackage_t_zi 28
62#define spanpackage_t_size 32
63
64// edge_t structure
65// !!! if this is changed, it must be changed in r_shared.h too !!!
66#define et_u 0
67#define et_u_step 4
68#define et_prev 8
69#define et_next 12
70#define et_surfs 16
71#define et_nextremove 20
72#define et_nearzi 24
73#define et_owner 28
74#define et_size 32
75
76// surf_t structure
77// !!! if this is changed, it must be changed in r_shared.h too !!!
78#define SURF_T_SHIFT 6
79#define st_next 0
80#define st_prev 4
81#define st_spans 8
82#define st_key 12
83#define st_last_u 16
84#define st_spanstate 20
85#define st_flags 24
86#define st_data 28
87#define st_entity 32
88#define st_nearzi 36
89#define st_insubmodel 40
90#define st_d_ziorigin 44
91#define st_d_zistepu 48
92#define st_d_zistepv 52
93#define st_pad 56
94#define st_size 64
95
96// clipplane_t structure
97// !!! if this is changed, it must be changed in r_local.h too !!!
98#define cp_normal 0
99#define cp_dist 12
100#define cp_next 16
101#define cp_leftedge 20
102#define cp_rightedge 21
103#define cp_reserved 22
104#define cp_size 24
105
106// medge_t structure
107// !!! if this is changed, it must be changed in model.h too !!!
108#define me_v 0
109#define me_cachededgeoffset 4
110#define me_size 8
111
112// mvertex_t structure
113// !!! if this is changed, it must be changed in model.h too !!!
114#define mv_position 0
115#define mv_size 12
116
117// refdef_t structure
118// !!! if this is changed, it must be changed in render.h too !!!
119#define rd_vrect 0
120#define rd_aliasvrect 20
121#define rd_vrectright 40
122#define rd_vrectbottom 44
123#define rd_aliasvrectright 48
124#define rd_aliasvrectbottom 52
125#define rd_vrectrightedge 56
126#define rd_fvrectx 60
127#define rd_fvrecty 64
128#define rd_fvrectx_adj 68
129#define rd_fvrecty_adj 72
130#define rd_vrect_x_adj_shift20 76
131#define rd_vrectright_adj_shift20 80
132#define rd_fvrectright_adj 84
133#define rd_fvrectbottom_adj 88
134#define rd_fvrectright 92
135#define rd_fvrectbottom 96
136#define rd_horizontalFieldOfView 100
137#define rd_xOrigin 104
138#define rd_yOrigin 108
139#define rd_vieworg 112
140#define rd_viewangles 124
141#define rd_ambientlight 136
142#define rd_size 140
143
144// mtriangle_t structure
145// !!! if this is changed, it must be changed in model.h too !!!
146#define mtri_facesfront 0
147#define mtri_vertindex 4
148#define mtri_size 16 // !!! if this changes, array indexing in !!!
149 // !!! d_polysa.s must be changed to match !!!
150#define mtri_shift 4
151
diff --git a/apps/plugins/sdl/progs/quake/asm_i386.h b/apps/plugins/sdl/progs/quake/asm_i386.h
new file mode 100644
index 0000000000..03dc2aae8a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/asm_i386.h
@@ -0,0 +1,97 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#ifndef __ASM_I386__
22#define __ASM_I386__
23
24#ifdef ELF
25#define C(label) label
26#else
27#define C(label) _##label
28#endif
29
30//
31// !!! note that this file must match the corresponding C structures at all
32// times !!!
33//
34
35// plane_t structure
36// !!! if this is changed, it must be changed in model.h too !!!
37// !!! if the size of this is changed, the array lookup in SV_HullPointContents
38// must be changed too !!!
39#define pl_normal 0
40#define pl_dist 12
41#define pl_type 16
42#define pl_signbits 17
43#define pl_pad 18
44#define pl_size 20
45
46// hull_t structure
47// !!! if this is changed, it must be changed in model.h too !!!
48#define hu_clipnodes 0
49#define hu_planes 4
50#define hu_firstclipnode 8
51#define hu_lastclipnode 12
52#define hu_clip_mins 16
53#define hu_clip_maxs 28
54#define hu_size 40
55
56// dnode_t structure
57// !!! if this is changed, it must be changed in bspfile.h too !!!
58#define nd_planenum 0
59#define nd_children 4
60#define nd_mins 8
61#define nd_maxs 20
62#define nd_firstface 32
63#define nd_numfaces 36
64#define nd_size 40
65
66// sfxcache_t structure
67// !!! if this is changed, it much be changed in sound.h too !!!
68#define sfxc_length 0
69#define sfxc_loopstart 4
70#define sfxc_speed 8
71#define sfxc_width 12
72#define sfxc_stereo 16
73#define sfxc_data 20
74
75// channel_t structure
76// !!! if this is changed, it much be changed in sound.h too !!!
77#define ch_sfx 0
78#define ch_leftvol 4
79#define ch_rightvol 8
80#define ch_end 12
81#define ch_pos 16
82#define ch_looping 20
83#define ch_entnum 24
84#define ch_entchannel 28
85#define ch_origin 32
86#define ch_dist_mult 44
87#define ch_master_vol 48
88#define ch_size 52
89
90// portable_samplepair_t structure
91// !!! if this is changed, it much be changed in sound.h too !!!
92#define psp_left 0
93#define psp_right 4
94#define psp_size 8
95
96#endif
97
diff --git a/apps/plugins/sdl/progs/quake/block16.h b/apps/plugins/sdl/progs/quake/block16.h
new file mode 100644
index 0000000000..96f222e188
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/block16.h
@@ -0,0 +1,142 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20LEnter16_16:
21 movb (%esi),%al
22 movb (%esi,%ebx,),%cl
23 movb %dh,%ah
24 addl %ebp,%edx
25 movb %dh,%ch
26 leal (%esi,%ebx,2),%esi
27 movw 0x12345678(,%eax,2),%ax
28LBPatch0:
29 addl %ebp,%edx
30 movw %ax,(%edi)
31 movw 0x12345678(,%ecx,2),%cx
32LBPatch1:
33 movw %cx,2(%edi)
34 addl $0x4,%edi
35
36 movb (%esi),%al
37 movb (%esi,%ebx,),%cl
38 movb %dh,%ah
39 addl %ebp,%edx
40 movb %dh,%ch
41 leal (%esi,%ebx,2),%esi
42 movw 0x12345678(,%eax,2),%ax
43LBPatch2:
44 addl %ebp,%edx
45 movw %ax,(%edi)
46 movw 0x12345678(,%ecx,2),%cx
47LBPatch3:
48 movw %cx,2(%edi)
49 addl $0x4,%edi
50
51 movb (%esi),%al
52 movb (%esi,%ebx,),%cl
53 movb %dh,%ah
54 addl %ebp,%edx
55 movb %dh,%ch
56 leal (%esi,%ebx,2),%esi
57 movw 0x12345678(,%eax,2),%ax
58LBPatch4:
59 addl %ebp,%edx
60 movw %ax,(%edi)
61 movw 0x12345678(,%ecx,2),%cx
62LBPatch5:
63 movw %cx,2(%edi)
64 addl $0x4,%edi
65
66 movb (%esi),%al
67 movb (%esi,%ebx,),%cl
68 movb %dh,%ah
69 addl %ebp,%edx
70 movb %dh,%ch
71 leal (%esi,%ebx,2),%esi
72 movw 0x12345678(,%eax,2),%ax
73LBPatch6:
74 addl %ebp,%edx
75 movw %ax,(%edi)
76 movw 0x12345678(,%ecx,2),%cx
77LBPatch7:
78 movw %cx,2(%edi)
79 addl $0x4,%edi
80
81LEnter8_16:
82 movb (%esi),%al
83 movb (%esi,%ebx,),%cl
84 movb %dh,%ah
85 addl %ebp,%edx
86 movb %dh,%ch
87 leal (%esi,%ebx,2),%esi
88 movw 0x12345678(,%eax,2),%ax
89LBPatch8:
90 addl %ebp,%edx
91 movw %ax,(%edi)
92 movw 0x12345678(,%ecx,2),%cx
93LBPatch9:
94 movw %cx,2(%edi)
95 addl $0x4,%edi
96
97 movb (%esi),%al
98 movb (%esi,%ebx,),%cl
99 movb %dh,%ah
100 addl %ebp,%edx
101 movb %dh,%ch
102 leal (%esi,%ebx,2),%esi
103 movw 0x12345678(,%eax,2),%ax
104LBPatch10:
105 addl %ebp,%edx
106 movw %ax,(%edi)
107 movw 0x12345678(,%ecx,2),%cx
108LBPatch11:
109 movw %cx,2(%edi)
110 addl $0x4,%edi
111
112LEnter4_16:
113 movb (%esi),%al
114 movb (%esi,%ebx,),%cl
115 movb %dh,%ah
116 addl %ebp,%edx
117 movb %dh,%ch
118 leal (%esi,%ebx,2),%esi
119 movw 0x12345678(,%eax,2),%ax
120LBPatch12:
121 addl %ebp,%edx
122 movw %ax,(%edi)
123 movw 0x12345678(,%ecx,2),%cx
124LBPatch13:
125 movw %cx,2(%edi)
126 addl $0x4,%edi
127
128LEnter2_16:
129 movb (%esi),%al
130 movb (%esi,%ebx,),%cl
131 movb %dh,%ah
132 addl %ebp,%edx
133 movb %dh,%ch
134 leal (%esi,%ebx,2),%esi
135 movw 0x12345678(,%eax,2),%ax
136LBPatch14:
137 addl %ebp,%edx
138 movw %ax,(%edi)
139 movw 0x12345678(,%ecx,2),%cx
140LBPatch15:
141 movw %cx,2(%edi)
142 addl $0x4,%edi
diff --git a/apps/plugins/sdl/progs/quake/block8.h b/apps/plugins/sdl/progs/quake/block8.h
new file mode 100644
index 0000000000..eb9b03c3af
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/block8.h
@@ -0,0 +1,143 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20LEnter16_8:
21 movb (%esi),%al
22 movb (%esi,%ebx,),%cl
23 movb %dh,%ah
24 addl %ebp,%edx
25 movb %dh,%ch
26 leal (%esi,%ebx,2),%esi
27 movb 0x12345678(%eax),%al
28LBPatch0:
29 addl %ebp,%edx
30 movb %al,(%edi)
31 movb 0x12345678(%ecx),%cl
32LBPatch1:
33 movb %cl,1(%edi)
34 addl $0x2,%edi
35
36 movb (%esi),%al
37 movb (%esi,%ebx,),%cl
38 movb %dh,%ah
39 addl %ebp,%edx
40 movb %dh,%ch
41 leal (%esi,%ebx,2),%esi
42 movb 0x12345678(%eax),%al
43LBPatch2:
44 addl %ebp,%edx
45 movb %al,(%edi)
46 movb 0x12345678(%ecx),%cl
47LBPatch3:
48 movb %cl,1(%edi)
49 addl $0x2,%edi
50
51 movb (%esi),%al
52 movb (%esi,%ebx,),%cl
53 movb %dh,%ah
54 addl %ebp,%edx
55 movb %dh,%ch
56 leal (%esi,%ebx,2),%esi
57 movb 0x12345678(%eax),%al
58LBPatch4:
59 addl %ebp,%edx
60 movb %al,(%edi)
61 movb 0x12345678(%ecx),%cl
62LBPatch5:
63 movb %cl,1(%edi)
64 addl $0x2,%edi
65
66 movb (%esi),%al
67 movb (%esi,%ebx,),%cl
68 movb %dh,%ah
69 addl %ebp,%edx
70 movb %dh,%ch
71 leal (%esi,%ebx,2),%esi
72 movb 0x12345678(%eax),%al
73LBPatch6:
74 addl %ebp,%edx
75 movb %al,(%edi)
76 movb 0x12345678(%ecx),%cl
77LBPatch7:
78 movb %cl,1(%edi)
79 addl $0x2,%edi
80
81LEnter8_8:
82 movb (%esi),%al
83 movb (%esi,%ebx,),%cl
84 movb %dh,%ah
85 addl %ebp,%edx
86 movb %dh,%ch
87 leal (%esi,%ebx,2),%esi
88 movb 0x12345678(%eax),%al
89LBPatch8:
90 addl %ebp,%edx
91 movb %al,(%edi)
92 movb 0x12345678(%ecx),%cl
93LBPatch9:
94 movb %cl,1(%edi)
95 addl $0x2,%edi
96
97 movb (%esi),%al
98 movb (%esi,%ebx,),%cl
99 movb %dh,%ah
100 addl %ebp,%edx
101 movb %dh,%ch
102 leal (%esi,%ebx,2),%esi
103 movb 0x12345678(%eax),%al
104LBPatch10:
105 addl %ebp,%edx
106 movb %al,(%edi)
107 movb 0x12345678(%ecx),%cl
108LBPatch11:
109 movb %cl,1(%edi)
110 addl $0x2,%edi
111
112LEnter4_8:
113 movb (%esi),%al
114 movb (%esi,%ebx,),%cl
115 movb %dh,%ah
116 addl %ebp,%edx
117 movb %dh,%ch
118 leal (%esi,%ebx,2),%esi
119 movb 0x12345678(%eax),%al
120LBPatch12:
121 addl %ebp,%edx
122 movb %al,(%edi)
123 movb 0x12345678(%ecx),%cl
124LBPatch13:
125 movb %cl,1(%edi)
126 addl $0x2,%edi
127
128LEnter2_8:
129 movb (%esi),%al
130 movb (%esi,%ebx,),%cl
131 movb %dh,%ah
132 addl %ebp,%edx
133 movb %dh,%ch
134 leal (%esi,%ebx,2),%esi
135 movb 0x12345678(%eax),%al
136LBPatch14:
137 addl %ebp,%edx
138 movb %al,(%edi)
139 movb 0x12345678(%ecx),%cl
140LBPatch15:
141 movb %cl,1(%edi)
142 addl $0x2,%edi
143
diff --git a/apps/plugins/sdl/progs/quake/bspfile.h b/apps/plugins/sdl/progs/quake/bspfile.h
new file mode 100644
index 0000000000..308902632b
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/bspfile.h
@@ -0,0 +1,324 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21
22// upper design bounds
23
24#define MAX_MAP_HULLS 4
25
26#define MAX_MAP_MODELS 256
27#define MAX_MAP_BRUSHES 4096
28#define MAX_MAP_ENTITIES 1024
29#define MAX_MAP_ENTSTRING 65536
30
31#define MAX_MAP_PLANES 32767
32#define MAX_MAP_NODES 32767 // because negative shorts are contents
33#define MAX_MAP_CLIPNODES 32767 //
34#define MAX_MAP_LEAFS 8192
35#define MAX_MAP_VERTS 65535
36#define MAX_MAP_FACES 65535
37#define MAX_MAP_MARKSURFACES 65535
38#define MAX_MAP_TEXINFO 4096
39#define MAX_MAP_EDGES 256000
40#define MAX_MAP_SURFEDGES 512000
41#define MAX_MAP_TEXTURES 512
42#define MAX_MAP_MIPTEX 0x200000
43#define MAX_MAP_LIGHTING 0x100000
44#define MAX_MAP_VISIBILITY 0x100000
45
46#define MAX_MAP_PORTALS 65536
47
48// key / value pair sizes
49
50#define MAX_KEY 32
51#define MAX_VALUE 1024
52
53//=============================================================================
54
55
56#define BSPVERSION 29
57#define TOOLVERSION 2
58
59typedef struct
60{
61 int fileofs, filelen;
62} lump_t;
63
64#define LUMP_ENTITIES 0
65#define LUMP_PLANES 1
66#define LUMP_TEXTURES 2
67#define LUMP_VERTEXES 3
68#define LUMP_VISIBILITY 4
69#define LUMP_NODES 5
70#define LUMP_TEXINFO 6
71#define LUMP_FACES 7
72#define LUMP_LIGHTING 8
73#define LUMP_CLIPNODES 9
74#define LUMP_LEAFS 10
75#define LUMP_MARKSURFACES 11
76#define LUMP_EDGES 12
77#define LUMP_SURFEDGES 13
78#define LUMP_MODELS 14
79
80#define HEADER_LUMPS 15
81
82typedef struct
83{
84 float mins[3], maxs[3];
85 float origin[3];
86 int headnode[MAX_MAP_HULLS];
87 int visleafs; // not including the solid leaf 0
88 int firstface, numfaces;
89} dmodel_t;
90
91typedef struct
92{
93 int version;
94 lump_t lumps[HEADER_LUMPS];
95} dheader_t;
96
97typedef struct
98{
99 int nummiptex;
100 int dataofs[4]; // [nummiptex]
101} dmiptexlump_t;
102
103#define MIPLEVELS 4
104typedef struct miptex_s
105{
106 char name[16];
107 unsigned width, height;
108 unsigned offsets[MIPLEVELS]; // four mip maps stored
109} miptex_t;
110
111
112typedef struct
113{
114 float point[3];
115} dvertex_t;
116
117
118// 0-2 are axial planes
119#define PLANE_X 0
120#define PLANE_Y 1
121#define PLANE_Z 2
122
123// 3-5 are non-axial planes snapped to the nearest
124#define PLANE_ANYX 3
125#define PLANE_ANYY 4
126#define PLANE_ANYZ 5
127
128typedef struct
129{
130 float normal[3];
131 float dist;
132 int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
133} dplane_t;
134
135
136
137#define CONTENTS_EMPTY -1
138#define CONTENTS_SOLID -2
139#define CONTENTS_WATER -3
140#define CONTENTS_SLIME -4
141#define CONTENTS_LAVA -5
142#define CONTENTS_SKY -6
143#define CONTENTS_ORIGIN -7 // removed at csg time
144#define CONTENTS_CLIP -8 // changed to contents_solid
145
146#define CONTENTS_CURRENT_0 -9
147#define CONTENTS_CURRENT_90 -10
148#define CONTENTS_CURRENT_180 -11
149#define CONTENTS_CURRENT_270 -12
150#define CONTENTS_CURRENT_UP -13
151#define CONTENTS_CURRENT_DOWN -14
152
153
154// !!! if this is changed, it must be changed in asm_i386.h too !!!
155typedef struct
156{
157 int planenum;
158 short children[2]; // negative numbers are -(leafs+1), not nodes
159 short mins[3]; // for sphere culling
160 short maxs[3];
161 unsigned short firstface;
162 unsigned short numfaces; // counting both sides
163} dnode_t;
164
165typedef struct
166{
167 int planenum;
168 short children[2]; // negative numbers are contents
169} dclipnode_t;
170
171
172typedef struct texinfo_s
173{
174 float vecs[2][4]; // [s/t][xyz offset]
175 int miptex;
176 int flags;
177} texinfo_t;
178#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
179
180// note that edge 0 is never used, because negative edge nums are used for
181// counterclockwise use of the edge in a face
182typedef struct
183{
184 unsigned short v[2]; // vertex numbers
185} dedge_t;
186
187#define MAXLIGHTMAPS 4
188typedef struct
189{
190 short planenum;
191 short side;
192
193 int firstedge; // we must support > 64k edges
194 short numedges;
195 short texinfo;
196
197// lighting info
198 byte styles[MAXLIGHTMAPS];
199 int lightofs; // start of [numstyles*surfsize] samples
200} dface_t;
201
202
203
204#define AMBIENT_WATER 0
205#define AMBIENT_SKY 1
206#define AMBIENT_SLIME 2
207#define AMBIENT_LAVA 3
208
209#define NUM_AMBIENTS 4 // automatic ambient sounds
210
211// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
212// all other leafs need visibility info
213typedef struct
214{
215 int contents;
216 int visofs; // -1 = no visibility info
217
218 short mins[3]; // for frustum culling
219 short maxs[3];
220
221 unsigned short firstmarksurface;
222 unsigned short nummarksurfaces;
223
224 byte ambient_level[NUM_AMBIENTS];
225} dleaf_t;
226
227
228//============================================================================
229
230#ifndef QUAKE_GAME
231
232#define ANGLE_UP -1
233#define ANGLE_DOWN -2
234
235
236// the utilities get to be lazy and just use large static arrays
237
238extern int nummodels;
239extern dmodel_t dmodels[MAX_MAP_MODELS];
240
241extern int visdatasize;
242extern byte dvisdata[MAX_MAP_VISIBILITY];
243
244extern int lightdatasize;
245extern byte dlightdata[MAX_MAP_LIGHTING];
246
247extern int texdatasize;
248extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
249
250extern int entdatasize;
251extern char dentdata[MAX_MAP_ENTSTRING];
252
253extern int numleafs;
254extern dleaf_t dleafs[MAX_MAP_LEAFS];
255
256extern int numplanes;
257extern dplane_t dplanes[MAX_MAP_PLANES];
258
259extern int numvertexes;
260extern dvertex_t dvertexes[MAX_MAP_VERTS];
261
262extern int numnodes;
263extern dnode_t dnodes[MAX_MAP_NODES];
264
265extern int numtexinfo;
266extern texinfo_t texinfo[MAX_MAP_TEXINFO];
267
268extern int numfaces;
269extern dface_t dfaces[MAX_MAP_FACES];
270
271extern int numclipnodes;
272extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];
273
274extern int numedges;
275extern dedge_t dedges[MAX_MAP_EDGES];
276
277extern int nummarksurfaces;
278extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];
279
280extern int numsurfedges;
281extern int dsurfedges[MAX_MAP_SURFEDGES];
282
283
284void DecompressVis (byte *in, byte *decompressed);
285int CompressVis (byte *vis, byte *dest);
286
287void LoadBSPFile (char *filename);
288void WriteBSPFile (char *filename);
289void PrintBSPFileSizes (void);
290
291//===============
292
293
294typedef struct epair_s
295{
296 struct epair_s *next;
297 char *key;
298 char *value;
299} epair_t;
300
301typedef struct
302{
303 vec3_t origin;
304 int firstbrush;
305 int numbrushes;
306 epair_t *epairs;
307} entity_t;
308
309extern int num_entities;
310extern entity_t entities[MAX_MAP_ENTITIES];
311
312void ParseEntities (void);
313void UnparseEntities (void);
314
315void SetKeyValue (entity_t *ent, char *key, char *value);
316char *ValueForKey (entity_t *ent, char *key);
317// will return "" if not present
318
319vec_t FloatForKey (entity_t *ent, char *key);
320void GetVectorForKey (entity_t *ent, char *key, vec3_t vec);
321
322epair_t *ParseEpair (void);
323
324#endif
diff --git a/apps/plugins/sdl/progs/quake/cd_linux.c b/apps/plugins/sdl/progs/quake/cd_linux.c
new file mode 100644
index 0000000000..0e23d96035
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cd_linux.c
@@ -0,0 +1,416 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
21// rights reserved.
22
23#include <stdio.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <sys/ioctl.h>
27#include <sys/file.h>
28#include <sys/types.h>
29#include <fcntl.h>
30#include <string.h>
31#include <time.h>
32#include <errno.h>
33
34#include <linux/cdrom.h>
35
36#include "quakedef.h"
37
38static qboolean cdValid = false;
39static qboolean playing = false;
40static qboolean wasPlaying = false;
41static qboolean initialized = false;
42static qboolean enabled = true;
43static qboolean playLooping = false;
44static float cdvolume;
45static byte remap[100];
46static byte playTrack;
47static byte maxTrack;
48
49static int cdfile = -1;
50static char cd_dev[64] = "/dev/cdrom";
51
52static void CDAudio_Eject(void)
53{
54 if (cdfile == -1 || !enabled)
55 return; // no cd init'd
56
57 if ( ioctl(cdfile, CDROMEJECT) == -1 )
58 Con_DPrintf("ioctl cdromeject failed\n");
59}
60
61
62static void CDAudio_CloseDoor(void)
63{
64 if (cdfile == -1 || !enabled)
65 return; // no cd init'd
66
67 if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 )
68 Con_DPrintf("ioctl cdromclosetray failed\n");
69}
70
71static int CDAudio_GetAudioDiskInfo(void)
72{
73 struct cdrom_tochdr tochdr;
74
75 cdValid = false;
76
77 if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 )
78 {
79 Con_DPrintf("ioctl cdromreadtochdr failed\n");
80 return -1;
81 }
82
83 if (tochdr.cdth_trk0 < 1)
84 {
85 Con_DPrintf("CDAudio: no music tracks\n");
86 return -1;
87 }
88
89 cdValid = true;
90 maxTrack = tochdr.cdth_trk1;
91
92 return 0;
93}
94
95
96void CDAudio_Play(byte track, qboolean looping)
97{
98 struct cdrom_tocentry entry;
99 struct cdrom_ti ti;
100
101 if (cdfile == -1 || !enabled)
102 return;
103
104 if (!cdValid)
105 {
106 CDAudio_GetAudioDiskInfo();
107 if (!cdValid)
108 return;
109 }
110
111 track = remap[track];
112
113 if (track < 1 || track > maxTrack)
114 {
115 Con_DPrintf("CDAudio: Bad track number %u.\n", track);
116 return;
117 }
118
119 // don't try to play a non-audio track
120 entry.cdte_track = track;
121 entry.cdte_format = CDROM_MSF;
122 if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 )
123 {
124 Con_DPrintf("ioctl cdromreadtocentry failed\n");
125 return;
126 }
127 if (entry.cdte_ctrl == CDROM_DATA_TRACK)
128 {
129 Con_Printf("CDAudio: track %i is not audio\n", track);
130 return;
131 }
132
133 if (playing)
134 {
135 if (playTrack == track)
136 return;
137 CDAudio_Stop();
138 }
139
140 ti.cdti_trk0 = track;
141 ti.cdti_trk1 = track;
142 ti.cdti_ind0 = 1;
143 ti.cdti_ind1 = 99;
144
145 if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 )
146 {
147 Con_DPrintf("ioctl cdromplaytrkind failed\n");
148 return;
149 }
150
151 if ( ioctl(cdfile, CDROMRESUME) == -1 )
152 Con_DPrintf("ioctl cdromresume failed\n");
153
154 playLooping = looping;
155 playTrack = track;
156 playing = true;
157
158 if (cdvolume == 0.0)
159 CDAudio_Pause ();
160}
161
162
163void CDAudio_Stop(void)
164{
165 if (cdfile == -1 || !enabled)
166 return;
167
168 if (!playing)
169 return;
170
171 if ( ioctl(cdfile, CDROMSTOP) == -1 )
172 Con_DPrintf("ioctl cdromstop failed (%d)\n", errno);
173
174 wasPlaying = false;
175 playing = false;
176}
177
178void CDAudio_Pause(void)
179{
180 if (cdfile == -1 || !enabled)
181 return;
182
183 if (!playing)
184 return;
185
186 if ( ioctl(cdfile, CDROMPAUSE) == -1 )
187 Con_DPrintf("ioctl cdrompause failed\n");
188
189 wasPlaying = playing;
190 playing = false;
191}
192
193
194void CDAudio_Resume(void)
195{
196 if (cdfile == -1 || !enabled)
197 return;
198
199 if (!cdValid)
200 return;
201
202 if (!wasPlaying)
203 return;
204
205 if ( ioctl(cdfile, CDROMRESUME) == -1 )
206 Con_DPrintf("ioctl cdromresume failed\n");
207 playing = true;
208}
209
210static void CD_f (void)
211{
212 char *command;
213 int ret;
214 int n;
215
216 if (Cmd_Argc() < 2)
217 return;
218
219 command = Cmd_Argv (1);
220
221 if (Q_strcasecmp(command, "on") == 0)
222 {
223 enabled = true;
224 return;
225 }
226
227 if (Q_strcasecmp(command, "off") == 0)
228 {
229 if (playing)
230 CDAudio_Stop();
231 enabled = false;
232 return;
233 }
234
235 if (Q_strcasecmp(command, "reset") == 0)
236 {
237 enabled = true;
238 if (playing)
239 CDAudio_Stop();
240 for (n = 0; n < 100; n++)
241 remap[n] = n;
242 CDAudio_GetAudioDiskInfo();
243 return;
244 }
245
246 if (Q_strcasecmp(command, "remap") == 0)
247 {
248 ret = Cmd_Argc() - 2;
249 if (ret <= 0)
250 {
251 for (n = 1; n < 100; n++)
252 if (remap[n] != n)
253 Con_Printf(" %u -> %u\n", n, remap[n]);
254 return;
255 }
256 for (n = 1; n <= ret; n++)
257 remap[n] = Q_atoi(Cmd_Argv (n+1));
258 return;
259 }
260
261 if (Q_strcasecmp(command, "close") == 0)
262 {
263 CDAudio_CloseDoor();
264 return;
265 }
266
267 if (!cdValid)
268 {
269 CDAudio_GetAudioDiskInfo();
270 if (!cdValid)
271 {
272 Con_Printf("No CD in player.\n");
273 return;
274 }
275 }
276
277 if (Q_strcasecmp(command, "play") == 0)
278 {
279 CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), false);
280 return;
281 }
282
283 if (Q_strcasecmp(command, "loop") == 0)
284 {
285 CDAudio_Play((byte)Q_atoi(Cmd_Argv (2)), true);
286 return;
287 }
288
289 if (Q_strcasecmp(command, "stop") == 0)
290 {
291 CDAudio_Stop();
292 return;
293 }
294
295 if (Q_strcasecmp(command, "pause") == 0)
296 {
297 CDAudio_Pause();
298 return;
299 }
300
301 if (Q_strcasecmp(command, "resume") == 0)
302 {
303 CDAudio_Resume();
304 return;
305 }
306
307 if (Q_strcasecmp(command, "eject") == 0)
308 {
309 if (playing)
310 CDAudio_Stop();
311 CDAudio_Eject();
312 cdValid = false;
313 return;
314 }
315
316 if (Q_strcasecmp(command, "info") == 0)
317 {
318 Con_Printf("%u tracks\n", maxTrack);
319 if (playing)
320 Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
321 else if (wasPlaying)
322 Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
323 Con_Printf("Volume is %f\n", cdvolume);
324 return;
325 }
326}
327
328void CDAudio_Update(void)
329{
330 struct cdrom_subchnl subchnl;
331 static time_t lastchk;
332
333 if (!enabled)
334 return;
335
336 if (bgmvolume.value != cdvolume)
337 {
338 if (cdvolume)
339 {
340 Cvar_SetValue ("bgmvolume", 0.0);
341 cdvolume = bgmvolume.value;
342 CDAudio_Pause ();
343 }
344 else
345 {
346 Cvar_SetValue ("bgmvolume", 1.0);
347 cdvolume = bgmvolume.value;
348 CDAudio_Resume ();
349 }
350 }
351
352 if (playing && lastchk < time(NULL)) {
353 lastchk = time(NULL) + 2; //two seconds between chks
354 subchnl.cdsc_format = CDROM_MSF;
355 if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) {
356 Con_DPrintf("ioctl cdromsubchnl failed\n");
357 playing = false;
358 return;
359 }
360 if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY &&
361 subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) {
362 playing = false;
363 if (playLooping)
364 CDAudio_Play(playTrack, true);
365 }
366 }
367}
368
369int CDAudio_Init(void)
370{
371 int i;
372
373 if (cls.state == ca_dedicated)
374 return -1;
375
376 if (COM_CheckParm("-nocdaudio"))
377 return -1;
378
379 if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) {
380 strncpy(cd_dev, com_argv[i + 1], sizeof(cd_dev));
381 cd_dev[sizeof(cd_dev) - 1] = 0;
382 }
383
384 if ((cdfile = open(cd_dev, O_RDONLY)) == -1) {
385 Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno);
386 cdfile = -1;
387 return -1;
388 }
389
390 for (i = 0; i < 100; i++)
391 remap[i] = i;
392 initialized = true;
393 enabled = true;
394
395 if (CDAudio_GetAudioDiskInfo())
396 {
397 Con_Printf("CDAudio_Init: No CD in player.\n");
398 cdValid = false;
399 }
400
401 Cmd_AddCommand ("cd", CD_f);
402
403 Con_Printf("CD Audio Initialized\n");
404
405 return 0;
406}
407
408
409void CDAudio_Shutdown(void)
410{
411 if (!initialized)
412 return;
413 CDAudio_Stop();
414 close(cdfile);
415 cdfile = -1;
416}
diff --git a/apps/plugins/sdl/progs/quake/cd_null.c b/apps/plugins/sdl/progs/quake/cd_null.c
new file mode 100644
index 0000000000..d5eeec8ad2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cd_null.c
@@ -0,0 +1,55 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22void CDAudio_Play(byte track, qboolean looping)
23{
24}
25
26
27void CDAudio_Stop(void)
28{
29}
30
31
32void CDAudio_Pause(void)
33{
34}
35
36
37void CDAudio_Resume(void)
38{
39}
40
41
42void CDAudio_Update(void)
43{
44}
45
46
47int CDAudio_Init(void)
48{
49 return 0;
50}
51
52
53void CDAudio_Shutdown(void)
54{
55} \ No newline at end of file
diff --git a/apps/plugins/sdl/progs/quake/cd_sdl.c b/apps/plugins/sdl/progs/quake/cd_sdl.c
new file mode 100644
index 0000000000..46b2aa2835
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cd_sdl.c
@@ -0,0 +1,223 @@
1/*
2 Some of this may not work. I'm not overly familiar with SDL, I just sort
3 of podged this together from the SDL headers, and the other cd-rom code.
4
5 Mark Baker <homer1@together.net>
6*/
7
8#include <SDL.h>
9
10#include "quakedef.h"
11
12static qboolean cdValid = false;
13static qboolean initialized = false;
14static qboolean enabled = true;
15static qboolean playLooping = false;
16static SDL_CD *cd_id;
17static float cdvolume = 1.0;
18
19static void CD_f();
20
21static void CDAudio_Eject()
22{
23 if(!cd_id || !enabled) return;
24
25 if(SDL_CDEject(cd_id))
26 Con_DPrintf("Unable to eject CD-ROM tray.\n");
27}
28
29void CDAudio_Play(byte track, qboolean looping)
30{
31 CDstatus cd_stat;
32 if(!cd_id || !enabled) return;
33
34 if(!cdValid)
35 {
36 if(!CD_INDRIVE(cd_stat=SDL_CDStatus(cd_id)) ||(!cd_id->numtracks)) return;
37 cdValid = true;
38 }
39
40 if((track < 1) || (track >= cd_id->numtracks))
41 {
42 Con_DPrintf("CDAudio: Bad track number: %d\n",track);
43 return;
44 }
45 track--; /* Convert track from person to SDL value */
46 if(cd_stat == CD_PLAYING)
47 {
48 if(cd_id->cur_track == track) return;
49 CDAudio_Stop();
50 }
51
52 if(SDL_CDPlay(cd_id,cd_id->track[track].offset,
53 cd_id->track[track].length))
54 {
55 Con_DPrintf("CDAudio_Play: Unable to play track: %d\n",track+1);
56 return;
57 }
58 playLooping = looping;
59}
60
61
62void CDAudio_Stop()
63{
64 int cdstate;
65 if(!cd_id || !enabled) return;
66 cdstate = SDL_CDStatus(cd_id);
67 if((cdstate != CD_PLAYING) && (cdstate != CD_PAUSED)) return;
68
69 if(SDL_CDStop(cd_id))
70 Con_DPrintf("CDAudio_Stop: Failed to stop track.\n");
71}
72
73void CDAudio_Pause()
74{
75 if(!cd_id || !enabled) return;
76 if(SDL_CDStatus(cd_id) != CD_PLAYING) return;
77
78 if(SDL_CDPause(cd_id))
79 Con_DPrintf("CDAudio_Pause: Failed to pause track.\n");
80}
81
82
83void CDAudio_Resume()
84{
85 if(!cd_id || !enabled) return;
86 if(SDL_CDStatus(cd_id) != CD_PAUSED) return;
87
88 if(SDL_CDResume(cd_id))
89 Con_DPrintf("CDAudio_Resume: Failed tp resume track.\n");
90}
91
92void CDAudio_Update()
93{
94 if(!cd_id || !enabled) return;
95 if(bgmvolume.value != cdvolume)
96 {
97 if(cdvolume)
98 {
99 Cvar_SetValue("bgmvolume",0.0);
100 CDAudio_Pause();
101 }
102 else
103 {
104 Cvar_SetValue("bgmvolume",1.0);
105 CDAudio_Resume();
106 }
107 cdvolume = bgmvolume.value;
108 return;
109 }
110 if(playLooping && (SDL_CDStatus(cd_id) != CD_PLAYING)
111 && (SDL_CDStatus(cd_id) != CD_PAUSED))
112 CDAudio_Play(cd_id->cur_track+1,true);
113}
114
115int CDAudio_Init()
116{
117 if((cls.state == ca_dedicated) || COM_CheckParm("-nocdaudio"))
118 return -1;
119
120 cd_id = SDL_CDOpen(0);
121 if(!cd_id)
122 {
123 Con_Printf("CDAudio_Init: Unable to open default CD-ROM drive: %s\n",
124 SDL_GetError());
125 return -1;
126 }
127
128 initialized = true;
129 enabled = true;
130 cdValid = true;
131
132 if(!CD_INDRIVE(SDL_CDStatus(cd_id)))
133 {
134 Con_Printf("CDAudio_Init: No CD in drive.\n");
135 cdValid = false;
136 }
137 if(!cd_id->numtracks)
138 {
139 Con_Printf("CDAudio_Init: CD contains no audio tracks.\n");
140 cdValid = false;
141 }
142 Cmd_AddCommand("cd",CD_f);
143 Con_Printf("CD Audio Initialized.\n");
144 return 0;
145}
146
147
148void CDAudio_Shutdown()
149{
150 if(!cd_id) return;
151 CDAudio_Stop();
152 SDL_CDClose(cd_id);
153 cd_id = NULL;
154}
155
156static void CD_f()
157{
158 char *command;
159 int cdstate;
160 if(Cmd_Argc() < 2) return;
161
162 command = Cmd_Argv(1);
163 if(!Q_strcasecmp(command,"on"))
164 {
165 enabled = true;
166 }
167 if(!Q_strcasecmp(command,"off"))
168 {
169 if(!cd_id) return;
170 cdstate = SDL_CDStatus(cd_id);
171 if((cdstate == CD_PLAYING) || (cdstate == CD_PAUSED))
172 CDAudio_Stop();
173 enabled = false;
174 return;
175 }
176 if(!Q_strcasecmp(command,"play"))
177 {
178 CDAudio_Play(Q_atoi(Cmd_Argv(2)),false);
179 return;
180 }
181 if(!Q_strcasecmp(command,"loop"))
182 {
183 CDAudio_Play(Q_atoi(Cmd_Argv(2)),true);
184 return;
185 }
186 if(!Q_strcasecmp(command,"stop"))
187 {
188 CDAudio_Stop();
189 return;
190 }
191 if(!Q_strcasecmp(command,"pause"))
192 {
193 CDAudio_Pause();
194 return;
195 }
196 if(!Q_strcasecmp(command,"resume"))
197 {
198 CDAudio_Resume();
199 return;
200 }
201 if(!Q_strcasecmp(command,"eject"))
202 {
203 CDAudio_Eject();
204 return;
205 }
206 if(!Q_strcasecmp(command,"info"))
207 {
208 if(!cd_id) return;
209 cdstate = SDL_CDStatus(cd_id);
210 Con_Printf("%d tracks\n",cd_id->numtracks);
211 if(cdstate == CD_PLAYING)
212 Con_Printf("Currently %s track %d\n",
213 playLooping ? "looping" : "playing",
214 cd_id->cur_track+1);
215 else
216 if(cdstate == CD_PAUSED)
217 Con_Printf("Paused %s track %d\n",
218 playLooping ? "looping" : "playing",
219 cd_id->cur_track+1);
220 return;
221 }
222}
223
diff --git a/apps/plugins/sdl/progs/quake/cdaudio.h b/apps/plugins/sdl/progs/quake/cdaudio.h
new file mode 100644
index 0000000000..80e975be23
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cdaudio.h
@@ -0,0 +1,27 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21int CDAudio_Init(void);
22void CDAudio_Play(byte track, qboolean looping);
23void CDAudio_Stop(void);
24void CDAudio_Pause(void);
25void CDAudio_Resume(void);
26void CDAudio_Shutdown(void);
27void CDAudio_Update(void);
diff --git a/apps/plugins/sdl/progs/quake/chase.c b/apps/plugins/sdl/progs/quake/chase.c
new file mode 100644
index 0000000000..23061e341a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/chase.c
@@ -0,0 +1,92 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// chase.c -- chase camera code
21
22#include "quakedef.h"
23
24cvar_t chase_back = {"chase_back", "100"};
25cvar_t chase_up = {"chase_up", "16"};
26cvar_t chase_right = {"chase_right", "0"};
27cvar_t chase_active = {"chase_active", "0"};
28
29vec3_t chase_pos;
30vec3_t chase_angles;
31
32vec3_t chase_dest;
33vec3_t chase_dest_angles;
34
35
36void Chase_Init (void)
37{
38 Cvar_RegisterVariable (&chase_back);
39 Cvar_RegisterVariable (&chase_up);
40 Cvar_RegisterVariable (&chase_right);
41 Cvar_RegisterVariable (&chase_active);
42}
43
44void Chase_Reset (void)
45{
46 // for respawning and teleporting
47// start position 12 units behind head
48}
49
50void TraceLine (vec3_t start, vec3_t end, vec3_t impact)
51{
52 trace_t trace;
53
54 memset (&trace, 0, sizeof(trace));
55 SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);
56
57 VectorCopy (trace.endpos, impact);
58}
59
60void Chase_Update (void)
61{
62 int i;
63 float dist;
64 vec3_t forward, up, right;
65 vec3_t dest, stop;
66
67
68 // if can't see player, reset
69 AngleVectors (cl.viewangles, forward, right, up);
70
71 // calc exact destination
72 for (i=0 ; i<3 ; i++)
73 chase_dest[i] = r_refdef.vieworg[i]
74 - forward[i]*chase_back.value
75 - right[i]*chase_right.value;
76 chase_dest[2] = r_refdef.vieworg[2] + chase_up.value;
77
78 // find the spot the player is looking at
79 VectorMA (r_refdef.vieworg, 4096, forward, dest);
80 TraceLine (r_refdef.vieworg, dest, stop);
81
82 // calculate pitch to look at the same spot from camera
83 VectorSubtract (stop, r_refdef.vieworg, stop);
84 dist = DotProduct (stop, forward);
85 if (dist < 1)
86 dist = 1;
87 r_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180;
88
89 // move towards destination
90 VectorCopy (chase_dest, r_refdef.vieworg);
91}
92
diff --git a/apps/plugins/sdl/progs/quake/cl_demo.c b/apps/plugins/sdl/progs/quake/cl_demo.c
new file mode 100644
index 0000000000..45ddef3139
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cl_demo.c
@@ -0,0 +1,367 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22
23void CL_FinishTimeDemo (void);
24
25/*
26==============================================================================
27
28DEMO CODE
29
30When a demo is playing back, all NET_SendMessages are skipped, and
31NET_GetMessages are read from the demo file.
32
33Whenever cl.time gets past the last received message, another message is
34read from the demo file.
35==============================================================================
36*/
37
38/*
39==============
40CL_StopPlayback
41
42Called when a demo file runs out, or the user starts a game
43==============
44*/
45void CL_StopPlayback (void)
46{
47 if (!cls.demoplayback)
48 return;
49
50 fclose (cls.demofile);
51 cls.demoplayback = false;
52 cls.demofile = NULL;
53 cls.state = ca_disconnected;
54
55 if (cls.timedemo)
56 CL_FinishTimeDemo ();
57}
58
59/*
60====================
61CL_WriteDemoMessage
62
63Dumps the current net message, prefixed by the length and view angles
64====================
65*/
66void CL_WriteDemoMessage (void)
67{
68 int len;
69 int i;
70 float f;
71
72 len = LittleLong (net_message.cursize);
73 fwrite (&len, 4, 1, cls.demofile);
74 for (i=0 ; i<3 ; i++)
75 {
76 f = LittleFloat (cl.viewangles[i]);
77 fwrite (&f, 4, 1, cls.demofile);
78 }
79 fwrite (net_message.data, net_message.cursize, 1, cls.demofile);
80 fflush (cls.demofile);
81}
82
83/*
84====================
85CL_GetMessage
86
87Handles recording and playback of demos, on top of NET_ code
88====================
89*/
90int CL_GetMessage (void)
91{
92 int r, i;
93 float f;
94
95 if (cls.demoplayback)
96 {
97 // decide if it is time to grab the next message
98 if (cls.signon == SIGNONS) // allways grab until fully connected
99 {
100 if (cls.timedemo)
101 {
102 if (host_framecount == cls.td_lastframe)
103 return 0; // allready read this frame's message
104 cls.td_lastframe = host_framecount;
105 // if this is the second frame, grab the real td_starttime
106 // so the bogus time on the first frame doesn't count
107 if (host_framecount == cls.td_startframe + 1)
108 cls.td_starttime = realtime;
109 }
110 else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])
111 {
112 return 0; // don't need another message yet
113 }
114 }
115
116 // get the next message
117 fread (&net_message.cursize, 4, 1, cls.demofile);
118 VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
119 for (i=0 ; i<3 ; i++)
120 {
121 r = fread (&f, 4, 1, cls.demofile);
122 cl.mviewangles[0][i] = LittleFloat (f);
123 }
124
125 net_message.cursize = LittleLong (net_message.cursize);
126 if (net_message.cursize > MAX_MSGLEN)
127 Sys_Error ("Demo message > MAX_MSGLEN");
128 r = fread (net_message.data, net_message.cursize, 1, cls.demofile);
129 if (r != 1)
130 {
131 CL_StopPlayback ();
132 return 0;
133 }
134
135 return 1;
136 }
137
138 while (1)
139 {
140 r = NET_GetMessage (cls.netcon);
141
142 if (r != 1 && r != 2)
143 return r;
144
145 // discard nop keepalive message
146 if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
147 Con_Printf ("<-- server to client keepalive\n");
148 else
149 break;
150 }
151
152 if (cls.demorecording)
153 CL_WriteDemoMessage ();
154
155 return r;
156}
157
158
159/*
160====================
161CL_Stop_f
162
163stop recording a demo
164====================
165*/
166void CL_Stop_f (void)
167{
168 if (cmd_source != src_command)
169 return;
170
171 if (!cls.demorecording)
172 {
173 Con_Printf ("Not recording a demo.\n");
174 return;
175 }
176
177// write a disconnect message to the demo file
178 SZ_Clear (&net_message);
179 MSG_WriteByte (&net_message, svc_disconnect);
180 CL_WriteDemoMessage ();
181
182// finish up
183 fclose (cls.demofile);
184 cls.demofile = NULL;
185 cls.demorecording = false;
186 Con_Printf ("Completed demo\n");
187}
188
189/*
190====================
191CL_Record_f
192
193record <demoname> <map> [cd track]
194====================
195*/
196void CL_Record_f (void)
197{
198 int c;
199 char name[MAX_OSPATH];
200 int track;
201
202 if (cmd_source != src_command)
203 return;
204
205 c = Cmd_Argc();
206 if (c != 2 && c != 3 && c != 4)
207 {
208 Con_Printf ("record <demoname> [<map> [cd track]]\n");
209 return;
210 }
211
212 if (strstr(Cmd_Argv(1), ".."))
213 {
214 Con_Printf ("Relative pathnames are not allowed.\n");
215 return;
216 }
217
218 if (c == 2 && cls.state == ca_connected)
219 {
220 Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
221 return;
222 }
223
224// write the forced cd track number, or -1
225 if (c == 4)
226 {
227 track = atoi(Cmd_Argv(3));
228 Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
229 }
230 else
231 track = -1;
232
233 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
234
235//
236// start the map up
237//
238 if (c > 2)
239 Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
240
241//
242// open the demo file
243//
244 COM_DefaultExtension (name, ".dem");
245
246 Con_Printf ("recording to %s.\n", name);
247 cls.demofile = fopen (name, "wb");
248 if (!cls.demofile)
249 {
250 Con_Printf ("ERROR: couldn't open.\n");
251 return;
252 }
253
254 cls.forcetrack = track;
255 fprintf (cls.demofile, "%i\n", cls.forcetrack);
256
257 cls.demorecording = true;
258}
259
260
261/*
262====================
263CL_PlayDemo_f
264
265play [demoname]
266====================
267*/
268void CL_PlayDemo_f (void)
269{
270 char name[256];
271 int c;
272 qboolean neg = false;
273
274 if (cmd_source != src_command)
275 return;
276
277 if (Cmd_Argc() != 2)
278 {
279 Con_Printf ("play <demoname> : plays a demo\n");
280 return;
281 }
282
283//
284// disconnect from server
285//
286 CL_Disconnect ();
287
288//
289// open the demo file
290//
291 strcpy (name, Cmd_Argv(1));
292 COM_DefaultExtension (name, ".dem");
293
294 Con_Printf ("Playing demo from %s.\n", name);
295 COM_FOpenFile (name, &cls.demofile);
296 if (!cls.demofile)
297 {
298 Con_Printf ("ERROR: couldn't open.\n");
299 cls.demonum = -1; // stop demo loop
300 return;
301 }
302
303 cls.demoplayback = true;
304 cls.state = ca_connected;
305 cls.forcetrack = 0;
306
307 while ((c = getc(cls.demofile)) != '\n')
308 if (c == '-')
309 neg = true;
310 else
311 cls.forcetrack = cls.forcetrack * 10 + (c - '0');
312
313 if (neg)
314 cls.forcetrack = -cls.forcetrack;
315// ZOID, fscanf is evil
316 //fscanf (cls.demofile, "%i\n", &cls.forcetrack);
317}
318
319/*
320====================
321CL_FinishTimeDemo
322
323====================
324*/
325void CL_FinishTimeDemo (void)
326{
327 int frames;
328 float time;
329
330 cls.timedemo = false;
331
332// the first frame didn't count
333 frames = (host_framecount - cls.td_startframe) - 1;
334 time = realtime - cls.td_starttime;
335 if (!time)
336 time = 1;
337 Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);
338}
339
340/*
341====================
342CL_TimeDemo_f
343
344timedemo [demoname]
345====================
346*/
347void CL_TimeDemo_f (void)
348{
349 if (cmd_source != src_command)
350 return;
351
352 if (Cmd_Argc() != 2)
353 {
354 Con_Printf ("timedemo <demoname> : gets demo speeds\n");
355 return;
356 }
357
358 CL_PlayDemo_f ();
359
360// cls.td_starttime will be grabbed at the second frame of the demo, so
361// all the loading time doesn't get counted
362
363 cls.timedemo = true;
364 cls.td_startframe = host_framecount;
365 cls.td_lastframe = -1; // get a new message this frame
366}
367
diff --git a/apps/plugins/sdl/progs/quake/cl_input.c b/apps/plugins/sdl/progs/quake/cl_input.c
new file mode 100644
index 0000000000..5327b7363e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cl_input.c
@@ -0,0 +1,448 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cl.input.c -- builds an intended movement command to send to the server
21
22// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
23// rights reserved.
24
25#include "quakedef.h"
26
27/*
28===============================================================================
29
30KEY BUTTONS
31
32Continuous button event tracking is complicated by the fact that two different
33input sources (say, mouse button 1 and the control key) can both press the
34same button, but the button should only be released when both of the
35pressing key have been released.
36
37When a key event issues a button command (+forward, +attack, etc), it appends
38its key number as a parameter to the command so it can be matched up with
39the release.
40
41state bit 0 is the current state of the key
42state bit 1 is edge triggered on the up to down transition
43state bit 2 is edge triggered on the down to up transition
44
45===============================================================================
46*/
47
48
49kbutton_t in_mlook, in_klook;
50kbutton_t in_left, in_right, in_forward, in_back;
51kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
52kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack;
53kbutton_t in_up, in_down;
54
55int in_impulse;
56
57
58void KeyDown (kbutton_t *b)
59{
60 int k;
61 char *c;
62
63 c = Cmd_Argv(1);
64 if (c[0])
65 k = atoi(c);
66 else
67 k = -1; // typed manually at the console for continuous down
68
69 if (k == b->down[0] || k == b->down[1])
70 return; // repeating key
71
72 if (!b->down[0])
73 b->down[0] = k;
74 else if (!b->down[1])
75 b->down[1] = k;
76 else
77 {
78 Con_Printf ("Three keys down for a button!\n");
79 return;
80 }
81
82 if (b->state & 1)
83 return; // still down
84 b->state |= 1 + 2; // down + impulse down
85}
86
87void KeyUp (kbutton_t *b)
88{
89 int k;
90 char *c;
91
92 c = Cmd_Argv(1);
93 if (c[0])
94 k = atoi(c);
95 else
96 { // typed manually at the console, assume for unsticking, so clear all
97 b->down[0] = b->down[1] = 0;
98 b->state = 4; // impulse up
99 return;
100 }
101
102 if (b->down[0] == k)
103 b->down[0] = 0;
104 else if (b->down[1] == k)
105 b->down[1] = 0;
106 else
107 return; // key up without coresponding down (menu pass through)
108 if (b->down[0] || b->down[1])
109 return; // some other key is still holding it down
110
111 if (!(b->state & 1))
112 return; // still up (this should not happen)
113 b->state &= ~1; // now up
114 b->state |= 4; // impulse up
115}
116
117void IN_KLookDown (void) {KeyDown(&in_klook);}
118void IN_KLookUp (void) {KeyUp(&in_klook);}
119void IN_MLookDown (void) {KeyDown(&in_mlook);}
120void IN_MLookUp (void) {
121KeyUp(&in_mlook);
122if ( !(in_mlook.state&1) && lookspring.value)
123 V_StartPitchDrift();
124}
125void IN_UpDown(void) {KeyDown(&in_up);}
126void IN_UpUp(void) {KeyUp(&in_up);}
127void IN_DownDown(void) {KeyDown(&in_down);}
128void IN_DownUp(void) {KeyUp(&in_down);}
129void IN_LeftDown(void) {KeyDown(&in_left);}
130void IN_LeftUp(void) {KeyUp(&in_left);}
131void IN_RightDown(void) {KeyDown(&in_right);}
132void IN_RightUp(void) {KeyUp(&in_right);}
133void IN_ForwardDown(void) {KeyDown(&in_forward);}
134void IN_ForwardUp(void) {KeyUp(&in_forward);}
135void IN_BackDown(void) {KeyDown(&in_back);}
136void IN_BackUp(void) {KeyUp(&in_back);}
137void IN_LookupDown(void) {KeyDown(&in_lookup);}
138void IN_LookupUp(void) {KeyUp(&in_lookup);}
139void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
140void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
141void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
142void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
143void IN_MoverightDown(void) {KeyDown(&in_moveright);}
144void IN_MoverightUp(void) {KeyUp(&in_moveright);}
145
146void IN_SpeedDown(void) {KeyDown(&in_speed);}
147void IN_SpeedUp(void) {KeyUp(&in_speed);}
148void IN_StrafeDown(void) {KeyDown(&in_strafe);}
149void IN_StrafeUp(void) {KeyUp(&in_strafe);}
150
151void IN_AttackDown(void) {KeyDown(&in_attack);}
152void IN_AttackUp(void) {KeyUp(&in_attack);}
153
154void IN_UseDown (void) {KeyDown(&in_use);}
155void IN_UseUp (void) {KeyUp(&in_use);}
156void IN_JumpDown (void) {KeyDown(&in_jump);}
157void IN_JumpUp (void) {KeyUp(&in_jump);}
158
159void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));}
160
161/*
162===============
163CL_KeyState
164
165Returns 0.25 if a key was pressed and released during the frame,
1660.5 if it was pressed and held
1670 if held then released, and
1681.0 if held for the entire time
169===============
170*/
171float CL_KeyState (kbutton_t *key)
172{
173 float val;
174 qboolean impulsedown, impulseup, down;
175
176 impulsedown = key->state & 2;
177 impulseup = key->state & 4;
178 down = key->state & 1;
179 val = 0;
180
181 if (impulsedown && !impulseup)
182 if (down)
183 val = 0.5; // pressed and held this frame
184 else
185 val = 0; // I_Error ();
186 if (impulseup && !impulsedown)
187 if (down)
188 val = 0; // I_Error ();
189 else
190 val = 0; // released this frame
191 if (!impulsedown && !impulseup)
192 if (down)
193 val = 1.0; // held the entire frame
194 else
195 val = 0; // up the entire frame
196 if (impulsedown && impulseup)
197 if (down)
198 val = 0.75; // released and re-pressed this frame
199 else
200 val = 0.25; // pressed and released this frame
201
202 key->state &= 1; // clear impulses
203
204 return val;
205}
206
207
208
209
210//==========================================================================
211
212cvar_t cl_upspeed = {"cl_upspeed","200"};
213cvar_t cl_forwardspeed = {"cl_forwardspeed","200", true};
214cvar_t cl_backspeed = {"cl_backspeed","200", true};
215cvar_t cl_sidespeed = {"cl_sidespeed","350"};
216
217cvar_t cl_movespeedkey = {"cl_movespeedkey","2.0"};
218
219cvar_t cl_yawspeed = {"cl_yawspeed","140"};
220cvar_t cl_pitchspeed = {"cl_pitchspeed","150"};
221
222cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5"};
223
224
225/*
226================
227CL_AdjustAngles
228
229Moves the local angle positions
230================
231*/
232void CL_AdjustAngles (void)
233{
234 float speed;
235 float up, down;
236
237 if (in_speed.state & 1)
238 speed = host_frametime * cl_anglespeedkey.value;
239 else
240 speed = host_frametime;
241
242 if (!(in_strafe.state & 1))
243 {
244 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
245 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
246 cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);
247 }
248 if (in_klook.state & 1)
249 {
250 V_StopPitchDrift ();
251 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
252 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
253 }
254
255 up = CL_KeyState (&in_lookup);
256 down = CL_KeyState(&in_lookdown);
257
258 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
259 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
260
261 if (up || down)
262 V_StopPitchDrift ();
263
264 if (cl.viewangles[PITCH] > 80)
265 cl.viewangles[PITCH] = 80;
266 if (cl.viewangles[PITCH] < -70)
267 cl.viewangles[PITCH] = -70;
268
269 if (cl.viewangles[ROLL] > 50)
270 cl.viewangles[ROLL] = 50;
271 if (cl.viewangles[ROLL] < -50)
272 cl.viewangles[ROLL] = -50;
273
274}
275
276/*
277================
278CL_BaseMove
279
280Send the intended movement message to the server
281================
282*/
283void CL_BaseMove (usercmd_t *cmd)
284{
285 if (cls.signon != SIGNONS)
286 return;
287
288 CL_AdjustAngles ();
289
290 Q_memset (cmd, 0, sizeof(*cmd));
291
292 if (in_strafe.state & 1)
293 {
294 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
295 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
296 }
297
298 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
299 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
300
301 cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);
302 cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);
303
304 if (! (in_klook.state & 1) )
305 {
306 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
307 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
308 }
309
310//
311// adjust for speed key
312//
313 if (in_speed.state & 1)
314 {
315 cmd->forwardmove *= cl_movespeedkey.value;
316 cmd->sidemove *= cl_movespeedkey.value;
317 cmd->upmove *= cl_movespeedkey.value;
318 }
319
320#ifdef QUAKE2
321 cmd->lightlevel = cl.light_level;
322#endif
323}
324
325
326
327/*
328==============
329CL_SendMove
330==============
331*/
332void CL_SendMove (usercmd_t *cmd)
333{
334 int i;
335 int bits;
336 sizebuf_t buf;
337 byte data[128];
338
339 buf.maxsize = 128;
340 buf.cursize = 0;
341 buf.data = data;
342
343 cl.cmd = *cmd;
344
345//
346// send the movement message
347//
348 MSG_WriteByte (&buf, clc_move);
349
350 MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
351
352 for (i=0 ; i<3 ; i++)
353 MSG_WriteAngle (&buf, cl.viewangles[i]);
354
355 MSG_WriteShort (&buf, cmd->forwardmove);
356 MSG_WriteShort (&buf, cmd->sidemove);
357 MSG_WriteShort (&buf, cmd->upmove);
358
359//
360// send button bits
361//
362 bits = 0;
363
364 if ( in_attack.state & 3 )
365 bits |= 1;
366 in_attack.state &= ~2;
367
368 if (in_jump.state & 3)
369 bits |= 2;
370 in_jump.state &= ~2;
371
372 MSG_WriteByte (&buf, bits);
373
374 MSG_WriteByte (&buf, in_impulse);
375 in_impulse = 0;
376
377#ifdef QUAKE2
378//
379// light level
380//
381 MSG_WriteByte (&buf, cmd->lightlevel);
382#endif
383
384//
385// deliver the message
386//
387 if (cls.demoplayback)
388 return;
389
390//
391// allways dump the first two message, because it may contain leftover inputs
392// from the last level
393//
394 if (++cl.movemessages <= 2)
395 return;
396
397 if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
398 {
399 Con_Printf ("CL_SendMove: lost server connection\n");
400 CL_Disconnect ();
401 }
402}
403
404/*
405============
406CL_InitInput
407============
408*/
409void CL_InitInput (void)
410{
411 Cmd_AddCommand ("+moveup",IN_UpDown);
412 Cmd_AddCommand ("-moveup",IN_UpUp);
413 Cmd_AddCommand ("+movedown",IN_DownDown);
414 Cmd_AddCommand ("-movedown",IN_DownUp);
415 Cmd_AddCommand ("+left",IN_LeftDown);
416 Cmd_AddCommand ("-left",IN_LeftUp);
417 Cmd_AddCommand ("+right",IN_RightDown);
418 Cmd_AddCommand ("-right",IN_RightUp);
419 Cmd_AddCommand ("+forward",IN_ForwardDown);
420 Cmd_AddCommand ("-forward",IN_ForwardUp);
421 Cmd_AddCommand ("+back",IN_BackDown);
422 Cmd_AddCommand ("-back",IN_BackUp);
423 Cmd_AddCommand ("+lookup", IN_LookupDown);
424 Cmd_AddCommand ("-lookup", IN_LookupUp);
425 Cmd_AddCommand ("+lookdown", IN_LookdownDown);
426 Cmd_AddCommand ("-lookdown", IN_LookdownUp);
427 Cmd_AddCommand ("+strafe", IN_StrafeDown);
428 Cmd_AddCommand ("-strafe", IN_StrafeUp);
429 Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
430 Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
431 Cmd_AddCommand ("+moveright", IN_MoverightDown);
432 Cmd_AddCommand ("-moveright", IN_MoverightUp);
433 Cmd_AddCommand ("+speed", IN_SpeedDown);
434 Cmd_AddCommand ("-speed", IN_SpeedUp);
435 Cmd_AddCommand ("+attack", IN_AttackDown);
436 Cmd_AddCommand ("-attack", IN_AttackUp);
437 Cmd_AddCommand ("+use", IN_UseDown);
438 Cmd_AddCommand ("-use", IN_UseUp);
439 Cmd_AddCommand ("+jump", IN_JumpDown);
440 Cmd_AddCommand ("-jump", IN_JumpUp);
441 Cmd_AddCommand ("impulse", IN_Impulse);
442 Cmd_AddCommand ("+klook", IN_KLookDown);
443 Cmd_AddCommand ("-klook", IN_KLookUp);
444 Cmd_AddCommand ("+mlook", IN_MLookDown);
445 Cmd_AddCommand ("-mlook", IN_MLookUp);
446
447}
448
diff --git a/apps/plugins/sdl/progs/quake/cl_main.c b/apps/plugins/sdl/progs/quake/cl_main.c
new file mode 100644
index 0000000000..58121434bc
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cl_main.c
@@ -0,0 +1,757 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cl_main.c -- client main loop
21
22#include "quakedef.h"
23
24// we need to declare some mouse variables here, because the menu system
25// references them even when on a unix system.
26
27// these two are not intended to be set directly
28cvar_t cl_name = {"_cl_name", "player", true};
29cvar_t cl_color = {"_cl_color", "0", true};
30
31cvar_t cl_shownet = {"cl_shownet","0"}; // can be 0, 1, or 2
32cvar_t cl_nolerp = {"cl_nolerp","0"};
33
34cvar_t lookspring = {"lookspring","0", true};
35cvar_t lookstrafe = {"lookstrafe","0", true};
36cvar_t sensitivity = {"sensitivity","3", true};
37
38cvar_t m_pitch = {"m_pitch","0.022", true};
39cvar_t m_yaw = {"m_yaw","0.022", true};
40cvar_t m_forward = {"m_forward","1", true};
41cvar_t m_side = {"m_side","0.8", true};
42
43
44client_static_t cls;
45client_state_t cl;
46// FIXME: put these on hunk?
47efrag_t cl_efrags[MAX_EFRAGS];
48entity_t cl_entities[MAX_EDICTS];
49entity_t cl_static_entities[MAX_STATIC_ENTITIES];
50lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
51dlight_t cl_dlights[MAX_DLIGHTS];
52
53int cl_numvisedicts;
54entity_t *cl_visedicts[MAX_VISEDICTS];
55
56/*
57=====================
58CL_ClearState
59
60=====================
61*/
62void CL_ClearState (void)
63{
64 int i;
65
66 if (!sv.active)
67 Host_ClearMemory ();
68
69// wipe the entire cl structure
70 memset (&cl, 0, sizeof(cl));
71
72 SZ_Clear (&cls.message);
73
74// clear other arrays
75 memset (cl_efrags, 0, sizeof(cl_efrags));
76 memset (cl_entities, 0, sizeof(cl_entities));
77 memset (cl_dlights, 0, sizeof(cl_dlights));
78 memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
79 memset (cl_temp_entities, 0, sizeof(cl_temp_entities));
80 memset (cl_beams, 0, sizeof(cl_beams));
81
82//
83// allocate the efrags and chain together into a free list
84//
85 cl.free_efrags = cl_efrags;
86 for (i=0 ; i<MAX_EFRAGS-1 ; i++)
87 cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
88 cl.free_efrags[i].entnext = NULL;
89}
90
91/*
92=====================
93CL_Disconnect
94
95Sends a disconnect message to the server
96This is also called on Host_Error, so it shouldn't cause any errors
97=====================
98*/
99void CL_Disconnect (void)
100{
101// stop sounds (especially looping!)
102 S_StopAllSounds (true);
103
104// bring the console down and fade the colors back to normal
105// SCR_BringDownConsole ();
106
107// if running a local server, shut it down
108 if (cls.demoplayback)
109 CL_StopPlayback ();
110 else if (cls.state == ca_connected)
111 {
112 if (cls.demorecording)
113 CL_Stop_f ();
114
115 Con_DPrintf ("Sending clc_disconnect\n");
116 SZ_Clear (&cls.message);
117 MSG_WriteByte (&cls.message, clc_disconnect);
118 NET_SendUnreliableMessage (cls.netcon, &cls.message);
119 SZ_Clear (&cls.message);
120 NET_Close (cls.netcon);
121
122 cls.state = ca_disconnected;
123 if (sv.active)
124 Host_ShutdownServer(false);
125 }
126
127 cls.demoplayback = cls.timedemo = false;
128 cls.signon = 0;
129}
130
131void CL_Disconnect_f (void)
132{
133 CL_Disconnect ();
134 if (sv.active)
135 Host_ShutdownServer (false);
136}
137
138
139
140
141/*
142=====================
143CL_EstablishConnection
144
145Host should be either "local" or a net address to be passed on
146=====================
147*/
148void CL_EstablishConnection (char *host)
149{
150 if (cls.state == ca_dedicated)
151 return;
152
153 if (cls.demoplayback)
154 return;
155
156 CL_Disconnect ();
157
158 cls.netcon = NET_Connect (host);
159 if (!cls.netcon)
160 Host_Error ("CL_Connect: connect failed\n");
161 Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
162
163 cls.demonum = -1; // not in the demo loop now
164 cls.state = ca_connected;
165 cls.signon = 0; // need all the signon messages before playing
166}
167
168/*
169=====================
170CL_SignonReply
171
172An svc_signonnum has been received, perform a client side setup
173=====================
174*/
175void CL_SignonReply (void)
176{
177 char str[8192];
178
179Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
180
181 switch (cls.signon)
182 {
183 case 1:
184 MSG_WriteByte (&cls.message, clc_stringcmd);
185 MSG_WriteString (&cls.message, "prespawn");
186 break;
187
188 case 2:
189 MSG_WriteByte (&cls.message, clc_stringcmd);
190 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
191
192 MSG_WriteByte (&cls.message, clc_stringcmd);
193 MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));
194
195 MSG_WriteByte (&cls.message, clc_stringcmd);
196 sprintf (str, "spawn %s", cls.spawnparms);
197 MSG_WriteString (&cls.message, str);
198 break;
199
200 case 3:
201 MSG_WriteByte (&cls.message, clc_stringcmd);
202 MSG_WriteString (&cls.message, "begin");
203 Cache_Report (); // print remaining memory
204 break;
205
206 case 4:
207 SCR_EndLoadingPlaque (); // allow normal screen updates
208 break;
209 }
210}
211
212/*
213=====================
214CL_NextDemo
215
216Called to play the next demo in the demo loop
217=====================
218*/
219void CL_NextDemo (void)
220{
221 char str[1024];
222
223 if (cls.demonum == -1)
224 return; // don't play demos
225
226 SCR_BeginLoadingPlaque ();
227
228 if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
229 {
230 cls.demonum = 0;
231 if (!cls.demos[cls.demonum][0])
232 {
233 Con_Printf ("No demos listed with startdemos\n");
234 cls.demonum = -1;
235 return;
236 }
237 }
238
239 sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
240 Cbuf_InsertText (str);
241 cls.demonum++;
242}
243
244/*
245==============
246CL_PrintEntities_f
247==============
248*/
249void CL_PrintEntities_f (void)
250{
251 entity_t *ent;
252 int i;
253
254 for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
255 {
256 Con_Printf ("%3i:",i);
257 if (!ent->model)
258 {
259 Con_Printf ("EMPTY\n");
260 continue;
261 }
262 Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
263 ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
264 }
265}
266
267
268/*
269===============
270SetPal
271
272Debugging tool, just flashes the screen
273===============
274*/
275void SetPal (int i)
276{
277#if 0
278 static int old;
279 byte pal[768];
280 int c;
281
282 if (i == old)
283 return;
284 old = i;
285
286 if (i==0)
287 VID_SetPalette (host_basepal);
288 else if (i==1)
289 {
290 for (c=0 ; c<768 ; c+=3)
291 {
292 pal[c] = 0;
293 pal[c+1] = 255;
294 pal[c+2] = 0;
295 }
296 VID_SetPalette (pal);
297 }
298 else
299 {
300 for (c=0 ; c<768 ; c+=3)
301 {
302 pal[c] = 0;
303 pal[c+1] = 0;
304 pal[c+2] = 255;
305 }
306 VID_SetPalette (pal);
307 }
308#endif
309}
310
311/*
312===============
313CL_AllocDlight
314
315===============
316*/
317dlight_t *CL_AllocDlight (int key)
318{
319 int i;
320 dlight_t *dl;
321
322// first look for an exact key match
323 if (key)
324 {
325 dl = cl_dlights;
326 for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
327 {
328 if (dl->key == key)
329 {
330 memset (dl, 0, sizeof(*dl));
331 dl->key = key;
332 return dl;
333 }
334 }
335 }
336
337// then look for anything else
338 dl = cl_dlights;
339 for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
340 {
341 if (dl->die < cl.time)
342 {
343 memset (dl, 0, sizeof(*dl));
344 dl->key = key;
345 return dl;
346 }
347 }
348
349 dl = &cl_dlights[0];
350 memset (dl, 0, sizeof(*dl));
351 dl->key = key;
352 return dl;
353}
354
355
356/*
357===============
358CL_DecayLights
359
360===============
361*/
362void CL_DecayLights (void)
363{
364 int i;
365 dlight_t *dl;
366 float time;
367
368 time = cl.time - cl.oldtime;
369
370 dl = cl_dlights;
371 for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
372 {
373 if (dl->die < cl.time || !dl->radius)
374 continue;
375
376 dl->radius -= time*dl->decay;
377 if (dl->radius < 0)
378 dl->radius = 0;
379 }
380}
381
382
383/*
384===============
385CL_LerpPoint
386
387Determines the fraction between the last two messages that the objects
388should be put at.
389===============
390*/
391float CL_LerpPoint (void)
392{
393 float f, frac;
394
395 f = cl.mtime[0] - cl.mtime[1];
396
397 if (!f || cl_nolerp.value || cls.timedemo || sv.active)
398 {
399 cl.time = cl.mtime[0];
400 return 1;
401 }
402
403 if (f > 0.1)
404 { // dropped packet, or start of demo
405 cl.mtime[1] = cl.mtime[0] - 0.1;
406 f = 0.1;
407 }
408 frac = (cl.time - cl.mtime[1]) / f;
409//Con_Printf ("frac: %f\n",frac);
410 if (frac < 0)
411 {
412 if (frac < -0.01)
413 {
414SetPal(1);
415 cl.time = cl.mtime[1];
416// Con_Printf ("low frac\n");
417 }
418 frac = 0;
419 }
420 else if (frac > 1)
421 {
422 if (frac > 1.01)
423 {
424SetPal(2);
425 cl.time = cl.mtime[0];
426// Con_Printf ("high frac\n");
427 }
428 frac = 1;
429 }
430 else
431 SetPal(0);
432
433 return frac;
434}
435
436
437/*
438===============
439CL_RelinkEntities
440===============
441*/
442void CL_RelinkEntities (void)
443{
444 entity_t *ent;
445 int i, j;
446 float frac, f, d;
447 vec3_t delta;
448 float bobjrotate;
449 vec3_t oldorg;
450 dlight_t *dl;
451
452// determine partial update time
453 frac = CL_LerpPoint ();
454
455 cl_numvisedicts = 0;
456
457//
458// interpolate player info
459//
460 for (i=0 ; i<3 ; i++)
461 cl.velocity[i] = cl.mvelocity[1][i] +
462 frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);
463
464 if (cls.demoplayback)
465 {
466 // interpolate the angles
467 for (j=0 ; j<3 ; j++)
468 {
469 d = cl.mviewangles[0][j] - cl.mviewangles[1][j];
470 if (d > 180)
471 d -= 360;
472 else if (d < -180)
473 d += 360;
474 cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;
475 }
476 }
477
478 bobjrotate = anglemod(100*cl.time);
479
480// start on the entity after the world
481 for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)
482 {
483 if (!ent->model)
484 { // empty slot
485 if (ent->forcelink)
486 R_RemoveEfrags (ent); // just became empty
487 continue;
488 }
489
490// if the object wasn't included in the last packet, remove it
491 if (ent->msgtime != cl.mtime[0])
492 {
493 ent->model = NULL;
494 continue;
495 }
496
497 VectorCopy (ent->origin, oldorg);
498
499 if (ent->forcelink)
500 { // the entity was not updated in the last message
501 // so move to the final spot
502 VectorCopy (ent->msg_origins[0], ent->origin);
503 VectorCopy (ent->msg_angles[0], ent->angles);
504 }
505 else
506 { // if the delta is large, assume a teleport and don't lerp
507 f = frac;
508 for (j=0 ; j<3 ; j++)
509 {
510 delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
511 if (delta[j] > 100 || delta[j] < -100)
512 f = 1; // assume a teleportation, not a motion
513 }
514
515 // interpolate the origin and angles
516 for (j=0 ; j<3 ; j++)
517 {
518 ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
519
520 d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
521 if (d > 180)
522 d -= 360;
523 else if (d < -180)
524 d += 360;
525 ent->angles[j] = ent->msg_angles[1][j] + f*d;
526 }
527
528 }
529
530// rotate binary objects locally
531 if (ent->model->flags & EF_ROTATE)
532 ent->angles[1] = bobjrotate;
533
534 if (ent->effects & EF_BRIGHTFIELD)
535 R_EntityParticles (ent);
536#ifdef QUAKE2
537 if (ent->effects & EF_DARKFIELD)
538 R_DarkFieldParticles (ent);
539#endif
540 if (ent->effects & EF_MUZZLEFLASH)
541 {
542 vec3_t fv, rv, uv;
543
544 dl = CL_AllocDlight (i);
545 VectorCopy (ent->origin, dl->origin);
546 dl->origin[2] += 16;
547 AngleVectors (ent->angles, fv, rv, uv);
548
549 VectorMA (dl->origin, 18, fv, dl->origin);
550 dl->radius = 200 + (rand()&31);
551 dl->minlight = 32;
552 dl->die = cl.time + 0.1;
553 }
554 if (ent->effects & EF_BRIGHTLIGHT)
555 {
556 dl = CL_AllocDlight (i);
557 VectorCopy (ent->origin, dl->origin);
558 dl->origin[2] += 16;
559 dl->radius = 400 + (rand()&31);
560 dl->die = cl.time + 0.001;
561 }
562 if (ent->effects & EF_DIMLIGHT)
563 {
564 dl = CL_AllocDlight (i);
565 VectorCopy (ent->origin, dl->origin);
566 dl->radius = 200 + (rand()&31);
567 dl->die = cl.time + 0.001;
568 }
569#ifdef QUAKE2
570 if (ent->effects & EF_DARKLIGHT)
571 {
572 dl = CL_AllocDlight (i);
573 VectorCopy (ent->origin, dl->origin);
574 dl->radius = 200.0 + (rand()&31);
575 dl->die = cl.time + 0.001;
576 dl->dark = true;
577 }
578 if (ent->effects & EF_LIGHT)
579 {
580 dl = CL_AllocDlight (i);
581 VectorCopy (ent->origin, dl->origin);
582 dl->radius = 200;
583 dl->die = cl.time + 0.001;
584 }
585#endif
586
587 if (ent->model->flags & EF_GIB)
588 R_RocketTrail (oldorg, ent->origin, 2);
589 else if (ent->model->flags & EF_ZOMGIB)
590 R_RocketTrail (oldorg, ent->origin, 4);
591 else if (ent->model->flags & EF_TRACER)
592 R_RocketTrail (oldorg, ent->origin, 3);
593 else if (ent->model->flags & EF_TRACER2)
594 R_RocketTrail (oldorg, ent->origin, 5);
595 else if (ent->model->flags & EF_ROCKET)
596 {
597 R_RocketTrail (oldorg, ent->origin, 0);
598 dl = CL_AllocDlight (i);
599 VectorCopy (ent->origin, dl->origin);
600 dl->radius = 200;
601 dl->die = cl.time + 0.01;
602 }
603 else if (ent->model->flags & EF_GRENADE)
604 R_RocketTrail (oldorg, ent->origin, 1);
605 else if (ent->model->flags & EF_TRACER3)
606 R_RocketTrail (oldorg, ent->origin, 6);
607
608 ent->forcelink = false;
609
610 if (i == cl.viewentity && !chase_active.value)
611 continue;
612
613#ifdef QUAKE2
614 if ( ent->effects & EF_NODRAW )
615 continue;
616#endif
617 if (cl_numvisedicts < MAX_VISEDICTS)
618 {
619 cl_visedicts[cl_numvisedicts] = ent;
620 cl_numvisedicts++;
621 }
622 }
623
624}
625
626
627/*
628===============
629CL_ReadFromServer
630
631Read all incoming data from the server
632===============
633*/
634int CL_ReadFromServer (void)
635{
636 int ret;
637
638 cl.oldtime = cl.time;
639 cl.time += host_frametime;
640
641 do
642 {
643 ret = CL_GetMessage ();
644 if (ret == -1)
645 Host_Error ("CL_ReadFromServer: lost server connection");
646 if (!ret)
647 break;
648
649 cl.last_received_message = realtime;
650 CL_ParseServerMessage ();
651 } while (ret && cls.state == ca_connected);
652
653 if (cl_shownet.value)
654 Con_Printf ("\n");
655
656 CL_RelinkEntities ();
657 CL_UpdateTEnts ();
658
659//
660// bring the links up to date
661//
662 return 0;
663}
664
665/*
666=================
667CL_SendCmd
668=================
669*/
670void CL_SendCmd (void)
671{
672 usercmd_t cmd;
673
674 if (cls.state != ca_connected)
675 return;
676
677 if (cls.signon == SIGNONS)
678 {
679 // get basic movement from keyboard
680 CL_BaseMove (&cmd);
681
682 // allow mice or other external controllers to add to the move
683 IN_Move (&cmd);
684
685 // send the unreliable message
686 CL_SendMove (&cmd);
687
688 }
689
690 if (cls.demoplayback)
691 {
692 SZ_Clear (&cls.message);
693 return;
694 }
695
696// send the reliable message
697 if (!cls.message.cursize)
698 return; // no message at all
699
700 if (!NET_CanSendMessage (cls.netcon))
701 {
702 Con_DPrintf ("CL_WriteToServer: can't send\n");
703 return;
704 }
705
706 if (NET_SendMessage (cls.netcon, &cls.message) == -1)
707 Host_Error ("CL_WriteToServer: lost server connection");
708
709 SZ_Clear (&cls.message);
710}
711
712/*
713=================
714CL_Init
715=================
716*/
717void CL_Init (void)
718{
719 SZ_Alloc (&cls.message, 1024);
720
721 CL_InitInput ();
722 CL_InitTEnts ();
723
724//
725// register our commands
726//
727 Cvar_RegisterVariable (&cl_name);
728 Cvar_RegisterVariable (&cl_color);
729 Cvar_RegisterVariable (&cl_upspeed);
730 Cvar_RegisterVariable (&cl_forwardspeed);
731 Cvar_RegisterVariable (&cl_backspeed);
732 Cvar_RegisterVariable (&cl_sidespeed);
733 Cvar_RegisterVariable (&cl_movespeedkey);
734 Cvar_RegisterVariable (&cl_yawspeed);
735 Cvar_RegisterVariable (&cl_pitchspeed);
736 Cvar_RegisterVariable (&cl_anglespeedkey);
737 Cvar_RegisterVariable (&cl_shownet);
738 Cvar_RegisterVariable (&cl_nolerp);
739 Cvar_RegisterVariable (&lookspring);
740 Cvar_RegisterVariable (&lookstrafe);
741 Cvar_RegisterVariable (&sensitivity);
742
743 Cvar_RegisterVariable (&m_pitch);
744 Cvar_RegisterVariable (&m_yaw);
745 Cvar_RegisterVariable (&m_forward);
746 Cvar_RegisterVariable (&m_side);
747
748// Cvar_RegisterVariable (&cl_autofire);
749
750 Cmd_AddCommand ("entities", CL_PrintEntities_f);
751 Cmd_AddCommand ("disconnect", CL_Disconnect_f);
752 Cmd_AddCommand ("record", CL_Record_f);
753 Cmd_AddCommand ("stop", CL_Stop_f);
754 Cmd_AddCommand ("playdemo", CL_PlayDemo_f);
755 Cmd_AddCommand ("timedemo", CL_TimeDemo_f);
756}
757
diff --git a/apps/plugins/sdl/progs/quake/cl_parse.c b/apps/plugins/sdl/progs/quake/cl_parse.c
new file mode 100644
index 0000000000..c79ca47545
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cl_parse.c
@@ -0,0 +1,963 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cl_parse.c -- parse a message received from the server
21
22#include "quakedef.h"
23
24char *svc_strings[] =
25{
26 "svc_bad",
27 "svc_nop",
28 "svc_disconnect",
29 "svc_updatestat",
30 "svc_version", // [long] server version
31 "svc_setview", // [short] entity number
32 "svc_sound", // <see code>
33 "svc_time", // [float] server time
34 "svc_print", // [string] null terminated string
35 "svc_stufftext", // [string] stuffed into client's console buffer
36 // the string should be \n terminated
37 "svc_setangle", // [vec3] set the view angle to this absolute value
38
39 "svc_serverinfo", // [long] version
40 // [string] signon string
41 // [string]..[0]model cache [string]...[0]sounds cache
42 // [string]..[0]item cache
43 "svc_lightstyle", // [byte] [string]
44 "svc_updatename", // [byte] [string]
45 "svc_updatefrags", // [byte] [short]
46 "svc_clientdata", // <shortbits + data>
47 "svc_stopsound", // <see code>
48 "svc_updatecolors", // [byte] [byte]
49 "svc_particle", // [vec3] <variable>
50 "svc_damage", // [byte] impact [byte] blood [vec3] from
51
52 "svc_spawnstatic",
53 "OBSOLETE svc_spawnbinary",
54 "svc_spawnbaseline",
55
56 "svc_temp_entity", // <variable>
57 "svc_setpause",
58 "svc_signonnum",
59 "svc_centerprint",
60 "svc_killedmonster",
61 "svc_foundsecret",
62 "svc_spawnstaticsound",
63 "svc_intermission",
64 "svc_finale", // [string] music [string] text
65 "svc_cdtrack", // [byte] track [byte] looptrack
66 "svc_sellscreen",
67 "svc_cutscene"
68};
69
70//=============================================================================
71
72/*
73===============
74CL_EntityNum
75
76This error checks and tracks the total number of entities
77===============
78*/
79entity_t *CL_EntityNum (int num)
80{
81 if (num >= cl.num_entities)
82 {
83 if (num >= MAX_EDICTS)
84 Host_Error ("CL_EntityNum: %i is an invalid number",num);
85 while (cl.num_entities<=num)
86 {
87 cl_entities[cl.num_entities].colormap = vid.colormap;
88 cl.num_entities++;
89 }
90 }
91
92 return &cl_entities[num];
93}
94
95
96/*
97==================
98CL_ParseStartSoundPacket
99==================
100*/
101void CL_ParseStartSoundPacket(void)
102{
103 vec3_t pos;
104 int channel, ent;
105 int sound_num;
106 int volume;
107 int field_mask;
108 float attenuation;
109 int i;
110
111 field_mask = MSG_ReadByte();
112
113 if (field_mask & SND_VOLUME)
114 volume = MSG_ReadByte ();
115 else
116 volume = DEFAULT_SOUND_PACKET_VOLUME;
117
118 if (field_mask & SND_ATTENUATION)
119 attenuation = MSG_ReadByte () / 64.0;
120 else
121 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
122
123 channel = MSG_ReadShort ();
124 sound_num = MSG_ReadByte ();
125
126 ent = channel >> 3;
127 channel &= 7;
128
129 if (ent > MAX_EDICTS)
130 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
131
132 for (i=0 ; i<3 ; i++)
133 pos[i] = MSG_ReadCoord ();
134
135 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
136}
137
138/*
139==================
140CL_KeepaliveMessage
141
142When the client is taking a long time to load stuff, send keepalive messages
143so the server doesn't disconnect.
144==================
145*/
146void CL_KeepaliveMessage (void)
147{
148 float time;
149 static float lastmsg;
150 int ret;
151 sizebuf_t old;
152 byte olddata[8192];
153
154 if (sv.active)
155 return; // no need if server is local
156 if (cls.demoplayback)
157 return;
158
159// read messages from server, should just be nops
160 old = net_message;
161 memcpy (olddata, net_message.data, net_message.cursize);
162
163 do
164 {
165 ret = CL_GetMessage ();
166 switch (ret)
167 {
168 default:
169 Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
170 case 0:
171 break; // nothing waiting
172 case 1:
173 Host_Error ("CL_KeepaliveMessage: received a message");
174 break;
175 case 2:
176 if (MSG_ReadByte() != svc_nop)
177 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
178 break;
179 }
180 } while (ret);
181
182 net_message = old;
183 memcpy (net_message.data, olddata, net_message.cursize);
184
185// check time
186 time = Sys_FloatTime ();
187 if (time - lastmsg < 5)
188 return;
189 lastmsg = time;
190
191// write out a nop
192 Con_Printf ("--> client to server keepalive\n");
193
194 MSG_WriteByte (&cls.message, clc_nop);
195 NET_SendMessage (cls.netcon, &cls.message);
196 SZ_Clear (&cls.message);
197}
198
199/*
200==================
201CL_ParseServerInfo
202==================
203*/
204void CL_ParseServerInfo (void)
205{
206 char *str;
207 int i;
208 int nummodels, numsounds;
209 char model_precache[MAX_MODELS][MAX_QPATH];
210 char sound_precache[MAX_SOUNDS][MAX_QPATH];
211
212 Con_DPrintf ("Serverinfo packet received.\n");
213//
214// wipe the client_state_t struct
215//
216 CL_ClearState ();
217
218// parse protocol version number
219 i = MSG_ReadLong ();
220 if (i != PROTOCOL_VERSION)
221 {
222 Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION);
223 return;
224 }
225
226// parse maxclients
227 cl.maxclients = MSG_ReadByte ();
228 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
229 {
230 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
231 return;
232 }
233 cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
234
235// parse gametype
236 cl.gametype = MSG_ReadByte ();
237
238// parse signon message
239 str = MSG_ReadString ();
240 strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
241
242// seperate the printfs so the server message can have a color
243 Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
244 Con_Printf ("%c%s\n", 2, str);
245
246//
247// first we go through and touch all of the precache data that still
248// happens to be in the cache, so precaching something else doesn't
249// needlessly purge it
250//
251
252// precache models
253 memset (cl.model_precache, 0, sizeof(cl.model_precache));
254 for (nummodels=1 ; ; nummodels++)
255 {
256 str = MSG_ReadString ();
257 if (!str[0])
258 break;
259 if (nummodels==MAX_MODELS)
260 {
261 Con_Printf ("Server sent too many model precaches\n");
262 return;
263 }
264 strcpy (model_precache[nummodels], str);
265 Mod_TouchModel (str);
266 }
267
268// precache sounds
269 memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
270 for (numsounds=1 ; ; numsounds++)
271 {
272 str = MSG_ReadString ();
273 if (!str[0])
274 break;
275 if (numsounds==MAX_SOUNDS)
276 {
277 Con_Printf ("Server sent too many sound precaches\n");
278 return;
279 }
280 strcpy (sound_precache[numsounds], str);
281 S_TouchSound (str);
282 }
283
284//
285// now we try to load everything else until a cache allocation fails
286//
287
288 for (i=1 ; i<nummodels ; i++)
289 {
290 cl.model_precache[i] = Mod_ForName (model_precache[i], false);
291 if (cl.model_precache[i] == NULL)
292 {
293 Con_Printf("Model %s not found\n", model_precache[i]);
294 return;
295 }
296 CL_KeepaliveMessage ();
297 }
298
299 S_BeginPrecaching ();
300 for (i=1 ; i<numsounds ; i++)
301 {
302 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
303 CL_KeepaliveMessage ();
304 }
305 S_EndPrecaching ();
306
307
308// local state
309 cl_entities[0].model = cl.worldmodel = cl.model_precache[1];
310
311 R_NewMap ();
312
313 Hunk_Check (); // make sure nothing is hurt
314
315 noclip_anglehack = false; // noclip is turned off at start
316}
317
318
319/*
320==================
321CL_ParseUpdate
322
323Parse an entity update message from the server
324If an entities model or origin changes from frame to frame, it must be
325relinked. Other attributes can change without relinking.
326==================
327*/
328int bitcounts[16];
329
330void CL_ParseUpdate (int bits)
331{
332 int i;
333 model_t *model;
334 int modnum;
335 qboolean forcelink;
336 entity_t *ent;
337 int num;
338 int skin;
339
340 if (cls.signon == SIGNONS - 1)
341 { // first update is the final signon stage
342 cls.signon = SIGNONS;
343 CL_SignonReply ();
344 }
345
346 if (bits & U_MOREBITS)
347 {
348 i = MSG_ReadByte ();
349 bits |= (i<<8);
350 }
351
352 if (bits & U_LONGENTITY)
353 num = MSG_ReadShort ();
354 else
355 num = MSG_ReadByte ();
356
357 ent = CL_EntityNum (num);
358
359for (i=0 ; i<16 ; i++)
360if (bits&(1<<i))
361 bitcounts[i]++;
362
363 if (ent->msgtime != cl.mtime[1])
364 forcelink = true; // no previous frame to lerp from
365 else
366 forcelink = false;
367
368 ent->msgtime = cl.mtime[0];
369
370 if (bits & U_MODEL)
371 {
372 modnum = MSG_ReadByte ();
373 if (modnum >= MAX_MODELS)
374 Host_Error ("CL_ParseModel: bad modnum");
375 }
376 else
377 modnum = ent->baseline.modelindex;
378
379 model = cl.model_precache[modnum];
380 if (model != ent->model)
381 {
382 ent->model = model;
383 // automatic animation (torches, etc) can be either all together
384 // or randomized
385 if (model)
386 {
387 if (model->synctype == ST_RAND)
388 ent->syncbase = (float)(rand()&0x7fff) / 0x7fff;
389 else
390 ent->syncbase = 0.0;
391 }
392 else
393 forcelink = true; // hack to make null model players work
394#ifdef GLQUAKE
395 if (num > 0 && num <= cl.maxclients)
396 R_TranslatePlayerSkin (num - 1);
397#endif
398 }
399
400 if (bits & U_FRAME)
401 ent->frame = MSG_ReadByte ();
402 else
403 ent->frame = ent->baseline.frame;
404
405 if (bits & U_COLORMAP)
406 i = MSG_ReadByte();
407 else
408 i = ent->baseline.colormap;
409 if (!i)
410 ent->colormap = vid.colormap;
411 else
412 {
413 if (i > cl.maxclients)
414 Sys_Error ("i >= cl.maxclients");
415 ent->colormap = cl.scores[i-1].translations;
416 }
417
418#ifdef GLQUAKE
419 if (bits & U_SKIN)
420 skin = MSG_ReadByte();
421 else
422 skin = ent->baseline.skin;
423 if (skin != ent->skinnum) {
424 ent->skinnum = skin;
425 if (num > 0 && num <= cl.maxclients)
426 R_TranslatePlayerSkin (num - 1);
427 }
428
429#else
430
431 if (bits & U_SKIN)
432 ent->skinnum = MSG_ReadByte();
433 else
434 ent->skinnum = ent->baseline.skin;
435#endif
436
437 if (bits & U_EFFECTS)
438 ent->effects = MSG_ReadByte();
439 else
440 ent->effects = ent->baseline.effects;
441
442// shift the known values for interpolation
443 VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
444 VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
445
446 if (bits & U_ORIGIN1)
447 ent->msg_origins[0][0] = MSG_ReadCoord ();
448 else
449 ent->msg_origins[0][0] = ent->baseline.origin[0];
450 if (bits & U_ANGLE1)
451 ent->msg_angles[0][0] = MSG_ReadAngle();
452 else
453 ent->msg_angles[0][0] = ent->baseline.angles[0];
454
455 if (bits & U_ORIGIN2)
456 ent->msg_origins[0][1] = MSG_ReadCoord ();
457 else
458 ent->msg_origins[0][1] = ent->baseline.origin[1];
459 if (bits & U_ANGLE2)
460 ent->msg_angles[0][1] = MSG_ReadAngle();
461 else
462 ent->msg_angles[0][1] = ent->baseline.angles[1];
463
464 if (bits & U_ORIGIN3)
465 ent->msg_origins[0][2] = MSG_ReadCoord ();
466 else
467 ent->msg_origins[0][2] = ent->baseline.origin[2];
468 if (bits & U_ANGLE3)
469 ent->msg_angles[0][2] = MSG_ReadAngle();
470 else
471 ent->msg_angles[0][2] = ent->baseline.angles[2];
472
473 if ( bits & U_NOLERP )
474 ent->forcelink = true;
475
476 if ( forcelink )
477 { // didn't have an update last message
478 VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
479 VectorCopy (ent->msg_origins[0], ent->origin);
480 VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
481 VectorCopy (ent->msg_angles[0], ent->angles);
482 ent->forcelink = true;
483 }
484}
485
486/*
487==================
488CL_ParseBaseline
489==================
490*/
491void CL_ParseBaseline (entity_t *ent)
492{
493 int i;
494
495 ent->baseline.modelindex = MSG_ReadByte ();
496 ent->baseline.frame = MSG_ReadByte ();
497 ent->baseline.colormap = MSG_ReadByte();
498 ent->baseline.skin = MSG_ReadByte();
499 for (i=0 ; i<3 ; i++)
500 {
501 ent->baseline.origin[i] = MSG_ReadCoord ();
502 ent->baseline.angles[i] = MSG_ReadAngle ();
503 }
504}
505
506
507/*
508==================
509CL_ParseClientdata
510
511Server information pertaining to this client only
512==================
513*/
514void CL_ParseClientdata (int bits)
515{
516 int i, j;
517
518 if (bits & SU_VIEWHEIGHT)
519 cl.viewheight = MSG_ReadChar ();
520 else
521 cl.viewheight = DEFAULT_VIEWHEIGHT;
522
523 if (bits & SU_IDEALPITCH)
524 cl.idealpitch = MSG_ReadChar ();
525 else
526 cl.idealpitch = 0;
527
528 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
529 for (i=0 ; i<3 ; i++)
530 {
531 if (bits & (SU_PUNCH1<<i) )
532 cl.punchangle[i] = MSG_ReadChar();
533 else
534 cl.punchangle[i] = 0;
535 if (bits & (SU_VELOCITY1<<i) )
536 cl.mvelocity[0][i] = MSG_ReadChar()*16;
537 else
538 cl.mvelocity[0][i] = 0;
539 }
540
541// [always sent] if (bits & SU_ITEMS)
542 i = MSG_ReadLong ();
543
544 if (cl.items != i)
545 { // set flash times
546 Sbar_Changed ();
547 for (j=0 ; j<32 ; j++)
548 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
549 cl.item_gettime[j] = cl.time;
550 cl.items = i;
551 }
552
553 cl.onground = (bits & SU_ONGROUND) != 0;
554 cl.inwater = (bits & SU_INWATER) != 0;
555
556 if (bits & SU_WEAPONFRAME)
557 cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
558 else
559 cl.stats[STAT_WEAPONFRAME] = 0;
560
561 if (bits & SU_ARMOR)
562 i = MSG_ReadByte ();
563 else
564 i = 0;
565 if (cl.stats[STAT_ARMOR] != i)
566 {
567 cl.stats[STAT_ARMOR] = i;
568 Sbar_Changed ();
569 }
570
571 if (bits & SU_WEAPON)
572 i = MSG_ReadByte ();
573 else
574 i = 0;
575 if (cl.stats[STAT_WEAPON] != i)
576 {
577 cl.stats[STAT_WEAPON] = i;
578 Sbar_Changed ();
579 }
580
581 i = MSG_ReadShort ();
582 if (cl.stats[STAT_HEALTH] != i)
583 {
584 cl.stats[STAT_HEALTH] = i;
585 Sbar_Changed ();
586 }
587
588 i = MSG_ReadByte ();
589 if (cl.stats[STAT_AMMO] != i)
590 {
591 cl.stats[STAT_AMMO] = i;
592 Sbar_Changed ();
593 }
594
595 for (i=0 ; i<4 ; i++)
596 {
597 j = MSG_ReadByte ();
598 if (cl.stats[STAT_SHELLS+i] != j)
599 {
600 cl.stats[STAT_SHELLS+i] = j;
601 Sbar_Changed ();
602 }
603 }
604
605 i = MSG_ReadByte ();
606
607 if (standard_quake)
608 {
609 if (cl.stats[STAT_ACTIVEWEAPON] != i)
610 {
611 cl.stats[STAT_ACTIVEWEAPON] = i;
612 Sbar_Changed ();
613 }
614 }
615 else
616 {
617 if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
618 {
619 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
620 Sbar_Changed ();
621 }
622 }
623}
624
625/*
626=====================
627CL_NewTranslation
628=====================
629*/
630void CL_NewTranslation (int slot)
631{
632 int i, j;
633 int top, bottom;
634 byte *dest, *source;
635
636 if (slot > cl.maxclients)
637 Sys_Error ("CL_NewTranslation: slot > cl.maxclients");
638 dest = cl.scores[slot].translations;
639 source = vid.colormap;
640 memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations));
641 top = cl.scores[slot].colors & 0xf0;
642 bottom = (cl.scores[slot].colors &15)<<4;
643#ifdef GLQUAKE
644 R_TranslatePlayerSkin (slot);
645#endif
646
647 for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
648 {
649 if (top < 128) // the artists made some backwards ranges. sigh.
650 memcpy (dest + TOP_RANGE, source + top, 16);
651 else
652 for (j=0 ; j<16 ; j++)
653 dest[TOP_RANGE+j] = source[top+15-j];
654
655 if (bottom < 128)
656 memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
657 else
658 for (j=0 ; j<16 ; j++)
659 dest[BOTTOM_RANGE+j] = source[bottom+15-j];
660 }
661}
662
663/*
664=====================
665CL_ParseStatic
666=====================
667*/
668void CL_ParseStatic (void)
669{
670 entity_t *ent;
671 int i;
672
673 i = cl.num_statics;
674 if (i >= MAX_STATIC_ENTITIES)
675 Host_Error ("Too many static entities");
676 ent = &cl_static_entities[i];
677 cl.num_statics++;
678 CL_ParseBaseline (ent);
679
680// copy it to the current state
681 ent->model = cl.model_precache[ent->baseline.modelindex];
682 ent->frame = ent->baseline.frame;
683 ent->colormap = vid.colormap;
684 ent->skinnum = ent->baseline.skin;
685 ent->effects = ent->baseline.effects;
686
687 VectorCopy (ent->baseline.origin, ent->origin);
688 VectorCopy (ent->baseline.angles, ent->angles);
689 R_AddEfrags (ent);
690}
691
692/*
693===================
694CL_ParseStaticSound
695===================
696*/
697void CL_ParseStaticSound (void)
698{
699 vec3_t org;
700 int sound_num, vol, atten;
701 int i;
702
703 for (i=0 ; i<3 ; i++)
704 org[i] = MSG_ReadCoord ();
705 sound_num = MSG_ReadByte ();
706 vol = MSG_ReadByte ();
707 atten = MSG_ReadByte ();
708
709 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
710}
711
712
713#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
714
715/*
716=====================
717CL_ParseServerMessage
718=====================
719*/
720void CL_ParseServerMessage (void)
721{
722 int cmd;
723 int i;
724
725//
726// if recording demos, copy the message out
727//
728 if (cl_shownet.value == 1)
729 Con_Printf ("%i ",net_message.cursize);
730 else if (cl_shownet.value == 2)
731 Con_Printf ("------------------\n");
732
733 cl.onground = false; // unless the server says otherwise
734//
735// parse the message
736//
737 MSG_BeginReading ();
738
739 while (1)
740 {
741 if (msg_badread)
742 Host_Error ("CL_ParseServerMessage: Bad server message");
743
744 cmd = MSG_ReadByte ();
745
746 if (cmd == -1)
747 {
748 SHOWNET("END OF MESSAGE");
749 return; // end of message
750 }
751
752 // if the high bit of the command byte is set, it is a fast update
753 if (cmd & 128)
754 {
755 SHOWNET("fast update");
756 CL_ParseUpdate (cmd&127);
757 continue;
758 }
759
760 SHOWNET(svc_strings[cmd]);
761
762 // other commands
763 switch (cmd)
764 {
765 default:
766 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
767 break;
768
769 case svc_nop:
770// Con_Printf ("svc_nop\n");
771 break;
772
773 case svc_time:
774 cl.mtime[1] = cl.mtime[0];
775 cl.mtime[0] = MSG_ReadFloat ();
776 break;
777
778 case svc_clientdata:
779 i = MSG_ReadShort ();
780 CL_ParseClientdata (i);
781 break;
782
783 case svc_version:
784 i = MSG_ReadLong ();
785 if (i != PROTOCOL_VERSION)
786 Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION);
787 break;
788
789 case svc_disconnect:
790 Host_EndGame ("Server disconnected\n");
791
792 case svc_print:
793 Con_Printf ("%s", MSG_ReadString ());
794 break;
795
796 case svc_centerprint:
797 SCR_CenterPrint (MSG_ReadString ());
798 break;
799
800 case svc_stufftext:
801 Cbuf_AddText (MSG_ReadString ());
802 break;
803
804 case svc_damage:
805 V_ParseDamage ();
806 break;
807
808 case svc_serverinfo:
809 CL_ParseServerInfo ();
810 vid.recalc_refdef = true; // leave intermission full screen
811 break;
812
813 case svc_setangle:
814 for (i=0 ; i<3 ; i++)
815 cl.viewangles[i] = MSG_ReadAngle ();
816 break;
817
818 case svc_setview:
819 cl.viewentity = MSG_ReadShort ();
820 break;
821
822 case svc_lightstyle:
823 i = MSG_ReadByte ();
824 if (i >= MAX_LIGHTSTYLES)
825 Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
826 Q_strcpy (cl_lightstyle[i].map, MSG_ReadString());
827 cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map);
828 break;
829
830 case svc_sound:
831 CL_ParseStartSoundPacket();
832 break;
833
834 case svc_stopsound:
835 i = MSG_ReadShort();
836 S_StopSound(i>>3, i&7);
837 break;
838
839 case svc_updatename:
840 Sbar_Changed ();
841 i = MSG_ReadByte ();
842 if (i >= cl.maxclients)
843 Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD");
844 strcpy (cl.scores[i].name, MSG_ReadString ());
845 break;
846
847 case svc_updatefrags:
848 Sbar_Changed ();
849 i = MSG_ReadByte ();
850 if (i >= cl.maxclients)
851 Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
852 cl.scores[i].frags = MSG_ReadShort ();
853 break;
854
855 case svc_updatecolors:
856 Sbar_Changed ();
857 i = MSG_ReadByte ();
858 if (i >= cl.maxclients)
859 Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
860 cl.scores[i].colors = MSG_ReadByte ();
861 CL_NewTranslation (i);
862 break;
863
864 case svc_particle:
865 R_ParseParticleEffect ();
866 break;
867
868 case svc_spawnbaseline:
869 i = MSG_ReadShort ();
870 // must use CL_EntityNum() to force cl.num_entities up
871 CL_ParseBaseline (CL_EntityNum(i));
872 break;
873 case svc_spawnstatic:
874 CL_ParseStatic ();
875 break;
876 case svc_temp_entity:
877 CL_ParseTEnt ();
878 break;
879
880 case svc_setpause:
881 {
882 cl.paused = MSG_ReadByte ();
883
884 if (cl.paused)
885 {
886 CDAudio_Pause ();
887#ifdef _WIN32
888 VID_HandlePause (true);
889#endif
890 }
891 else
892 {
893 CDAudio_Resume ();
894#ifdef _WIN32
895 VID_HandlePause (false);
896#endif
897 }
898 }
899 break;
900
901 case svc_signonnum:
902 i = MSG_ReadByte ();
903 if (i <= cls.signon)
904 Host_Error ("Received signon %i when at %i", i, cls.signon);
905 cls.signon = i;
906 CL_SignonReply ();
907 break;
908
909 case svc_killedmonster:
910 cl.stats[STAT_MONSTERS]++;
911 break;
912
913 case svc_foundsecret:
914 cl.stats[STAT_SECRETS]++;
915 break;
916
917 case svc_updatestat:
918 i = MSG_ReadByte ();
919 if (i < 0 || i >= MAX_CL_STATS)
920 Sys_Error ("svc_updatestat: %i is invalid", i);
921 cl.stats[i] = MSG_ReadLong ();;
922 break;
923
924 case svc_spawnstaticsound:
925 CL_ParseStaticSound ();
926 break;
927
928 case svc_cdtrack:
929 cl.cdtrack = MSG_ReadByte ();
930 cl.looptrack = MSG_ReadByte ();
931 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
932 CDAudio_Play ((byte)cls.forcetrack, true);
933 else
934 CDAudio_Play ((byte)cl.cdtrack, true);
935 break;
936
937 case svc_intermission:
938 cl.intermission = 1;
939 cl.completed_time = cl.time;
940 vid.recalc_refdef = true; // go to full screen
941 break;
942
943 case svc_finale:
944 cl.intermission = 2;
945 cl.completed_time = cl.time;
946 vid.recalc_refdef = true; // go to full screen
947 SCR_CenterPrint (MSG_ReadString ());
948 break;
949
950 case svc_cutscene:
951 cl.intermission = 3;
952 cl.completed_time = cl.time;
953 vid.recalc_refdef = true; // go to full screen
954 SCR_CenterPrint (MSG_ReadString ());
955 break;
956
957 case svc_sellscreen:
958 Cmd_ExecuteString ("help", src_command);
959 break;
960 }
961 }
962}
963
diff --git a/apps/plugins/sdl/progs/quake/cl_tent.c b/apps/plugins/sdl/progs/quake/cl_tent.c
new file mode 100644
index 0000000000..546e832f8b
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cl_tent.c
@@ -0,0 +1,394 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cl_tent.c -- client side temporary entities
21
22#include "quakedef.h"
23
24int num_temp_entities;
25entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
26beam_t cl_beams[MAX_BEAMS];
27
28sfx_t *cl_sfx_wizhit;
29sfx_t *cl_sfx_knighthit;
30sfx_t *cl_sfx_tink1;
31sfx_t *cl_sfx_ric1;
32sfx_t *cl_sfx_ric2;
33sfx_t *cl_sfx_ric3;
34sfx_t *cl_sfx_r_exp3;
35#ifdef QUAKE2
36sfx_t *cl_sfx_imp;
37sfx_t *cl_sfx_rail;
38#endif
39
40/*
41=================
42CL_ParseTEnt
43=================
44*/
45void CL_InitTEnts (void)
46{
47 cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav");
48 cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav");
49 cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav");
50 cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav");
51 cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav");
52 cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav");
53 cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav");
54#ifdef QUAKE2
55 cl_sfx_imp = S_PrecacheSound ("shambler/sattck1.wav");
56 cl_sfx_rail = S_PrecacheSound ("weapons/lstart.wav");
57#endif
58}
59
60/*
61=================
62CL_ParseBeam
63=================
64*/
65void CL_ParseBeam (model_t *m)
66{
67 int ent;
68 vec3_t start, end;
69 beam_t *b;
70 int i;
71
72 ent = MSG_ReadShort ();
73
74 start[0] = MSG_ReadCoord ();
75 start[1] = MSG_ReadCoord ();
76 start[2] = MSG_ReadCoord ();
77
78 end[0] = MSG_ReadCoord ();
79 end[1] = MSG_ReadCoord ();
80 end[2] = MSG_ReadCoord ();
81
82// override any beam with the same entity
83 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
84 if (b->entity == ent)
85 {
86 b->entity = ent;
87 b->model = m;
88 b->endtime = cl.time + 0.2;
89 VectorCopy (start, b->start);
90 VectorCopy (end, b->end);
91 return;
92 }
93
94// find a free beam
95 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
96 {
97 if (!b->model || b->endtime < cl.time)
98 {
99 b->entity = ent;
100 b->model = m;
101 b->endtime = cl.time + 0.2;
102 VectorCopy (start, b->start);
103 VectorCopy (end, b->end);
104 return;
105 }
106 }
107 Con_Printf ("beam list overflow!\n");
108}
109
110/*
111=================
112CL_ParseTEnt
113=================
114*/
115void CL_ParseTEnt (void)
116{
117 int type;
118 vec3_t pos;
119#ifdef QUAKE2
120 vec3_t endpos;
121#endif
122 dlight_t *dl;
123 int rnd;
124 int colorStart, colorLength;
125
126 type = MSG_ReadByte ();
127 switch (type)
128 {
129 case TE_WIZSPIKE: // spike hitting wall
130 pos[0] = MSG_ReadCoord ();
131 pos[1] = MSG_ReadCoord ();
132 pos[2] = MSG_ReadCoord ();
133 R_RunParticleEffect (pos, vec3_origin, 20, 30);
134 S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
135 break;
136
137 case TE_KNIGHTSPIKE: // spike hitting wall
138 pos[0] = MSG_ReadCoord ();
139 pos[1] = MSG_ReadCoord ();
140 pos[2] = MSG_ReadCoord ();
141 R_RunParticleEffect (pos, vec3_origin, 226, 20);
142 S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
143 break;
144
145 case TE_SPIKE: // spike hitting wall
146 pos[0] = MSG_ReadCoord ();
147 pos[1] = MSG_ReadCoord ();
148 pos[2] = MSG_ReadCoord ();
149#ifdef GLTEST
150 Test_Spawn (pos);
151#else
152 R_RunParticleEffect (pos, vec3_origin, 0, 10);
153#endif
154 if ( rand() % 5 )
155 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
156 else
157 {
158 rnd = rand() & 3;
159 if (rnd == 1)
160 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
161 else if (rnd == 2)
162 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
163 else
164 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
165 }
166 break;
167 case TE_SUPERSPIKE: // super spike hitting wall
168 pos[0] = MSG_ReadCoord ();
169 pos[1] = MSG_ReadCoord ();
170 pos[2] = MSG_ReadCoord ();
171 R_RunParticleEffect (pos, vec3_origin, 0, 20);
172
173 if ( rand() % 5 )
174 S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
175 else
176 {
177 rnd = rand() & 3;
178 if (rnd == 1)
179 S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
180 else if (rnd == 2)
181 S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
182 else
183 S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
184 }
185 break;
186
187 case TE_GUNSHOT: // bullet hitting wall
188 pos[0] = MSG_ReadCoord ();
189 pos[1] = MSG_ReadCoord ();
190 pos[2] = MSG_ReadCoord ();
191 R_RunParticleEffect (pos, vec3_origin, 0, 20);
192 break;
193
194 case TE_EXPLOSION: // rocket explosion
195 pos[0] = MSG_ReadCoord ();
196 pos[1] = MSG_ReadCoord ();
197 pos[2] = MSG_ReadCoord ();
198 R_ParticleExplosion (pos);
199 dl = CL_AllocDlight (0);
200 VectorCopy (pos, dl->origin);
201 dl->radius = 350;
202 dl->die = cl.time + 0.5;
203 dl->decay = 300;
204 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
205 break;
206
207 case TE_TAREXPLOSION: // tarbaby explosion
208 pos[0] = MSG_ReadCoord ();
209 pos[1] = MSG_ReadCoord ();
210 pos[2] = MSG_ReadCoord ();
211 R_BlobExplosion (pos);
212
213 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
214 break;
215
216 case TE_LIGHTNING1: // lightning bolts
217 CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
218 break;
219
220 case TE_LIGHTNING2: // lightning bolts
221 CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
222 break;
223
224 case TE_LIGHTNING3: // lightning bolts
225 CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
226 break;
227
228// PGM 01/21/97
229 case TE_BEAM: // grappling hook beam
230 CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
231 break;
232// PGM 01/21/97
233
234 case TE_LAVASPLASH:
235 pos[0] = MSG_ReadCoord ();
236 pos[1] = MSG_ReadCoord ();
237 pos[2] = MSG_ReadCoord ();
238 R_LavaSplash (pos);
239 break;
240
241 case TE_TELEPORT:
242 pos[0] = MSG_ReadCoord ();
243 pos[1] = MSG_ReadCoord ();
244 pos[2] = MSG_ReadCoord ();
245 R_TeleportSplash (pos);
246 break;
247
248 case TE_EXPLOSION2: // color mapped explosion
249 pos[0] = MSG_ReadCoord ();
250 pos[1] = MSG_ReadCoord ();
251 pos[2] = MSG_ReadCoord ();
252 colorStart = MSG_ReadByte ();
253 colorLength = MSG_ReadByte ();
254 R_ParticleExplosion2 (pos, colorStart, colorLength);
255 dl = CL_AllocDlight (0);
256 VectorCopy (pos, dl->origin);
257 dl->radius = 350;
258 dl->die = cl.time + 0.5;
259 dl->decay = 300;
260 S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
261 break;
262
263#ifdef QUAKE2
264 case TE_IMPLOSION:
265 pos[0] = MSG_ReadCoord ();
266 pos[1] = MSG_ReadCoord ();
267 pos[2] = MSG_ReadCoord ();
268 S_StartSound (-1, 0, cl_sfx_imp, pos, 1, 1);
269 break;
270
271 case TE_RAILTRAIL:
272 pos[0] = MSG_ReadCoord ();
273 pos[1] = MSG_ReadCoord ();
274 pos[2] = MSG_ReadCoord ();
275 endpos[0] = MSG_ReadCoord ();
276 endpos[1] = MSG_ReadCoord ();
277 endpos[2] = MSG_ReadCoord ();
278 S_StartSound (-1, 0, cl_sfx_rail, pos, 1, 1);
279 S_StartSound (-1, 1, cl_sfx_r_exp3, endpos, 1, 1);
280 R_RocketTrail (pos, endpos, 0+128);
281 R_ParticleExplosion (endpos);
282 dl = CL_AllocDlight (-1);
283 VectorCopy (endpos, dl->origin);
284 dl->radius = 350;
285 dl->die = cl.time + 0.5;
286 dl->decay = 300;
287 break;
288#endif
289
290 default:
291 Sys_Error ("CL_ParseTEnt: bad type");
292 }
293}
294
295
296/*
297=================
298CL_NewTempEntity
299=================
300*/
301entity_t *CL_NewTempEntity (void)
302{
303 entity_t *ent;
304
305 if (cl_numvisedicts == MAX_VISEDICTS)
306 return NULL;
307 if (num_temp_entities == MAX_TEMP_ENTITIES)
308 return NULL;
309 ent = &cl_temp_entities[num_temp_entities];
310 memset (ent, 0, sizeof(*ent));
311 num_temp_entities++;
312 cl_visedicts[cl_numvisedicts] = ent;
313 cl_numvisedicts++;
314
315 ent->colormap = vid.colormap;
316 return ent;
317}
318
319
320/*
321=================
322CL_UpdateTEnts
323=================
324*/
325void CL_UpdateTEnts (void)
326{
327 int i;
328 beam_t *b;
329 vec3_t dist, org;
330 float d;
331 entity_t *ent;
332 float yaw, pitch;
333 float forward;
334
335 num_temp_entities = 0;
336
337// update lightning
338 for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
339 {
340 if (!b->model || b->endtime < cl.time)
341 continue;
342
343 // if coming from the player, update the start position
344 if (b->entity == cl.viewentity)
345 {
346 VectorCopy (cl_entities[cl.viewentity].origin, b->start);
347 }
348
349 // calculate pitch and yaw
350 VectorSubtract (b->end, b->start, dist);
351
352 if (dist[1] == 0 && dist[0] == 0)
353 {
354 yaw = 0;
355 if (dist[2] > 0)
356 pitch = 90;
357 else
358 pitch = 270;
359 }
360 else
361 {
362 yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);
363 if (yaw < 0)
364 yaw += 360;
365
366 forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);
367 pitch = (int) (atan2(dist[2], forward) * 180 / M_PI);
368 if (pitch < 0)
369 pitch += 360;
370 }
371
372 // add new entities for the lightning
373 VectorCopy (b->start, org);
374 d = VectorNormalize(dist);
375 while (d > 0)
376 {
377 ent = CL_NewTempEntity ();
378 if (!ent)
379 return;
380 VectorCopy (org, ent->origin);
381 ent->model = b->model;
382 ent->angles[0] = pitch;
383 ent->angles[1] = yaw;
384 ent->angles[2] = rand()%360;
385
386 for (i=0 ; i<3 ; i++)
387 org[i] += dist[i]*30;
388 d -= 30;
389 }
390 }
391
392}
393
394
diff --git a/apps/plugins/sdl/progs/quake/clean.bat b/apps/plugins/sdl/progs/quake/clean.bat
new file mode 100644
index 0000000000..8a5aad4867
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/clean.bat
@@ -0,0 +1,18 @@
1rmdir /s /q debug
2rmdir /s /q release
3rmdir /s /q debug_gl
4rmdir /s /q release_gl
5
6rmdir /s /q gas2masm\debug
7rmdir /s /q gas2masm\release
8
9del gas2masm\gas2masm.opt
10del gas2masm\gas2masm.plg
11del gas2masm\gas2masm.ncb
12del gas2masm\gas2masm.stt
13
14del WinQuake.opt
15del WinQuake.plg
16del WinQuake.ncb
17del WinQuake.stt
18
diff --git a/apps/plugins/sdl/progs/quake/client.h b/apps/plugins/sdl/progs/quake/client.h
new file mode 100644
index 0000000000..4d52bf907e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/client.h
@@ -0,0 +1,376 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// client.h
21
22typedef struct
23{
24 vec3_t viewangles;
25
26// intended velocities
27 float forwardmove;
28 float sidemove;
29 float upmove;
30#ifdef QUAKE2
31 byte lightlevel;
32#endif
33} usercmd_t;
34
35typedef struct
36{
37 int length;
38 char map[MAX_STYLESTRING];
39} lightstyle_t;
40
41typedef struct
42{
43 char name[MAX_SCOREBOARDNAME];
44 float entertime;
45 int frags;
46 int colors; // two 4 bit fields
47 byte translations[VID_GRADES*256];
48} scoreboard_t;
49
50typedef struct
51{
52 int destcolor[3];
53 int percent; // 0-256
54} cshift_t;
55
56#define CSHIFT_CONTENTS 0
57#define CSHIFT_DAMAGE 1
58#define CSHIFT_BONUS 2
59#define CSHIFT_POWERUP 3
60#define NUM_CSHIFTS 4
61
62#define NAME_LENGTH 64
63
64
65//
66// client_state_t should hold all pieces of the client state
67//
68
69#define SIGNONS 4 // signon messages to receive before connected
70
71#define MAX_DLIGHTS 32
72typedef struct
73{
74 vec3_t origin;
75 float radius;
76 float die; // stop lighting after this time
77 float decay; // drop this each second
78 float minlight; // don't add when contributing less
79 int key;
80#ifdef QUAKE2
81 qboolean dark; // subtracts light instead of adding
82#endif
83} dlight_t;
84
85
86#define MAX_BEAMS 24
87typedef struct
88{
89 int entity;
90 struct model_s *model;
91 float endtime;
92 vec3_t start, end;
93} beam_t;
94
95#define MAX_EFRAGS 640
96
97#define MAX_MAPSTRING 2048
98#define MAX_DEMOS 8
99#define MAX_DEMONAME 16
100
101typedef int cactive_t;
102enum {
103ca_dedicated, // a dedicated server with no ability to start a client
104ca_disconnected, // full screen console with no connection
105ca_connected // valid netcon, talking to a server
106};
107
108//
109// the client_static_t structure is persistant through an arbitrary number
110// of server connections
111//
112typedef struct
113{
114 cactive_t state;
115
116// personalization data sent to server
117 char mapstring[MAX_QPATH];
118 char spawnparms[MAX_MAPSTRING]; // to restart a level
119
120// demo loop control
121 int demonum; // -1 = don't play demos
122 char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing
123
124// demo recording info must be here, because record is started before
125// entering a map (and clearing client_state_t)
126 qboolean demorecording;
127 qboolean demoplayback;
128 qboolean timedemo;
129 int forcetrack; // -1 = use normal cd track
130 FILE *demofile;
131 int td_lastframe; // to meter out one message a frame
132 int td_startframe; // host_framecount at start
133 float td_starttime; // realtime at second frame of timedemo
134
135
136// connection information
137 int signon; // 0 to SIGNONS
138 struct qsocket_s *netcon;
139 sizebuf_t message; // writing buffer to send to server
140
141} client_static_t;
142
143extern client_static_t cls;
144
145//
146// the client_state_t structure is wiped completely at every
147// server signon
148//
149typedef struct
150{
151 int movemessages; // since connecting to this server
152 // throw out the first couple, so the player
153 // doesn't accidentally do something the
154 // first frame
155 usercmd_t cmd; // last command sent to the server
156
157// information for local display
158 int stats[MAX_CL_STATS]; // health, etc
159 int items; // inventory bit flags
160 float item_gettime[32]; // cl.time of aquiring item, for blinking
161 float faceanimtime; // use anim frame if cl.time < this
162
163 cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups
164 cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types
165
166// the client maintains its own idea of view angles, which are
167// sent to the server each frame. The server sets punchangle when
168// the view is temporarliy offset, and an angle reset commands at the start
169// of each level and after teleporting.
170 vec3_t mviewangles[2]; // during demo playback viewangles is lerped
171 // between these
172 vec3_t viewangles;
173
174 vec3_t mvelocity[2]; // update by server, used for lean+bob
175 // (0 is newest)
176 vec3_t velocity; // lerped between mvelocity[0] and [1]
177
178 vec3_t punchangle; // temporary offset
179
180// pitch drifting vars
181 float idealpitch;
182 float pitchvel;
183 qboolean nodrift;
184 float driftmove;
185 double laststop;
186
187 float viewheight;
188 float crouch; // local amount for smoothing stepups
189
190 qboolean paused; // send over by server
191 qboolean onground;
192 qboolean inwater;
193
194 int intermission; // don't change view angle, full screen, etc
195 int completed_time; // latched at intermission start
196
197 double mtime[2]; // the timestamp of last two messages
198 double time; // clients view of time, should be between
199 // servertime and oldservertime to generate
200 // a lerp point for other data
201 double oldtime; // previous cl.time, time-oldtime is used
202 // to decay light values and smooth step ups
203
204
205 float last_received_message; // (realtime) for net trouble icon
206
207//
208// information that is static for the entire time connected to a server
209//
210 struct model_s *model_precache[MAX_MODELS];
211 struct sfx_s *sound_precache[MAX_SOUNDS];
212
213 char levelname[40]; // for display on solo scoreboard
214 int viewentity; // cl_entitites[cl.viewentity] = player
215 int maxclients;
216 int gametype;
217
218// refresh related state
219 struct model_s *worldmodel; // cl_entitites[0].model
220 struct efrag_s *free_efrags;
221 int num_entities; // held in cl_entities array
222 int num_statics; // held in cl_staticentities array
223 entity_t viewent; // the gun model
224
225 int cdtrack, looptrack; // cd audio
226
227// frag scoreboard
228 scoreboard_t *scores; // [cl.maxclients]
229
230#ifdef QUAKE2
231// light level at player's position including dlights
232// this is sent back to the server each frame
233// architectually ugly but it works
234 int light_level;
235#endif
236} client_state_t;
237
238
239//
240// cvars
241//
242extern cvar_t cl_name;
243extern cvar_t cl_color;
244
245extern cvar_t cl_upspeed;
246extern cvar_t cl_forwardspeed;
247extern cvar_t cl_backspeed;
248extern cvar_t cl_sidespeed;
249
250extern cvar_t cl_movespeedkey;
251
252extern cvar_t cl_yawspeed;
253extern cvar_t cl_pitchspeed;
254
255extern cvar_t cl_anglespeedkey;
256
257extern cvar_t cl_autofire;
258
259extern cvar_t cl_shownet;
260extern cvar_t cl_nolerp;
261
262extern cvar_t cl_pitchdriftspeed;
263extern cvar_t lookspring;
264extern cvar_t lookstrafe;
265extern cvar_t sensitivity;
266
267extern cvar_t m_pitch;
268extern cvar_t m_yaw;
269extern cvar_t m_forward;
270extern cvar_t m_side;
271
272
273#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc
274#define MAX_STATIC_ENTITIES 128 // torches, etc
275
276extern client_state_t cl;
277
278// FIXME, allocate dynamically
279extern efrag_t cl_efrags[MAX_EFRAGS];
280extern entity_t cl_entities[MAX_EDICTS];
281extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
282extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
283extern dlight_t cl_dlights[MAX_DLIGHTS];
284extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES];
285extern beam_t cl_beams[MAX_BEAMS];
286
287//=============================================================================
288
289//
290// cl_main
291//
292dlight_t *CL_AllocDlight (int key);
293void CL_DecayLights (void);
294
295void CL_Init (void);
296
297void CL_EstablishConnection (char *host);
298void CL_Signon1 (void);
299void CL_Signon2 (void);
300void CL_Signon3 (void);
301void CL_Signon4 (void);
302
303void CL_Disconnect (void);
304void CL_Disconnect_f (void);
305void CL_NextDemo (void);
306
307#define MAX_VISEDICTS 256
308extern int cl_numvisedicts;
309extern entity_t *cl_visedicts[MAX_VISEDICTS];
310
311//
312// cl_input
313//
314typedef struct
315{
316 int down[2]; // key nums holding it down
317 int state; // low bit is down state
318} kbutton_t;
319
320extern kbutton_t in_mlook, in_klook;
321extern kbutton_t in_strafe;
322extern kbutton_t in_speed;
323
324void CL_InitInput (void);
325void CL_SendCmd (void);
326void CL_SendMove (usercmd_t *cmd);
327
328void CL_ParseTEnt (void);
329void CL_UpdateTEnts (void);
330
331void CL_ClearState (void);
332
333
334int CL_ReadFromServer (void);
335void CL_WriteToServer (usercmd_t *cmd);
336void CL_BaseMove (usercmd_t *cmd);
337
338
339float CL_KeyState (kbutton_t *key);
340char *Key_KeynumToString (int keynum);
341
342//
343// cl_demo.c
344//
345void CL_StopPlayback (void);
346int CL_GetMessage (void);
347
348void CL_Stop_f (void);
349void CL_Record_f (void);
350void CL_PlayDemo_f (void);
351void CL_TimeDemo_f (void);
352
353//
354// cl_parse.c
355//
356void CL_ParseServerMessage (void);
357void CL_NewTranslation (int slot);
358
359//
360// view
361//
362void V_StartPitchDrift (void);
363void V_StopPitchDrift (void);
364
365void V_RenderView (void);
366void V_UpdatePalette (void);
367void V_Register (void);
368void V_ParseDamage (void);
369void V_SetContentsColor (int contents);
370
371
372//
373// cl_tent
374//
375void CL_InitTEnts (void);
376void CL_SignonReply (void);
diff --git a/apps/plugins/sdl/progs/quake/cmd.c b/apps/plugins/sdl/progs/quake/cmd.c
new file mode 100644
index 0000000000..95807065d3
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cmd.c
@@ -0,0 +1,721 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cmd.c -- Quake script command processing module
21
22#include "quakedef.h"
23
24void Cmd_ForwardToServer (void);
25
26#define MAX_ALIAS_NAME 32
27
28typedef struct cmdalias_s
29{
30 struct cmdalias_s *next;
31 char name[MAX_ALIAS_NAME];
32 char *value;
33} cmdalias_t;
34
35cmdalias_t *cmd_alias;
36
37int trashtest;
38int *trashspot;
39
40qboolean cmd_wait;
41
42//=============================================================================
43
44/*
45============
46Cmd_Wait_f
47
48Causes execution of the remainder of the command buffer to be delayed until
49next frame. This allows commands like:
50bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
51============
52*/
53void Cmd_Wait_f (void)
54{
55 cmd_wait = true;
56}
57
58/*
59=============================================================================
60
61 COMMAND BUFFER
62
63=============================================================================
64*/
65
66sizebuf_t cmd_text;
67
68/*
69============
70Cbuf_Init
71============
72*/
73void Cbuf_Init (void)
74{
75 SZ_Alloc (&cmd_text, 8192); // space for commands and script files
76}
77
78
79/*
80============
81Cbuf_AddText
82
83Adds command text at the end of the buffer
84============
85*/
86void Cbuf_AddText (char *text)
87{
88 int l;
89
90 l = Q_strlen (text);
91
92 if (cmd_text.cursize + l >= cmd_text.maxsize)
93 {
94 Con_Printf ("Cbuf_AddText: overflow\n");
95 return;
96 }
97
98 SZ_Write (&cmd_text, text, Q_strlen (text));
99}
100
101
102/*
103============
104Cbuf_InsertText
105
106FW19: before???
107
108Adds command text immediately after the current command
109Adds a \n to the text
110FIXME: actually change the command buffer to do less copying
111============
112*/
113void Cbuf_InsertText (char *text)
114{
115 char *temp;
116 int templen;
117
118// copy off any commands still remaining in the exec buffer
119 templen = cmd_text.cursize;
120 if (templen)
121 {
122 temp = Z_Malloc (templen);
123 Q_memcpy (temp, cmd_text.data, templen);
124 SZ_Clear (&cmd_text);
125 }
126 else
127 temp = NULL; // shut up compiler
128
129// add the entire text of the file
130 Cbuf_AddText (text);
131
132// add the copied off data
133 if (templen)
134 {
135 SZ_Write (&cmd_text, temp, templen);
136 Z_Free (temp);
137 }
138}
139
140/*
141============
142Cbuf_Execute
143============
144*/
145void Cbuf_Execute (void)
146{
147 int i;
148 char *text;
149 char line[1024];
150 int quotes;
151
152 while (cmd_text.cursize)
153 {
154// find a \n or ; line break
155 text = (char *)cmd_text.data;
156
157 quotes = 0;
158 for (i=0 ; i< cmd_text.cursize ; i++)
159 {
160 if (text[i] == '"')
161 quotes++;
162 if ( !(quotes&1) && text[i] == ';')
163 break; // don't break if inside a quoted string
164 if (text[i] == '\n')
165 break;
166 }
167
168
169 memcpy (line, text, i);
170 line[i] = 0;
171
172// delete the text from the command buffer and move remaining commands down
173// this is necessary because commands (exec, alias) can insert data at the
174// beginning of the text buffer
175
176 if (i == cmd_text.cursize)
177 cmd_text.cursize = 0;
178 else
179 {
180 i++;
181 cmd_text.cursize -= i;
182 Q_memcpy (text, text+i, cmd_text.cursize);
183 }
184
185// execute the command line
186 Cmd_ExecuteString (line, src_command);
187
188 if (cmd_wait)
189 { // skip out while text still remains in buffer, leaving it
190 // for next frame
191 cmd_wait = false;
192 break;
193 }
194 }
195}
196
197/*
198==============================================================================
199
200 SCRIPT COMMANDS
201
202==============================================================================
203*/
204
205/*
206===============
207Cmd_StuffCmds_f
208
209Adds command line parameters as script statements
210Commands lead with a +, and continue until a - or another +
211quake +prog jctest.qp +cmd amlev1
212quake -nosound +cmd amlev1
213===============
214*/
215void Cmd_StuffCmds_f (void)
216{
217 int i, j;
218 int s;
219 char *text, *build, c;
220
221 if (Cmd_Argc () != 1)
222 {
223 Con_Printf ("stuffcmds : execute command line parameters\n");
224 return;
225 }
226
227// build the combined string to parse from
228 s = 0;
229 for (i=1 ; i<com_argc ; i++)
230 {
231 if (!com_argv[i])
232 continue; // NEXTSTEP nulls out -NXHost
233 s += Q_strlen (com_argv[i]) + 1;
234 }
235 if (!s)
236 return;
237
238 text = Z_Malloc (s+1);
239 text[0] = 0;
240 for (i=1 ; i<com_argc ; i++)
241 {
242 if (!com_argv[i])
243 continue; // NEXTSTEP nulls out -NXHost
244 Q_strcat (text,com_argv[i]);
245 if (i != com_argc-1)
246 Q_strcat (text, " ");
247 }
248
249// pull out the commands
250 build = Z_Malloc (s+1);
251 build[0] = 0;
252
253 for (i=0 ; i<s-1 ; i++)
254 {
255 if (text[i] == '+')
256 {
257 i++;
258
259 for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
260 ;
261
262 c = text[j];
263 text[j] = 0;
264
265 Q_strcat (build, text+i);
266 Q_strcat (build, "\n");
267 text[j] = c;
268 i = j-1;
269 }
270 }
271
272 if (build[0])
273 Cbuf_InsertText (build);
274
275 Z_Free (text);
276 Z_Free (build);
277}
278
279extern int bind_nooverride;
280
281/*
282===============
283Cmd_Exec_f
284===============
285*/
286void Cmd_Exec_f (void)
287{
288 char *f;
289 int mark;
290
291 if (Cmd_Argc () != 2)
292 {
293 Con_Printf ("exec <filename> : execute a script file\n");
294 return;
295 }
296
297
298 mark = Hunk_LowMark ();
299 f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
300 if (!f)
301 {
302 Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
303 return;
304 }
305 Con_Printf ("execing %s\n",Cmd_Argv(1));
306
307 Cbuf_InsertText (f); // insert to next space in buffer
308 Hunk_FreeToLowMark (mark);
309
310 // if we are running config, tell bind not to override defaults (see keys.c)
311 if(!strcmp(Cmd_Argv(1), "config.cfg"))
312 {
313 // force binds to continue
314 bind_nooverride = 1;
315 }
316 else if(!strcmp(Cmd_Argv(1), "default.cfg"))
317 {
318 // allow override
319 bind_nooverride = 0;
320 }
321}
322
323
324/*
325===============
326Cmd_Echo_f
327
328Just prints the rest of the line to the console
329===============
330*/
331void Cmd_Echo_f (void)
332{
333 int i;
334
335 for (i=1 ; i<Cmd_Argc() ; i++)
336 Con_Printf ("%s ",Cmd_Argv(i));
337 Con_Printf ("\n");
338}
339
340/*
341===============
342Cmd_Alias_f
343
344Creates a new command that executes a command string (possibly ; seperated)
345===============
346*/
347
348char *CopyString (char *in)
349{
350 char *out;
351
352 out = Z_Malloc (strlen(in)+1);
353 strcpy (out, in);
354 return out;
355}
356
357void Cmd_Alias_f (void)
358{
359 cmdalias_t *a;
360 char cmd[1024];
361 int i, c;
362 char *s;
363
364 if (Cmd_Argc() == 1)
365 {
366 Con_Printf ("Current alias commands:\n");
367 for (a = cmd_alias ; a ; a=a->next)
368 Con_Printf ("%s : %s\n", a->name, a->value);
369 return;
370 }
371
372 s = Cmd_Argv(1);
373 if (strlen(s) >= MAX_ALIAS_NAME)
374 {
375 Con_Printf ("Alias name is too long\n");
376 return;
377 }
378
379 // if the alias allready exists, reuse it
380 for (a = cmd_alias ; a ; a=a->next)
381 {
382 if (!strcmp(s, a->name))
383 {
384 Z_Free (a->value);
385 break;
386 }
387 }
388
389 if (!a)
390 {
391 a = Z_Malloc (sizeof(cmdalias_t));
392 a->next = cmd_alias;
393 cmd_alias = a;
394 }
395 strcpy (a->name, s);
396
397// copy the rest of the command line
398 cmd[0] = 0; // start out with a null string
399 c = Cmd_Argc();
400 for (i=2 ; i< c ; i++)
401 {
402 strcat (cmd, Cmd_Argv(i));
403 if (i != c)
404 strcat (cmd, " ");
405 }
406 strcat (cmd, "\n");
407
408 a->value = CopyString (cmd);
409}
410
411/*
412=============================================================================
413
414 COMMAND EXECUTION
415
416=============================================================================
417*/
418
419typedef struct cmd_function_s
420{
421 struct cmd_function_s *next;
422 char *name;
423 xcommand_t function;
424} cmd_function_t;
425
426
427#define MAX_ARGS 80
428
429static int cmd_argc;
430static char *cmd_argv[MAX_ARGS];
431static char *cmd_null_string = "";
432static char *cmd_args = NULL;
433
434cmd_source_t cmd_source;
435
436
437static cmd_function_t *cmd_functions; // possible commands to execute
438
439/*
440============
441Cmd_Init
442============
443*/
444void Cmd_Init (void)
445{
446//
447// register our commands
448//
449 Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
450 Cmd_AddCommand ("exec",Cmd_Exec_f);
451 Cmd_AddCommand ("echo",Cmd_Echo_f);
452 Cmd_AddCommand ("alias",Cmd_Alias_f);
453 Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
454 Cmd_AddCommand ("wait", Cmd_Wait_f);
455}
456
457/*
458============
459Cmd_Argc
460============
461*/
462int Cmd_Argc (void)
463{
464 return cmd_argc;
465}
466
467/*
468============
469Cmd_Argv
470============
471*/
472char *Cmd_Argv (int arg)
473{
474 if ( (unsigned)arg >= cmd_argc )
475 return cmd_null_string;
476 return cmd_argv[arg];
477}
478
479/*
480============
481Cmd_Args
482============
483*/
484char *Cmd_Args (void)
485{
486 return cmd_args;
487}
488
489
490/*
491============
492Cmd_TokenizeString
493
494Parses the given string into command line tokens.
495============
496*/
497void Cmd_TokenizeString (char *text)
498{
499 int i;
500
501// clear the args from the last string
502 for (i=0 ; i<cmd_argc ; i++)
503 Z_Free (cmd_argv[i]);
504
505 cmd_argc = 0;
506 cmd_args = NULL;
507
508 while (1)
509 {
510// skip whitespace up to a /n
511 while (*text && *text <= ' ' && *text != '\n')
512 {
513 text++;
514 }
515
516 if (*text == '\n')
517 { // a newline seperates commands in the buffer
518 text++;
519 break;
520 }
521
522 if (!*text)
523 return;
524
525 if (cmd_argc == 1)
526 cmd_args = text;
527
528 text = COM_Parse (text);
529 if (!text)
530 return;
531
532 if (cmd_argc < MAX_ARGS)
533 {
534 cmd_argv[cmd_argc] = Z_Malloc (Q_strlen(com_token)+1);
535 Q_strcpy (cmd_argv[cmd_argc], com_token);
536 cmd_argc++;
537 }
538 }
539
540}
541
542
543/*
544============
545Cmd_AddCommand
546============
547*/
548void Cmd_AddCommand (char *cmd_name, xcommand_t function)
549{
550 cmd_function_t *cmd;
551
552 if (host_initialized) // because hunk allocation would get stomped
553 Sys_Error ("Cmd_AddCommand after host_initialized");
554
555// fail if the command is a variable name
556 if (Cvar_VariableString(cmd_name)[0])
557 {
558 Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
559 return;
560 }
561
562// fail if the command already exists
563 for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
564 {
565 if (!Q_strcmp (cmd_name, cmd->name))
566 {
567 Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
568 return;
569 }
570 }
571
572 cmd = Hunk_Alloc (sizeof(cmd_function_t));
573 cmd->name = cmd_name;
574 cmd->function = function;
575 cmd->next = cmd_functions;
576 cmd_functions = cmd;
577}
578
579/*
580============
581Cmd_Exists
582============
583*/
584qboolean Cmd_Exists (char *cmd_name)
585{
586 cmd_function_t *cmd;
587
588 for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
589 {
590 if (!Q_strcmp (cmd_name,cmd->name))
591 return true;
592 }
593
594 return false;
595}
596
597
598
599/*
600============
601Cmd_CompleteCommand
602============
603*/
604char *Cmd_CompleteCommand (char *partial)
605{
606 cmd_function_t *cmd;
607 int len;
608
609 len = Q_strlen(partial);
610
611 if (!len)
612 return NULL;
613
614// check functions
615 for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
616 if (!Q_strncmp (partial,cmd->name, len))
617 return cmd->name;
618
619 return NULL;
620}
621
622/*
623============
624Cmd_ExecuteString
625
626A complete command line has been parsed, so try to execute it
627FIXME: lookupnoadd the token to speed search?
628============
629*/
630void Cmd_ExecuteString (char *text, cmd_source_t src)
631{
632 cmd_function_t *cmd;
633 cmdalias_t *a;
634
635 cmd_source = src;
636 Cmd_TokenizeString (text);
637
638// execute the command line
639 if (!Cmd_Argc())
640 return; // no tokens
641
642// check functions
643 for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
644 {
645 if (!Q_strcasecmp (cmd_argv[0],cmd->name))
646 {
647 cmd->function ();
648 return;
649 }
650 }
651
652// check alias
653 for (a=cmd_alias ; a ; a=a->next)
654 {
655 if (!Q_strcasecmp (cmd_argv[0], a->name))
656 {
657 Cbuf_InsertText (a->value);
658 return;
659 }
660 }
661
662// check cvars
663 if (!Cvar_Command ())
664 Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
665
666}
667
668
669/*
670===================
671Cmd_ForwardToServer
672
673Sends the entire command line over to the server
674===================
675*/
676void Cmd_ForwardToServer (void)
677{
678 if (cls.state != ca_connected)
679 {
680 Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
681 return;
682 }
683
684 if (cls.demoplayback)
685 return; // not really connected
686
687 MSG_WriteByte (&cls.message, clc_stringcmd);
688 if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0)
689 {
690 SZ_Print (&cls.message, Cmd_Argv(0));
691 SZ_Print (&cls.message, " ");
692 }
693 if (Cmd_Argc() > 1)
694 SZ_Print (&cls.message, Cmd_Args());
695 else
696 SZ_Print (&cls.message, "\n");
697}
698
699
700/*
701================
702Cmd_CheckParm
703
704Returns the position (1 to argc-1) in the command's argument list
705where the given parameter apears, or 0 if not present
706================
707*/
708
709int Cmd_CheckParm (char *parm)
710{
711 int i;
712
713 if (!parm)
714 Sys_Error ("Cmd_CheckParm: NULL");
715
716 for (i = 1; i < Cmd_Argc (); i++)
717 if (! Q_strcasecmp (parm, Cmd_Argv (i)))
718 return i;
719
720 return 0;
721}
diff --git a/apps/plugins/sdl/progs/quake/cmd.h b/apps/plugins/sdl/progs/quake/cmd.h
new file mode 100644
index 0000000000..d4a0dd9b63
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cmd.h
@@ -0,0 +1,123 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// cmd.h -- Command buffer and command execution
22
23//===========================================================================
24
25/*
26
27Any number of commands can be added in a frame, from several different sources.
28Most commands come from either keybindings or console line input, but remote
29servers can also send across commands and entire text files can be execed.
30
31The + command line options are also added to the command buffer.
32
33The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
34
35*/
36
37
38void Cbuf_Init (void);
39// allocates an initial text buffer that will grow as needed
40
41void Cbuf_AddText (char *text);
42// as new commands are generated from the console or keybindings,
43// the text is added to the end of the command buffer.
44
45void Cbuf_InsertText (char *text);
46// when a command wants to issue other commands immediately, the text is
47// inserted at the beginning of the buffer, before any remaining unexecuted
48// commands.
49
50void Cbuf_Execute (void);
51// Pulls off \n terminated lines of text from the command buffer and sends
52// them through Cmd_ExecuteString. Stops when the buffer is empty.
53// Normally called once per frame, but may be explicitly invoked.
54// Do not call inside a command function!
55
56//===========================================================================
57
58/*
59
60Command execution takes a null terminated string, breaks it into tokens,
61then searches for a command or variable that matches the first token.
62
63Commands can come from three sources, but the handler functions may choose
64to dissallow the action or forward it to a remote server if the source is
65not apropriate.
66
67*/
68
69typedef void (*xcommand_t) (void);
70
71typedef int cmd_source_t;
72
73enum
74{
75 src_client, // came in over a net connection as a clc_stringcmd
76 // host_client will be valid during this state.
77 src_command // from the command buffer
78};
79
80extern cmd_source_t cmd_source;
81
82void Cmd_Init (void);
83
84void Cmd_AddCommand (char *cmd_name, xcommand_t function);
85// called by the init functions of other parts of the program to
86// register commands and functions to call for them.
87// The cmd_name is referenced later, so it should not be in temp memory
88
89qboolean Cmd_Exists (char *cmd_name);
90// used by the cvar code to check for cvar / command name overlap
91
92char *Cmd_CompleteCommand (char *partial);
93// attempts to match a partial command for automatic command line completion
94// returns NULL if nothing fits
95
96int Cmd_Argc (void);
97char *Cmd_Argv (int arg);
98char *Cmd_Args (void);
99// The functions that execute commands get their parameters with these
100// functions. Cmd_Argv () will return an empty string, not a NULL
101// if arg > argc, so string operations are allways safe.
102
103int Cmd_CheckParm (char *parm);
104// Returns the position (1 to argc-1) in the command's argument list
105// where the given parameter apears, or 0 if not present
106
107void Cmd_TokenizeString (char *text);
108// Takes a null terminated string. Does not need to be /n terminated.
109// breaks the string up into arg tokens.
110
111void Cmd_ExecuteString (char *text, cmd_source_t src);
112// Parses a single line of text into arguments and tries to execute it.
113// The text can come from the command buffer, a remote client, or stdin.
114
115void Cmd_ForwardToServer (void);
116// adds the current command line as a clc_stringcmd to the client message.
117// things like godmode, noclip, etc, are commands directed to the server,
118// so when they are typed in at the console, they will need to be forwarded.
119
120void Cmd_Print (char *text);
121// used by command functions to send output to either the graphics console or
122// passed as a print message to the client
123
diff --git a/apps/plugins/sdl/progs/quake/common.c b/apps/plugins/sdl/progs/quake/common.c
new file mode 100644
index 0000000000..11be234834
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/common.c
@@ -0,0 +1,1856 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// common.c -- misc functions used in client and server
21
22#include "quakedef.h"
23
24#define NUM_SAFE_ARGVS 7
25
26static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
27static char *argvdummy = " ";
28
29static char *safeargvs[NUM_SAFE_ARGVS] =
30 {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
31
32cvar_t registered = {"registered","0"};
33cvar_t cmdline = {"cmdline","0", false, true};
34
35qboolean com_modified; // set true if using non-id files
36
37qboolean proghack;
38
39int static_registered = 1; // only for startup check, then set
40
41qboolean msg_suppress_1 = 0;
42
43void COM_InitFilesystem (void);
44
45// if a packfile directory differs from this, it is assumed to be hacked
46#define PAK0_COUNT 339
47#define PAK0_CRC 32981
48
49char com_token[1024];
50int com_argc;
51char **com_argv;
52
53#define CMDLINE_LENGTH 256
54char com_cmdline[CMDLINE_LENGTH];
55
56qboolean standard_quake = true, rogue, hipnotic;
57
58// this graphic needs to be in the pak file to use registered features
59unsigned short pop[] =
60{
61 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
62,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
63,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
64,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
65,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
66,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
67,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
68,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
69,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
70,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
71,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
72,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
73,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
74,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
75,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
76,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
77};
78
79/*
80
81
82All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
83
84The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
85only used during filesystem initialization.
86
87The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
88
89The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory
90specified, when a file is found by the normal search path, it will be mirrored
91into the cache directory, then opened there.
92
93
94
95FIXME:
96The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently. This could be used to add a "-sspeed 22050" for the high quality sound edition. Because they are added at the end, they will not override an explicit setting on the original command line.
97
98*/
99
100//============================================================================
101
102
103// ClearLink is used for new headnodes
104void ClearLink (link_t *l)
105{
106 l->prev = l->next = l;
107}
108
109void RemoveLink (link_t *l)
110{
111 l->next->prev = l->prev;
112 l->prev->next = l->next;
113}
114
115void InsertLinkBefore (link_t *l, link_t *before)
116{
117 l->next = before;
118 l->prev = before->prev;
119 l->prev->next = l;
120 l->next->prev = l;
121}
122void InsertLinkAfter (link_t *l, link_t *after)
123{
124 l->next = after->next;
125 l->prev = after;
126 l->prev->next = l;
127 l->next->prev = l;
128}
129
130/*
131============================================================================
132
133 LIBRARY REPLACEMENT FUNCTIONS
134
135============================================================================
136*/
137
138void Q_memset (void *dest, int fill, int count)
139{
140 int i;
141
142 if ( (((long)dest | count) & 3) == 0)
143 {
144 count >>= 2;
145 fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
146 for (i=0 ; i<count ; i++)
147 ((int *)dest)[i] = fill;
148 }
149 else
150 for (i=0 ; i<count ; i++)
151 ((byte *)dest)[i] = fill;
152}
153
154void Q_memcpy (void *dest, void *src, int count)
155{
156 int i;
157
158 if (( ( (long)dest | (long)src | count) & 3) == 0 )
159 {
160 count>>=2;
161 for (i=0 ; i<count ; i++)
162 ((int *)dest)[i] = ((int *)src)[i];
163 }
164 else
165 for (i=0 ; i<count ; i++)
166 ((byte *)dest)[i] = ((byte *)src)[i];
167}
168
169int Q_memcmp (void *m1, void *m2, int count)
170{
171 while(count)
172 {
173 count--;
174 if (((byte *)m1)[count] != ((byte *)m2)[count])
175 return -1;
176 }
177 return 0;
178}
179
180void Q_strcpy (char *dest, char *src)
181{
182 while (*src)
183 {
184 *dest++ = *src++;
185 }
186 *dest++ = 0;
187}
188
189void Q_strncpy (char *dest, char *src, int count)
190{
191 while (*src && count--)
192 {
193 *dest++ = *src++;
194 }
195 if (count)
196 *dest++ = 0;
197}
198
199int Q_strlen (char *str)
200{
201 int count;
202
203 count = 0;
204 while (str[count])
205 count++;
206
207 return count;
208}
209
210char *Q_strrchr(char *s, char c)
211{
212 int len = Q_strlen(s);
213 s += len;
214 while (len--)
215 if (*--s == c) return s;
216 return 0;
217}
218
219void Q_strcat (char *dest, char *src)
220{
221 dest += Q_strlen(dest);
222 Q_strcpy (dest, src);
223}
224
225int Q_strcmp (char *s1, char *s2)
226{
227 while (1)
228 {
229 if (*s1 != *s2)
230 return -1; // strings not equal
231 if (!*s1)
232 return 0; // strings are equal
233 s1++;
234 s2++;
235 }
236
237 return -1;
238}
239
240int Q_strncmp (char *s1, char *s2, int count)
241{
242 while (1)
243 {
244 if (!count--)
245 return 0;
246 if (*s1 != *s2)
247 return -1; // strings not equal
248 if (!*s1)
249 return 0; // strings are equal
250 s1++;
251 s2++;
252 }
253
254 return -1;
255}
256
257int Q_strncasecmp (char *s1, char *s2, int n)
258{
259 int c1, c2;
260
261 while (1)
262 {
263 c1 = *s1++;
264 c2 = *s2++;
265
266 if (!n--)
267 return 0; // strings are equal until end point
268
269 if (c1 != c2)
270 {
271 if (c1 >= 'a' && c1 <= 'z')
272 c1 -= ('a' - 'A');
273 if (c2 >= 'a' && c2 <= 'z')
274 c2 -= ('a' - 'A');
275 if (c1 != c2)
276 return -1; // strings not equal
277 }
278 if (!c1)
279 return 0; // strings are equal
280// s1++;
281// s2++;
282 }
283
284 return -1;
285}
286
287int Q_strcasecmp (char *s1, char *s2)
288{
289 return Q_strncasecmp (s1, s2, 99999);
290}
291
292int Q_atoi (char *str)
293{
294 int val;
295 int sign;
296 int c;
297
298 if (*str == '-')
299 {
300 sign = -1;
301 str++;
302 }
303 else
304 sign = 1;
305
306 val = 0;
307
308//
309// check for hex
310//
311 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
312 {
313 str += 2;
314 while (1)
315 {
316 c = *str++;
317 if (c >= '0' && c <= '9')
318 val = (val<<4) + c - '0';
319 else if (c >= 'a' && c <= 'f')
320 val = (val<<4) + c - 'a' + 10;
321 else if (c >= 'A' && c <= 'F')
322 val = (val<<4) + c - 'A' + 10;
323 else
324 return val*sign;
325 }
326 }
327
328//
329// check for character
330//
331 if (str[0] == '\'')
332 {
333 return sign * str[1];
334 }
335
336//
337// assume decimal
338//
339 while (1)
340 {
341 c = *str++;
342 if (c <'0' || c > '9')
343 return val*sign;
344 val = val*10 + c - '0';
345 }
346
347 return 0;
348}
349
350
351float Q_atof (char *str)
352{
353 double val;
354 int sign;
355 int c;
356 int decimal, total;
357
358 if (*str == '-')
359 {
360 sign = -1;
361 str++;
362 }
363 else
364 sign = 1;
365
366 val = 0;
367
368//
369// check for hex
370//
371 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
372 {
373 str += 2;
374 while (1)
375 {
376 c = *str++;
377 if (c >= '0' && c <= '9')
378 val = (val*16) + c - '0';
379 else if (c >= 'a' && c <= 'f')
380 val = (val*16) + c - 'a' + 10;
381 else if (c >= 'A' && c <= 'F')
382 val = (val*16) + c - 'A' + 10;
383 else
384 return val*sign;
385 }
386 }
387
388//
389// check for character
390//
391 if (str[0] == '\'')
392 {
393 return sign * str[1];
394 }
395
396//
397// assume decimal
398//
399 decimal = -1;
400 total = 0;
401 while (1)
402 {
403 c = *str++;
404 if (c == '.')
405 {
406 decimal = total;
407 continue;
408 }
409 if (c <'0' || c > '9')
410 break;
411 val = val*10 + c - '0';
412 total++;
413 }
414
415 if (decimal == -1)
416 return val*sign;
417 while (total > decimal)
418 {
419 val /= 10;
420 total--;
421 }
422
423 return val*sign;
424}
425
426/*
427============================================================================
428
429 BYTE ORDER FUNCTIONS
430
431============================================================================
432*/
433
434#ifdef SDL
435#include "SDL_byteorder.h"
436#endif
437
438qboolean bigendien;
439
440short (*BigShort) (short l);
441short (*LittleShort) (short l);
442int (*BigLong) (int l);
443int (*LittleLong) (int l);
444float (*BigFloat) (float l);
445float (*LittleFloat) (float l);
446
447short ShortSwap (short l)
448{
449 byte b1,b2;
450
451 b1 = l&255;
452 b2 = (l>>8)&255;
453
454 return (b1<<8) + b2;
455}
456
457short ShortNoSwap (short l)
458{
459 return l;
460}
461
462int LongSwap (int l)
463{
464 byte b1,b2,b3,b4;
465
466 b1 = l&255;
467 b2 = (l>>8)&255;
468 b3 = (l>>16)&255;
469 b4 = (l>>24)&255;
470
471 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
472}
473
474int LongNoSwap (int l)
475{
476 return l;
477}
478
479float FloatSwap (float f)
480{
481 union
482 {
483 float f;
484 byte b[4];
485 } dat1, dat2;
486
487
488 dat1.f = f;
489 dat2.b[0] = dat1.b[3];
490 dat2.b[1] = dat1.b[2];
491 dat2.b[2] = dat1.b[1];
492 dat2.b[3] = dat1.b[0];
493 return dat2.f;
494}
495
496float FloatNoSwap (float f)
497{
498 return f;
499}
500
501/*
502==============================================================================
503
504 MESSAGE IO FUNCTIONS
505
506Handles byte ordering and avoids alignment errors
507==============================================================================
508*/
509
510//
511// writing functions
512//
513
514void MSG_WriteChar (sizebuf_t *sb, int c)
515{
516 byte *buf;
517
518#ifdef PARANOID
519 if (c < -128 || c > 127)
520 Sys_Error ("MSG_WriteChar: range error");
521#endif
522
523 buf = SZ_GetSpace (sb, 1);
524 buf[0] = c;
525}
526
527void MSG_WriteByte (sizebuf_t *sb, int c)
528{
529 byte *buf;
530
531#ifdef PARANOID
532 if (c < 0 || c > 255)
533 Sys_Error ("MSG_WriteByte: range error");
534#endif
535
536 buf = SZ_GetSpace (sb, 1);
537 buf[0] = c;
538}
539
540void MSG_WriteShort (sizebuf_t *sb, int c)
541{
542 byte *buf;
543
544#ifdef PARANOID
545 if (c < ((short)0x8000) || c > (short)0x7fff)
546 Sys_Error ("MSG_WriteShort: range error");
547#endif
548
549 buf = SZ_GetSpace (sb, 2);
550 buf[0] = c&0xff;
551 buf[1] = c>>8;
552}
553
554void MSG_WriteLong (sizebuf_t *sb, int c)
555{
556 byte *buf;
557
558 buf = SZ_GetSpace (sb, 4);
559 buf[0] = c&0xff;
560 buf[1] = (c>>8)&0xff;
561 buf[2] = (c>>16)&0xff;
562 buf[3] = c>>24;
563}
564
565void MSG_WriteFloat (sizebuf_t *sb, float f)
566{
567 union
568 {
569 float f;
570 int l;
571 } dat;
572
573
574 dat.f = f;
575 dat.l = LittleLong (dat.l);
576
577 SZ_Write (sb, &dat.l, 4);
578}
579
580void MSG_WriteString (sizebuf_t *sb, char *s)
581{
582 if (!s)
583 SZ_Write (sb, "", 1);
584 else
585 SZ_Write (sb, s, Q_strlen(s)+1);
586}
587
588void MSG_WriteCoord (sizebuf_t *sb, float f)
589{
590 MSG_WriteShort (sb, (int)(f*8));
591}
592
593void MSG_WriteAngle (sizebuf_t *sb, float f)
594{
595 MSG_WriteByte (sb, ((int)f*256/360) & 255);
596}
597
598//
599// reading functions
600//
601int msg_readcount;
602qboolean msg_badread;
603
604void MSG_BeginReading (void)
605{
606 msg_readcount = 0;
607 msg_badread = false;
608}
609
610// returns -1 and sets msg_badread if no more characters are available
611int MSG_ReadChar (void)
612{
613 int c;
614
615 if (msg_readcount+1 > net_message.cursize)
616 {
617 msg_badread = true;
618 return -1;
619 }
620
621 c = (signed char)net_message.data[msg_readcount];
622 msg_readcount++;
623
624 return c;
625}
626
627int MSG_ReadByte (void)
628{
629 int c;
630
631 if (msg_readcount+1 > net_message.cursize)
632 {
633 msg_badread = true;
634 return -1;
635 }
636
637 c = (unsigned char)net_message.data[msg_readcount];
638 msg_readcount++;
639
640 return c;
641}
642
643int MSG_ReadShort (void)
644{
645 int c;
646
647 if (msg_readcount+2 > net_message.cursize)
648 {
649 msg_badread = true;
650 return -1;
651 }
652
653 c = (short)(net_message.data[msg_readcount]
654 + (net_message.data[msg_readcount+1]<<8));
655
656 msg_readcount += 2;
657
658 return c;
659}
660
661int MSG_ReadLong (void)
662{
663 int c;
664
665 if (msg_readcount+4 > net_message.cursize)
666 {
667 msg_badread = true;
668 return -1;
669 }
670
671 c = net_message.data[msg_readcount]
672 + (net_message.data[msg_readcount+1]<<8)
673 + (net_message.data[msg_readcount+2]<<16)
674 + (net_message.data[msg_readcount+3]<<24);
675
676 msg_readcount += 4;
677
678 return c;
679}
680
681float MSG_ReadFloat (void)
682{
683 union
684 {
685 byte b[4];
686 float f;
687 int l;
688 } dat;
689
690 dat.b[0] = net_message.data[msg_readcount];
691 dat.b[1] = net_message.data[msg_readcount+1];
692 dat.b[2] = net_message.data[msg_readcount+2];
693 dat.b[3] = net_message.data[msg_readcount+3];
694 msg_readcount += 4;
695
696 dat.l = LittleLong (dat.l);
697
698 return dat.f;
699}
700
701char *MSG_ReadString (void)
702{
703 static char string[2048];
704 int l,c;
705
706 l = 0;
707 do
708 {
709 c = MSG_ReadChar ();
710 if (c == -1 || c == 0)
711 break;
712 string[l] = c;
713 l++;
714 } while (l < sizeof(string)-1);
715
716 string[l] = 0;
717
718 return string;
719}
720
721float MSG_ReadCoord (void)
722{
723 return MSG_ReadShort() * (1.0/8);
724}
725
726float MSG_ReadAngle (void)
727{
728 return MSG_ReadChar() * (360.0/256);
729}
730
731
732
733//===========================================================================
734
735void SZ_Alloc (sizebuf_t *buf, int startsize)
736{
737 if (startsize < 256)
738 startsize = 256;
739 buf->data = Hunk_AllocName (startsize, "sizebuf");
740 buf->maxsize = startsize;
741 buf->cursize = 0;
742}
743
744
745void SZ_Free (sizebuf_t *buf)
746{
747// Z_Free (buf->data);
748// buf->data = NULL;
749// buf->maxsize = 0;
750 buf->cursize = 0;
751}
752
753void SZ_Clear (sizebuf_t *buf)
754{
755 buf->cursize = 0;
756}
757
758void *SZ_GetSpace (sizebuf_t *buf, int length)
759{
760 void *data;
761
762 if (buf->cursize + length > buf->maxsize)
763 {
764 if (!buf->allowoverflow)
765 Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");
766
767 if (length > buf->maxsize)
768 Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
769
770 buf->overflowed = true;
771 Con_Printf ("SZ_GetSpace: overflow");
772 SZ_Clear (buf);
773 }
774
775 data = buf->data + buf->cursize;
776 buf->cursize += length;
777
778 return data;
779}
780
781void SZ_Write (sizebuf_t *buf, void *data, int length)
782{
783 Q_memcpy (SZ_GetSpace(buf,length),data,length);
784}
785
786void SZ_Print (sizebuf_t *buf, char *data)
787{
788 int len;
789
790 len = Q_strlen(data)+1;
791
792// byte * cast to keep VC++ happy
793 if (buf->data[buf->cursize-1])
794 Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
795 else
796 Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
797}
798
799
800//============================================================================
801
802
803/*
804============
805COM_SkipPath
806============
807*/
808char *COM_SkipPath (char *pathname)
809{
810 char *last;
811
812 last = pathname;
813 while (*pathname)
814 {
815 if (*pathname=='/')
816 last = pathname+1;
817 pathname++;
818 }
819 return last;
820}
821
822/*
823============
824COM_StripExtension
825============
826*/
827void COM_StripExtension (char *in, char *out)
828{
829 while (*in && *in != '.')
830 *out++ = *in++;
831 *out = 0;
832}
833
834/*
835============
836COM_FileExtension
837============
838*/
839char *COM_FileExtension (char *in)
840{
841 static char exten[8];
842 int i;
843
844 while (*in && *in != '.')
845 in++;
846 if (!*in)
847 return "";
848 in++;
849 for (i=0 ; i<7 && *in ; i++,in++)
850 exten[i] = *in;
851 exten[i] = 0;
852 return exten;
853}
854
855/*
856============
857COM_FileBase
858============
859*/
860int *check_ptr = NULL;
861
862void COM_FileBase (char *in, char *out)
863{
864 char *s, *s2;
865
866 s = in + strlen(in) - 1;
867
868 while (s != in && *s != '.')
869 s--;
870
871 for (s2 = s ; *s2 && *s2 != '/' && s2 != in; s2--)
872 ;
873
874 if (s-s2 < 2)
875 {
876 strcpy (out,"?model?");
877 }
878 else
879 {
880 /* BUG */
881 s--;
882 //printf("writing %d bytes to outbuf", s-s2);
883 Q_strncpy (out,s2+1, s-s2);
884 out[s-s2] = 0;
885 }
886}
887
888
889/*
890==================
891COM_DefaultExtension
892==================
893*/
894void COM_DefaultExtension (char *path, char *extension)
895{
896 char *src;
897//
898// if path doesn't have a .EXT, append extension
899// (extension should include the .)
900//
901 src = path + strlen(path) - 1;
902
903 while (*src != '/' && src != path)
904 {
905 if (*src == '.')
906 return; // it has an extension
907 src--;
908 }
909
910 strcat (path, extension);
911}
912
913
914/*
915==============
916COM_Parse
917
918Parse a token out of a string
919==============
920*/
921char *COM_Parse (char *data)
922{
923 int c;
924 int len;
925
926 len = 0;
927 com_token[0] = 0;
928
929 if (!data)
930 return NULL;
931
932// skip whitespace
933skipwhite:
934 while ( (c = *data) <= ' ')
935 {
936 if (c == 0)
937 return NULL; // end of file;
938 data++;
939 }
940
941// skip // comments
942 if (c=='/' && data[1] == '/')
943 {
944 while (*data && *data != '\n')
945 data++;
946 goto skipwhite;
947 }
948
949
950// handle quoted strings specially
951 if (c == '\"')
952 {
953 data++;
954 while (1)
955 {
956 c = *data++;
957 if (c=='\"' || !c)
958 {
959 com_token[len] = 0;
960 return data;
961 }
962 com_token[len] = c;
963 len++;
964 }
965 }
966
967// parse single characters
968 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
969 {
970 com_token[len] = c;
971 len++;
972 com_token[len] = 0;
973 return data+1;
974 }
975
976// parse a regular word
977 do
978 {
979 com_token[len] = c;
980 data++;
981 len++;
982 c = *data;
983 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
984 break;
985 } while (c>32);
986
987 com_token[len] = 0;
988 return data;
989}
990
991
992/*
993================
994COM_CheckParm
995
996Returns the position (1 to argc-1) in the program's argument list
997where the given parameter apears, or 0 if not present
998================
999*/
1000int COM_CheckParm (char *parm)
1001{
1002 int i;
1003
1004 for (i=1 ; i<com_argc ; i++)
1005 {
1006 if (!com_argv[i])
1007 continue; // NEXTSTEP sometimes clears appkit vars.
1008 if (!Q_strcmp (parm,com_argv[i]))
1009 return i;
1010 }
1011
1012 return 0;
1013}
1014
1015/*
1016================
1017COM_CheckRegistered
1018
1019Looks for the pop.txt file and verifies it.
1020Sets the "registered" cvar.
1021Immediately exits out if an alternate game was attempted to be started without
1022being registered.
1023================
1024*/
1025void COM_CheckRegistered (void)
1026{
1027 int h;
1028 unsigned short check[128];
1029 int i;
1030
1031 COM_OpenFile("gfx/pop.lmp", &h);
1032 static_registered = 0;
1033
1034 if (h == -1)
1035 {
1036#if WINDED
1037 Sys_Error ("This dedicated server requires a full registered copy of Quake");
1038#endif
1039 Con_Printf ("Playing shareware version.\n");
1040 if (com_modified)
1041 Sys_Error ("You must have the registered version to use modified games");
1042 return;
1043 }
1044
1045 Sys_FileRead (h, check, sizeof(check));
1046 COM_CloseFile (h);
1047
1048 for (i=0 ; i<128 ; i++)
1049 if (pop[i] != (unsigned short)BigShort (check[i]))
1050 Sys_Error ("Corrupted data file.");
1051
1052 Cvar_Set ("cmdline", com_cmdline);
1053 Cvar_Set ("registered", "1");
1054 static_registered = 1;
1055 Con_Printf ("Playing registered version.\n");
1056}
1057
1058
1059void COM_Path_f (void);
1060
1061
1062/*
1063================
1064COM_InitArgv
1065================
1066*/
1067void COM_InitArgv (int argc, char **argv)
1068{
1069 qboolean safe;
1070 int i, j, n;
1071
1072// reconstitute the command line for the cmdline externally visible cvar
1073 n = 0;
1074
1075 for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
1076 {
1077 i = 0;
1078
1079 while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1080 {
1081 com_cmdline[n++] = argv[j][i++];
1082 }
1083
1084 if (n < (CMDLINE_LENGTH - 1))
1085 com_cmdline[n++] = ' ';
1086 else
1087 break;
1088 }
1089
1090 com_cmdline[n] = 0;
1091
1092 safe = false;
1093
1094 for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1095 com_argc++)
1096 {
1097 largv[com_argc] = argv[com_argc];
1098 if (!Q_strcmp ("-safe", argv[com_argc]))
1099 safe = true;
1100 }
1101
1102 if (safe)
1103 {
1104 // force all the safe-mode switches. Note that we reserved extra space in
1105 // case we need to add these, so we don't need an overflow check
1106 for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1107 {
1108 largv[com_argc] = safeargvs[i];
1109 com_argc++;
1110 }
1111 }
1112
1113 largv[com_argc] = argvdummy;
1114 com_argv = largv;
1115
1116 if (COM_CheckParm ("-rogue"))
1117 {
1118 rogue = true;
1119 standard_quake = false;
1120 }
1121
1122 if (COM_CheckParm ("-hipnotic"))
1123 {
1124 hipnotic = true;
1125 standard_quake = false;
1126 }
1127}
1128
1129
1130/*
1131================
1132COM_Init
1133================
1134*/
1135void COM_Init (char *basedir)
1136{
1137 byte swaptest[2] = {1,0};
1138
1139// set the byte swapping variables in a portable manner
1140#ifdef SDL
1141 // This is necessary because egcs 1.1.1 mis-compiles swaptest with -O2
1142 if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
1143#else
1144 if ( *(short *)swaptest == 1)
1145#endif
1146 {
1147 bigendien = false;
1148 BigShort = ShortSwap;
1149 LittleShort = ShortNoSwap;
1150 BigLong = LongSwap;
1151 LittleLong = LongNoSwap;
1152 BigFloat = FloatSwap;
1153 LittleFloat = FloatNoSwap;
1154 }
1155 else
1156 {
1157 bigendien = true;
1158 BigShort = ShortNoSwap;
1159 LittleShort = ShortSwap;
1160 BigLong = LongNoSwap;
1161 LittleLong = LongSwap;
1162 BigFloat = FloatNoSwap;
1163 LittleFloat = FloatSwap;
1164 }
1165
1166 Cvar_RegisterVariable (&registered);
1167 Cvar_RegisterVariable (&cmdline);
1168 Cmd_AddCommand ("path", COM_Path_f);
1169
1170 COM_InitFilesystem ();
1171 COM_CheckRegistered ();
1172}
1173
1174
1175/*
1176============
1177va
1178
1179does a varargs printf into a temp buffer, so I don't need to have
1180varargs versions of all text functions.
1181FIXME: make this buffer size safe someday
1182============
1183*/
1184char *va(char *format, ...)
1185{
1186 va_list argptr;
1187 static char string[1024];
1188
1189 va_start (argptr, format);
1190 vsprintf (string, format,argptr);
1191 va_end (argptr);
1192
1193 return string;
1194}
1195
1196
1197/// just for debugging
1198int memsearch (byte *start, int count, int search)
1199{
1200 int i;
1201
1202 for (i=0 ; i<count ; i++)
1203 if (start[i] == search)
1204 return i;
1205 return -1;
1206}
1207
1208/*
1209=============================================================================
1210
1211QUAKE FILESYSTEM
1212
1213=============================================================================
1214*/
1215
1216int com_filesize;
1217
1218
1219//
1220// in memory
1221//
1222
1223typedef struct
1224{
1225 char name[MAX_QPATH];
1226 int filepos, filelen;
1227} packfile_t;
1228
1229typedef struct pack_s
1230{
1231 char filename[MAX_OSPATH];
1232 int handle;
1233 int numfiles;
1234 packfile_t *files;
1235} pack_t;
1236
1237//
1238// on disk
1239//
1240typedef struct
1241{
1242 char name[56];
1243 int filepos, filelen;
1244} dpackfile_t;
1245
1246typedef struct
1247{
1248 char id[4];
1249 int dirofs;
1250 int dirlen;
1251} dpackheader_t;
1252
1253#define MAX_FILES_IN_PACK 2048
1254
1255char com_cachedir[MAX_OSPATH];
1256char com_gamedir[MAX_OSPATH];
1257
1258typedef struct searchpath_s
1259{
1260 char filename[MAX_OSPATH];
1261 pack_t *pack; // only one of filename / pack will be used
1262 struct searchpath_s *next;
1263} searchpath_t;
1264
1265searchpath_t *com_searchpaths;
1266
1267/*
1268============
1269COM_Path_f
1270
1271============
1272*/
1273void COM_Path_f (void)
1274{
1275 searchpath_t *s;
1276
1277 Con_Printf ("Current search path:\n");
1278 for (s=com_searchpaths ; s ; s=s->next)
1279 {
1280 if (s->pack)
1281 {
1282 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1283 }
1284 else
1285 Con_Printf ("%s\n", s->filename);
1286 }
1287}
1288
1289/*
1290============
1291COM_WriteFile
1292
1293The filename will be prefixed by the current game directory
1294============
1295*/
1296void COM_WriteFile (char *filename, void *data, int len)
1297{
1298 int handle;
1299 char name[MAX_OSPATH];
1300
1301 sprintf (name, "%s/%s", com_gamedir, filename);
1302
1303 handle = Sys_FileOpenWrite (name);
1304 if (handle == -1)
1305 {
1306 Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1307 return;
1308 }
1309
1310 Sys_Printf ("COM_WriteFile: %s\n", name);
1311 Sys_FileWrite (handle, data, len);
1312 Sys_FileClose (handle);
1313}
1314
1315
1316/*
1317============
1318COM_CreatePath
1319
1320Only used for CopyFile
1321============
1322*/
1323void COM_CreatePath (char *path)
1324{
1325 char *ofs;
1326
1327 for (ofs = path+1 ; *ofs ; ofs++)
1328 {
1329 if (*ofs == '/')
1330 { // create the directory
1331 *ofs = 0;
1332 Sys_mkdir (path);
1333 *ofs = '/';
1334 }
1335 }
1336}
1337
1338
1339/*
1340===========
1341COM_CopyFile
1342
1343Copies a file over from the net to the local cache, creating any directories
1344needed. This is for the convenience of developers using ISDN from home.
1345===========
1346*/
1347void COM_CopyFile (char *netpath, char *cachepath)
1348{
1349 int in, out;
1350 int remaining, count;
1351 char buf[4096];
1352
1353 remaining = Sys_FileOpenRead (netpath, &in);
1354 COM_CreatePath (cachepath); // create directories up to the cache file
1355 out = Sys_FileOpenWrite (cachepath);
1356
1357 while (remaining)
1358 {
1359 if (remaining < sizeof(buf))
1360 count = remaining;
1361 else
1362 count = sizeof(buf);
1363 Sys_FileRead (in, buf, count);
1364 Sys_FileWrite (out, buf, count);
1365 remaining -= count;
1366 }
1367
1368 Sys_FileClose (in);
1369 Sys_FileClose (out);
1370}
1371
1372/*
1373===========
1374COM_FindFile
1375
1376Finds the file in the search path.
1377Sets com_filesize and one of handle or file
1378===========
1379*/
1380int COM_FindFile (char *filename, int *handle, FILE **file)
1381{
1382 searchpath_t *search;
1383 char netpath[MAX_OSPATH];
1384 char cachepath[MAX_OSPATH];
1385 pack_t *pak;
1386 int i;
1387 int findtime, cachetime;
1388
1389 if (file && handle)
1390 Sys_Error ("COM_FindFile: both handle and file set");
1391 if (!file && !handle)
1392 Sys_Error ("COM_FindFile: neither handle or file set");
1393
1394//
1395// search through the path, one element at a time
1396//
1397 search = com_searchpaths;
1398 if (proghack)
1399 { // gross hack to use quake 1 progs with quake 2 maps
1400 if (!strcmp(filename, "progs.dat"))
1401 search = search->next;
1402 }
1403
1404 for ( ; search ; search = search->next)
1405 {
1406 // is the element a pak file?
1407 if (search->pack)
1408 {
1409 // look through all the pak file elements
1410 pak = search->pack;
1411 for (i=0 ; i<pak->numfiles ; i++)
1412 if (!strcmp (pak->files[i].name, filename))
1413 { // found it!
1414 Con_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
1415 if (handle)
1416 {
1417 *handle = pak->handle;
1418 Sys_FileSeek (pak->handle, pak->files[i].filepos);
1419 //if(*handle != 1)
1420 //rb->splashf(HZ, "handle found: %d", *handle);
1421 }
1422 else
1423 { // open a new file on the pakfile
1424 *file = fopen (pak->filename, "rb");
1425 if (*file)
1426 fseek (*file, pak->files[i].filepos, SEEK_SET);
1427 else
1428 {
1429 Sys_Error("open failed: %d", 0);
1430 }
1431 }
1432 com_filesize = pak->files[i].filelen;
1433 return com_filesize;
1434 }
1435 }
1436 else
1437 {
1438 // check a file in the directory tree
1439 if (!static_registered)
1440 { // if not a registered version, don't ever go beyond base
1441 if ( strchr (filename, '/') || strchr (filename,'\\'))
1442 continue;
1443 }
1444
1445 sprintf (netpath, "%s/%s",search->filename, filename);
1446
1447 findtime = Sys_FileTime (netpath);
1448 if (findtime == -1)
1449 continue;
1450
1451 // see if the file needs to be updated in the cache
1452 if (!com_cachedir[0])
1453 strcpy (cachepath, netpath);
1454 else
1455 {
1456#if defined(_WIN32)
1457 if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1458 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1459 else
1460 sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1461#else
1462 sprintf (cachepath,"%s/%s", com_cachedir, netpath);
1463#endif
1464
1465 cachetime = Sys_FileTime (cachepath);
1466
1467 if (cachetime < findtime)
1468 COM_CopyFile (netpath, cachepath);
1469 strcpy (netpath, cachepath);
1470 }
1471
1472 Sys_Printf ("FindFile: %s\n",netpath);
1473 com_filesize = Sys_FileOpenRead (netpath, &i);
1474 if (handle)
1475 *handle = i;
1476 else
1477 {
1478 Sys_FileClose (i);
1479 *file = fopen (netpath, "rb");
1480 }
1481 return com_filesize;
1482 }
1483
1484 }
1485
1486 Sys_Printf ("FindFile: can't find %s\n", filename);
1487
1488 if (handle)
1489 *handle = -1;
1490 else
1491 *file = NULL;
1492 com_filesize = -1;
1493 return -1;
1494}
1495
1496
1497/*
1498===========
1499COM_OpenFile
1500
1501filename never has a leading slash, but may contain directory walks
1502returns a handle and a length
1503it may actually be inside a pak file
1504===========
1505*/
1506int COM_OpenFile (char *filename, int *handle)
1507{
1508 return COM_FindFile (filename, handle, NULL);
1509}
1510
1511/*
1512===========
1513COM_FOpenFile
1514
1515If the requested file is inside a packfile, a new FILE * will be opened
1516into the file.
1517===========
1518*/
1519int COM_FOpenFile (char *filename, FILE **file)
1520{
1521 return COM_FindFile (filename, NULL, file);
1522}
1523
1524/*
1525============
1526COM_CloseFile
1527
1528If it is a pak file handle, don't really close it
1529============
1530*/
1531void COM_CloseFile (int h)
1532{
1533 searchpath_t *s;
1534
1535 for (s = com_searchpaths ; s ; s=s->next)
1536 if (s->pack && s->pack->handle == h)
1537 return;
1538
1539 Sys_FileClose (h);
1540}
1541
1542
1543/*
1544============
1545COM_LoadFile
1546
1547Filename are reletive to the quake directory.
1548Allways appends a 0 byte.
1549============
1550*/
1551cache_user_t *loadcache;
1552byte *loadbuf;
1553int loadsize;
1554byte *COM_LoadFile (char *path, int usehunk)
1555{
1556 //printf("COM_LoadFile(%s)", path);
1557 int h;
1558 byte *buf;
1559 char base[32];
1560 int len;
1561
1562 buf = NULL; // quiet compiler warning
1563
1564// look for it in the filesystem or pack files
1565 len = COM_OpenFile (path, &h);
1566 if (h == -1)
1567 return NULL;
1568
1569 check_ptr = &h;
1570
1571 //printf("handle %d", h);
1572// extract the filename base name for hunk tag
1573 /* BUG IS HERE */
1574 COM_FileBase (path, base);
1575
1576 //printf("handle %d base \"%s\"", h, base);
1577 //printf("");
1578
1579 if (usehunk == 1)
1580 buf = Hunk_AllocName (len+1, base);
1581 else if (usehunk == 2)
1582 buf = Hunk_TempAlloc (len+1);
1583 else if (usehunk == 0)
1584 buf = Z_Malloc (len+1);
1585 else if (usehunk == 3)
1586 buf = Cache_Alloc (loadcache, len+1, base);
1587 else if (usehunk == 4)
1588 {
1589 if (len+1 > loadsize)
1590 buf = Hunk_TempAlloc (len+1);
1591 else
1592 buf = loadbuf;
1593 }
1594 else
1595 Sys_Error ("COM_LoadFile: bad usehunk");
1596
1597 if (!buf)
1598 Sys_Error ("COM_LoadFile: not enough space for %s", path);
1599
1600 ((byte *)buf)[len] = 0;
1601
1602 Draw_BeginDisc ();
1603 Sys_FileRead (h, buf, len);
1604 COM_CloseFile (h);
1605 Draw_EndDisc ();
1606
1607 return buf;
1608}
1609
1610byte *COM_LoadHunkFile (char *path)
1611{
1612 return COM_LoadFile (path, 1);
1613}
1614
1615byte *COM_LoadTempFile (char *path)
1616{
1617 return COM_LoadFile (path, 2);
1618}
1619
1620void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
1621{
1622 loadcache = cu;
1623 COM_LoadFile (path, 3);
1624}
1625
1626// uses temp hunk if larger than bufsize
1627byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)
1628{
1629 byte *buf;
1630
1631 loadbuf = (byte *)buffer;
1632 loadsize = bufsize;
1633 buf = COM_LoadFile (path, 4);
1634
1635 return buf;
1636}
1637
1638/*
1639=================
1640COM_LoadPackFile
1641
1642Takes an explicit (not game tree related) path to a pak file.
1643
1644Loads the header and directory, adding the files at the beginning
1645of the list so they override previous pack files.
1646=================
1647*/
1648pack_t *COM_LoadPackFile (char *packfile)
1649{
1650 dpackheader_t header;
1651 int i;
1652 packfile_t *newfiles;
1653 int numpackfiles;
1654 pack_t *pack;
1655 int packhandle;
1656 dpackfile_t info[MAX_FILES_IN_PACK];
1657 unsigned short crc;
1658
1659 if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1660 {
1661// Con_Printf ("Couldn't open %s\n", packfile);
1662 return NULL;
1663 }
1664 Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1665 if (header.id[0] != 'P' || header.id[1] != 'A'
1666 || header.id[2] != 'C' || header.id[3] != 'K')
1667 Sys_Error ("%s is not a packfile", packfile);
1668 header.dirofs = LittleLong (header.dirofs);
1669 header.dirlen = LittleLong (header.dirlen);
1670
1671 numpackfiles = header.dirlen / sizeof(dpackfile_t);
1672
1673 if (numpackfiles > MAX_FILES_IN_PACK)
1674 Sys_Error ("%s has %i files", packfile, numpackfiles);
1675
1676 if (numpackfiles != PAK0_COUNT)
1677 com_modified = true; // not the original file
1678
1679 newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
1680
1681 Sys_FileSeek (packhandle, header.dirofs);
1682 Sys_FileRead (packhandle, (void *)info, header.dirlen);
1683
1684// crc the directory to check for modifications
1685 CRC_Init (&crc);
1686 for (i=0 ; i<header.dirlen ; i++)
1687 CRC_ProcessByte (&crc, ((byte *)info)[i]);
1688 if (crc != PAK0_CRC)
1689 com_modified = true;
1690
1691// parse the directory
1692 for (i=0 ; i<numpackfiles ; i++)
1693 {
1694 strcpy (newfiles[i].name, info[i].name);
1695 newfiles[i].filepos = LittleLong(info[i].filepos);
1696 newfiles[i].filelen = LittleLong(info[i].filelen);
1697 }
1698
1699 pack = Hunk_Alloc (sizeof (pack_t));
1700 strcpy (pack->filename, packfile);
1701 pack->handle = packhandle;
1702 pack->numfiles = numpackfiles;
1703 pack->files = newfiles;
1704
1705 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1706 return pack;
1707}
1708
1709
1710/*
1711================
1712COM_AddGameDirectory
1713
1714Sets com_gamedir, adds the directory to the head of the path,
1715then loads and adds pak1.pak pak2.pak ...
1716================
1717*/
1718void COM_AddGameDirectory (char *dir)
1719{
1720 int i;
1721 searchpath_t *search;
1722 pack_t *pak;
1723 char pakfile[MAX_OSPATH];
1724
1725 strcpy (com_gamedir, dir);
1726
1727//
1728// add the directory to the search path
1729//
1730 search = Hunk_Alloc (sizeof(searchpath_t));
1731 strcpy (search->filename, dir);
1732 search->next = com_searchpaths;
1733 com_searchpaths = search;
1734
1735//
1736// add any pak files in the format pak0.pak pak1.pak, ...
1737//
1738 for (i=0 ; ; i++)
1739 {
1740 sprintf (pakfile, "%s/pak%i.pak", dir, i);
1741 pak = COM_LoadPackFile (pakfile);
1742 if (!pak)
1743 break;
1744 search = Hunk_Alloc (sizeof(searchpath_t));
1745 search->pack = pak;
1746 search->next = com_searchpaths;
1747 com_searchpaths = search;
1748 }
1749
1750//
1751// add the contents of the parms.txt file to the end of the command line
1752//
1753
1754}
1755
1756/*
1757================
1758COM_InitFilesystem
1759================
1760*/
1761void COM_InitFilesystem (void)
1762{
1763 int i, j;
1764 char basedir[MAX_OSPATH];
1765 searchpath_t *search;
1766
1767//
1768// -basedir <path>
1769// Overrides the system supplied base directory (under GAMENAME)
1770//
1771 i = COM_CheckParm ("-basedir");
1772 if (i && i < com_argc-1)
1773 strcpy (basedir, com_argv[i+1]);
1774 else
1775 strcpy (basedir, host_parms.basedir);
1776
1777 j = strlen (basedir);
1778
1779 if (j > 0)
1780 {
1781 if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1782 basedir[j-1] = 0;
1783 }
1784
1785//
1786// -cachedir <path>
1787// Overrides the system supplied cache directory (NULL or /qcache)
1788// -cachedir - will disable caching.
1789//
1790 i = COM_CheckParm ("-cachedir");
1791 if (i && i < com_argc-1)
1792 {
1793 if (com_argv[i+1][0] == '-')
1794 com_cachedir[0] = 0;
1795 else
1796 strcpy (com_cachedir, com_argv[i+1]);
1797 }
1798 else if (host_parms.cachedir)
1799 strcpy (com_cachedir, host_parms.cachedir);
1800 else
1801 com_cachedir[0] = 0;
1802
1803//
1804// start up with GAMENAME by default (id1)
1805//
1806 COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1807
1808 if (COM_CheckParm ("-rogue"))
1809 COM_AddGameDirectory (va("%s/rogue", basedir) );
1810 if (COM_CheckParm ("-hipnotic"))
1811 COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1812
1813//
1814// -game <gamedir>
1815// Adds basedir/gamedir as an override game
1816//
1817 i = COM_CheckParm ("-game");
1818 if (i && i < com_argc-1)
1819 {
1820 com_modified = true;
1821 COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1822 }
1823
1824//
1825// -path <dir or packfile> [<dir or packfile>] ...
1826// Fully specifies the exact serach path, overriding the generated one
1827//
1828 i = COM_CheckParm ("-path");
1829 if (i)
1830 {
1831 com_modified = true;
1832 com_searchpaths = NULL;
1833 while (++i < com_argc)
1834 {
1835 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1836 break;
1837
1838 search = Hunk_Alloc (sizeof(searchpath_t));
1839 if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1840 {
1841 search->pack = COM_LoadPackFile (com_argv[i]);
1842 if (!search->pack)
1843 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1844 }
1845 else
1846 strcpy (search->filename, com_argv[i]);
1847 search->next = com_searchpaths;
1848 com_searchpaths = search;
1849 }
1850 }
1851
1852 if (COM_CheckParm ("-proghack"))
1853 proghack = true;
1854}
1855
1856
diff --git a/apps/plugins/sdl/progs/quake/common.h b/apps/plugins/sdl/progs/quake/common.h
new file mode 100644
index 0000000000..a1ac227aff
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/common.h
@@ -0,0 +1,184 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// comndef.h -- general definitions
21
22#if !defined BYTE_DEFINED
23typedef unsigned char byte;
24#define BYTE_DEFINED 1
25#endif
26
27#undef true
28#undef false
29
30typedef int qboolean;
31enum {false, true};
32
33//============================================================================
34
35typedef struct sizebuf_s
36{
37 qboolean allowoverflow; // if false, do a Sys_Error
38 qboolean overflowed; // set to true if the buffer size failed
39 byte *data;
40 int maxsize;
41 int cursize;
42} sizebuf_t;
43
44void SZ_Alloc (sizebuf_t *buf, int startsize);
45void SZ_Free (sizebuf_t *buf);
46void SZ_Clear (sizebuf_t *buf);
47void *SZ_GetSpace (sizebuf_t *buf, int length);
48void SZ_Write (sizebuf_t *buf, void *data, int length);
49void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf
50
51//============================================================================
52
53typedef struct link_s
54{
55 struct link_s *prev, *next;
56} link_t;
57
58
59void ClearLink (link_t *l);
60void RemoveLink (link_t *l);
61void InsertLinkBefore (link_t *l, link_t *before);
62void InsertLinkAfter (link_t *l, link_t *after);
63
64// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
65// ent = STRUCT_FROM_LINK(link,entity_t,order)
66// FIXME: remove this mess!
67#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
68
69//============================================================================
70
71#ifndef NULL
72#define NULL ((void *)0)
73#endif
74
75#define Q_MAXCHAR ((char)0x7f)
76#define Q_MAXSHORT ((short)0x7fff)
77#define Q_MAXINT ((int)0x7fffffff)
78#define Q_MAXLONG ((int)0x7fffffff)
79#define Q_MAXFLOAT ((int)0x7fffffff)
80
81#define Q_MINCHAR ((char)0x80)
82#define Q_MINSHORT ((short)0x8000)
83#define Q_MININT ((int)0x80000000)
84#define Q_MINLONG ((int)0x80000000)
85#define Q_MINFLOAT ((int)0x7fffffff)
86
87//============================================================================
88
89extern qboolean bigendien;
90
91extern short (*BigShort) (short l);
92extern short (*LittleShort) (short l);
93extern int (*BigLong) (int l);
94extern int (*LittleLong) (int l);
95extern float (*BigFloat) (float l);
96extern float (*LittleFloat) (float l);
97
98//============================================================================
99
100void MSG_WriteChar (sizebuf_t *sb, int c);
101void MSG_WriteByte (sizebuf_t *sb, int c);
102void MSG_WriteShort (sizebuf_t *sb, int c);
103void MSG_WriteLong (sizebuf_t *sb, int c);
104void MSG_WriteFloat (sizebuf_t *sb, float f);
105void MSG_WriteString (sizebuf_t *sb, char *s);
106void MSG_WriteCoord (sizebuf_t *sb, float f);
107void MSG_WriteAngle (sizebuf_t *sb, float f);
108
109extern int msg_readcount;
110extern qboolean msg_badread; // set if a read goes beyond end of message
111
112void MSG_BeginReading (void);
113int MSG_ReadChar (void);
114int MSG_ReadByte (void);
115int MSG_ReadShort (void);
116int MSG_ReadLong (void);
117float MSG_ReadFloat (void);
118char *MSG_ReadString (void);
119
120float MSG_ReadCoord (void);
121float MSG_ReadAngle (void);
122
123//============================================================================
124
125void Q_memset (void *dest, int fill, int count);
126void Q_memcpy (void *dest, void *src, int count);
127int Q_memcmp (void *m1, void *m2, int count);
128void Q_strcpy (char *dest, char *src);
129void Q_strncpy (char *dest, char *src, int count);
130int Q_strlen (char *str);
131char *Q_strrchr (char *s, char c);
132void Q_strcat (char *dest, char *src);
133int Q_strcmp (char *s1, char *s2);
134int Q_strncmp (char *s1, char *s2, int count);
135int Q_strcasecmp (char *s1, char *s2);
136int Q_strncasecmp (char *s1, char *s2, int n);
137int Q_atoi (char *str);
138float Q_atof (char *str);
139
140//============================================================================
141
142extern char com_token[1024];
143extern qboolean com_eof;
144
145char *COM_Parse (char *data);
146
147
148extern int com_argc;
149extern char **com_argv;
150
151int COM_CheckParm (char *parm);
152void COM_Init (char *path);
153void COM_InitArgv (int argc, char **argv);
154
155char *COM_SkipPath (char *pathname);
156void COM_StripExtension (char *in, char *out);
157void COM_FileBase (char *in, char *out);
158void COM_DefaultExtension (char *path, char *extension);
159
160char *va(char *format, ...);
161// does a varargs printf into a temp buffer
162
163
164//============================================================================
165
166extern int com_filesize;
167struct cache_user_s;
168
169extern char com_gamedir[MAX_OSPATH];
170
171void COM_WriteFile (char *filename, void *data, int len);
172int COM_OpenFile (char *filename, int *hndl);
173int COM_FOpenFile (char *filename, FILE **file);
174void COM_CloseFile (int h);
175
176byte *COM_LoadStackFile (char *path, void *buffer, int bufsize);
177byte *COM_LoadTempFile (char *path);
178byte *COM_LoadHunkFile (char *path);
179void COM_LoadCacheFile (char *path, struct cache_user_s *cu);
180
181
182extern struct cvar_s registered;
183
184extern qboolean standard_quake, rogue, hipnotic;
diff --git a/apps/plugins/sdl/progs/quake/conproc.h b/apps/plugins/sdl/progs/quake/conproc.h
new file mode 100644
index 0000000000..743526f878
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/conproc.h
@@ -0,0 +1,37 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// conproc.h
21
22#define CCOM_WRITE_TEXT 0x2
23// Param1 : Text
24
25#define CCOM_GET_TEXT 0x3
26// Param1 : Begin line
27// Param2 : End line
28
29#define CCOM_GET_SCR_LINES 0x4
30// No params
31
32#define CCOM_SET_SCR_LINES 0x5
33// Param1 : Number of lines
34
35void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild);
36void DeinitConProc (void);
37
diff --git a/apps/plugins/sdl/progs/quake/console.c b/apps/plugins/sdl/progs/quake/console.c
new file mode 100644
index 0000000000..59c7de368c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/console.c
@@ -0,0 +1,644 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// console.c
21
22#include "quakedef.h"
23
24int con_linewidth;
25
26float con_cursorspeed = 4;
27
28#define CON_TEXTSIZE 16384
29
30qboolean con_forcedup; // because no entities to refresh
31
32int con_totallines; // total lines in console scrollback
33int con_backscroll; // lines up from bottom to display
34int con_current; // where next message will be printed
35int con_x; // offset in current line for next print
36char *con_text=0;
37
38cvar_t con_notifytime = {"con_notifytime","3"}; //seconds
39
40#define NUM_CON_TIMES 4
41float con_times[NUM_CON_TIMES]; // realtime time the line was generated
42 // for transparent notify lines
43
44int con_vislines;
45
46qboolean con_debuglog;
47
48#define MAXCMDLINE 256
49extern char key_lines[32][MAXCMDLINE];
50extern int edit_line;
51extern int key_linepos;
52
53
54qboolean con_initialized;
55
56int con_notifylines; // scan lines to clear for notify lines
57
58extern void M_Menu_Main_f (void);
59
60/*
61================
62Con_ToggleConsole_f
63================
64*/
65void Con_ToggleConsole_f (void)
66{
67 if (key_dest == key_console)
68 {
69 if (cls.state == ca_connected)
70 {
71 key_dest = key_game;
72 key_lines[edit_line][1] = 0; // clear any typing
73 key_linepos = 1;
74 }
75 else
76 {
77 M_Menu_Main_f ();
78 }
79 }
80 else
81 key_dest = key_console;
82
83 SCR_EndLoadingPlaque ();
84 memset (con_times, 0, sizeof(con_times));
85}
86
87/*
88================
89Con_Clear_f
90================
91*/
92void Con_Clear_f (void)
93{
94 if (con_text)
95 Q_memset (con_text, ' ', CON_TEXTSIZE);
96}
97
98
99/*
100================
101Con_ClearNotify
102================
103*/
104void Con_ClearNotify (void)
105{
106 int i;
107
108 for (i=0 ; i<NUM_CON_TIMES ; i++)
109 con_times[i] = 0;
110}
111
112
113/*
114================
115Con_MessageMode_f
116================
117*/
118extern qboolean team_message;
119
120void Con_MessageMode_f (void)
121{
122 key_dest = key_message;
123 team_message = false;
124}
125
126
127/*
128================
129Con_MessageMode2_f
130================
131*/
132void Con_MessageMode2_f (void)
133{
134 key_dest = key_message;
135 team_message = true;
136}
137
138
139/*
140================
141Con_CheckResize
142
143If the line width has changed, reformat the buffer.
144================
145*/
146void Con_CheckResize (void)
147{
148 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
149 char tbuf[CON_TEXTSIZE];
150
151 width = (vid.width >> 3) - 2;
152
153 if (width == con_linewidth)
154 return;
155
156 if (width < 1) // video hasn't been initialized yet
157 {
158 width = 38;
159 con_linewidth = width;
160 con_totallines = CON_TEXTSIZE / con_linewidth;
161 Q_memset (con_text, ' ', CON_TEXTSIZE);
162 }
163 else
164 {
165 oldwidth = con_linewidth;
166 con_linewidth = width;
167 oldtotallines = con_totallines;
168 con_totallines = CON_TEXTSIZE / con_linewidth;
169 numlines = oldtotallines;
170
171 if (con_totallines < numlines)
172 numlines = con_totallines;
173
174 numchars = oldwidth;
175
176 if (con_linewidth < numchars)
177 numchars = con_linewidth;
178
179 Q_memcpy (tbuf, con_text, CON_TEXTSIZE);
180 Q_memset (con_text, ' ', CON_TEXTSIZE);
181
182 for (i=0 ; i<numlines ; i++)
183 {
184 for (j=0 ; j<numchars ; j++)
185 {
186 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
187 tbuf[((con_current - i + oldtotallines) %
188 oldtotallines) * oldwidth + j];
189 }
190 }
191
192 Con_ClearNotify ();
193 }
194
195 con_backscroll = 0;
196 con_current = con_totallines - 1;
197}
198
199
200/*
201================
202Con_Init
203================
204*/
205void Con_Init (void)
206{
207#define MAXGAMEDIRLEN 1000
208 char temp[MAXGAMEDIRLEN+1];
209 char *t2 = "/qconsole.log";
210
211 con_debuglog = COM_CheckParm("-condebug");
212
213 if (con_debuglog)
214 {
215 if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
216 {
217 sprintf (temp, "%s%s", com_gamedir, t2);
218 unlink (temp);
219 }
220 }
221
222 con_text = Hunk_AllocName (CON_TEXTSIZE, "context");
223 Q_memset (con_text, ' ', CON_TEXTSIZE);
224 con_linewidth = -1;
225 Con_CheckResize ();
226
227 Con_Printf ("Console initialized.\n");
228
229//
230// register our commands
231//
232 Cvar_RegisterVariable (&con_notifytime);
233
234 Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
235 Cmd_AddCommand ("messagemode", Con_MessageMode_f);
236 Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
237 Cmd_AddCommand ("clear", Con_Clear_f);
238 con_initialized = true;
239}
240
241
242/*
243===============
244Con_Linefeed
245===============
246*/
247void Con_Linefeed (void)
248{
249 if ( ! con_initialized ) return;
250 con_x = 0;
251 con_current++;
252 Q_memset (&con_text[(con_current%con_totallines)*con_linewidth]
253 , ' ', con_linewidth);
254}
255
256/*
257================
258Con_Print
259
260Handles cursor positioning, line wrapping, etc
261All console printing must go through this in order to be logged to disk
262If no console is visible, the notify window will pop up.
263================
264*/
265void Con_Print (char *txt)
266{
267 int y;
268 int c, l;
269 static int cr;
270 int mask;
271
272 if ( ! con_initialized ) return;
273 con_backscroll = 0;
274
275 if (txt[0] == 1)
276 {
277 mask = 128; // go to colored text
278 S_LocalSound ("misc/talk.wav");
279 // play talk wav
280 txt++;
281 }
282 else if (txt[0] == 2)
283 {
284 mask = 128; // go to colored text
285 txt++;
286 }
287 else
288 mask = 0;
289
290
291 while ( (c = *txt) )
292 {
293 // count word length
294 for (l=0 ; l< con_linewidth ; l++)
295 if ( txt[l] <= ' ')
296 break;
297
298 // word wrap
299 if (l != con_linewidth && (con_x + l > con_linewidth) )
300 con_x = 0;
301
302 txt++;
303
304 if (cr)
305 {
306 con_current--;
307 cr = false;
308 }
309
310
311 if (!con_x)
312 {
313 Con_Linefeed ();
314 // mark time for transparent overlay
315 if (con_current >= 0)
316 con_times[con_current % NUM_CON_TIMES] = realtime;
317 }
318
319 switch (c)
320 {
321 case '\n':
322 con_x = 0;
323 break;
324
325 case '\r':
326 con_x = 0;
327 cr = 1;
328 break;
329
330 default: // display character and advance
331 y = con_current % con_totallines;
332 con_text[y*con_linewidth+con_x] = c | mask;
333 con_x++;
334 if (con_x >= con_linewidth)
335 con_x = 0;
336 break;
337 }
338
339 }
340}
341
342
343/*
344================
345Con_DebugLog
346================
347*/
348void Con_DebugLog(char *file, char *fmt, ...)
349{
350 va_list argptr;
351 static char data[1024];
352 int fd;
353
354 va_start(argptr, fmt);
355 vsprintf(data, fmt, argptr);
356 va_end(argptr);
357 fd = rb->open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
358 rb->write(fd, data, strlen(data));
359 rb->close(fd);
360}
361
362
363/*
364================
365Con_Printf
366
367Handles cursor positioning, line wrapping, etc
368================
369*/
370#define MAXPRINTMSG 4096
371// FIXME: make a buffer size safe vsprintf?
372void Con_Printf (char *fmt, ...)
373{
374 va_list argptr;
375 char msg[MAXPRINTMSG];
376 static qboolean inupdate;
377
378 va_start (argptr,fmt);
379 vsprintf (msg,fmt,argptr);
380 va_end (argptr);
381
382// also echo to debugging console
383 Sys_Printf ("%s", msg); // also echo to debugging console
384
385// log all messages to file
386 if (con_debuglog)
387 Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
388
389 if (!con_initialized)
390 return;
391
392 if (cls.state == ca_dedicated)
393 return; // no graphics mode
394
395// write it to the scrollable buffer
396 Con_Print (msg);
397
398// update the screen if the console is displayed
399 if (cls.signon != SIGNONS && !scr_disabled_for_loading )
400 {
401 // protect against infinite loop if something in SCR_UpdateScreen calls
402 // Con_Printd
403 if (!inupdate)
404 {
405 inupdate = true;
406 SCR_UpdateScreen ();
407 inupdate = false;
408 }
409 }
410}
411
412/*
413================
414Con_DPrintf
415
416A Con_Printf that only shows up if the "developer" cvar is set
417================
418*/
419void Con_DPrintf (char *fmt, ...)
420{
421 va_list argptr;
422 char msg[MAXPRINTMSG];
423
424 if (!developer.value)
425 return; // don't confuse non-developers with techie stuff...
426
427 va_start (argptr,fmt);
428 vsprintf (msg,fmt,argptr);
429 va_end (argptr);
430
431 Con_Printf ("%s", msg);
432}
433
434
435/*
436==================
437Con_SafePrintf
438
439Okay to call even when the screen can't be updated
440==================
441*/
442void Con_SafePrintf (char *fmt, ...)
443{
444 va_list argptr;
445 char msg[1024];
446 int temp;
447
448 va_start (argptr,fmt);
449 vsprintf (msg,fmt,argptr);
450 va_end (argptr);
451
452 temp = scr_disabled_for_loading;
453 scr_disabled_for_loading = true;
454 Con_Printf ("%s", msg);
455 scr_disabled_for_loading = temp;
456}
457
458
459/*
460==============================================================================
461
462DRAWING
463
464==============================================================================
465*/
466
467
468/*
469================
470Con_DrawInput
471
472The input line scrolls horizontally if typing goes beyond the right edge
473================
474*/
475void Con_DrawInput (void)
476{
477 int y;
478 int i;
479 char *text;
480
481 if (key_dest != key_console && !con_forcedup)
482 return; // don't draw anything
483
484 text = key_lines[edit_line];
485
486// add the cursor frame
487 text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
488
489// fill out remainder with spaces
490 for (i=key_linepos+1 ; i< con_linewidth ; i++)
491 text[i] = ' ';
492
493// prestep if horizontally scrolling
494 if (key_linepos >= con_linewidth)
495 text += 1 + key_linepos - con_linewidth;
496
497// draw it
498 y = con_vislines-16;
499
500 for (i=0 ; i<con_linewidth ; i++)
501 Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
502
503// remove cursor
504 key_lines[edit_line][key_linepos] = 0;
505}
506
507
508/*
509================
510Con_DrawNotify
511
512Draws the last few lines of output transparently over the game top
513================
514*/
515void Con_DrawNotify (void)
516{
517 int x, v;
518 char *text;
519 int i;
520 float time;
521 extern char chat_buffer[];
522
523 v = 0;
524 for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
525 {
526 if (i < 0)
527 continue;
528 time = con_times[i % NUM_CON_TIMES];
529 if (time == 0)
530 continue;
531 time = realtime - time;
532 if (time > con_notifytime.value)
533 continue;
534 text = con_text + (i % con_totallines)*con_linewidth;
535
536 clearnotify = 0;
537 scr_copytop = 1;
538
539 for (x = 0 ; x < con_linewidth ; x++)
540 Draw_Character ( (x+1)<<3, v, text[x]);
541
542 v += 8;
543 }
544
545
546 if (key_dest == key_message)
547 {
548 clearnotify = 0;
549 scr_copytop = 1;
550
551 x = 0;
552
553 Draw_String (8, v, "say:");
554 while(chat_buffer[x])
555 {
556 Draw_Character ( (x+5)<<3, v, chat_buffer[x]);
557 x++;
558 }
559 Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
560 v += 8;
561 }
562
563 if (v > con_notifylines)
564 con_notifylines = v;
565}
566
567/*
568================
569Con_DrawConsole
570
571Draws the console with the solid background
572The typing input line at the bottom should only be drawn if typing is allowed
573================
574*/
575void Con_DrawConsole (int lines, qboolean drawinput)
576{
577 int i, x, y;
578 int rows;
579 char *text;
580 int j;
581
582 if (lines <= 0)
583 return;
584
585// draw the background
586 Draw_ConsoleBackground (lines);
587
588// draw the text
589 con_vislines = lines;
590
591 rows = (lines-16)>>3; // rows of text to draw
592 y = lines - 16 - (rows<<3); // may start slightly negative
593
594 for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 )
595 {
596 j = i - con_backscroll;
597 if (j<0)
598 j = 0;
599 text = con_text + (j % con_totallines)*con_linewidth;
600
601 for (x=0 ; x<con_linewidth ; x++)
602 Draw_Character ( (x+1)<<3, y, text[x]);
603 }
604
605// draw the input prompt, user text, and cursor if desired
606 if (drawinput)
607 Con_DrawInput ();
608}
609
610
611/*
612==================
613Con_NotifyBox
614==================
615*/
616void Con_NotifyBox (char *text)
617{
618 double t1, t2;
619
620// during startup for sound / cd warnings
621 Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
622
623 Con_Printf (text);
624
625 Con_Printf ("Press a key.\n");
626 Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
627
628 key_count = -2; // wait for a key down and up
629 key_dest = key_console;
630
631 do
632 {
633 t1 = Sys_FloatTime ();
634 SCR_UpdateScreen ();
635 Sys_SendKeyEvents ();
636 t2 = Sys_FloatTime ();
637 realtime += t2-t1; // make the cursor blink
638 } while (key_count < 0);
639
640 Con_Printf ("\n");
641 key_dest = key_game;
642 realtime = 0; // put the cursor back to invisible
643}
644
diff --git a/apps/plugins/sdl/progs/quake/console.h b/apps/plugins/sdl/progs/quake/console.h
new file mode 100644
index 0000000000..ef01f008ad
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/console.h
@@ -0,0 +1,46 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21//
22// console
23//
24extern int con_totallines;
25extern int con_backscroll;
26extern qboolean con_forcedup; // because no entities to refresh
27extern qboolean con_initialized;
28extern byte *con_chars;
29extern int con_notifylines; // scan lines to clear for notify lines
30
31void Con_DrawCharacter (int cx, int line, int num);
32
33void Con_CheckResize (void);
34void Con_Init (void);
35void Con_DrawConsole (int lines, qboolean drawinput);
36void Con_Print (char *txt);
37void Con_Printf (char *fmt, ...);
38void Con_DPrintf (char *fmt, ...);
39void Con_SafePrintf (char *fmt, ...);
40void Con_Clear_f (void);
41void Con_DrawNotify (void);
42void Con_ClearNotify (void);
43void Con_ToggleConsole_f (void);
44
45void Con_NotifyBox (char *text); // during startup for sound / cd warnings
46
diff --git a/apps/plugins/sdl/progs/quake/crc.c b/apps/plugins/sdl/progs/quake/crc.c
new file mode 100644
index 0000000000..ed4880cea9
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/crc.c
@@ -0,0 +1,81 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20/* crc.c */
21
22#include "quakedef.h"
23#include "crc.h"
24
25// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
26// and the initial and final xor values shown below... in other words, the
27// CCITT standard CRC used by XMODEM
28
29#define CRC_INIT_VALUE 0xffff
30#define CRC_XOR_VALUE 0x0000
31
32static unsigned short crctable[256] =
33{
34 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
35 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
36 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
37 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
38 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
39 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
40 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
41 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
42 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
43 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
44 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
45 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
46 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
47 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
48 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
49 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
50 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
51 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
52 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
53 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
54 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
55 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
56 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
57 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
58 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
59 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
60 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
61 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
62 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
63 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
64 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
65 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
66};
67
68void CRC_Init(unsigned short *crcvalue)
69{
70 *crcvalue = CRC_INIT_VALUE;
71}
72
73void CRC_ProcessByte(unsigned short *crcvalue, byte data)
74{
75 *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
76}
77
78unsigned short CRC_Value(unsigned short crcvalue)
79{
80 return crcvalue ^ CRC_XOR_VALUE;
81} \ No newline at end of file
diff --git a/apps/plugins/sdl/progs/quake/crc.h b/apps/plugins/sdl/progs/quake/crc.h
new file mode 100644
index 0000000000..cad97725b2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/crc.h
@@ -0,0 +1,24 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20/* crc.h */
21
22void CRC_Init(unsigned short *crcvalue);
23void CRC_ProcessByte(unsigned short *crcvalue, byte data);
24unsigned short CRC_Value(unsigned short crcvalue);
diff --git a/apps/plugins/sdl/progs/quake/cvar.c b/apps/plugins/sdl/progs/quake/cvar.c
new file mode 100644
index 0000000000..07a761a332
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cvar.c
@@ -0,0 +1,224 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cvar.c -- dynamic variable tracking
21
22#include "quakedef.h"
23
24cvar_t *cvar_vars;
25char *cvar_null_string = "";
26
27/*
28============
29Cvar_FindVar
30============
31*/
32cvar_t *Cvar_FindVar (char *var_name)
33{
34 cvar_t *var;
35
36 for (var=cvar_vars ; var ; var=var->next)
37 if (!Q_strcmp (var_name, var->name))
38 return var;
39
40 return NULL;
41}
42
43/*
44============
45Cvar_VariableValue
46============
47*/
48float Cvar_VariableValue (char *var_name)
49{
50 cvar_t *var;
51
52 var = Cvar_FindVar (var_name);
53 if (!var)
54 return 0;
55 return Q_atof (var->string);
56}
57
58
59/*
60============
61Cvar_VariableString
62============
63*/
64char *Cvar_VariableString (char *var_name)
65{
66 cvar_t *var;
67
68 var = Cvar_FindVar (var_name);
69 if (!var)
70 return cvar_null_string;
71 return var->string;
72}
73
74
75/*
76============
77Cvar_CompleteVariable
78============
79*/
80char *Cvar_CompleteVariable (char *partial)
81{
82 cvar_t *cvar;
83 int len;
84
85 len = Q_strlen(partial);
86
87 if (!len)
88 return NULL;
89
90// check functions
91 for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
92 if (!Q_strncmp (partial,cvar->name, len))
93 return cvar->name;
94
95 return NULL;
96}
97
98
99/*
100============
101Cvar_Set
102============
103*/
104void Cvar_Set (char *var_name, char *value)
105{
106 cvar_t *var;
107 qboolean changed;
108
109 var = Cvar_FindVar (var_name);
110 if (!var)
111 { // there is an error in C code if this happens
112 Con_Printf ("Cvar_Set: variable %s not found\n", var_name);
113 return;
114 }
115
116 changed = Q_strcmp(var->string, value);
117
118 Z_Free (var->string); // free the old value string
119
120 var->string = Z_Malloc (Q_strlen(value)+1);
121 Q_strcpy (var->string, value);
122 var->value = Q_atof (var->string);
123 if (var->server && changed)
124 {
125 if (sv.active)
126 SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string);
127 }
128}
129
130/*
131============
132Cvar_SetValue
133============
134*/
135void Cvar_SetValue (char *var_name, float value)
136{
137 char val[32];
138
139 sprintf (val, "%f",value);
140 Cvar_Set (var_name, val);
141}
142
143
144/*
145============
146Cvar_RegisterVariable
147
148Adds a freestanding variable to the variable list.
149============
150*/
151void Cvar_RegisterVariable (cvar_t *variable)
152{
153 char *oldstr;
154
155// first check to see if it has allready been defined
156 if (Cvar_FindVar (variable->name))
157 {
158 Con_Printf ("Can't register variable %s, allready defined\n", variable->name);
159 return;
160 }
161
162// check for overlap with a command
163 if (Cmd_Exists (variable->name))
164 {
165 Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name);
166 return;
167 }
168
169// copy the value off, because future sets will Z_Free it
170 oldstr = variable->string;
171 variable->string = Z_Malloc (Q_strlen(variable->string)+1);
172 Q_strcpy (variable->string, oldstr);
173 variable->value = Q_atof (variable->string);
174
175// link the variable in
176 variable->next = cvar_vars;
177 cvar_vars = variable;
178}
179
180/*
181============
182Cvar_Command
183
184Handles variable inspection and changing from the console
185============
186*/
187qboolean Cvar_Command (void)
188{
189 cvar_t *v;
190
191// check variables
192 v = Cvar_FindVar (Cmd_Argv(0));
193 if (!v)
194 return false;
195
196// perform a variable print or set
197 if (Cmd_Argc() == 1)
198 {
199 Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
200 return true;
201 }
202
203 Cvar_Set (v->name, Cmd_Argv(1));
204 return true;
205}
206
207
208/*
209============
210Cvar_WriteVariables
211
212Writes lines containing "set variable value" for all variables
213with the archive flag set to true.
214============
215*/
216void Cvar_WriteVariables (FILE *f)
217{
218 cvar_t *var;
219
220 for (var = cvar_vars ; var ; var = var->next)
221 if (var->archive)
222 fprintf (f, "%s \"%s\"\n", var->name, var->string);
223}
224
diff --git a/apps/plugins/sdl/progs/quake/cvar.h b/apps/plugins/sdl/progs/quake/cvar.h
new file mode 100644
index 0000000000..009b74783f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/cvar.h
@@ -0,0 +1,97 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// cvar.h
21
22/*
23
24cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly
25in C code.
26
27it is sufficient to initialize a cvar_t with just the first two fields, or
28you can add a ,true flag for variables that you want saved to the configuration
29file when the game is quit:
30
31cvar_t r_draworder = {"r_draworder","1"};
32cvar_t scr_screensize = {"screensize","1",true};
33
34Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string. Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed:
35Cvar_RegisterVariable (&host_framerate);
36
37
38C code usually just references a cvar in place:
39if ( r_draworder.value )
40
41It could optionally ask for the value to be looked up for a string name:
42if (Cvar_VariableValue ("r_draworder"))
43
44Interpreted prog code can access cvars with the cvar(name) or
45cvar_set (name, value) internal functions:
46teamplay = cvar("teamplay");
47cvar_set ("registered", "1");
48
49The user can access cvars from the console in two ways:
50r_draworder prints the current value
51r_draworder 0 sets the current value to 0
52Cvars are restricted from having the same names as commands to keep this
53interface from being ambiguous.
54*/
55
56typedef struct cvar_s
57{
58 char *name;
59 char *string;
60 qboolean archive; // set to true to cause it to be saved to vars.rc
61 qboolean server; // notifies players when changed
62 float value;
63 struct cvar_s *next;
64} cvar_t;
65
66void Cvar_RegisterVariable (cvar_t *variable);
67// registers a cvar that allready has the name, string, and optionally the
68// archive elements set.
69
70void Cvar_Set (char *var_name, char *value);
71// equivelant to "<name> <variable>" typed at the console
72
73void Cvar_SetValue (char *var_name, float value);
74// expands value to a string and calls Cvar_Set
75
76float Cvar_VariableValue (char *var_name);
77// returns 0 if not defined or non numeric
78
79char *Cvar_VariableString (char *var_name);
80// returns an empty string if not defined
81
82char *Cvar_CompleteVariable (char *partial);
83// attempts to match a partial variable name for command line completion
84// returns NULL if nothing fits
85
86qboolean Cvar_Command (void);
87// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
88// command. Returns true if the command was a variable reference that
89// was handled. (print or change)
90
91void Cvar_WriteVariables (FILE *f);
92// Writes lines containing "set variable value" for all variables
93// with the archive flag set to true.
94
95cvar_t *Cvar_FindVar (char *var_name);
96
97extern cvar_t *cvar_vars;
diff --git a/apps/plugins/sdl/progs/quake/d_copy.S b/apps/plugins/sdl/progs/quake/d_copy.S
new file mode 100644
index 0000000000..92e414a1bf
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_copy.S
@@ -0,0 +1,149 @@
1//
2// d_copy.s
3// x86 assembly-language screen copying code.
4//
5
6#include "asm_i386.h"
7#include "quakeasm.h"
8#include "asm_draw.h"
9
10 .data
11
12LCopyWidth: .long 0
13LBlockSrcStep: .long 0
14LBlockDestStep: .long 0
15LSrcDelta: .long 0
16LDestDelta: .long 0
17
18#define bufptr 4+16
19
20// copies 16 rows per plane at a pop; idea is that 16*512 = 8k, and since
21// no Mode X mode is wider than 360, all the data should fit in the cache for
22// the passes for the next 3 planes
23
24 .text
25
26.globl C(VGA_UpdatePlanarScreen)
27C(VGA_UpdatePlanarScreen):
28 pushl %ebp // preserve caller's stack frame
29 pushl %edi
30 pushl %esi // preserve register variables
31 pushl %ebx
32
33 movl C(VGA_bufferrowbytes),%eax
34 shll $1,%eax
35 movl %eax,LBlockSrcStep
36 movl C(VGA_rowbytes),%eax
37 shll $1,%eax
38 movl %eax,LBlockDestStep
39
40 movl $0x3C4,%edx
41 movb $2,%al
42 outb %al,%dx // point the SC to the Map Mask
43 incl %edx
44
45 movl bufptr(%esp),%esi
46 movl C(VGA_pagebase),%edi
47 movl C(VGA_height),%ebp
48 shrl $1,%ebp
49
50 movl C(VGA_width),%ecx
51 movl C(VGA_bufferrowbytes),%eax
52 subl %ecx,%eax
53 movl %eax,LSrcDelta
54 movl C(VGA_rowbytes),%eax
55 shll $2,%eax
56 subl %ecx,%eax
57 movl %eax,LDestDelta
58 shrl $4,%ecx
59 movl %ecx,LCopyWidth
60
61LRowLoop:
62 movb $1,%al
63
64LPlaneLoop:
65 outb %al,%dx
66 movb $2,%ah
67
68 pushl %esi
69 pushl %edi
70LRowSetLoop:
71 movl LCopyWidth,%ecx
72LColumnLoop:
73 movb 12(%esi),%bh
74 movb 8(%esi),%bl
75 shll $16,%ebx
76 movb 4(%esi),%bh
77 movb (%esi),%bl
78 movl %ebx,(%edi)
79 addl $16,%esi
80 addl $4,%edi
81 decl %ecx
82 jnz LColumnLoop
83
84 addl LDestDelta,%edi
85 addl LSrcDelta,%esi
86 decb %ah
87 jnz LRowSetLoop
88
89 popl %edi
90 popl %esi
91 incl %esi
92
93 shlb $1,%al
94 cmpb $16,%al
95 jnz LPlaneLoop
96
97 subl $4,%esi
98 addl LBlockSrcStep,%esi
99 addl LBlockDestStep,%edi
100 decl %ebp
101 jnz LRowLoop
102
103 popl %ebx // restore register variables
104 popl %esi
105 popl %edi
106 popl %ebp // restore the caller's stack frame
107
108 ret
109
110
111#define srcptr 4+16
112#define destptr 8+16
113#define width 12+16
114#define height 16+16
115#define srcrowbytes 20+16
116#define destrowbytes 24+16
117
118.globl C(VGA_UpdateLinearScreen)
119C(VGA_UpdateLinearScreen):
120 pushl %ebp // preserve caller's stack frame
121 pushl %edi
122 pushl %esi // preserve register variables
123 pushl %ebx
124
125 cld
126 movl srcptr(%esp),%esi
127 movl destptr(%esp),%edi
128 movl width(%esp),%ebx
129 movl srcrowbytes(%esp),%eax
130 subl %ebx,%eax
131 movl destrowbytes(%esp),%edx
132 subl %ebx,%edx
133 shrl $2,%ebx
134 movl height(%esp),%ebp
135LLRowLoop:
136 movl %ebx,%ecx
137 rep/movsl (%esi),(%edi)
138 addl %eax,%esi
139 addl %edx,%edi
140 decl %ebp
141 jnz LLRowLoop
142
143 popl %ebx // restore register variables
144 popl %esi
145 popl %edi
146 popl %ebp // restore the caller's stack frame
147
148 ret
149
diff --git a/apps/plugins/sdl/progs/quake/d_edge.c b/apps/plugins/sdl/progs/quake/d_edge.c
new file mode 100644
index 0000000000..52cc8eb276
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_edge.c
@@ -0,0 +1,331 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_edge.c
21
22#include "quakedef.h"
23#include "d_local.h"
24
25static int miplevel;
26
27float scale_for_mip;
28int screenwidth;
29int ubasestep, errorterm, erroradjustup, erroradjustdown;
30int vstartscan;
31
32// FIXME: should go away
33extern void R_RotateBmodel (void);
34extern void R_TransformFrustum (void);
35
36vec3_t transformed_modelorg;
37
38/*
39==============
40D_DrawPoly
41
42==============
43*/
44void D_DrawPoly (void)
45{
46// this driver takes spans, not polygons
47}
48
49
50/*
51=============
52D_MipLevelForScale
53=============
54*/
55int D_MipLevelForScale (float scale)
56{
57 int lmiplevel;
58
59 if (scale >= d_scalemip[0] )
60 lmiplevel = 0;
61 else if (scale >= d_scalemip[1] )
62 lmiplevel = 1;
63 else if (scale >= d_scalemip[2] )
64 lmiplevel = 2;
65 else
66 lmiplevel = 3;
67
68 if (lmiplevel < d_minmip)
69 lmiplevel = d_minmip;
70
71 return lmiplevel;
72}
73
74
75/*
76==============
77D_DrawSolidSurface
78==============
79*/
80
81// FIXME: clean this up
82
83void D_DrawSolidSurface (surf_t *surf, int color)
84{
85 espan_t *span;
86 byte *pdest;
87 int u, u2, pix;
88
89 pix = (color<<24) | (color<<16) | (color<<8) | color;
90 for (span=surf->spans ; span ; span=span->pnext)
91 {
92 pdest = (byte *)d_viewbuffer + screenwidth*span->v;
93 u = span->u;
94 u2 = span->u + span->count - 1;
95 ((byte *)pdest)[u] = pix;
96
97 if (u2 - u < 8)
98 {
99 for (u++ ; u <= u2 ; u++)
100 ((byte *)pdest)[u] = pix;
101 }
102 else
103 {
104 for (u++ ; u & 3 ; u++)
105 ((byte *)pdest)[u] = pix;
106
107 u2 -= 4;
108 for ( ; u <= u2 ; u+=4)
109 *(int *)((byte *)pdest + u) = pix;
110 u2 += 4;
111 for ( ; u <= u2 ; u++)
112 ((byte *)pdest)[u] = pix;
113 }
114 }
115}
116
117
118/*
119==============
120D_CalcGradients
121==============
122*/
123void D_CalcGradients (msurface_t *pface)
124{
125 mplane_t *pplane;
126 float mipscale;
127 vec3_t p_temp1;
128 vec3_t p_saxis, p_taxis;
129 float t;
130
131 pplane = pface->plane;
132
133 mipscale = 1.0 / (float)(1 << miplevel);
134
135 TransformVector (pface->texinfo->vecs[0], p_saxis);
136 TransformVector (pface->texinfo->vecs[1], p_taxis);
137
138 t = xscaleinv * mipscale;
139 d_sdivzstepu = p_saxis[0] * t;
140 d_tdivzstepu = p_taxis[0] * t;
141
142 t = yscaleinv * mipscale;
143 d_sdivzstepv = -p_saxis[1] * t;
144 d_tdivzstepv = -p_taxis[1] * t;
145
146 d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu -
147 ycenter * d_sdivzstepv;
148 d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu -
149 ycenter * d_tdivzstepv;
150
151 VectorScale (transformed_modelorg, mipscale, p_temp1);
152
153 t = 0x10000*mipscale;
154 sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
155 ((pface->texturemins[0] << 16) >> miplevel)
156 + pface->texinfo->vecs[0][3]*t;
157 tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
158 ((pface->texturemins[1] << 16) >> miplevel)
159 + pface->texinfo->vecs[1][3]*t;
160
161//
162// -1 (-epsilon) so we never wander off the edge of the texture
163//
164 bbextents = ((pface->extents[0] << 16) >> miplevel) - 1;
165 bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1;
166}
167
168
169/*
170==============
171D_DrawSurfaces
172==============
173*/
174void D_DrawSurfaces (void)
175{
176 surf_t *s;
177 msurface_t *pface;
178 surfcache_t *pcurrentcache;
179 vec3_t world_transformed_modelorg;
180 vec3_t local_modelorg;
181
182 currententity = &cl_entities[0];
183 TransformVector (modelorg, transformed_modelorg);
184 VectorCopy (transformed_modelorg, world_transformed_modelorg);
185
186// TODO: could preset a lot of this at mode set time
187 if (r_drawflat.value)
188 {
189 for (s = &surfaces[1] ; s<surface_p ; s++)
190 {
191 if (!s->spans)
192 continue;
193
194 d_zistepu = s->d_zistepu;
195 d_zistepv = s->d_zistepv;
196 d_ziorigin = s->d_ziorigin;
197
198 D_DrawSolidSurface (s, (int)s->data & 0xFF);
199 D_DrawZSpans (s->spans);
200 }
201 }
202 else
203 {
204 for (s = &surfaces[1] ; s<surface_p ; s++)
205 {
206 if (!s->spans)
207 continue;
208
209 r_drawnpolycount++;
210
211 d_zistepu = s->d_zistepu;
212 d_zistepv = s->d_zistepv;
213 d_ziorigin = s->d_ziorigin;
214
215 if (s->flags & SURF_DRAWSKY)
216 {
217 if (!r_skymade)
218 {
219 R_MakeSky ();
220 }
221
222 D_DrawSkyScans8 (s->spans);
223 D_DrawZSpans (s->spans);
224 }
225 else if (s->flags & SURF_DRAWBACKGROUND)
226 {
227 // set up a gradient for the background surface that places it
228 // effectively at infinity distance from the viewpoint
229 d_zistepu = 0;
230 d_zistepv = 0;
231 d_ziorigin = -0.9;
232
233 D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF);
234 D_DrawZSpans (s->spans);
235 }
236 else if (s->flags & SURF_DRAWTURB)
237 {
238 pface = s->data;
239 miplevel = 0;
240 cacheblock = (pixel_t *)
241 ((byte *)pface->texinfo->texture +
242 pface->texinfo->texture->offsets[0]);
243 cachewidth = 64;
244
245 if (s->insubmodel)
246 {
247 // FIXME: we don't want to do all this for every polygon!
248 // TODO: store once at start of frame
249 currententity = s->entity; //FIXME: make this passed in to
250 // R_RotateBmodel ()
251 VectorSubtract (r_origin, currententity->origin,
252 local_modelorg);
253 TransformVector (local_modelorg, transformed_modelorg);
254
255 R_RotateBmodel (); // FIXME: don't mess with the frustum,
256 // make entity passed in
257 }
258
259 D_CalcGradients (pface);
260 Turbulent8 (s->spans);
261 D_DrawZSpans (s->spans);
262
263 if (s->insubmodel)
264 {
265 //
266 // restore the old drawing state
267 // FIXME: we don't want to do this every time!
268 // TODO: speed up
269 //
270 currententity = &cl_entities[0];
271 VectorCopy (world_transformed_modelorg,
272 transformed_modelorg);
273 VectorCopy (base_vpn, vpn);
274 VectorCopy (base_vup, vup);
275 VectorCopy (base_vright, vright);
276 VectorCopy (base_modelorg, modelorg);
277 R_TransformFrustum ();
278 }
279 }
280 else
281 {
282 if (s->insubmodel)
283 {
284 // FIXME: we don't want to do all this for every polygon!
285 // TODO: store once at start of frame
286 currententity = s->entity; //FIXME: make this passed in to
287 // R_RotateBmodel ()
288 VectorSubtract (r_origin, currententity->origin, local_modelorg);
289 TransformVector (local_modelorg, transformed_modelorg);
290
291 R_RotateBmodel (); // FIXME: don't mess with the frustum,
292 // make entity passed in
293 }
294
295 pface = s->data;
296 miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip
297 * pface->texinfo->mipadjust);
298
299 // FIXME: make this passed in to D_CacheSurface
300 pcurrentcache = D_CacheSurface (pface, miplevel);
301
302 cacheblock = (pixel_t *)pcurrentcache->data;
303 cachewidth = pcurrentcache->width;
304
305 D_CalcGradients (pface);
306
307 (*d_drawspans) (s->spans);
308
309 D_DrawZSpans (s->spans);
310
311 if (s->insubmodel)
312 {
313 //
314 // restore the old drawing state
315 // FIXME: we don't want to do this every time!
316 // TODO: speed up
317 //
318 currententity = &cl_entities[0];
319 VectorCopy (world_transformed_modelorg,
320 transformed_modelorg);
321 VectorCopy (base_vpn, vpn);
322 VectorCopy (base_vup, vup);
323 VectorCopy (base_vright, vright);
324 VectorCopy (base_modelorg, modelorg);
325 R_TransformFrustum ();
326 }
327 }
328 }
329 }
330}
331
diff --git a/apps/plugins/sdl/progs/quake/d_fill.c b/apps/plugins/sdl/progs/quake/d_fill.c
new file mode 100644
index 0000000000..e6c14733b4
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_fill.c
@@ -0,0 +1,88 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_clear: clears a specified rectangle to the specified color
21
22#include "quakedef.h"
23
24
25/*
26================
27D_FillRect
28================
29*/
30void D_FillRect (vrect_t *rect, int color)
31{
32 int rx, ry, rwidth, rheight;
33 unsigned char *dest;
34 unsigned *ldest;
35
36 rx = rect->x;
37 ry = rect->y;
38 rwidth = rect->width;
39 rheight = rect->height;
40
41 if (rx < 0)
42 {
43 rwidth += rx;
44 rx = 0;
45 }
46 if (ry < 0)
47 {
48 rheight += ry;
49 ry = 0;
50 }
51 if (rx+rwidth > vid.width)
52 rwidth = vid.width - rx;
53 if (ry+rheight > vid.height)
54 rheight = vid.height - rx;
55
56 if (rwidth < 1 || rheight < 1)
57 return;
58
59 dest = ((byte *)vid.buffer + ry*vid.rowbytes + rx);
60
61 if (((rwidth & 0x03) == 0) && (((long)dest & 0x03) == 0))
62 {
63 // faster aligned dword clear
64 ldest = (unsigned *)dest;
65 color += color << 16;
66
67 rwidth >>= 2;
68 color += color << 8;
69
70 for (ry=0 ; ry<rheight ; ry++)
71 {
72 for (rx=0 ; rx<rwidth ; rx++)
73 ldest[rx] = color;
74 ldest = (unsigned *)((byte*)ldest + vid.rowbytes);
75 }
76 }
77 else
78 {
79 // slower byte-by-byte clear for unaligned cases
80 for (ry=0 ; ry<rheight ; ry++)
81 {
82 for (rx=0 ; rx<rwidth ; rx++)
83 dest[rx] = color;
84 dest += vid.rowbytes;
85 }
86 }
87}
88
diff --git a/apps/plugins/sdl/progs/quake/d_iface.h b/apps/plugins/sdl/progs/quake/d_iface.h
new file mode 100644
index 0000000000..8dc5ce94bc
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_iface.h
@@ -0,0 +1,231 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_iface.h: interface header file for rasterization driver modules
21
22#define WARP_WIDTH 320
23#define WARP_HEIGHT 200
24
25#define MAX_LBM_HEIGHT 480
26
27typedef struct
28{
29 float u, v;
30 float s, t;
31 float zi;
32} emitpoint_t;
33
34typedef int ptype_t;
35
36enum {
37 pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2
38};
39
40// !!! if this is changed, it must be changed in d_ifacea.h too !!!
41typedef struct particle_s
42{
43// driver-usable fields
44 vec3_t org;
45 float color;
46// drivers never touch the following fields
47 struct particle_s *next;
48 vec3_t vel;
49 float ramp;
50 float die;
51 ptype_t type;
52} particle_t;
53
54#define PARTICLE_Z_CLIP 8.0
55
56typedef struct polyvert_s {
57 float u, v, zi, s, t;
58} polyvert_t;
59
60typedef struct polydesc_s {
61 int numverts;
62 float nearzi;
63 msurface_t *pcurrentface;
64 polyvert_t *pverts;
65} polydesc_t;
66
67// !!! if this is changed, it must be changed in d_ifacea.h too !!!
68typedef struct finalvert_s {
69 int v[6]; // u, v, s, t, l, 1/z
70 int flags;
71 float reserved;
72} finalvert_t;
73
74// !!! if this is changed, it must be changed in d_ifacea.h too !!!
75typedef struct
76{
77 void *pskin;
78 maliasskindesc_t *pskindesc;
79 int skinwidth;
80 int skinheight;
81 mtriangle_t *ptriangles;
82 finalvert_t *pfinalverts;
83 int numtriangles;
84 int drawtype;
85 int seamfixupX16;
86} affinetridesc_t;
87
88// !!! if this is changed, it must be changed in d_ifacea.h too !!!
89typedef struct {
90 float u, v, zi, color;
91} screenpart_t;
92
93typedef struct
94{
95 int nump;
96 emitpoint_t *pverts; // there's room for an extra element at [nump],
97 // if the driver wants to duplicate element [0] at
98 // element [nump] to avoid dealing with wrapping
99 mspriteframe_t *pspriteframe;
100 vec3_t vup, vright, vpn; // in worldspace
101 float nearzi;
102} spritedesc_t;
103
104typedef struct
105{
106 int u, v;
107 float zi;
108 int color;
109} zpointdesc_t;
110
111extern cvar_t r_drawflat;
112extern int d_spanpixcount;
113extern int r_framecount; // sequence # of current frame since Quake
114 // started
115extern qboolean r_drawpolys; // 1 if driver wants clipped polygons
116 // rather than a span list
117extern qboolean r_drawculledpolys; // 1 if driver wants clipped polygons that
118 // have been culled by the edge list
119extern qboolean r_worldpolysbacktofront; // 1 if driver wants polygons
120 // delivered back to front rather
121 // than front to back
122extern qboolean r_recursiveaffinetriangles; // true if a driver wants to use
123 // recursive triangular subdivison
124 // and vertex drawing via
125 // D_PolysetDrawFinalVerts() past
126 // a certain distance (normally
127 // only used by the software
128 // driver)
129extern float r_aliasuvscale; // scale-up factor for screen u and v
130 // on Alias vertices passed to driver
131extern int r_pixbytes;
132extern qboolean r_dowarp;
133
134extern affinetridesc_t r_affinetridesc;
135extern spritedesc_t r_spritedesc;
136extern zpointdesc_t r_zpointdesc;
137extern polydesc_t r_polydesc;
138
139extern int d_con_indirect; // if 0, Quake will draw console directly
140 // to vid.buffer; if 1, Quake will
141 // draw console via D_DrawRect. Must be
142 // defined by driver
143
144extern vec3_t r_pright, r_pup, r_ppn;
145
146
147void D_Aff8Patch (void *pcolormap);
148void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height);
149void D_DisableBackBufferAccess (void);
150void D_EndDirectRect (int x, int y, int width, int height);
151void D_PolysetDraw (void);
152void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts);
153void D_DrawParticle (particle_t *pparticle);
154void D_DrawPoly (void);
155void D_DrawSprite (void);
156void D_DrawSurfaces (void);
157void D_DrawZPoint (void);
158void D_EnableBackBufferAccess (void);
159void D_EndParticles (void);
160void D_Init (void);
161void D_ViewChanged (void);
162void D_SetupFrame (void);
163void D_StartParticles (void);
164void D_TurnZOn (void);
165void D_WarpScreen (void);
166
167void D_FillRect (vrect_t *vrect, int color);
168void D_DrawRect (void);
169void D_UpdateRects (vrect_t *prect);
170
171// currently for internal use only, and should be a do-nothing function in
172// hardware drivers
173// FIXME: this should go away
174void D_PolysetUpdateTables (void);
175
176// these are currently for internal use only, and should not be used by drivers
177extern int r_skydirect;
178extern byte *r_skysource;
179
180// transparency types for D_DrawRect ()
181#define DR_SOLID 0
182#define DR_TRANSPARENT 1
183
184// !!! must be kept the same as in quakeasm.h !!!
185#define TRANSPARENT_COLOR 0xFF
186
187extern void *acolormap; // FIXME: should go away
188
189//=======================================================================//
190
191// callbacks to Quake
192
193typedef struct
194{
195 pixel_t *surfdat; // destination for generated surface
196 int rowbytes; // destination logical width in bytes
197 msurface_t *surf; // description for surface to generate
198 fixed8_t lightadj[MAXLIGHTMAPS];
199 // adjust for lightmap levels for dynamic lighting
200 texture_t *texture; // corrected for animating textures
201 int surfmip; // mipmapped ratio of surface texels / world pixels
202 int surfwidth; // in mipmapped texels
203 int surfheight; // in mipmapped texels
204} drawsurf_t;
205
206extern drawsurf_t r_drawsurf;
207
208void R_DrawSurface (void);
209void R_GenTile (msurface_t *psurf, void *pdest);
210
211
212// !!! if this is changed, it must be changed in d_ifacea.h too !!!
213#define TURB_TEX_SIZE 64 // base turbulent texture size
214
215// !!! if this is changed, it must be changed in d_ifacea.h too !!!
216#define CYCLE 128 // turbulent cycle size
217
218#define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf
219
220#define SKYSHIFT 7
221#define SKYSIZE (1 << SKYSHIFT)
222#define SKYMASK (SKYSIZE - 1)
223
224extern float skyspeed, skyspeed2;
225extern float skytime;
226
227extern int c_surf;
228extern vrect_t scr_vrect;
229
230extern byte *r_warpbuffer;
231
diff --git a/apps/plugins/sdl/progs/quake/d_ifacea.h b/apps/plugins/sdl/progs/quake/d_ifacea.h
new file mode 100644
index 0000000000..241952af6f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_ifacea.h
@@ -0,0 +1,98 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// d_ifacea.h
22//
23// Include file for asm driver interface.
24//
25
26//
27// !!! note that this file must match the corresponding C structures in
28// d_iface.h at all times !!!
29//
30
31// !!! if this is changed, it must be changed in r_shared.h too !!!
32#define ALIAS_ONSEAM 0x0020
33
34// !!! if this is changed, it must be changed in d_iface.h too !!!
35#define TURB_TEX_SIZE 64 // base turbulent texture size
36
37// !!! if this is changed, it must be changed in d_iface.h too !!!
38#define CYCLE 128
39
40// !!! if this is changed, it must be changed in r_shared.h too !!!
41#define MAXHEIGHT 1024
42
43// !!! if this is changed, it must be changed in quakedef.h too !!!
44#define CACHE_SIZE 32 // used to align key data structures
45
46// particle_t structure
47// !!! if this is changed, it must be changed in d_iface.h too !!!
48// driver-usable fields
49#define pt_org 0
50#define pt_color 12
51// drivers never touch the following fields
52#define pt_next 16
53#define pt_vel 20
54#define pt_ramp 32
55#define pt_die 36
56#define pt_type 40
57#define pt_size 44
58
59#define PARTICLE_Z_CLIP 8.0
60
61// finalvert_t structure
62// !!! if this is changed, it must be changed in d_iface.h too !!!
63#define fv_v 0 // !!! if this is moved, cases where the !!!
64 // !!! address of this field is pushed in !!!
65 // !!! d_polysa.s must be changed !!!
66#define fv_flags 24
67#define fv_reserved 28
68#define fv_size 32
69#define fv_shift 5
70
71
72// stvert_t structure
73// !!! if this is changed, it must be changed in modelgen.h too !!!
74#define stv_onseam 0
75#define stv_s 4
76#define stv_t 8
77#define stv_size 12
78
79
80// trivertx_t structure
81// !!! if this is changed, it must be changed in modelgen.h too !!!
82#define tv_v 0
83#define tv_lightnormalindex 3
84#define tv_size 4
85
86// affinetridesc_t structure
87// !!! if this is changed, it must be changed in d_iface.h too !!!
88#define atd_pskin 0
89#define atd_pskindesc 4
90#define atd_skinwidth 8
91#define atd_skinheight 12
92#define atd_ptriangles 16
93#define atd_pfinalverts 20
94#define atd_numtriangles 24
95#define atd_drawtype 28
96#define atd_seamfixupX16 32
97#define atd_size 36
98
diff --git a/apps/plugins/sdl/progs/quake/d_init.c b/apps/plugins/sdl/progs/quake/d_init.c
new file mode 100644
index 0000000000..4c360fa1af
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_init.c
@@ -0,0 +1,173 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_init.c: rasterization driver initialization
21
22#include "quakedef.h"
23#include "d_local.h"
24
25#define NUM_MIPS 4
26
27cvar_t d_subdiv16 = {"d_subdiv16", "1"};
28cvar_t d_mipcap = {"d_mipcap", "0"};
29cvar_t d_mipscale = {"d_mipscale", "1"};
30
31surfcache_t *d_initial_rover;
32qboolean d_roverwrapped;
33int d_minmip;
34float d_scalemip[NUM_MIPS-1];
35
36static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
37
38extern int d_aflatcolor;
39
40void (*d_drawspans) (espan_t *pspan);
41
42
43/*
44===============
45D_Init
46===============
47*/
48void D_Init (void)
49{
50
51 r_skydirect = 1;
52
53 Cvar_RegisterVariable (&d_subdiv16);
54 Cvar_RegisterVariable (&d_mipcap);
55 Cvar_RegisterVariable (&d_mipscale);
56
57 r_drawpolys = false;
58 r_worldpolysbacktofront = false;
59 r_recursiveaffinetriangles = true;
60 r_pixbytes = 1;
61 r_aliasuvscale = 1.0;
62}
63
64
65/*
66===============
67D_CopyRects
68===============
69*/
70void D_CopyRects (vrect_t *prects, int transparent)
71{
72
73// this function is only required if the CPU doesn't have direct access to the
74// back buffer, and there's some driver interface function that the driver
75// doesn't support and requires Quake to do in software (such as drawing the
76// console); Quake will then draw into wherever the driver points vid.buffer
77// and will call this function before swapping buffers
78
79 UNUSED(prects);
80 UNUSED(transparent);
81}
82
83
84/*
85===============
86D_EnableBackBufferAccess
87===============
88*/
89void D_EnableBackBufferAccess (void)
90{
91 VID_LockBuffer ();
92}
93
94
95/*
96===============
97D_TurnZOn
98===============
99*/
100void D_TurnZOn (void)
101{
102// not needed for software version
103}
104
105
106/*
107===============
108D_DisableBackBufferAccess
109===============
110*/
111void D_DisableBackBufferAccess (void)
112{
113 VID_UnlockBuffer ();
114}
115
116
117/*
118===============
119D_SetupFrame
120===============
121*/
122void D_SetupFrame (void)
123{
124 int i;
125
126 if (r_dowarp)
127 d_viewbuffer = r_warpbuffer;
128 else
129 d_viewbuffer = (void *)(byte *)vid.buffer;
130
131 if (r_dowarp)
132 screenwidth = WARP_WIDTH;
133 else
134 screenwidth = vid.rowbytes;
135
136 d_roverwrapped = false;
137 d_initial_rover = sc_rover;
138
139 d_minmip = d_mipcap.value;
140 if (d_minmip > 3)
141 d_minmip = 3;
142 else if (d_minmip < 0)
143 d_minmip = 0;
144
145 for (i=0 ; i<(NUM_MIPS-1) ; i++)
146 d_scalemip[i] = basemip[i] * d_mipscale.value;
147
148#if id386
149 if (d_subdiv16.value)
150 d_drawspans = D_DrawSpans16;
151 else
152 d_drawspans = D_DrawSpans8;
153#else
154 d_drawspans = D_DrawSpans8;
155#endif
156
157 d_aflatcolor = 0;
158}
159
160
161/*
162===============
163D_UpdateRects
164===============
165*/
166void D_UpdateRects (vrect_t *prect)
167{
168
169// the software driver draws these directly to the vid buffer
170
171 UNUSED(prect);
172}
173
diff --git a/apps/plugins/sdl/progs/quake/d_local.h b/apps/plugins/sdl/progs/quake/d_local.h
new file mode 100644
index 0000000000..af924899e5
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_local.h
@@ -0,0 +1,111 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_local.h: private rasterization driver defs
21
22#include "r_shared.h"
23
24//
25// TODO: fine-tune this; it's based on providing some overage even if there
26// is a 2k-wide scan, with subdivision every 8, for 256 spans of 12 bytes each
27//
28#define SCANBUFFERPAD 0x1000
29
30#define R_SKY_SMASK 0x007F0000
31#define R_SKY_TMASK 0x007F0000
32
33#define DS_SPAN_LIST_END -128
34
35#define SURFCACHE_SIZE_AT_320X200 600*1024
36
37typedef struct surfcache_s
38{
39 struct surfcache_s *next;
40 struct surfcache_s **owner; // NULL is an empty chunk of memory
41 int lightadj[MAXLIGHTMAPS]; // checked for strobe flush
42 int dlight;
43 int size; // including header
44 unsigned width;
45 unsigned height; // DEBUG only needed for debug
46 float mipscale;
47 struct texture_s *texture; // checked for animating textures
48 byte data[4]; // width*height elements
49} surfcache_t;
50
51// !!! if this is changed, it must be changed in asm_draw.h too !!!
52typedef struct sspan_s
53{
54 int u, v, count;
55} sspan_t;
56
57extern cvar_t d_subdiv16;
58
59extern float scale_for_mip;
60
61extern qboolean d_roverwrapped;
62extern surfcache_t *sc_rover;
63extern surfcache_t *d_initial_rover;
64
65extern float d_sdivzstepu, d_tdivzstepu, d_zistepu;
66extern float d_sdivzstepv, d_tdivzstepv, d_zistepv;
67extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
68
69fixed16_t sadjust, tadjust;
70fixed16_t bbextents, bbextentt;
71
72
73void D_DrawSpans8 (espan_t *pspans);
74void D_DrawSpans16 (espan_t *pspans);
75void D_DrawZSpans (espan_t *pspans);
76void Turbulent8 (espan_t *pspan);
77void D_SpriteDrawSpans (sspan_t *pspan);
78
79void D_DrawSkyScans8 (espan_t *pspan);
80void D_DrawSkyScans16 (espan_t *pspan);
81
82void R_ShowSubDiv (void);
83void (*prealspandrawer)(void);
84surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel);
85
86extern int D_MipLevelForScale (float scale);
87
88#if id386
89extern void D_PolysetAff8Start (void);
90extern void D_PolysetAff8End (void);
91#endif
92
93extern short *d_pzbuffer;
94extern unsigned int d_zrowbytes, d_zwidth;
95
96extern int *d_pscantable;
97extern int d_scantable[MAXHEIGHT];
98
99extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
100
101extern int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift;
102
103extern pixel_t *d_viewbuffer;
104
105extern short *zspantable[MAXHEIGHT];
106
107extern int d_minmip;
108extern float d_scalemip[3];
109
110extern void (*d_drawspans) (espan_t *pspan);
111
diff --git a/apps/plugins/sdl/progs/quake/d_modech.c b/apps/plugins/sdl/progs/quake/d_modech.c
new file mode 100644
index 0000000000..75c188e362
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_modech.c
@@ -0,0 +1,107 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_modech.c: called when mode has just changed
21
22#include "quakedef.h"
23#include "d_local.h"
24
25int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
26
27int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift;
28
29int d_scantable[MAXHEIGHT];
30short *zspantable[MAXHEIGHT];
31
32/*
33================
34D_Patch
35================
36*/
37void D_Patch (void)
38{
39#if id386
40
41 static qboolean protectset8 = false;
42
43 if (!protectset8)
44 {
45 Sys_MakeCodeWriteable ((int)D_PolysetAff8Start,
46 (int)D_PolysetAff8End - (int)D_PolysetAff8Start);
47 protectset8 = true;
48 }
49
50#endif // id386
51}
52
53
54/*
55================
56D_ViewChanged
57================
58*/
59void D_ViewChanged (void)
60{
61 int rowbytes;
62
63 if (r_dowarp)
64 rowbytes = WARP_WIDTH;
65 else
66 rowbytes = vid.rowbytes;
67
68 scale_for_mip = xscale;
69 if (yscale > xscale)
70 scale_for_mip = yscale;
71
72 d_zrowbytes = vid.width * 2;
73 d_zwidth = vid.width;
74
75 d_pix_min = r_refdef.vrect.width / 320;
76 if (d_pix_min < 1)
77 d_pix_min = 1;
78
79 d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
80 d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
81 if (d_pix_max < 1)
82 d_pix_max = 1;
83
84 if (pixelAspect > 1.4)
85 d_y_aspect_shift = 1;
86 else
87 d_y_aspect_shift = 0;
88
89 d_vrectx = r_refdef.vrect.x;
90 d_vrecty = r_refdef.vrect.y;
91 d_vrectright_particle = r_refdef.vrectright - d_pix_max;
92 d_vrectbottom_particle =
93 r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift);
94
95 {
96 int i;
97
98 for (i=0 ; i<vid.height; i++)
99 {
100 d_scantable[i] = i*rowbytes;
101 zspantable[i] = d_pzbuffer + i*d_zwidth;
102 }
103 }
104
105 D_Patch ();
106}
107
diff --git a/apps/plugins/sdl/progs/quake/d_part.c b/apps/plugins/sdl/progs/quake/d_part.c
new file mode 100644
index 0000000000..176b76beab
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_part.c
@@ -0,0 +1,207 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_part.c: software driver module for drawing particles
21
22#include "quakedef.h"
23#include "d_local.h"
24
25
26/*
27==============
28D_EndParticles
29==============
30*/
31void D_EndParticles (void)
32{
33// not used by software driver
34}
35
36
37/*
38==============
39D_StartParticles
40==============
41*/
42void D_StartParticles (void)
43{
44// not used by software driver
45}
46
47
48#if !id386
49
50/*
51==============
52D_DrawParticle
53==============
54*/
55void D_DrawParticle (particle_t *pparticle)
56{
57 vec3_t local, transformed;
58 float zi;
59 byte *pdest;
60 short *pz;
61 int i, izi, pix, count, u, v;
62
63// transform point
64 VectorSubtract (pparticle->org, r_origin, local);
65
66 transformed[0] = DotProduct(local, r_pright);
67 transformed[1] = DotProduct(local, r_pup);
68 transformed[2] = DotProduct(local, r_ppn);
69
70 if (transformed[2] < PARTICLE_Z_CLIP)
71 return;
72
73// project the point
74// FIXME: preadjust xcenter and ycenter
75 zi = 1.0 / transformed[2];
76 u = (int)(xcenter + zi * transformed[0] + 0.5);
77 v = (int)(ycenter - zi * transformed[1] + 0.5);
78
79 if ((v > d_vrectbottom_particle) ||
80 (u > d_vrectright_particle) ||
81 (v < d_vrecty) ||
82 (u < d_vrectx))
83 {
84 return;
85 }
86
87 pz = d_pzbuffer + (d_zwidth * v) + u;
88 pdest = d_viewbuffer + d_scantable[v] + u;
89 izi = (int)(zi * 0x8000);
90
91 pix = izi >> d_pix_shift;
92
93 if (pix < d_pix_min)
94 pix = d_pix_min;
95 else if (pix > d_pix_max)
96 pix = d_pix_max;
97
98 switch (pix)
99 {
100 case 1:
101 count = 1 << d_y_aspect_shift;
102
103 for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
104 {
105 if (pz[0] <= izi)
106 {
107 pz[0] = izi;
108 pdest[0] = pparticle->color;
109 }
110 }
111 break;
112
113 case 2:
114 count = 2 << d_y_aspect_shift;
115
116 for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
117 {
118 if (pz[0] <= izi)
119 {
120 pz[0] = izi;
121 pdest[0] = pparticle->color;
122 }
123
124 if (pz[1] <= izi)
125 {
126 pz[1] = izi;
127 pdest[1] = pparticle->color;
128 }
129 }
130 break;
131
132 case 3:
133 count = 3 << d_y_aspect_shift;
134
135 for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
136 {
137 if (pz[0] <= izi)
138 {
139 pz[0] = izi;
140 pdest[0] = pparticle->color;
141 }
142
143 if (pz[1] <= izi)
144 {
145 pz[1] = izi;
146 pdest[1] = pparticle->color;
147 }
148
149 if (pz[2] <= izi)
150 {
151 pz[2] = izi;
152 pdest[2] = pparticle->color;
153 }
154 }
155 break;
156
157 case 4:
158 count = 4 << d_y_aspect_shift;
159
160 for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
161 {
162 if (pz[0] <= izi)
163 {
164 pz[0] = izi;
165 pdest[0] = pparticle->color;
166 }
167
168 if (pz[1] <= izi)
169 {
170 pz[1] = izi;
171 pdest[1] = pparticle->color;
172 }
173
174 if (pz[2] <= izi)
175 {
176 pz[2] = izi;
177 pdest[2] = pparticle->color;
178 }
179
180 if (pz[3] <= izi)
181 {
182 pz[3] = izi;
183 pdest[3] = pparticle->color;
184 }
185 }
186 break;
187
188 default:
189 count = pix << d_y_aspect_shift;
190
191 for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
192 {
193 for (i=0 ; i<pix ; i++)
194 {
195 if (pz[i] <= izi)
196 {
197 pz[i] = izi;
198 pdest[i] = pparticle->color;
199 }
200 }
201 }
202 break;
203 }
204}
205
206#endif // !id386
207
diff --git a/apps/plugins/sdl/progs/quake/d_polyse.c b/apps/plugins/sdl/progs/quake/d_polyse.c
new file mode 100644
index 0000000000..9acd34b102
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_polyse.c
@@ -0,0 +1,1111 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_polyset.c: routines for drawing sets of polygons sharing the same
21// texture (used for Alias models)
22
23#include "quakedef.h"
24#include "r_local.h"
25#include "d_local.h"
26
27// TODO: put in span spilling to shrink list size
28// !!! if this is changed, it must be changed in d_polysa.s too !!!
29#define DPS_MAXSPANS MAXHEIGHT+1
30 // 1 extra for spanpackage that marks end
31
32// !!! if this is changed, it must be changed in asm_draw.h too !!!
33typedef struct {
34 void *pdest;
35 short *pz;
36 int count;
37 byte *ptex;
38 int sfrac, tfrac, light, zi;
39} spanpackage_t;
40
41typedef struct {
42 int isflattop;
43 int numleftedges;
44 int *pleftedgevert0;
45 int *pleftedgevert1;
46 int *pleftedgevert2;
47 int numrightedges;
48 int *prightedgevert0;
49 int *prightedgevert1;
50 int *prightedgevert2;
51} edgetable;
52
53int r_p0[6], r_p1[6], r_p2[6];
54
55byte *d_pcolormap;
56
57int d_aflatcolor;
58int d_xdenom;
59
60edgetable *pedgetable;
61
62edgetable edgetables[12] = {
63 {0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 },
64 {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, NULL},
65 {1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL},
66 {0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 },
67 {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, NULL},
68 {0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL},
69 {0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 },
70 {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, NULL},
71 {0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL},
72 {1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL},
73 {1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL},
74 {0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL},
75};
76
77// FIXME: some of these can become statics
78int a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
79int r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
80int r_zistepx, r_zistepy;
81int d_aspancount, d_countextrastep;
82
83spanpackage_t *a_spans;
84spanpackage_t *d_pedgespanpackage;
85static int ystart;
86byte *d_pdest, *d_ptex;
87short *d_pz;
88int d_sfrac, d_tfrac, d_light, d_zi;
89int d_ptexextrastep, d_sfracextrastep;
90int d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
91int d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
92int d_sfracbasestep, d_tfracbasestep;
93int d_ziextrastep, d_zibasestep;
94int d_pzextrastep, d_pzbasestep;
95
96typedef struct {
97 int quotient;
98 int remainder;
99} adivtab_t;
100
101static adivtab_t adivtab[32*32] = {
102#include "adivtab.h"
103};
104
105byte *skintable[MAX_LBM_HEIGHT];
106int skinwidth;
107byte *skinstart;
108
109void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage);
110void D_PolysetCalcGradients (int skinwidth);
111void D_DrawSubdiv (void);
112void D_DrawNonSubdiv (void);
113void D_PolysetRecursiveTriangle (int *p1, int *p2, int *p3);
114void D_PolysetSetEdgeTable (void);
115void D_RasterizeAliasPolySmooth (void);
116void D_PolysetScanLeftEdge (int height);
117
118#if !id386
119
120/*
121================
122D_PolysetDraw
123================
124*/
125void D_PolysetDraw (void)
126{
127 spanpackage_t spans[DPS_MAXSPANS + 1 +
128 ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1];
129 // one extra because of cache line pretouching
130
131 a_spans = (spanpackage_t *)
132 (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
133
134 if (r_affinetridesc.drawtype)
135 {
136 D_DrawSubdiv ();
137 }
138 else
139 {
140 D_DrawNonSubdiv ();
141 }
142}
143
144
145/*
146================
147D_PolysetDrawFinalVerts
148================
149*/
150void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts)
151{
152 int i, z;
153 short *zbuf;
154
155 for (i=0 ; i<numverts ; i++, fv++)
156 {
157 // valid triangle coordinates for filling can include the bottom and
158 // right clip edges, due to the fill rule; these shouldn't be drawn
159 if ((fv->v[0] < r_refdef.vrectright) &&
160 (fv->v[1] < r_refdef.vrectbottom))
161 {
162 z = fv->v[5]>>16;
163 zbuf = zspantable[fv->v[1]] + fv->v[0];
164 if (z >= *zbuf)
165 {
166 int pix;
167
168 *zbuf = z;
169 pix = skintable[fv->v[3]>>16][fv->v[2]>>16];
170 pix = ((byte *)acolormap)[pix + (fv->v[4] & 0xFF00) ];
171 d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix;
172 }
173 }
174 }
175}
176
177
178/*
179================
180D_DrawSubdiv
181================
182*/
183void D_DrawSubdiv (void)
184{
185 mtriangle_t *ptri;
186 finalvert_t *pfv, *index0, *index1, *index2;
187 int i;
188 int lnumtriangles;
189
190 pfv = r_affinetridesc.pfinalverts;
191 ptri = r_affinetridesc.ptriangles;
192 lnumtriangles = r_affinetridesc.numtriangles;
193
194 for (i=0 ; i<lnumtriangles ; i++)
195 {
196 index0 = pfv + ptri[i].vertindex[0];
197 index1 = pfv + ptri[i].vertindex[1];
198 index2 = pfv + ptri[i].vertindex[2];
199
200 if (((index0->v[1]-index1->v[1]) *
201 (index0->v[0]-index2->v[0]) -
202 (index0->v[0]-index1->v[0]) *
203 (index0->v[1]-index2->v[1])) >= 0)
204 {
205 continue;
206 }
207
208 d_pcolormap = &((byte *)acolormap)[index0->v[4] & 0xFF00];
209
210 if (ptri[i].facesfront)
211 {
212 D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v);
213 }
214 else
215 {
216 int s0, s1, s2;
217
218 s0 = index0->v[2];
219 s1 = index1->v[2];
220 s2 = index2->v[2];
221
222 if (index0->flags & ALIAS_ONSEAM)
223 index0->v[2] += r_affinetridesc.seamfixupX16;
224 if (index1->flags & ALIAS_ONSEAM)
225 index1->v[2] += r_affinetridesc.seamfixupX16;
226 if (index2->flags & ALIAS_ONSEAM)
227 index2->v[2] += r_affinetridesc.seamfixupX16;
228
229 D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v);
230
231 index0->v[2] = s0;
232 index1->v[2] = s1;
233 index2->v[2] = s2;
234 }
235 }
236}
237
238
239/*
240================
241D_DrawNonSubdiv
242================
243*/
244void D_DrawNonSubdiv (void)
245{
246 mtriangle_t *ptri;
247 finalvert_t *pfv, *index0, *index1, *index2;
248 int i;
249 int lnumtriangles;
250
251 pfv = r_affinetridesc.pfinalverts;
252 ptri = r_affinetridesc.ptriangles;
253 lnumtriangles = r_affinetridesc.numtriangles;
254
255 for (i=0 ; i<lnumtriangles ; i++, ptri++)
256 {
257 index0 = pfv + ptri->vertindex[0];
258 index1 = pfv + ptri->vertindex[1];
259 index2 = pfv + ptri->vertindex[2];
260
261 d_xdenom = (index0->v[1]-index1->v[1]) *
262 (index0->v[0]-index2->v[0]) -
263 (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]);
264
265 if (d_xdenom >= 0)
266 {
267 continue;
268 }
269
270 r_p0[0] = index0->v[0]; // u
271 r_p0[1] = index0->v[1]; // v
272 r_p0[2] = index0->v[2]; // s
273 r_p0[3] = index0->v[3]; // t
274 r_p0[4] = index0->v[4]; // light
275 r_p0[5] = index0->v[5]; // iz
276
277 r_p1[0] = index1->v[0];
278 r_p1[1] = index1->v[1];
279 r_p1[2] = index1->v[2];
280 r_p1[3] = index1->v[3];
281 r_p1[4] = index1->v[4];
282 r_p1[5] = index1->v[5];
283
284 r_p2[0] = index2->v[0];
285 r_p2[1] = index2->v[1];
286 r_p2[2] = index2->v[2];
287 r_p2[3] = index2->v[3];
288 r_p2[4] = index2->v[4];
289 r_p2[5] = index2->v[5];
290
291 if (!ptri->facesfront)
292 {
293 if (index0->flags & ALIAS_ONSEAM)
294 r_p0[2] += r_affinetridesc.seamfixupX16;
295 if (index1->flags & ALIAS_ONSEAM)
296 r_p1[2] += r_affinetridesc.seamfixupX16;
297 if (index2->flags & ALIAS_ONSEAM)
298 r_p2[2] += r_affinetridesc.seamfixupX16;
299 }
300
301 D_PolysetSetEdgeTable ();
302 D_RasterizeAliasPolySmooth ();
303 }
304}
305
306
307/*
308================
309D_PolysetRecursiveTriangle
310================
311*/
312void D_PolysetRecursiveTriangle (int *lp1, int *lp2, int *lp3)
313{
314 int *temp;
315 int d;
316 int new[6];
317 int z;
318 short *zbuf;
319
320 d = lp2[0] - lp1[0];
321 if (d < -1 || d > 1)
322 goto split;
323 d = lp2[1] - lp1[1];
324 if (d < -1 || d > 1)
325 goto split;
326
327 d = lp3[0] - lp2[0];
328 if (d < -1 || d > 1)
329 goto split2;
330 d = lp3[1] - lp2[1];
331 if (d < -1 || d > 1)
332 goto split2;
333
334 d = lp1[0] - lp3[0];
335 if (d < -1 || d > 1)
336 goto split3;
337 d = lp1[1] - lp3[1];
338 if (d < -1 || d > 1)
339 {
340split3:
341 temp = lp1;
342 lp1 = lp3;
343 lp3 = lp2;
344 lp2 = temp;
345
346 goto split;
347 }
348
349 return; // entire tri is filled
350
351split2:
352 temp = lp1;
353 lp1 = lp2;
354 lp2 = lp3;
355 lp3 = temp;
356
357split:
358// split this edge
359 new[0] = (lp1[0] + lp2[0]) >> 1;
360 new[1] = (lp1[1] + lp2[1]) >> 1;
361 new[2] = (lp1[2] + lp2[2]) >> 1;
362 new[3] = (lp1[3] + lp2[3]) >> 1;
363 new[5] = (lp1[5] + lp2[5]) >> 1;
364
365// draw the point if splitting a leading edge
366 if (lp2[1] > lp1[1])
367 goto nodraw;
368 if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0]))
369 goto nodraw;
370
371
372 z = new[5]>>16;
373 zbuf = zspantable[new[1]] + new[0];
374 if (z >= *zbuf)
375 {
376 int pix;
377
378 *zbuf = z;
379 pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]];
380 d_viewbuffer[d_scantable[new[1]] + new[0]] = pix;
381 }
382
383nodraw:
384// recursively continue
385 D_PolysetRecursiveTriangle (lp3, lp1, new);
386 D_PolysetRecursiveTriangle (lp3, new, lp2);
387}
388
389#endif // !id386
390
391
392/*
393================
394D_PolysetUpdateTables
395================
396*/
397void D_PolysetUpdateTables (void)
398{
399 int i;
400 byte *s;
401
402 if (r_affinetridesc.skinwidth != skinwidth ||
403 r_affinetridesc.pskin != skinstart)
404 {
405 skinwidth = r_affinetridesc.skinwidth;
406 skinstart = r_affinetridesc.pskin;
407 s = skinstart;
408 for (i=0 ; i<MAX_LBM_HEIGHT ; i++, s+=skinwidth)
409 skintable[i] = s;
410 }
411}
412
413
414#if !id386
415
416/*
417===================
418D_PolysetScanLeftEdge
419====================
420*/
421void D_PolysetScanLeftEdge (int height)
422{
423
424 do
425 {
426 d_pedgespanpackage->pdest = d_pdest;
427 d_pedgespanpackage->pz = d_pz;
428 d_pedgespanpackage->count = d_aspancount;
429 d_pedgespanpackage->ptex = d_ptex;
430
431 d_pedgespanpackage->sfrac = d_sfrac;
432 d_pedgespanpackage->tfrac = d_tfrac;
433
434 // FIXME: need to clamp l, s, t, at both ends?
435 d_pedgespanpackage->light = d_light;
436 d_pedgespanpackage->zi = d_zi;
437
438 d_pedgespanpackage++;
439
440 errorterm += erroradjustup;
441 if (errorterm >= 0)
442 {
443 d_pdest += d_pdestextrastep;
444 d_pz += d_pzextrastep;
445 d_aspancount += d_countextrastep;
446 d_ptex += d_ptexextrastep;
447 d_sfrac += d_sfracextrastep;
448 d_ptex += d_sfrac >> 16;
449
450 d_sfrac &= 0xFFFF;
451 d_tfrac += d_tfracextrastep;
452 if (d_tfrac & 0x10000)
453 {
454 d_ptex += r_affinetridesc.skinwidth;
455 d_tfrac &= 0xFFFF;
456 }
457 d_light += d_lightextrastep;
458 d_zi += d_ziextrastep;
459 errorterm -= erroradjustdown;
460 }
461 else
462 {
463 d_pdest += d_pdestbasestep;
464 d_pz += d_pzbasestep;
465 d_aspancount += ubasestep;
466 d_ptex += d_ptexbasestep;
467 d_sfrac += d_sfracbasestep;
468 d_ptex += d_sfrac >> 16;
469 d_sfrac &= 0xFFFF;
470 d_tfrac += d_tfracbasestep;
471 if (d_tfrac & 0x10000)
472 {
473 d_ptex += r_affinetridesc.skinwidth;
474 d_tfrac &= 0xFFFF;
475 }
476 d_light += d_lightbasestep;
477 d_zi += d_zibasestep;
478 }
479 } while (--height);
480}
481
482#endif // !id386
483
484
485/*
486===================
487D_PolysetSetUpForLineScan
488====================
489*/
490void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
491 fixed8_t endvertu, fixed8_t endvertv)
492{
493 double dm, dn;
494 int tm, tn;
495 adivtab_t *ptemp;
496
497// TODO: implement x86 version
498
499 errorterm = -1;
500
501 tm = endvertu - startvertu;
502 tn = endvertv - startvertv;
503
504 if (((tm <= 16) && (tm >= -15)) &&
505 ((tn <= 16) && (tn >= -15)))
506 {
507 ptemp = &adivtab[((tm+15) << 5) + (tn+15)];
508 ubasestep = ptemp->quotient;
509 erroradjustup = ptemp->remainder;
510 erroradjustdown = tn;
511 }
512 else
513 {
514 dm = (double)tm;
515 dn = (double)tn;
516
517 FloorDivMod (dm, dn, &ubasestep, &erroradjustup);
518
519 erroradjustdown = dn;
520 }
521}
522
523
524#if !id386
525
526/*
527================
528D_PolysetCalcGradients
529================
530*/
531void D_PolysetCalcGradients (int skinwidth)
532{
533 float xstepdenominv, ystepdenominv, t0, t1;
534 float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20;
535
536 p00_minus_p20 = r_p0[0] - r_p2[0];
537 p01_minus_p21 = r_p0[1] - r_p2[1];
538 p10_minus_p20 = r_p1[0] - r_p2[0];
539 p11_minus_p21 = r_p1[1] - r_p2[1];
540
541 xstepdenominv = 1.0 / (float)d_xdenom;
542
543 ystepdenominv = -xstepdenominv;
544
545// ceil () for light so positive steps are exaggerated, negative steps
546// diminished, pushing us away from underflow toward overflow. Underflow is
547// very visible, overflow is very unlikely, because of ambient lighting
548 t0 = r_p0[4] - r_p2[4];
549 t1 = r_p1[4] - r_p2[4];
550 r_lstepx = (int)
551 ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
552 r_lstepy = (int)
553 ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);
554
555 t0 = r_p0[2] - r_p2[2];
556 t1 = r_p1[2] - r_p2[2];
557 r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
558 xstepdenominv);
559 r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) *
560 ystepdenominv);
561
562 t0 = r_p0[3] - r_p2[3];
563 t1 = r_p1[3] - r_p2[3];
564 r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
565 xstepdenominv);
566 r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
567 ystepdenominv);
568
569 t0 = r_p0[5] - r_p2[5];
570 t1 = r_p1[5] - r_p2[5];
571 r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
572 xstepdenominv);
573 r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
574 ystepdenominv);
575
576#if id386
577 a_sstepxfrac = r_sstepx << 16;
578 a_tstepxfrac = r_tstepx << 16;
579#else
580 a_sstepxfrac = r_sstepx & 0xFFFF;
581 a_tstepxfrac = r_tstepx & 0xFFFF;
582#endif
583
584 a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
585}
586
587#endif // !id386
588
589
590#if 0
591byte gelmap[256];
592void InitGel (byte *palette)
593{
594 int i;
595 int r;
596
597 for (i=0 ; i<256 ; i++)
598 {
599// r = (palette[i*3]>>4);
600 r = (palette[i*3] + palette[i*3+1] + palette[i*3+2])/(16*3);
601 gelmap[i] = /* 64 */ 0 + r;
602 }
603}
604#endif
605
606
607#if !id386
608
609/*
610================
611D_PolysetDrawSpans8
612================
613*/
614void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage)
615{
616 int lcount;
617 byte *lpdest;
618 byte *lptex;
619 int lsfrac, ltfrac;
620 int llight;
621 int lzi;
622 short *lpz;
623
624 do
625 {
626 lcount = d_aspancount - pspanpackage->count;
627
628 errorterm += erroradjustup;
629 if (errorterm >= 0)
630 {
631 d_aspancount += d_countextrastep;
632 errorterm -= erroradjustdown;
633 }
634 else
635 {
636 d_aspancount += ubasestep;
637 }
638
639 if (lcount)
640 {
641 lpdest = pspanpackage->pdest;
642 lptex = pspanpackage->ptex;
643 lpz = pspanpackage->pz;
644 lsfrac = pspanpackage->sfrac;
645 ltfrac = pspanpackage->tfrac;
646 llight = pspanpackage->light;
647 lzi = pspanpackage->zi;
648
649 do
650 {
651 if ((lzi >> 16) >= *lpz)
652 {
653 *lpdest = ((byte *)acolormap)[*lptex + (llight & 0xFF00)];
654// gel mapping *lpdest = gelmap[*lpdest];
655 *lpz = lzi >> 16;
656 }
657 lpdest++;
658 lzi += r_zistepx;
659 lpz++;
660 llight += r_lstepx;
661 lptex += a_ststepxwhole;
662 lsfrac += a_sstepxfrac;
663 lptex += lsfrac >> 16;
664 lsfrac &= 0xFFFF;
665 ltfrac += a_tstepxfrac;
666 if (ltfrac & 0x10000)
667 {
668 lptex += r_affinetridesc.skinwidth;
669 ltfrac &= 0xFFFF;
670 }
671 } while (--lcount);
672 }
673
674 pspanpackage++;
675 } while (pspanpackage->count != -999999);
676}
677#endif // !id386
678
679
680/*
681================
682D_PolysetFillSpans8
683================
684*/
685void D_PolysetFillSpans8 (spanpackage_t *pspanpackage)
686{
687 int color;
688
689// FIXME: do z buffering
690
691 color = d_aflatcolor++;
692
693 while (1)
694 {
695 int lcount;
696 byte *lpdest;
697
698 lcount = pspanpackage->count;
699
700 if (lcount == -1)
701 return;
702
703 if (lcount)
704 {
705 lpdest = pspanpackage->pdest;
706
707 do
708 {
709 *lpdest++ = color;
710 } while (--lcount);
711 }
712
713 pspanpackage++;
714 }
715}
716
717/*
718================
719D_RasterizeAliasPolySmooth
720================
721*/
722void D_RasterizeAliasPolySmooth (void)
723{
724 int initialleftheight, initialrightheight;
725 int *plefttop, *prighttop, *pleftbottom, *prightbottom;
726 int working_lstepx, originalcount;
727
728 plefttop = pedgetable->pleftedgevert0;
729 prighttop = pedgetable->prightedgevert0;
730
731 pleftbottom = pedgetable->pleftedgevert1;
732 prightbottom = pedgetable->prightedgevert1;
733
734 initialleftheight = pleftbottom[1] - plefttop[1];
735 initialrightheight = prightbottom[1] - prighttop[1];
736
737//
738// set the s, t, and light gradients, which are consistent across the triangle
739// because being a triangle, things are affine
740//
741 D_PolysetCalcGradients (r_affinetridesc.skinwidth);
742
743//
744// rasterize the polygon
745//
746
747//
748// scan out the top (and possibly only) part of the left edge
749//
750 d_pedgespanpackage = a_spans;
751
752 ystart = plefttop[1];
753 d_aspancount = plefttop[0] - prighttop[0];
754
755 d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
756 (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
757#if id386
758 d_sfrac = (plefttop[2] & 0xFFFF) << 16;
759 d_tfrac = (plefttop[3] & 0xFFFF) << 16;
760#else
761 d_sfrac = plefttop[2] & 0xFFFF;
762 d_tfrac = plefttop[3] & 0xFFFF;
763#endif
764 d_light = plefttop[4];
765 d_zi = plefttop[5];
766
767 d_pdest = (byte *)d_viewbuffer +
768 ystart * screenwidth + plefttop[0];
769 d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
770
771 if (initialleftheight == 1)
772 {
773 d_pedgespanpackage->pdest = d_pdest;
774 d_pedgespanpackage->pz = d_pz;
775 d_pedgespanpackage->count = d_aspancount;
776 d_pedgespanpackage->ptex = d_ptex;
777
778 d_pedgespanpackage->sfrac = d_sfrac;
779 d_pedgespanpackage->tfrac = d_tfrac;
780
781 // FIXME: need to clamp l, s, t, at both ends?
782 d_pedgespanpackage->light = d_light;
783 d_pedgespanpackage->zi = d_zi;
784
785 d_pedgespanpackage++;
786 }
787 else
788 {
789 D_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
790 pleftbottom[0], pleftbottom[1]);
791
792 #if id386
793 d_pzbasestep = (d_zwidth + ubasestep) << 1;
794 d_pzextrastep = d_pzbasestep + 2;
795 #else
796 d_pzbasestep = d_zwidth + ubasestep;
797 d_pzextrastep = d_pzbasestep + 1;
798 #endif
799
800 d_pdestbasestep = screenwidth + ubasestep;
801 d_pdestextrastep = d_pdestbasestep + 1;
802
803 // TODO: can reuse partial expressions here
804
805 // for negative steps in x along left edge, bias toward overflow rather than
806 // underflow (sort of turning the floor () we did in the gradient calcs into
807 // ceil (), but plus a little bit)
808 if (ubasestep < 0)
809 working_lstepx = r_lstepx - 1;
810 else
811 working_lstepx = r_lstepx;
812
813 d_countextrastep = ubasestep + 1;
814 d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
815 ((r_tstepy + r_tstepx * ubasestep) >> 16) *
816 r_affinetridesc.skinwidth;
817 #if id386
818 d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
819 d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
820 #else
821 d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
822 d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
823 #endif
824 d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
825 d_zibasestep = r_zistepy + r_zistepx * ubasestep;
826
827 d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
828 ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
829 r_affinetridesc.skinwidth;
830 #if id386
831 d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16;
832 d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16;
833 #else
834 d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
835 d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
836 #endif
837 d_lightextrastep = d_lightbasestep + working_lstepx;
838 d_ziextrastep = d_zibasestep + r_zistepx;
839
840 D_PolysetScanLeftEdge (initialleftheight);
841 }
842
843//
844// scan out the bottom part of the left edge, if it exists
845//
846 if (pedgetable->numleftedges == 2)
847 {
848 int height;
849
850 plefttop = pleftbottom;
851 pleftbottom = pedgetable->pleftedgevert2;
852
853 height = pleftbottom[1] - plefttop[1];
854
855// TODO: make this a function; modularize this function in general
856
857 ystart = plefttop[1];
858 d_aspancount = plefttop[0] - prighttop[0];
859 d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) +
860 (plefttop[3] >> 16) * r_affinetridesc.skinwidth;
861 d_sfrac = 0;
862 d_tfrac = 0;
863 d_light = plefttop[4];
864 d_zi = plefttop[5];
865
866 d_pdest = (byte *)d_viewbuffer + ystart * screenwidth + plefttop[0];
867 d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0];
868
869 if (height == 1)
870 {
871 d_pedgespanpackage->pdest = d_pdest;
872 d_pedgespanpackage->pz = d_pz;
873 d_pedgespanpackage->count = d_aspancount;
874 d_pedgespanpackage->ptex = d_ptex;
875
876 d_pedgespanpackage->sfrac = d_sfrac;
877 d_pedgespanpackage->tfrac = d_tfrac;
878
879 // FIXME: need to clamp l, s, t, at both ends?
880 d_pedgespanpackage->light = d_light;
881 d_pedgespanpackage->zi = d_zi;
882
883 d_pedgespanpackage++;
884 }
885 else
886 {
887 D_PolysetSetUpForLineScan(plefttop[0], plefttop[1],
888 pleftbottom[0], pleftbottom[1]);
889
890 d_pdestbasestep = screenwidth + ubasestep;
891 d_pdestextrastep = d_pdestbasestep + 1;
892
893 #if id386
894 d_pzbasestep = (d_zwidth + ubasestep) << 1;
895 d_pzextrastep = d_pzbasestep + 2;
896 #else
897 d_pzbasestep = d_zwidth + ubasestep;
898 d_pzextrastep = d_pzbasestep + 1;
899 #endif
900
901 if (ubasestep < 0)
902 working_lstepx = r_lstepx - 1;
903 else
904 working_lstepx = r_lstepx;
905
906 d_countextrastep = ubasestep + 1;
907 d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) +
908 ((r_tstepy + r_tstepx * ubasestep) >> 16) *
909 r_affinetridesc.skinwidth;
910 #if id386
911 d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16;
912 d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16;
913 #else
914 d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
915 d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
916 #endif
917 d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
918 d_zibasestep = r_zistepy + r_zistepx * ubasestep;
919
920 d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
921 ((r_tstepy + r_tstepx * d_countextrastep) >> 16) *
922 r_affinetridesc.skinwidth;
923 #if id386
924 d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16;
925 d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16;
926 #else
927 d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
928 d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
929 #endif
930 d_lightextrastep = d_lightbasestep + working_lstepx;
931 d_ziextrastep = d_zibasestep + r_zistepx;
932
933 D_PolysetScanLeftEdge (height);
934 }
935 }
936
937// scan out the top (and possibly only) part of the right edge, updating the
938// count field
939 d_pedgespanpackage = a_spans;
940
941 D_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
942 prightbottom[0], prightbottom[1]);
943 d_aspancount = 0;
944 d_countextrastep = ubasestep + 1;
945 originalcount = a_spans[initialrightheight].count;
946 a_spans[initialrightheight].count = -999999; // mark end of the spanpackages
947 D_PolysetDrawSpans8 (a_spans);
948
949// scan out the bottom part of the right edge, if it exists
950 if (pedgetable->numrightedges == 2)
951 {
952 int height;
953 spanpackage_t *pstart;
954
955 pstart = a_spans + initialrightheight;
956 pstart->count = originalcount;
957
958 d_aspancount = prightbottom[0] - prighttop[0];
959
960 prighttop = prightbottom;
961 prightbottom = pedgetable->prightedgevert2;
962
963 height = prightbottom[1] - prighttop[1];
964
965 D_PolysetSetUpForLineScan(prighttop[0], prighttop[1],
966 prightbottom[0], prightbottom[1]);
967
968 d_countextrastep = ubasestep + 1;
969 a_spans[initialrightheight + height].count = -999999;
970 // mark end of the spanpackages
971 D_PolysetDrawSpans8 (pstart);
972 }
973}
974
975
976/*
977================
978D_PolysetSetEdgeTable
979================
980*/
981void D_PolysetSetEdgeTable (void)
982{
983 int edgetableindex;
984
985 edgetableindex = 0; // assume the vertices are already in
986 // top to bottom order
987
988//
989// determine which edges are right & left, and the order in which
990// to rasterize them
991//
992 if (r_p0[1] >= r_p1[1])
993 {
994 if (r_p0[1] == r_p1[1])
995 {
996 if (r_p0[1] < r_p2[1])
997 pedgetable = &edgetables[2];
998 else
999 pedgetable = &edgetables[5];
1000
1001 return;
1002 }
1003 else
1004 {
1005 edgetableindex = 1;
1006 }
1007 }
1008
1009 if (r_p0[1] == r_p2[1])
1010 {
1011 if (edgetableindex)
1012 pedgetable = &edgetables[8];
1013 else
1014 pedgetable = &edgetables[9];
1015
1016 return;
1017 }
1018 else if (r_p1[1] == r_p2[1])
1019 {
1020 if (edgetableindex)
1021 pedgetable = &edgetables[10];
1022 else
1023 pedgetable = &edgetables[11];
1024
1025 return;
1026 }
1027
1028 if (r_p0[1] > r_p2[1])
1029 edgetableindex += 2;
1030
1031 if (r_p1[1] > r_p2[1])
1032 edgetableindex += 4;
1033
1034 pedgetable = &edgetables[edgetableindex];
1035}
1036
1037
1038#if 0
1039
1040void D_PolysetRecursiveDrawLine (int *lp1, int *lp2)
1041{
1042 int d;
1043 int new[6];
1044 int ofs;
1045
1046 d = lp2[0] - lp1[0];
1047 if (d < -1 || d > 1)
1048 goto split;
1049 d = lp2[1] - lp1[1];
1050 if (d < -1 || d > 1)
1051 goto split;
1052
1053 return; // line is completed
1054
1055split:
1056// split this edge
1057 new[0] = (lp1[0] + lp2[0]) >> 1;
1058 new[1] = (lp1[1] + lp2[1]) >> 1;
1059 new[5] = (lp1[5] + lp2[5]) >> 1;
1060 new[2] = (lp1[2] + lp2[2]) >> 1;
1061 new[3] = (lp1[3] + lp2[3]) >> 1;
1062 new[4] = (lp1[4] + lp2[4]) >> 1;
1063
1064// draw the point
1065 ofs = d_scantable[new[1]] + new[0];
1066 if (new[5] > d_pzbuffer[ofs])
1067 {
1068 int pix;
1069
1070 d_pzbuffer[ofs] = new[5];
1071 pix = skintable[new[3]>>16][new[2]>>16];
1072// pix = ((byte *)acolormap)[pix + (new[4] & 0xFF00)];
1073 d_viewbuffer[ofs] = pix;
1074 }
1075
1076// recursively continue
1077 D_PolysetRecursiveDrawLine (lp1, new);
1078 D_PolysetRecursiveDrawLine (new, lp2);
1079}
1080
1081void D_PolysetRecursiveTriangle2 (int *lp1, int *lp2, int *lp3)
1082{
1083 int d;
1084 int new[4];
1085
1086 d = lp2[0] - lp1[0];
1087 if (d < -1 || d > 1)
1088 goto split;
1089 d = lp2[1] - lp1[1];
1090 if (d < -1 || d > 1)
1091 goto split;
1092 return;
1093
1094split:
1095// split this edge
1096 new[0] = (lp1[0] + lp2[0]) >> 1;
1097 new[1] = (lp1[1] + lp2[1]) >> 1;
1098 new[5] = (lp1[5] + lp2[5]) >> 1;
1099 new[2] = (lp1[2] + lp2[2]) >> 1;
1100 new[3] = (lp1[3] + lp2[3]) >> 1;
1101 new[4] = (lp1[4] + lp2[4]) >> 1;
1102
1103 D_PolysetRecursiveDrawLine (new, lp3);
1104
1105// recursively continue
1106 D_PolysetRecursiveTriangle (lp1, new, lp3);
1107 D_PolysetRecursiveTriangle (new, lp2, lp3);
1108}
1109
1110#endif
1111
diff --git a/apps/plugins/sdl/progs/quake/d_scan.c b/apps/plugins/sdl/progs/quake/d_scan.c
new file mode 100644
index 0000000000..008c783be6
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_scan.c
@@ -0,0 +1,449 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_scan.c
21//
22// Portable C scan-level rasterization code, all pixel depths.
23
24#include "quakedef.h"
25#include "r_local.h"
26#include "d_local.h"
27
28unsigned char *r_turb_pbase, *r_turb_pdest;
29fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
30int *r_turb_turb;
31int r_turb_spancount;
32
33void D_DrawTurbulent8Span (void);
34
35
36/*
37=============
38D_WarpScreen
39
40// this performs a slight compression of the screen at the same time as
41// the sine warp, to keep the edges from wrapping
42=============
43*/
44void D_WarpScreen (void)
45{
46 int w, h;
47 int u,v;
48 byte *dest;
49 int *turb;
50 int *col;
51 byte **row;
52 byte *rowptr[MAXHEIGHT+(AMP2*2)];
53 int column[MAXWIDTH+(AMP2*2)];
54 float wratio, hratio;
55
56 w = r_refdef.vrect.width;
57 h = r_refdef.vrect.height;
58
59 wratio = w / (float)scr_vrect.width;
60 hratio = h / (float)scr_vrect.height;
61
62 for (v=0 ; v<scr_vrect.height+AMP2*2 ; v++)
63 {
64 rowptr[v] = d_viewbuffer + (r_refdef.vrect.y * screenwidth) +
65 (screenwidth * (int)((float)v * hratio * h / (h + AMP2 * 2)));
66 }
67
68 for (u=0 ; u<scr_vrect.width+AMP2*2 ; u++)
69 {
70 column[u] = r_refdef.vrect.x +
71 (int)((float)u * wratio * w / (w + AMP2 * 2));
72 }
73
74 turb = intsintable + ((int)(cl.time*SPEED)&(CYCLE-1));
75 dest = vid.buffer + scr_vrect.y * vid.rowbytes + scr_vrect.x;
76
77 for (v=0 ; v<scr_vrect.height ; v++, dest += vid.rowbytes)
78 {
79 col = &column[turb[v]];
80 row = &rowptr[v];
81
82 for (u=0 ; u<scr_vrect.width ; u+=4)
83 {
84 dest[u+0] = row[turb[u+0]][col[u+0]];
85 dest[u+1] = row[turb[u+1]][col[u+1]];
86 dest[u+2] = row[turb[u+2]][col[u+2]];
87 dest[u+3] = row[turb[u+3]][col[u+3]];
88 }
89 }
90}
91
92
93#if !id386
94
95/*
96=============
97D_DrawTurbulent8Span
98=============
99*/
100void D_DrawTurbulent8Span (void)
101{
102 int sturb, tturb;
103
104 do
105 {
106 sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
107 tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
108 *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
109 r_turb_s += r_turb_sstep;
110 r_turb_t += r_turb_tstep;
111 } while (--r_turb_spancount > 0);
112}
113
114#endif // !id386
115
116
117/*
118=============
119Turbulent8
120=============
121*/
122void Turbulent8 (espan_t *pspan)
123{
124 int count;
125 fixed16_t snext, tnext;
126 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
127 float sdivz16stepu, tdivz16stepu, zi16stepu;
128
129 r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
130
131 r_turb_sstep = 0; // keep compiler happy
132 r_turb_tstep = 0; // ditto
133
134 r_turb_pbase = (unsigned char *)cacheblock;
135
136 sdivz16stepu = d_sdivzstepu * 16;
137 tdivz16stepu = d_tdivzstepu * 16;
138 zi16stepu = d_zistepu * 16;
139
140 do
141 {
142 r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
143 (screenwidth * pspan->v) + pspan->u);
144
145 count = pspan->count;
146
147 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
148 du = (float)pspan->u;
149 dv = (float)pspan->v;
150
151 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
152 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
153 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
154 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
155
156 r_turb_s = (int)(sdivz * z) + sadjust;
157 if (r_turb_s > bbextents)
158 r_turb_s = bbextents;
159 else if (r_turb_s < 0)
160 r_turb_s = 0;
161
162 r_turb_t = (int)(tdivz * z) + tadjust;
163 if (r_turb_t > bbextentt)
164 r_turb_t = bbextentt;
165 else if (r_turb_t < 0)
166 r_turb_t = 0;
167
168 do
169 {
170 // calculate s and t at the far end of the span
171 if (count >= 16)
172 r_turb_spancount = 16;
173 else
174 r_turb_spancount = count;
175
176 count -= r_turb_spancount;
177
178 if (count)
179 {
180 // calculate s/z, t/z, zi->fixed s and t at far end of span,
181 // calculate s and t steps across span by shifting
182 sdivz += sdivz16stepu;
183 tdivz += tdivz16stepu;
184 zi += zi16stepu;
185 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
186
187 snext = (int)(sdivz * z) + sadjust;
188 if (snext > bbextents)
189 snext = bbextents;
190 else if (snext < 16)
191 snext = 16; // prevent round-off error on <0 steps from
192 // from causing overstepping & running off the
193 // edge of the texture
194
195 tnext = (int)(tdivz * z) + tadjust;
196 if (tnext > bbextentt)
197 tnext = bbextentt;
198 else if (tnext < 16)
199 tnext = 16; // guard against round-off error on <0 steps
200
201 r_turb_sstep = (snext - r_turb_s) >> 4;
202 r_turb_tstep = (tnext - r_turb_t) >> 4;
203 }
204 else
205 {
206 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
207 // can't step off polygon), clamp, calculate s and t steps across
208 // span by division, biasing steps low so we don't run off the
209 // texture
210 spancountminus1 = (float)(r_turb_spancount - 1);
211 sdivz += d_sdivzstepu * spancountminus1;
212 tdivz += d_tdivzstepu * spancountminus1;
213 zi += d_zistepu * spancountminus1;
214 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
215 snext = (int)(sdivz * z) + sadjust;
216 if (snext > bbextents)
217 snext = bbextents;
218 else if (snext < 16)
219 snext = 16; // prevent round-off error on <0 steps from
220 // from causing overstepping & running off the
221 // edge of the texture
222
223 tnext = (int)(tdivz * z) + tadjust;
224 if (tnext > bbextentt)
225 tnext = bbextentt;
226 else if (tnext < 16)
227 tnext = 16; // guard against round-off error on <0 steps
228
229 if (r_turb_spancount > 1)
230 {
231 r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
232 r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
233 }
234 }
235
236 r_turb_s = r_turb_s & ((CYCLE<<16)-1);
237 r_turb_t = r_turb_t & ((CYCLE<<16)-1);
238
239 D_DrawTurbulent8Span ();
240
241 r_turb_s = snext;
242 r_turb_t = tnext;
243
244 } while (count > 0);
245
246 } while ((pspan = pspan->pnext) != NULL);
247}
248
249
250#if !id386
251
252/*
253=============
254D_DrawSpans8
255=============
256*/
257void D_DrawSpans8 (espan_t *pspan)
258{
259 int count, spancount;
260 unsigned char *pbase, *pdest;
261 fixed16_t s, t, snext, tnext, sstep, tstep;
262 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
263 float sdivz8stepu, tdivz8stepu, zi8stepu;
264
265 sstep = 0; // keep compiler happy
266 tstep = 0; // ditto
267
268 pbase = (unsigned char *)cacheblock;
269
270 sdivz8stepu = d_sdivzstepu * 8;
271 tdivz8stepu = d_tdivzstepu * 8;
272 zi8stepu = d_zistepu * 8;
273
274 do
275 {
276 pdest = (unsigned char *)((byte *)d_viewbuffer +
277 (screenwidth * pspan->v) + pspan->u);
278
279 count = pspan->count;
280
281 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
282 du = (float)pspan->u;
283 dv = (float)pspan->v;
284
285 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
286 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
287 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
288 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
289
290 s = (int)(sdivz * z) + sadjust;
291 if (s > bbextents)
292 s = bbextents;
293 else if (s < 0)
294 s = 0;
295
296 t = (int)(tdivz * z) + tadjust;
297 if (t > bbextentt)
298 t = bbextentt;
299 else if (t < 0)
300 t = 0;
301
302 do
303 {
304 // calculate s and t at the far end of the span
305 if (count >= 8)
306 spancount = 8;
307 else
308 spancount = count;
309
310 count -= spancount;
311
312 if (count)
313 {
314 // calculate s/z, t/z, zi->fixed s and t at far end of span,
315 // calculate s and t steps across span by shifting
316 sdivz += sdivz8stepu;
317 tdivz += tdivz8stepu;
318 zi += zi8stepu;
319 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
320
321 snext = (int)(sdivz * z) + sadjust;
322 if (snext > bbextents)
323 snext = bbextents;
324 else if (snext < 8)
325 snext = 8; // prevent round-off error on <0 steps from
326 // from causing overstepping & running off the
327 // edge of the texture
328
329 tnext = (int)(tdivz * z) + tadjust;
330 if (tnext > bbextentt)
331 tnext = bbextentt;
332 else if (tnext < 8)
333 tnext = 8; // guard against round-off error on <0 steps
334
335 sstep = (snext - s) >> 3;
336 tstep = (tnext - t) >> 3;
337 }
338 else
339 {
340 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
341 // can't step off polygon), clamp, calculate s and t steps across
342 // span by division, biasing steps low so we don't run off the
343 // texture
344 spancountminus1 = (float)(spancount - 1);
345 sdivz += d_sdivzstepu * spancountminus1;
346 tdivz += d_tdivzstepu * spancountminus1;
347 zi += d_zistepu * spancountminus1;
348 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
349 snext = (int)(sdivz * z) + sadjust;
350 if (snext > bbextents)
351 snext = bbextents;
352 else if (snext < 8)
353 snext = 8; // prevent round-off error on <0 steps from
354 // from causing overstepping & running off the
355 // edge of the texture
356
357 tnext = (int)(tdivz * z) + tadjust;
358 if (tnext > bbextentt)
359 tnext = bbextentt;
360 else if (tnext < 8)
361 tnext = 8; // guard against round-off error on <0 steps
362
363 if (spancount > 1)
364 {
365 sstep = (snext - s) / (spancount - 1);
366 tstep = (tnext - t) / (spancount - 1);
367 }
368 }
369
370 do
371 {
372 *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
373 s += sstep;
374 t += tstep;
375 } while (--spancount > 0);
376
377 s = snext;
378 t = tnext;
379
380 } while (count > 0);
381
382 } while ((pspan = pspan->pnext) != NULL);
383}
384
385#endif
386
387
388#if !id386
389
390/*
391=============
392D_DrawZSpans
393=============
394*/
395void D_DrawZSpans (espan_t *pspan)
396{
397 int count, doublecount, izistep;
398 int izi;
399 short *pdest;
400 unsigned ltemp;
401 double zi;
402 float du, dv;
403
404// FIXME: check for clamping/range problems
405// we count on FP exceptions being turned off to avoid range problems
406 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
407
408 do
409 {
410 pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
411
412 count = pspan->count;
413
414 // calculate the initial 1/z
415 du = (float)pspan->u;
416 dv = (float)pspan->v;
417
418 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
419 // we count on FP exceptions being turned off to avoid range problems
420 izi = (int)(zi * 0x8000 * 0x10000);
421
422 if ((long)pdest & 0x02)
423 {
424 *pdest++ = (short)(izi >> 16);
425 izi += izistep;
426 count--;
427 }
428
429 if ((doublecount = count >> 1) > 0)
430 {
431 do
432 {
433 ltemp = izi >> 16;
434 izi += izistep;
435 ltemp |= izi & 0xFFFF0000;
436 izi += izistep;
437 *(int *)pdest = ltemp;
438 pdest += 2;
439 } while (--doublecount > 0);
440 }
441
442 if (count & 1)
443 *pdest = (short)(izi >> 16);
444
445 } while ((pspan = pspan->pnext) != NULL);
446}
447
448#endif
449
diff --git a/apps/plugins/sdl/progs/quake/d_sky.c b/apps/plugins/sdl/progs/quake/d_sky.c
new file mode 100644
index 0000000000..9e28a8e576
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_sky.c
@@ -0,0 +1,138 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_sky.c
21
22#include "quakedef.h"
23#include "r_local.h"
24#include "d_local.h"
25
26#define SKY_SPAN_SHIFT 5
27#define SKY_SPAN_MAX (1 << SKY_SPAN_SHIFT)
28
29
30/*
31=================
32D_Sky_uv_To_st
33=================
34*/
35void D_Sky_uv_To_st (int u, int v, fixed16_t *s, fixed16_t *t)
36{
37 float wu, wv, temp;
38 vec3_t end;
39
40 if (r_refdef.vrect.width >= r_refdef.vrect.height)
41 temp = (float)r_refdef.vrect.width;
42 else
43 temp = (float)r_refdef.vrect.height;
44
45 wu = 8192.0 * (float)(u-((int)vid.width>>1)) / temp;
46 wv = 8192.0 * (float)(((int)vid.height>>1)-v) / temp;
47
48 end[0] = 4096*vpn[0] + wu*vright[0] + wv*vup[0];
49 end[1] = 4096*vpn[1] + wu*vright[1] + wv*vup[1];
50 end[2] = 4096*vpn[2] + wu*vright[2] + wv*vup[2];
51 end[2] *= 3;
52 VectorNormalizeNoRet (end);
53
54 temp = skytime*skyspeed; // TODO: add D_SetupFrame & set this there
55 *s = (int)((temp + 6*(SKYSIZE/2-1)*end[0]) * 0x10000);
56 *t = (int)((temp + 6*(SKYSIZE/2-1)*end[1]) * 0x10000);
57}
58
59
60/*
61=================
62D_DrawSkyScans8
63=================
64*/
65void D_DrawSkyScans8 (espan_t *pspan)
66{
67 int count, spancount, u, v;
68 unsigned char *pdest;
69 fixed16_t s, t, snext, tnext, sstep, tstep;
70 int spancountminus1;
71
72 sstep = 0; // keep compiler happy
73 tstep = 0; // ditto
74
75 do
76 {
77 pdest = (unsigned char *)((byte *)d_viewbuffer +
78 (screenwidth * pspan->v) + pspan->u);
79
80 count = pspan->count;
81
82 // calculate the initial s & t
83 u = pspan->u;
84 v = pspan->v;
85 D_Sky_uv_To_st (u, v, &s, &t);
86
87 do
88 {
89 if (count >= SKY_SPAN_MAX)
90 spancount = SKY_SPAN_MAX;
91 else
92 spancount = count;
93
94 count -= spancount;
95
96 if (count)
97 {
98 u += spancount;
99
100 // calculate s and t at far end of span,
101 // calculate s and t steps across span by shifting
102 D_Sky_uv_To_st (u, v, &snext, &tnext);
103
104 sstep = (snext - s) >> SKY_SPAN_SHIFT;
105 tstep = (tnext - t) >> SKY_SPAN_SHIFT;
106 }
107 else
108 {
109 // calculate s and t at last pixel in span,
110 // calculate s and t steps across span by division
111 spancountminus1 = (float)(spancount - 1);
112
113 if (spancountminus1 > 0)
114 {
115 u += spancountminus1;
116 D_Sky_uv_To_st (u, v, &snext, &tnext);
117
118 sstep = (snext - s) / spancountminus1;
119 tstep = (tnext - t) / spancountminus1;
120 }
121 }
122
123 do
124 {
125 *pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) +
126 ((s & R_SKY_SMASK) >> 16)];
127 s += sstep;
128 t += tstep;
129 } while (--spancount > 0);
130
131 s = snext;
132 t = tnext;
133
134 } while (count > 0);
135
136 } while ((pspan = pspan->pnext) != NULL);
137}
138
diff --git a/apps/plugins/sdl/progs/quake/d_sprite.c b/apps/plugins/sdl/progs/quake/d_sprite.c
new file mode 100644
index 0000000000..2f02ad2c64
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_sprite.c
@@ -0,0 +1,442 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_sprite.c: software top-level rasterization driver module for drawing
21// sprites
22
23#include "quakedef.h"
24#include "d_local.h"
25
26static int sprite_height;
27static int minindex, maxindex;
28static sspan_t *sprite_spans;
29
30#if !id386
31
32/*
33=====================
34D_SpriteDrawSpans
35=====================
36*/
37void D_SpriteDrawSpans (sspan_t *pspan)
38{
39 int count, spancount, izistep;
40 int izi;
41 byte *pbase, *pdest;
42 fixed16_t s, t, snext, tnext, sstep, tstep;
43 float sdivz, tdivz, zi, z, du, dv, spancountminus1;
44 float sdivz8stepu, tdivz8stepu, zi8stepu;
45 byte btemp;
46 short *pz;
47
48 sstep = 0; // keep compiler happy
49 tstep = 0; // ditto
50
51 pbase = cacheblock;
52
53 sdivz8stepu = d_sdivzstepu * 8;
54 tdivz8stepu = d_tdivzstepu * 8;
55 zi8stepu = d_zistepu * 8;
56
57// we count on FP exceptions being turned off to avoid range problems
58 izistep = (int)(d_zistepu * 0x8000 * 0x10000);
59
60 do
61 {
62 pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
63 pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
64
65 count = pspan->count;
66
67 if (count <= 0)
68 goto NextSpan;
69
70 // calculate the initial s/z, t/z, 1/z, s, and t and clamp
71 du = (float)pspan->u;
72 dv = (float)pspan->v;
73
74 sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
75 tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
76 zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
77 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
78 // we count on FP exceptions being turned off to avoid range problems
79 izi = (int)(zi * 0x8000 * 0x10000);
80
81 s = (int)(sdivz * z) + sadjust;
82 if (s > bbextents)
83 s = bbextents;
84 else if (s < 0)
85 s = 0;
86
87 t = (int)(tdivz * z) + tadjust;
88 if (t > bbextentt)
89 t = bbextentt;
90 else if (t < 0)
91 t = 0;
92
93 do
94 {
95 // calculate s and t at the far end of the span
96 if (count >= 8)
97 spancount = 8;
98 else
99 spancount = count;
100
101 count -= spancount;
102
103 if (count)
104 {
105 // calculate s/z, t/z, zi->fixed s and t at far end of span,
106 // calculate s and t steps across span by shifting
107 sdivz += sdivz8stepu;
108 tdivz += tdivz8stepu;
109 zi += zi8stepu;
110 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
111
112 snext = (int)(sdivz * z) + sadjust;
113 if (snext > bbextents)
114 snext = bbextents;
115 else if (snext < 8)
116 snext = 8; // prevent round-off error on <0 steps from
117 // from causing overstepping & running off the
118 // edge of the texture
119
120 tnext = (int)(tdivz * z) + tadjust;
121 if (tnext > bbextentt)
122 tnext = bbextentt;
123 else if (tnext < 8)
124 tnext = 8; // guard against round-off error on <0 steps
125
126 sstep = (snext - s) >> 3;
127 tstep = (tnext - t) >> 3;
128 }
129 else
130 {
131 // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
132 // can't step off polygon), clamp, calculate s and t steps across
133 // span by division, biasing steps low so we don't run off the
134 // texture
135 spancountminus1 = (float)(spancount - 1);
136 sdivz += d_sdivzstepu * spancountminus1;
137 tdivz += d_tdivzstepu * spancountminus1;
138 zi += d_zistepu * spancountminus1;
139 z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
140 snext = (int)(sdivz * z) + sadjust;
141 if (snext > bbextents)
142 snext = bbextents;
143 else if (snext < 8)
144 snext = 8; // prevent round-off error on <0 steps from
145 // from causing overstepping & running off the
146 // edge of the texture
147
148 tnext = (int)(tdivz * z) + tadjust;
149 if (tnext > bbextentt)
150 tnext = bbextentt;
151 else if (tnext < 8)
152 tnext = 8; // guard against round-off error on <0 steps
153
154 if (spancount > 1)
155 {
156 sstep = (snext - s) / (spancount - 1);
157 tstep = (tnext - t) / (spancount - 1);
158 }
159 }
160
161 do
162 {
163 btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
164 if (btemp != 255)
165 {
166 if (*pz <= (izi >> 16))
167 {
168 *pz = izi >> 16;
169 *pdest = btemp;
170 }
171 }
172
173 izi += izistep;
174 pdest++;
175 pz++;
176 s += sstep;
177 t += tstep;
178 } while (--spancount > 0);
179
180 s = snext;
181 t = tnext;
182
183 } while (count > 0);
184
185NextSpan:
186 pspan++;
187
188 } while (pspan->count != DS_SPAN_LIST_END);
189}
190
191#endif
192
193
194/*
195=====================
196D_SpriteScanLeftEdge
197=====================
198*/
199void D_SpriteScanLeftEdge (void)
200{
201 int i, v, itop, ibottom, lmaxindex;
202 emitpoint_t *pvert, *pnext;
203 sspan_t *pspan;
204 float du, dv, vtop, vbottom, slope;
205 fixed16_t u, u_step;
206
207 pspan = sprite_spans;
208 i = minindex;
209 if (i == 0)
210 i = r_spritedesc.nump;
211
212 lmaxindex = maxindex;
213 if (lmaxindex == 0)
214 lmaxindex = r_spritedesc.nump;
215
216 vtop = ceil (r_spritedesc.pverts[i].v);
217
218 do
219 {
220 pvert = &r_spritedesc.pverts[i];
221 pnext = pvert - 1;
222
223 vbottom = ceil (pnext->v);
224
225 if (vtop < vbottom)
226 {
227 du = pnext->u - pvert->u;
228 dv = pnext->v - pvert->v;
229 slope = du / dv;
230 u_step = (int)(slope * 0x10000);
231 // adjust u to ceil the integer portion
232 u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
233 (0x10000 - 1);
234 itop = (int)vtop;
235 ibottom = (int)vbottom;
236
237 for (v=itop ; v<ibottom ; v++)
238 {
239 pspan->u = u >> 16;
240 pspan->v = v;
241 u += u_step;
242 pspan++;
243 }
244 }
245
246 vtop = vbottom;
247
248 i--;
249 if (i == 0)
250 i = r_spritedesc.nump;
251
252 } while (i != lmaxindex);
253}
254
255
256/*
257=====================
258D_SpriteScanRightEdge
259=====================
260*/
261void D_SpriteScanRightEdge (void)
262{
263 int i, v, itop, ibottom;
264 emitpoint_t *pvert, *pnext;
265 sspan_t *pspan;
266 float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
267 fixed16_t u, u_step;
268
269 pspan = sprite_spans;
270 i = minindex;
271
272 vvert = r_spritedesc.pverts[i].v;
273 if (vvert < r_refdef.fvrecty_adj)
274 vvert = r_refdef.fvrecty_adj;
275 if (vvert > r_refdef.fvrectbottom_adj)
276 vvert = r_refdef.fvrectbottom_adj;
277
278 vtop = ceil (vvert);
279
280 do
281 {
282 pvert = &r_spritedesc.pverts[i];
283 pnext = pvert + 1;
284
285 vnext = pnext->v;
286 if (vnext < r_refdef.fvrecty_adj)
287 vnext = r_refdef.fvrecty_adj;
288 if (vnext > r_refdef.fvrectbottom_adj)
289 vnext = r_refdef.fvrectbottom_adj;
290
291 vbottom = ceil (vnext);
292
293 if (vtop < vbottom)
294 {
295 uvert = pvert->u;
296 if (uvert < r_refdef.fvrectx_adj)
297 uvert = r_refdef.fvrectx_adj;
298 if (uvert > r_refdef.fvrectright_adj)
299 uvert = r_refdef.fvrectright_adj;
300
301 unext = pnext->u;
302 if (unext < r_refdef.fvrectx_adj)
303 unext = r_refdef.fvrectx_adj;
304 if (unext > r_refdef.fvrectright_adj)
305 unext = r_refdef.fvrectright_adj;
306
307 du = unext - uvert;
308 dv = vnext - vvert;
309 slope = du / dv;
310 u_step = (int)(slope * 0x10000);
311 // adjust u to ceil the integer portion
312 u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
313 (0x10000 - 1);
314 itop = (int)vtop;
315 ibottom = (int)vbottom;
316
317 for (v=itop ; v<ibottom ; v++)
318 {
319 pspan->count = (u >> 16) - pspan->u;
320 u += u_step;
321 pspan++;
322 }
323 }
324
325 vtop = vbottom;
326 vvert = vnext;
327
328 i++;
329 if (i == r_spritedesc.nump)
330 i = 0;
331
332 } while (i != maxindex);
333
334 pspan->count = DS_SPAN_LIST_END; // mark the end of the span list
335}
336
337
338/*
339=====================
340D_SpriteCalculateGradients
341=====================
342*/
343void D_SpriteCalculateGradients (void)
344{
345 vec3_t p_normal, p_saxis, p_taxis, p_temp1;
346 float distinv;
347
348 TransformVector (r_spritedesc.vpn, p_normal);
349 TransformVector (r_spritedesc.vright, p_saxis);
350 TransformVector (r_spritedesc.vup, p_taxis);
351 VectorInverse (p_taxis);
352
353 distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
354
355 d_sdivzstepu = p_saxis[0] * xscaleinv;
356 d_tdivzstepu = p_taxis[0] * xscaleinv;
357
358 d_sdivzstepv = -p_saxis[1] * yscaleinv;
359 d_tdivzstepv = -p_taxis[1] * yscaleinv;
360
361 d_zistepu = p_normal[0] * xscaleinv * distinv;
362 d_zistepv = -p_normal[1] * yscaleinv * distinv;
363
364 d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
365 ycenter * d_sdivzstepv;
366 d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
367 ycenter * d_tdivzstepv;
368 d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
369 ycenter * d_zistepv;
370
371 TransformVector (modelorg, p_temp1);
372
373 sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
374 (-(cachewidth >> 1) << 16);
375 tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
376 (-(sprite_height >> 1) << 16);
377
378// -1 (-epsilon) so we never wander off the edge of the texture
379 bbextents = (cachewidth << 16) - 1;
380 bbextentt = (sprite_height << 16) - 1;
381}
382
383
384/*
385=====================
386D_DrawSprite
387=====================
388*/
389void D_DrawSprite (void)
390{
391 int i, nump;
392 float ymin, ymax;
393 emitpoint_t *pverts;
394 sspan_t spans[MAXHEIGHT+1];
395
396 sprite_spans = spans;
397
398// find the top and bottom vertices, and make sure there's at least one scan to
399// draw
400 ymin = 999999.9;
401 ymax = -999999.9;
402 pverts = r_spritedesc.pverts;
403
404 for (i=0 ; i<r_spritedesc.nump ; i++)
405 {
406 if (pverts->v < ymin)
407 {
408 ymin = pverts->v;
409 minindex = i;
410 }
411
412 if (pverts->v > ymax)
413 {
414 ymax = pverts->v;
415 maxindex = i;
416 }
417
418 pverts++;
419 }
420
421 ymin = ceil (ymin);
422 ymax = ceil (ymax);
423
424 if (ymin >= ymax)
425 return; // doesn't cross any scans at all
426
427 cachewidth = r_spritedesc.pspriteframe->width;
428 sprite_height = r_spritedesc.pspriteframe->height;
429 cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
430
431// copy the first vertex to the last vertex, so we don't have to deal with
432// wrapping
433 nump = r_spritedesc.nump;
434 pverts = r_spritedesc.pverts;
435 pverts[nump] = pverts[0];
436
437 D_SpriteCalculateGradients ();
438 D_SpriteScanLeftEdge ();
439 D_SpriteScanRightEdge ();
440 D_SpriteDrawSpans (sprite_spans);
441}
442
diff --git a/apps/plugins/sdl/progs/quake/d_surf.c b/apps/plugins/sdl/progs/quake/d_surf.c
new file mode 100644
index 0000000000..b09c5f896e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_surf.c
@@ -0,0 +1,335 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_surf.c: rasterization driver surface heap manager
21
22#include "quakedef.h"
23#include "d_local.h"
24#include "r_local.h"
25
26float surfscale;
27qboolean r_cache_thrash; // set if surface cache is thrashing
28
29int sc_size;
30surfcache_t *sc_rover, *sc_base;
31
32#define GUARDSIZE 4
33
34
35int D_SurfaceCacheForRes (int width, int height)
36{
37 int size, pix;
38
39 if (COM_CheckParm ("-surfcachesize"))
40 {
41 size = Q_atoi(com_argv[COM_CheckParm("-surfcachesize")+1]) * 1024;
42 return size;
43 }
44
45 size = SURFCACHE_SIZE_AT_320X200;
46
47 pix = width*height;
48 if (pix > 64000)
49 size += (pix-64000)*3;
50
51
52 return size;
53}
54
55void D_CheckCacheGuard (void)
56{
57 byte *s;
58 int i;
59
60 s = (byte *)sc_base + sc_size;
61 for (i=0 ; i<GUARDSIZE ; i++)
62 if (s[i] != (byte)i)
63 Sys_Error ("D_CheckCacheGuard: failed");
64}
65
66void D_ClearCacheGuard (void)
67{
68 byte *s;
69 int i;
70
71 s = (byte *)sc_base + sc_size;
72 for (i=0 ; i<GUARDSIZE ; i++)
73 s[i] = (byte)i;
74}
75
76
77/*
78================
79D_InitCaches
80
81================
82*/
83void D_InitCaches (void *buffer, int size)
84{
85
86 if (!msg_suppress_1)
87 Con_Printf ("%ik surface cache\n", size/1024);
88
89 sc_size = size - GUARDSIZE;
90 sc_base = (surfcache_t *)buffer;
91 sc_rover = sc_base;
92
93 sc_base->next = NULL;
94 sc_base->owner = NULL;
95 sc_base->size = sc_size;
96
97 D_ClearCacheGuard ();
98}
99
100
101/*
102==================
103D_FlushCaches
104==================
105*/
106void D_FlushCaches (void)
107{
108 surfcache_t *c;
109
110 if (!sc_base)
111 return;
112
113 for (c = sc_base ; c ; c = c->next)
114 {
115 if (c->owner)
116 *c->owner = NULL;
117 }
118
119 sc_rover = sc_base;
120 sc_base->next = NULL;
121 sc_base->owner = NULL;
122 sc_base->size = sc_size;
123}
124
125/*
126=================
127D_SCAlloc
128=================
129*/
130surfcache_t *D_SCAlloc (int width, int size)
131{
132 surfcache_t *new;
133 qboolean wrapped_this_time;
134
135 if ((width < 0) || (width > 256))
136 Sys_Error ("D_SCAlloc: bad cache width %d\n", width);
137
138 if ((size <= 0) || (size > 0x10000))
139 Sys_Error ("D_SCAlloc: bad cache size %d\n", size);
140
141 size = (int)&((surfcache_t *)0)->data[size];
142 size = (size + 3) & ~3;
143 if (size > sc_size)
144 Sys_Error ("D_SCAlloc: %i > cache size",size);
145
146// if there is not size bytes after the rover, reset to the start
147 wrapped_this_time = false;
148
149 if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
150 {
151 if (sc_rover)
152 {
153 wrapped_this_time = true;
154 }
155 sc_rover = sc_base;
156 }
157
158// colect and free surfcache_t blocks until the rover block is large enough
159 new = sc_rover;
160 if (sc_rover->owner)
161 *sc_rover->owner = NULL;
162
163 while (new->size < size)
164 {
165 // free another
166 sc_rover = sc_rover->next;
167 if (!sc_rover)
168 Sys_Error ("D_SCAlloc: hit the end of memory");
169 if (sc_rover->owner)
170 *sc_rover->owner = NULL;
171
172 new->size += sc_rover->size;
173 new->next = sc_rover->next;
174 }
175
176// create a fragment out of any leftovers
177 if (new->size - size > 256)
178 {
179 sc_rover = (surfcache_t *)( (byte *)new + size);
180 sc_rover->size = new->size - size;
181 sc_rover->next = new->next;
182 sc_rover->width = 0;
183 sc_rover->owner = NULL;
184 new->next = sc_rover;
185 new->size = size;
186 }
187 else
188 sc_rover = new->next;
189
190 new->width = width;
191// DEBUG
192 if (width > 0)
193 new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
194
195 new->owner = NULL; // should be set properly after return
196
197 if (d_roverwrapped)
198 {
199 if (wrapped_this_time || (sc_rover >= d_initial_rover))
200 r_cache_thrash = true;
201 }
202 else if (wrapped_this_time)
203 {
204 d_roverwrapped = true;
205 }
206
207D_CheckCacheGuard (); // DEBUG
208 return new;
209}
210
211
212/*
213=================
214D_SCDump
215=================
216*/
217void D_SCDump (void)
218{
219 surfcache_t *test;
220
221 for (test = sc_base ; test ; test = test->next)
222 {
223 if (test == sc_rover)
224 Sys_Printf ("ROVER:\n");
225 printf ("%p : %i bytes %i width\n",test, test->size, test->width);
226 }
227}
228
229//=============================================================================
230
231// if the num is not a power of 2, assume it will not repeat
232
233int MaskForNum (int num)
234{
235 if (num==128)
236 return 127;
237 if (num==64)
238 return 63;
239 if (num==32)
240 return 31;
241 if (num==16)
242 return 15;
243 return 255;
244}
245
246int D_log2 (int num)
247{
248 int c;
249
250 c = 0;
251
252 while (num>>=1)
253 c++;
254 return c;
255}
256
257//=============================================================================
258
259/*
260================
261D_CacheSurface
262================
263*/
264surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
265{
266 surfcache_t *cache;
267
268//
269// if the surface is animating or flashing, flush the cache
270//
271 r_drawsurf.texture = R_TextureAnimation (surface->texinfo->texture);
272 r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]];
273 r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]];
274 r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]];
275 r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]];
276
277//
278// see if the cache holds apropriate data
279//
280 cache = surface->cachespots[miplevel];
281
282 if (cache && !cache->dlight && surface->dlightframe != r_framecount
283 && cache->texture == r_drawsurf.texture
284 && cache->lightadj[0] == r_drawsurf.lightadj[0]
285 && cache->lightadj[1] == r_drawsurf.lightadj[1]
286 && cache->lightadj[2] == r_drawsurf.lightadj[2]
287 && cache->lightadj[3] == r_drawsurf.lightadj[3] )
288 return cache;
289
290//
291// determine shape of surface
292//
293 surfscale = 1.0 / (1<<miplevel);
294 r_drawsurf.surfmip = miplevel;
295 r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
296 r_drawsurf.rowbytes = r_drawsurf.surfwidth;
297 r_drawsurf.surfheight = surface->extents[1] >> miplevel;
298
299//
300// allocate memory if needed
301//
302 if (!cache) // if a texture just animated, don't reallocate it
303 {
304 cache = D_SCAlloc (r_drawsurf.surfwidth,
305 r_drawsurf.surfwidth * r_drawsurf.surfheight);
306 surface->cachespots[miplevel] = cache;
307 cache->owner = &surface->cachespots[miplevel];
308 cache->mipscale = surfscale;
309 }
310
311 if (surface->dlightframe == r_framecount)
312 cache->dlight = 1;
313 else
314 cache->dlight = 0;
315
316 r_drawsurf.surfdat = (pixel_t *)cache->data;
317
318 cache->texture = r_drawsurf.texture;
319 cache->lightadj[0] = r_drawsurf.lightadj[0];
320 cache->lightadj[1] = r_drawsurf.lightadj[1];
321 cache->lightadj[2] = r_drawsurf.lightadj[2];
322 cache->lightadj[3] = r_drawsurf.lightadj[3];
323
324//
325// draw and light the surface texture
326//
327 r_drawsurf.surf = surface;
328
329 c_surf++;
330 R_DrawSurface ();
331
332 return surface->cachespots[miplevel];
333}
334
335
diff --git a/apps/plugins/sdl/progs/quake/d_vars.c b/apps/plugins/sdl/progs/quake/d_vars.c
new file mode 100644
index 0000000000..88cc841ab8
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_vars.c
@@ -0,0 +1,50 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_vars.c: global refresh variables
21
22#include "quakedef.h"
23
24#if !id386
25
26// all global and static refresh variables are collected in a contiguous block
27// to avoid cache conflicts.
28
29//-------------------------------------------------------
30// global refresh variables
31//-------------------------------------------------------
32
33// FIXME: make into one big structure, like cl or sv
34// FIXME: do separately for refresh engine and driver
35
36float d_sdivzstepu, d_tdivzstepu, d_zistepu;
37float d_sdivzstepv, d_tdivzstepv, d_zistepv;
38float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
39
40fixed16_t sadjust, tadjust, bbextents, bbextentt;
41
42pixel_t *cacheblock;
43int cachewidth;
44pixel_t *d_viewbuffer;
45short *d_pzbuffer;
46unsigned int d_zrowbytes;
47unsigned int d_zwidth;
48
49#endif // !id386
50
diff --git a/apps/plugins/sdl/progs/quake/d_zpoint.c b/apps/plugins/sdl/progs/quake/d_zpoint.c
new file mode 100644
index 0000000000..909f25013f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/d_zpoint.c
@@ -0,0 +1,47 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// d_zpoint.c: software driver module for drawing z-buffered points
21
22#include "quakedef.h"
23#include "d_local.h"
24
25
26/*
27=====================
28D_DrawZPoint
29=====================
30*/
31void D_DrawZPoint (void)
32{
33 byte *pdest;
34 short *pz;
35 int izi;
36
37 pz = d_pzbuffer + (d_zwidth * r_zpointdesc.v) + r_zpointdesc.u;
38 pdest = d_viewbuffer + d_scantable[r_zpointdesc.v] + r_zpointdesc.u;
39 izi = (int)(r_zpointdesc.zi * 0x8000);
40
41 if (*pz <= izi)
42 {
43 *pz = izi;
44 *pdest = r_zpointdesc.color;
45 }
46}
47
diff --git a/apps/plugins/sdl/progs/quake/dosasm.S b/apps/plugins/sdl/progs/quake/dosasm.S
new file mode 100644
index 0000000000..2633be9617
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/dosasm.S
@@ -0,0 +1,77 @@
1#include "asm_i386.h"
2
3.data
4fpenv: .long 0, 0, 0, 0, 0, 0, 0, 0
5
6.text
7.globl C(StartMSRInterval)
8C(StartMSRInterval):
9 movl $0x11,%ecx // read the CESR
10 .byte 0x0F
11 .byte 0x32 // RDMSR
12
13 andl $0xFE3FFE3F,%eax // stop both counters
14 .byte 0x0F
15 .byte 0x30 // WRMSR
16
17 movl 4(%esp),%eax // point counter 0 to desired event, with counters
18 andl $0x3F,%eax // still stopped
19 movl $0x11,%ecx
20 .byte 0x0F
21 .byte 0x30 // WRMSR
22
23 movl $0x12,%ecx // set counter 0 to the value 0
24 subl %eax,%eax
25 subl %edx,%edx
26 .byte 0x0F
27 .byte 0x30 // WRMSR
28
29 movl 4(%esp),%eax // restart counter 0 with selected event
30 andl $0x3F,%eax
31 subl %edx,%edx
32 orl $0xC0,%eax
33 movl $0x11,%ecx // control and event select
34 .byte 0x0F
35 .byte 0x30 // WRMSR
36
37 ret
38
39.globl C(EndMSRInterval)
40C(EndMSRInterval):
41 movl $0x12,%ecx // counter 0
42 .byte 0x0F
43 .byte 0x32 // RDMSR
44
45 ret // lower 32 bits of count in %eax
46
47#if 0
48 .data
49Lxxx: .long 0
50
51 .text
52
53.globl C(setstackcheck)
54C(setstackcheck):
55
56 movl %esp,%eax
57 subl $0x38000,%eax
58 movl $0x5A5A5A5A,(%eax)
59 movl %eax,Lxxx
60
61 ret
62
63
64.globl C(dostackcheck)
65C(dostackcheck):
66
67 movl Lxxx,%edx
68 movl $0,%eax
69
70 cmpl $0x5A5A5A5A,(%edx)
71 jz qqq
72 incl %eax
73qqq:
74
75 ret
76#endif
77
diff --git a/apps/plugins/sdl/progs/quake/dosisms.h b/apps/plugins/sdl/progs/quake/dosisms.h
new file mode 100644
index 0000000000..7f12268a2c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/dosisms.h
@@ -0,0 +1,100 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21//
22// dosisms.h: I'd call it dos.h, but the name's taken
23//
24
25#ifndef _DOSISMS_H_
26#define _DOSISMS_H_
27
28int dos_lockmem(void *addr, int size);
29int dos_unlockmem(void *addr, int size);
30
31typedef union {
32 struct {
33 unsigned long edi;
34 unsigned long esi;
35 unsigned long ebp;
36 unsigned long res;
37 unsigned long ebx;
38 unsigned long edx;
39 unsigned long ecx;
40 unsigned long eax;
41 } d;
42 struct {
43 unsigned short di, di_hi;
44 unsigned short si, si_hi;
45 unsigned short bp, bp_hi;
46 unsigned short res, res_hi;
47 unsigned short bx, bx_hi;
48 unsigned short dx, dx_hi;
49 unsigned short cx, cx_hi;
50 unsigned short ax, ax_hi;
51 unsigned short flags;
52 unsigned short es;
53 unsigned short ds;
54 unsigned short fs;
55 unsigned short gs;
56 unsigned short ip;
57 unsigned short cs;
58 unsigned short sp;
59 unsigned short ss;
60 } x;
61 struct {
62 unsigned char edi[4];
63 unsigned char esi[4];
64 unsigned char ebp[4];
65 unsigned char res[4];
66 unsigned char bl, bh, ebx_b2, ebx_b3;
67 unsigned char dl, dh, edx_b2, edx_b3;
68 unsigned char cl, ch, ecx_b2, ecx_b3;
69 unsigned char al, ah, eax_b2, eax_b3;
70 } h;
71} regs_t;
72
73unsigned int ptr2real(void *ptr);
74void *real2ptr(unsigned int real);
75void *far2ptr(unsigned int farptr);
76unsigned int ptr2far(void *ptr);
77
78int dos_inportb(int port);
79int dos_inportw(int port);
80void dos_outportb(int port, int val);
81void dos_outportw(int port, int val);
82
83void dos_irqenable(void);
84void dos_irqdisable(void);
85void dos_registerintr(int intr, void (*handler)(void));
86void dos_restoreintr(int intr);
87
88int dos_int86(int vec);
89
90void *dos_getmemory(int size);
91void dos_freememory(void *ptr);
92
93void dos_usleep(int usecs);
94
95int dos_getheapsize(void);
96
97extern regs_t regs;
98
99#endif // _DOSISMS_H_
100
diff --git a/apps/plugins/sdl/progs/quake/draw.c b/apps/plugins/sdl/progs/quake/draw.c
new file mode 100644
index 0000000000..2a2f65bf4c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/draw.c
@@ -0,0 +1,890 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// draw.c -- this is the only file outside the refresh that touches the
22// vid buffer
23
24#include "quakedef.h"
25
26typedef struct {
27 vrect_t rect;
28 int width;
29 int height;
30 byte *ptexbytes;
31 int rowbytes;
32} rectdesc_t;
33
34static rectdesc_t r_rectdesc;
35
36byte *draw_chars; // 8*8 graphic characters
37qpic_t *draw_disc;
38qpic_t *draw_backtile;
39
40//=============================================================================
41/* Support Routines */
42
43typedef struct cachepic_s
44{
45 char name[MAX_QPATH];
46 cache_user_t cache;
47} cachepic_t;
48
49#define MAX_CACHED_PICS 128
50cachepic_t menu_cachepics[MAX_CACHED_PICS];
51int menu_numcachepics;
52
53
54qpic_t *Draw_PicFromWad (char *name)
55{
56 return W_GetLumpName (name);
57}
58
59/*
60================
61Draw_CachePic
62================
63*/
64qpic_t *Draw_CachePic (char *path)
65{
66 cachepic_t *pic;
67 int i;
68 qpic_t *dat;
69
70 for (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)
71 if (!strcmp (path, pic->name))
72 break;
73
74 if (i == menu_numcachepics)
75 {
76 if (menu_numcachepics == MAX_CACHED_PICS)
77 Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
78 menu_numcachepics++;
79 strcpy (pic->name, path);
80 }
81
82 dat = Cache_Check (&pic->cache);
83
84 if (dat)
85 return dat;
86
87//
88// load the pic from disk
89//
90 COM_LoadCacheFile (path, &pic->cache);
91
92 dat = (qpic_t *)pic->cache.data;
93 if (!dat)
94 {
95 Sys_Error ("Draw_CachePic: failed to load %s", path);
96 }
97
98 SwapPic (dat);
99
100 return dat;
101}
102
103
104
105/*
106===============
107Draw_Init
108===============
109*/
110void Draw_Init (void)
111{
112 int i;
113
114 draw_chars = W_GetLumpName ("conchars");
115 draw_disc = W_GetLumpName ("disc");
116 draw_backtile = W_GetLumpName ("backtile");
117
118 r_rectdesc.width = draw_backtile->width;
119 r_rectdesc.height = draw_backtile->height;
120 r_rectdesc.ptexbytes = draw_backtile->data;
121 r_rectdesc.rowbytes = draw_backtile->width;
122}
123
124
125
126/*
127================
128Draw_Character
129
130Draws one 8*8 graphics character with 0 being transparent.
131It can be clipped to the top of the screen to allow the console to be
132smoothly scrolled off.
133================
134*/
135void Draw_Character (int x, int y, int num)
136{
137 byte *dest;
138 byte *source;
139 unsigned short *pusdest;
140 int drawline;
141 int row, col;
142
143 num &= 255;
144
145 if (y <= -8)
146 return; // totally off screen
147
148#ifdef PARANOID
149 if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
150 Sys_Error ("Con_DrawCharacter: (%i, %i)", x, y);
151 if (num < 0 || num > 255)
152 Sys_Error ("Con_DrawCharacter: char %i", num);
153#endif
154
155 row = num>>4;
156 col = num&15;
157 source = draw_chars + (row<<10) + (col<<3);
158
159 if (y < 0)
160 { // clipped
161 drawline = 8 + y;
162 source -= 128*y;
163 y = 0;
164 }
165 else
166 drawline = 8;
167
168
169 if (r_pixbytes == 1)
170 {
171 dest = vid.conbuffer + y*vid.conrowbytes + x;
172
173 while (drawline--)
174 {
175 if (source[0])
176 dest[0] = source[0];
177 if (source[1])
178 dest[1] = source[1];
179 if (source[2])
180 dest[2] = source[2];
181 if (source[3])
182 dest[3] = source[3];
183 if (source[4])
184 dest[4] = source[4];
185 if (source[5])
186 dest[5] = source[5];
187 if (source[6])
188 dest[6] = source[6];
189 if (source[7])
190 dest[7] = source[7];
191 source += 128;
192 dest += vid.conrowbytes;
193 }
194 }
195 else
196 {
197 // FIXME: pre-expand to native format?
198 pusdest = (unsigned short *)
199 ((byte *)vid.conbuffer + y*vid.conrowbytes + (x<<1));
200
201 while (drawline--)
202 {
203 if (source[0])
204 pusdest[0] = d_8to16table[source[0]];
205 if (source[1])
206 pusdest[1] = d_8to16table[source[1]];
207 if (source[2])
208 pusdest[2] = d_8to16table[source[2]];
209 if (source[3])
210 pusdest[3] = d_8to16table[source[3]];
211 if (source[4])
212 pusdest[4] = d_8to16table[source[4]];
213 if (source[5])
214 pusdest[5] = d_8to16table[source[5]];
215 if (source[6])
216 pusdest[6] = d_8to16table[source[6]];
217 if (source[7])
218 pusdest[7] = d_8to16table[source[7]];
219
220 source += 128;
221 pusdest += (vid.conrowbytes >> 1);
222 }
223 }
224}
225
226/*
227================
228Draw_String
229================
230*/
231void Draw_String (int x, int y, char *str)
232{
233 while (*str)
234 {
235 Draw_Character (x, y, *str);
236 str++;
237 x += 8;
238 }
239}
240
241/*
242================
243Draw_DebugChar
244
245Draws a single character directly to the upper right corner of the screen.
246This is for debugging lockups by drawing different chars in different parts
247of the code.
248================
249*/
250void Draw_DebugChar (char num)
251{
252 byte *dest;
253 byte *source;
254 int drawline;
255 extern byte *draw_chars;
256 int row, col;
257
258 if (!vid.direct)
259 return; // don't have direct FB access, so no debugchars...
260
261 drawline = 8;
262
263 row = num>>4;
264 col = num&15;
265 source = draw_chars + (row<<10) + (col<<3);
266
267 dest = vid.direct + 312;
268
269 while (drawline--)
270 {
271 dest[0] = source[0];
272 dest[1] = source[1];
273 dest[2] = source[2];
274 dest[3] = source[3];
275 dest[4] = source[4];
276 dest[5] = source[5];
277 dest[6] = source[6];
278 dest[7] = source[7];
279 source += 128;
280 dest += 320;
281 }
282}
283
284/*
285=============
286Draw_Pic
287=============
288*/
289void Draw_Pic (int x, int y, qpic_t *pic)
290{
291 byte *dest, *source;
292 unsigned short *pusdest;
293 int v, u;
294
295 if ((x < 0) ||
296 (x + pic->width > vid.width) ||
297 (y < 0) ||
298 (y + pic->height > vid.height))
299 {
300 Sys_Error ("Draw_Pic: bad coordinates");
301 }
302
303 source = pic->data;
304
305 if (r_pixbytes == 1)
306 {
307 dest = vid.buffer + y * vid.rowbytes + x;
308
309 for (v=0 ; v<pic->height ; v++)
310 {
311 Q_memcpy (dest, source, pic->width);
312 dest += vid.rowbytes;
313 source += pic->width;
314 }
315 }
316 else
317 {
318 // FIXME: pretranslate at load time?
319 pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
320
321 for (v=0 ; v<pic->height ; v++)
322 {
323 for (u=0 ; u<pic->width ; u++)
324 {
325 pusdest[u] = d_8to16table[source[u]];
326 }
327
328 pusdest += vid.rowbytes >> 1;
329 source += pic->width;
330 }
331 }
332}
333
334
335/*
336=============
337Draw_TransPic
338=============
339*/
340void Draw_TransPic (int x, int y, qpic_t *pic)
341{
342 byte *dest, *source, tbyte;
343 unsigned short *pusdest;
344 int v, u;
345
346 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
347 (unsigned)(y + pic->height) > vid.height)
348 {
349 Sys_Error ("Draw_TransPic: bad coordinates");
350 }
351
352 source = pic->data;
353
354 if (r_pixbytes == 1)
355 {
356 dest = vid.buffer + y * vid.rowbytes + x;
357
358 if (pic->width & 7)
359 { // general
360 for (v=0 ; v<pic->height ; v++)
361 {
362 for (u=0 ; u<pic->width ; u++)
363 if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
364 dest[u] = tbyte;
365
366 dest += vid.rowbytes;
367 source += pic->width;
368 }
369 }
370 else
371 { // unwound
372 for (v=0 ; v<pic->height ; v++)
373 {
374 for (u=0 ; u<pic->width ; u+=8)
375 {
376 if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
377 dest[u] = tbyte;
378 if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
379 dest[u+1] = tbyte;
380 if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
381 dest[u+2] = tbyte;
382 if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
383 dest[u+3] = tbyte;
384 if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
385 dest[u+4] = tbyte;
386 if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
387 dest[u+5] = tbyte;
388 if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
389 dest[u+6] = tbyte;
390 if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
391 dest[u+7] = tbyte;
392 }
393 dest += vid.rowbytes;
394 source += pic->width;
395 }
396 }
397 }
398 else
399 {
400 // FIXME: pretranslate at load time?
401 pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
402
403 for (v=0 ; v<pic->height ; v++)
404 {
405 for (u=0 ; u<pic->width ; u++)
406 {
407 tbyte = source[u];
408
409 if (tbyte != TRANSPARENT_COLOR)
410 {
411 pusdest[u] = d_8to16table[tbyte];
412 }
413 }
414
415 pusdest += vid.rowbytes >> 1;
416 source += pic->width;
417 }
418 }
419}
420
421
422/*
423=============
424Draw_TransPicTranslate
425=============
426*/
427void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)
428{
429 byte *dest, *source, tbyte;
430 unsigned short *pusdest;
431 int v, u;
432
433 if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
434 (unsigned)(y + pic->height) > vid.height)
435 {
436 Sys_Error ("Draw_TransPic: bad coordinates");
437 }
438
439 source = pic->data;
440
441 if (r_pixbytes == 1)
442 {
443 dest = vid.buffer + y * vid.rowbytes + x;
444
445 if (pic->width & 7)
446 { // general
447 for (v=0 ; v<pic->height ; v++)
448 {
449 for (u=0 ; u<pic->width ; u++)
450 if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
451 dest[u] = translation[tbyte];
452
453 dest += vid.rowbytes;
454 source += pic->width;
455 }
456 }
457 else
458 { // unwound
459 for (v=0 ; v<pic->height ; v++)
460 {
461 for (u=0 ; u<pic->width ; u+=8)
462 {
463 if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
464 dest[u] = translation[tbyte];
465 if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
466 dest[u+1] = translation[tbyte];
467 if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
468 dest[u+2] = translation[tbyte];
469 if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
470 dest[u+3] = translation[tbyte];
471 if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
472 dest[u+4] = translation[tbyte];
473 if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
474 dest[u+5] = translation[tbyte];
475 if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
476 dest[u+6] = translation[tbyte];
477 if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
478 dest[u+7] = translation[tbyte];
479 }
480 dest += vid.rowbytes;
481 source += pic->width;
482 }
483 }
484 }
485 else
486 {
487 // FIXME: pretranslate at load time?
488 pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
489
490 for (v=0 ; v<pic->height ; v++)
491 {
492 for (u=0 ; u<pic->width ; u++)
493 {
494 tbyte = source[u];
495
496 if (tbyte != TRANSPARENT_COLOR)
497 {
498 pusdest[u] = d_8to16table[tbyte];
499 }
500 }
501
502 pusdest += vid.rowbytes >> 1;
503 source += pic->width;
504 }
505 }
506}
507
508
509void Draw_CharToConback (int num, byte *dest)
510{
511 int row, col;
512 byte *source;
513 int drawline;
514 int x;
515
516 row = num>>4;
517 col = num&15;
518 source = draw_chars + (row<<10) + (col<<3);
519
520 drawline = 8;
521
522 while (drawline--)
523 {
524 for (x=0 ; x<8 ; x++)
525 if (source[x])
526 dest[x] = 0x60 + source[x];
527 source += 128;
528 dest += 320;
529 }
530
531}
532
533/*
534================
535Draw_ConsoleBackground
536
537================
538*/
539void Draw_ConsoleBackground (int lines)
540{
541 int x, y, v;
542 byte *src, *dest;
543 unsigned short *pusdest;
544 int f, fstep;
545 qpic_t *conback;
546 char ver[100];
547
548 conback = Draw_CachePic ("gfx/conback.lmp");
549
550 dest = conback->data + 320 - 43 + 320*186;
551 sprintf (ver, "%.2f", (float)VERSION);
552
553 for (x=0 ; x<strlen(ver) ; x++)
554 Draw_CharToConback (ver[x], dest+(x<<3));
555
556// draw the pic
557 if (r_pixbytes == 1)
558 {
559 dest = vid.conbuffer;
560
561 for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
562 {
563 v = (vid.conheight - lines + y)*200/vid.conheight;
564 src = conback->data + v*320;
565 if (vid.conwidth == 320)
566 memcpy (dest, src, vid.conwidth);
567 else
568 {
569 f = 0;
570 fstep = 320*0x10000/vid.conwidth;
571 for (x=0 ; x<vid.conwidth ; x+=4)
572 {
573 dest[x] = src[f>>16];
574 f += fstep;
575 dest[x+1] = src[f>>16];
576 f += fstep;
577 dest[x+2] = src[f>>16];
578 f += fstep;
579 dest[x+3] = src[f>>16];
580 f += fstep;
581 }
582 }
583 }
584 }
585 else
586 {
587 pusdest = (unsigned short *)vid.conbuffer;
588
589 for (y=0 ; y<lines ; y++, pusdest += (vid.conrowbytes >> 1))
590 {
591 // FIXME: pre-expand to native format?
592 // FIXME: does the endian switching go away in production?
593 v = (vid.conheight - lines + y)*200/vid.conheight;
594 src = conback->data + v*320;
595 f = 0;
596 fstep = 320*0x10000/vid.conwidth;
597 for (x=0 ; x<vid.conwidth ; x+=4)
598 {
599 pusdest[x] = d_8to16table[src[f>>16]];
600 f += fstep;
601 pusdest[x+1] = d_8to16table[src[f>>16]];
602 f += fstep;
603 pusdest[x+2] = d_8to16table[src[f>>16]];
604 f += fstep;
605 pusdest[x+3] = d_8to16table[src[f>>16]];
606 f += fstep;
607 }
608 }
609 }
610}
611
612
613/*
614==============
615R_DrawRect8
616==============
617*/
618void R_DrawRect8 (vrect_t *prect, int rowbytes, byte *psrc,
619 int transparent)
620{
621 byte t;
622 int i, j, srcdelta, destdelta;
623 byte *pdest;
624
625 pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x;
626
627 srcdelta = rowbytes - prect->width;
628 destdelta = vid.rowbytes - prect->width;
629
630 if (transparent)
631 {
632 for (i=0 ; i<prect->height ; i++)
633 {
634 for (j=0 ; j<prect->width ; j++)
635 {
636 t = *psrc;
637 if (t != TRANSPARENT_COLOR)
638 {
639 *pdest = t;
640 }
641
642 psrc++;
643 pdest++;
644 }
645
646 psrc += srcdelta;
647 pdest += destdelta;
648 }
649 }
650 else
651 {
652 for (i=0 ; i<prect->height ; i++)
653 {
654 memcpy (pdest, psrc, prect->width);
655 psrc += rowbytes;
656 pdest += vid.rowbytes;
657 }
658 }
659}
660
661
662/*
663==============
664R_DrawRect16
665==============
666*/
667void R_DrawRect16 (vrect_t *prect, int rowbytes, byte *psrc,
668 int transparent)
669{
670 byte t;
671 int i, j, srcdelta, destdelta;
672 unsigned short *pdest;
673
674// FIXME: would it be better to pre-expand native-format versions?
675
676 pdest = (unsigned short *)vid.buffer +
677 (prect->y * (vid.rowbytes >> 1)) + prect->x;
678
679 srcdelta = rowbytes - prect->width;
680 destdelta = (vid.rowbytes >> 1) - prect->width;
681
682 if (transparent)
683 {
684 for (i=0 ; i<prect->height ; i++)
685 {
686 for (j=0 ; j<prect->width ; j++)
687 {
688 t = *psrc;
689 if (t != TRANSPARENT_COLOR)
690 {
691 *pdest = d_8to16table[t];
692 }
693
694 psrc++;
695 pdest++;
696 }
697
698 psrc += srcdelta;
699 pdest += destdelta;
700 }
701 }
702 else
703 {
704 for (i=0 ; i<prect->height ; i++)
705 {
706 for (j=0 ; j<prect->width ; j++)
707 {
708 *pdest = d_8to16table[*psrc];
709 psrc++;
710 pdest++;
711 }
712
713 psrc += srcdelta;
714 pdest += destdelta;
715 }
716 }
717}
718
719
720/*
721=============
722Draw_TileClear
723
724This repeats a 64*64 tile graphic to fill the screen around a sized down
725refresh window.
726=============
727*/
728void Draw_TileClear (int x, int y, int w, int h)
729{
730 int width, height, tileoffsetx, tileoffsety;
731 byte *psrc;
732 vrect_t vr;
733
734 r_rectdesc.rect.x = x;
735 r_rectdesc.rect.y = y;
736 r_rectdesc.rect.width = w;
737 r_rectdesc.rect.height = h;
738
739 vr.y = r_rectdesc.rect.y;
740 height = r_rectdesc.rect.height;
741
742 tileoffsety = vr.y % r_rectdesc.height;
743
744 while (height > 0)
745 {
746 vr.x = r_rectdesc.rect.x;
747 width = r_rectdesc.rect.width;
748
749 if (tileoffsety != 0)
750 vr.height = r_rectdesc.height - tileoffsety;
751 else
752 vr.height = r_rectdesc.height;
753
754 if (vr.height > height)
755 vr.height = height;
756
757 tileoffsetx = vr.x % r_rectdesc.width;
758
759 while (width > 0)
760 {
761 if (tileoffsetx != 0)
762 vr.width = r_rectdesc.width - tileoffsetx;
763 else
764 vr.width = r_rectdesc.width;
765
766 if (vr.width > width)
767 vr.width = width;
768
769 psrc = r_rectdesc.ptexbytes +
770 (tileoffsety * r_rectdesc.rowbytes) + tileoffsetx;
771
772 if (r_pixbytes == 1)
773 {
774 R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0);
775 }
776 else
777 {
778 R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0);
779 }
780
781 vr.x += vr.width;
782 width -= vr.width;
783 tileoffsetx = 0; // only the left tile can be left-clipped
784 }
785
786 vr.y += vr.height;
787 height -= vr.height;
788 tileoffsety = 0; // only the top tile can be top-clipped
789 }
790}
791
792
793/*
794=============
795Draw_Fill
796
797Fills a box of pixels with a single color
798=============
799*/
800void Draw_Fill (int x, int y, int w, int h, int c)
801{
802 byte *dest;
803 unsigned short *pusdest;
804 unsigned uc;
805 int u, v;
806
807 if (r_pixbytes == 1)
808 {
809 dest = vid.buffer + y*vid.rowbytes + x;
810 for (v=0 ; v<h ; v++, dest += vid.rowbytes)
811 for (u=0 ; u<w ; u++)
812 dest[u] = c;
813 }
814 else
815 {
816 uc = d_8to16table[c];
817
818 pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x;
819 for (v=0 ; v<h ; v++, pusdest += (vid.rowbytes >> 1))
820 for (u=0 ; u<w ; u++)
821 pusdest[u] = uc;
822 }
823}
824//=============================================================================
825
826/*
827================
828Draw_FadeScreen
829
830================
831*/
832void Draw_FadeScreen (void)
833{
834 int x,y;
835 byte *pbuf;
836
837 VID_UnlockBuffer ();
838 S_ExtraUpdate ();
839 VID_LockBuffer ();
840
841 for (y=0 ; y<vid.height ; y++)
842 {
843 int t;
844
845 pbuf = (byte *)(vid.buffer + vid.rowbytes*y);
846 t = (y & 1) << 1;
847
848 for (x=0 ; x<vid.width ; x++)
849 {
850 if ((x & 3) != t)
851 pbuf[x] = 0;
852 }
853 }
854
855 VID_UnlockBuffer ();
856 S_ExtraUpdate ();
857 VID_LockBuffer ();
858}
859
860//=============================================================================
861
862/*
863================
864Draw_BeginDisc
865
866Draws the little blue disc in the corner of the screen.
867Call before beginning any disc IO.
868================
869*/
870void Draw_BeginDisc (void)
871{
872
873 D_BeginDirectRect (vid.width - 24, 0, draw_disc->data, 24, 24);
874}
875
876
877/*
878================
879Draw_EndDisc
880
881Erases the disc icon.
882Call after completing any disc IO
883================
884*/
885void Draw_EndDisc (void)
886{
887
888 D_EndDirectRect (vid.width - 24, 0, 24, 24);
889}
890
diff --git a/apps/plugins/sdl/progs/quake/draw.h b/apps/plugins/sdl/progs/quake/draw.h
new file mode 100644
index 0000000000..5055b659c8
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/draw.h
@@ -0,0 +1,40 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// draw.h -- these are the only functions outside the refresh allowed
22// to touch the vid buffer
23
24extern qpic_t *draw_disc; // also used on sbar
25
26void Draw_Init (void);
27void Draw_Character (int x, int y, int num);
28void Draw_DebugChar (char num);
29void Draw_Pic (int x, int y, qpic_t *pic);
30void Draw_TransPic (int x, int y, qpic_t *pic);
31void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation);
32void Draw_ConsoleBackground (int lines);
33void Draw_BeginDisc (void);
34void Draw_EndDisc (void);
35void Draw_TileClear (int x, int y, int w, int h);
36void Draw_Fill (int x, int y, int w, int h, int c);
37void Draw_FadeScreen (void);
38void Draw_String (int x, int y, char *str);
39qpic_t *Draw_PicFromWad (char *name);
40qpic_t *Draw_CachePic (char *path);
diff --git a/apps/plugins/sdl/progs/quake/gl_vidlinux.c b/apps/plugins/sdl/progs/quake/gl_vidlinux.c
new file mode 100644
index 0000000000..c29f0423a3
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/gl_vidlinux.c
@@ -0,0 +1,866 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include <termios.h>
21#include <sys/ioctl.h>
22#include <sys/stat.h>
23#include <sys/vt.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <signal.h>
27
28#include <asm/io.h>
29#include <dlfcn.h>
30
31/*#include "vga.h" */
32#include "vgakeyboard.h"
33#include "vgamouse.h"
34
35#include "quakedef.h"
36#include "GL/fxmesa.h"
37
38#define WARP_WIDTH 320
39#define WARP_HEIGHT 200
40
41static fxMesaContext fc = NULL;
42#define stringify(m) { #m, m }
43
44unsigned short d_8to16table[256];
45unsigned d_8to24table[256];
46unsigned char d_15to8table[65536];
47
48int num_shades=32;
49
50struct
51{
52 char *name;
53 int num;
54} mice[] =
55{
56 stringify(MOUSE_MICROSOFT),
57 stringify(MOUSE_MOUSESYSTEMS),
58 stringify(MOUSE_MMSERIES),
59 stringify(MOUSE_LOGITECH),
60 stringify(MOUSE_BUSMOUSE),
61 stringify(MOUSE_PS2),
62};
63
64static unsigned char scantokey[128];
65
66int num_mice = sizeof (mice) / sizeof(mice[0]);
67
68int d_con_indirect = 0;
69
70int svgalib_inited=0;
71int UseMouse = 1;
72int UseKeyboard = 1;
73
74int mouserate = MOUSE_DEFAULTSAMPLERATE;
75
76cvar_t vid_mode = {"vid_mode","5",false};
77cvar_t vid_redrawfull = {"vid_redrawfull","0",false};
78cvar_t vid_waitforrefresh = {"vid_waitforrefresh","0",true};
79
80char *framebuffer_ptr;
81
82cvar_t mouse_button_commands[3] =
83{
84 {"mouse1","+attack"},
85 {"mouse2","+strafe"},
86 {"mouse3","+forward"},
87};
88
89int mouse_buttons;
90int mouse_buttonstate;
91int mouse_oldbuttonstate;
92float mouse_x, mouse_y;
93float old_mouse_x, old_mouse_y;
94int mx, my;
95
96cvar_t m_filter = {"m_filter","1"};
97
98int scr_width, scr_height;
99
100/*-----------------------------------------------------------------------*/
101
102//int texture_mode = GL_NEAREST;
103//int texture_mode = GL_NEAREST_MIPMAP_NEAREST;
104//int texture_mode = GL_NEAREST_MIPMAP_LINEAR;
105int texture_mode = GL_LINEAR;
106//int texture_mode = GL_LINEAR_MIPMAP_NEAREST;
107//int texture_mode = GL_LINEAR_MIPMAP_LINEAR;
108
109int texture_extension_number = 1;
110
111float gldepthmin, gldepthmax;
112
113cvar_t gl_ztrick = {"gl_ztrick","1"};
114
115const char *gl_vendor;
116const char *gl_renderer;
117const char *gl_version;
118const char *gl_extensions;
119
120void (*qgl3DfxSetPaletteEXT) (GLuint *);
121void (*qglColorTableEXT) (int, int, int, int, int, const void *);
122
123static float vid_gamma = 1.0;
124
125qboolean is8bit = false;
126qboolean isPermedia = false;
127qboolean gl_mtexable = false;
128
129/*-----------------------------------------------------------------------*/
130void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
131{
132}
133
134void D_EndDirectRect (int x, int y, int width, int height)
135{
136}
137
138int matchmouse(int mouse, char *name)
139{
140 int i;
141 for (i=0 ; i<num_mice ; i++)
142 if (!strcmp(mice[i].name, name))
143 return i;
144 return mouse;
145}
146
147#if 0
148
149void vtswitch(int newconsole)
150{
151
152 int fd;
153 struct vt_stat x;
154
155// switch consoles and wait until reactivated
156 fd = open("/dev/console", O_RDONLY);
157 ioctl(fd, VT_GETSTATE, &x);
158 ioctl(fd, VT_ACTIVATE, newconsole);
159 ioctl(fd, VT_WAITACTIVE, x.v_active);
160 close(fd);
161
162}
163
164#endif
165
166void keyhandler(int scancode, int state)
167{
168
169 int sc;
170
171 sc = scancode & 0x7f;
172
173 Key_Event(scantokey[sc], state == KEY_EVENTPRESS);
174
175}
176
177void VID_Shutdown(void)
178{
179 if (!fc)
180 return;
181
182 fxMesaDestroyContext(fc);
183
184 if (UseKeyboard)
185 keyboard_close();
186}
187
188void signal_handler(int sig)
189{
190 printf("Received signal %d, exiting...\n", sig);
191 Sys_Quit();
192 exit(0);
193}
194
195void InitSig(void)
196{
197 signal(SIGHUP, signal_handler);
198 signal(SIGINT, signal_handler);
199 signal(SIGQUIT, signal_handler);
200 signal(SIGILL, signal_handler);
201 signal(SIGTRAP, signal_handler);
202 signal(SIGIOT, signal_handler);
203 signal(SIGBUS, signal_handler);
204 signal(SIGFPE, signal_handler);
205 signal(SIGSEGV, signal_handler);
206 signal(SIGTERM, signal_handler);
207}
208
209void VID_ShiftPalette(unsigned char *p)
210{
211// VID_SetPalette(p);
212}
213
214void VID_SetPalette (unsigned char *palette)
215{
216 byte *pal;
217 unsigned r,g,b;
218 unsigned v;
219 int r1,g1,b1;
220 int j,k,l,m;
221 unsigned short i;
222 unsigned *table;
223 FILE *f;
224 char s[255];
225 int dist, bestdist;
226 static qboolean palflag = false;
227
228//
229// 8 8 8 encoding
230//
231 pal = palette;
232 table = d_8to24table;
233 for (i=0 ; i<256 ; i++)
234 {
235 r = pal[0];
236 g = pal[1];
237 b = pal[2];
238 pal += 3;
239
240 v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
241 *table++ = v;
242 }
243 d_8to24table[255] &= 0xffffff; // 255 is transparent
244
245 // JACK: 3D distance calcs - k is last closest, l is the distance.
246 for (i=0; i < (1<<15); i++) {
247 /* Maps
248 000000000000000
249 000000000011111 = Red = 0x1F
250 000001111100000 = Blue = 0x03E0
251 111110000000000 = Grn = 0x7C00
252 */
253 r = ((i & 0x1F) << 3)+4;
254 g = ((i & 0x03E0) >> 2)+4;
255 b = ((i & 0x7C00) >> 7)+4;
256 pal = (unsigned char *)d_8to24table;
257 for (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) {
258 r1 = (int)r - (int)pal[0];
259 g1 = (int)g - (int)pal[1];
260 b1 = (int)b - (int)pal[2];
261 dist = (r1*r1)+(g1*g1)+(b1*b1);
262 if (dist < bestdist) {
263 k=v;
264 bestdist = dist;
265 }
266 }
267 d_15to8table[i]=k;
268 }
269}
270
271void CheckMultiTextureExtensions(void)
272{
273 void *prjobj;
274
275 if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) {
276 Con_Printf("Found GL_SGIS_multitexture...\n");
277
278 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
279 Con_Printf("Unable to open symbol list for main program.\n");
280 return;
281 }
282
283 qglMTexCoord2fSGIS = (void *) dlsym(prjobj, "glMTexCoord2fSGIS");
284 qglSelectTextureSGIS = (void *) dlsym(prjobj, "glSelectTextureSGIS");
285
286 if (qglMTexCoord2fSGIS && qglSelectTextureSGIS) {
287 Con_Printf("Multitexture extensions found.\n");
288 gl_mtexable = true;
289 } else
290 Con_Printf("Symbol not found, disabled.\n");
291
292 dlclose(prjobj);
293 }
294}
295
296/*
297===============
298GL_Init
299===============
300*/
301void GL_Init (void)
302{
303 gl_vendor = glGetString (GL_VENDOR);
304 Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
305 gl_renderer = glGetString (GL_RENDERER);
306 Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
307
308 gl_version = glGetString (GL_VERSION);
309 Con_Printf ("GL_VERSION: %s\n", gl_version);
310 gl_extensions = glGetString (GL_EXTENSIONS);
311 Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
312
313// Con_Printf ("%s %s\n", gl_renderer, gl_version);
314
315 CheckMultiTextureExtensions ();
316
317 glClearColor (1,0,0,0);
318 glCullFace(GL_FRONT);
319 glEnable(GL_TEXTURE_2D);
320
321 glEnable(GL_ALPHA_TEST);
322 glAlphaFunc(GL_GREATER, 0.666);
323
324 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
325 glShadeModel (GL_FLAT);
326
327 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
328 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
329 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
330 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
331
332 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
333
334// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
335 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
336}
337
338/*
339=================
340GL_BeginRendering
341
342=================
343*/
344void GL_BeginRendering (int *x, int *y, int *width, int *height)
345{
346 extern cvar_t gl_clear;
347
348 *x = *y = 0;
349 *width = scr_width;
350 *height = scr_height;
351
352// if (!wglMakeCurrent( maindc, baseRC ))
353// Sys_Error ("wglMakeCurrent failed");
354
355// glViewport (*x, *y, *width, *height);
356}
357
358
359void GL_EndRendering (void)
360{
361 glFlush();
362 fxMesaSwapBuffers();
363}
364
365void Init_KBD(void)
366{
367 int i;
368
369 if (COM_CheckParm("-nokbd")) UseKeyboard = 0;
370
371 if (UseKeyboard)
372 {
373 for (i=0 ; i<128 ; i++)
374 scantokey[i] = ' ';
375
376 scantokey[42] = K_SHIFT;
377 scantokey[54] = K_SHIFT;
378 scantokey[72] = K_UPARROW;
379 scantokey[103] = K_UPARROW;
380 scantokey[80] = K_DOWNARROW;
381 scantokey[108] = K_DOWNARROW;
382 scantokey[75] = K_LEFTARROW;
383 scantokey[105] = K_LEFTARROW;
384 scantokey[77] = K_RIGHTARROW;
385 scantokey[106] = K_RIGHTARROW;
386 scantokey[29] = K_CTRL;
387 scantokey[97] = K_CTRL;
388 scantokey[56] = K_ALT;
389 scantokey[100] = K_ALT;
390// scantokey[58] = JK_CAPS;
391// scantokey[69] = JK_NUM_LOCK;
392 scantokey[71] = K_HOME;
393 scantokey[73] = K_PGUP;
394 scantokey[79] = K_END;
395 scantokey[81] = K_PGDN;
396 scantokey[82] = K_INS;
397 scantokey[83] = K_DEL;
398 scantokey[1 ] = K_ESCAPE;
399 scantokey[28] = K_ENTER;
400 scantokey[15] = K_TAB;
401 scantokey[14] = K_BACKSPACE;
402 scantokey[119] = K_PAUSE;
403 scantokey[57] = ' ';
404
405 scantokey[102] = K_HOME;
406 scantokey[104] = K_PGUP;
407 scantokey[107] = K_END;
408 scantokey[109] = K_PGDN;
409 scantokey[110] = K_INS;
410 scantokey[111] = K_DEL;
411
412 scantokey[2] = '1';
413 scantokey[3] = '2';
414 scantokey[4] = '3';
415 scantokey[5] = '4';
416 scantokey[6] = '5';
417 scantokey[7] = '6';
418 scantokey[8] = '7';
419 scantokey[9] = '8';
420 scantokey[10] = '9';
421 scantokey[11] = '0';
422 scantokey[12] = '-';
423 scantokey[13] = '=';
424 scantokey[41] = '`';
425 scantokey[26] = '[';
426 scantokey[27] = ']';
427 scantokey[39] = ';';
428 scantokey[40] = '\'';
429 scantokey[51] = ',';
430 scantokey[52] = '.';
431 scantokey[53] = '/';
432 scantokey[43] = '\\';
433
434 scantokey[59] = K_F1;
435 scantokey[60] = K_F2;
436 scantokey[61] = K_F3;
437 scantokey[62] = K_F4;
438 scantokey[63] = K_F5;
439 scantokey[64] = K_F6;
440 scantokey[65] = K_F7;
441 scantokey[66] = K_F8;
442 scantokey[67] = K_F9;
443 scantokey[68] = K_F10;
444 scantokey[87] = K_F11;
445 scantokey[88] = K_F12;
446 scantokey[30] = 'a';
447 scantokey[48] = 'b';
448 scantokey[46] = 'c';
449 scantokey[32] = 'd';
450 scantokey[18] = 'e';
451 scantokey[33] = 'f';
452 scantokey[34] = 'g';
453 scantokey[35] = 'h';
454 scantokey[23] = 'i';
455 scantokey[36] = 'j';
456 scantokey[37] = 'k';
457 scantokey[38] = 'l';
458 scantokey[50] = 'm';
459 scantokey[49] = 'n';
460 scantokey[24] = 'o';
461 scantokey[25] = 'p';
462 scantokey[16] = 'q';
463 scantokey[19] = 'r';
464 scantokey[31] = 's';
465 scantokey[20] = 't';
466 scantokey[22] = 'u';
467 scantokey[47] = 'v';
468 scantokey[17] = 'w';
469 scantokey[45] = 'x';
470 scantokey[21] = 'y';
471 scantokey[44] = 'z';
472
473 scantokey[78] = '+';
474 scantokey[74] = '-';
475
476 if (keyboard_init())
477 Sys_Error("keyboard_init() failed");
478 keyboard_seteventhandler(keyhandler);
479 }
480}
481
482#define NUM_RESOLUTIONS 16
483
484static int resolutions[NUM_RESOLUTIONS][3]={
485 320,200, GR_RESOLUTION_320x200,
486 320,240, GR_RESOLUTION_320x240,
487 400,256, GR_RESOLUTION_400x256,
488 400,300, GR_RESOLUTION_400x300,
489 512,384, GR_RESOLUTION_512x384,
490 640,200, GR_RESOLUTION_640x200,
491 640,350, GR_RESOLUTION_640x350,
492 640,400, GR_RESOLUTION_640x400,
493 640,480, GR_RESOLUTION_640x480,
494 800,600, GR_RESOLUTION_800x600,
495 960,720, GR_RESOLUTION_960x720,
496 856,480, GR_RESOLUTION_856x480,
497 512,256, GR_RESOLUTION_512x256,
498 1024,768, GR_RESOLUTION_1024x768,
499 1280,1024,GR_RESOLUTION_1280x1024,
500 1600,1200,GR_RESOLUTION_1600x1200
501};
502
503int findres(int *width, int *height)
504{
505 int i;
506
507 for(i=0;i<NUM_RESOLUTIONS;i++)
508 if((*width<=resolutions[i][0]) && (*height<=resolutions[i][1])) {
509 *width = resolutions[i][0];
510 *height = resolutions[i][1];
511 return resolutions[i][2];
512 }
513
514 *width = 640;
515 *height = 480;
516 return GR_RESOLUTION_640x480;
517}
518
519qboolean VID_Is8bit(void)
520{
521 return is8bit;
522}
523
524void VID_Init8bitPalette(void)
525{
526 // Check for 8bit Extensions and initialize them.
527 int i;
528 void *prjobj;
529
530 if (COM_CheckParm("-no8bit"))
531 return;
532
533 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
534 Con_Printf("Unable to open symbol list for main program.\n");
535 return;
536 }
537
538 if (strstr(gl_extensions, "3DFX_set_global_palette") &&
539 (qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL) {
540 GLubyte table[256][4];
541 char *oldpal;
542
543 Con_SafePrintf("... Using 3DFX_set_global_palette\n");
544 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
545 oldpal = (char *) d_8to24table; //d_8to24table3dfx;
546 for (i=0;i<256;i++) {
547 table[i][2] = *oldpal++;
548 table[i][1] = *oldpal++;
549 table[i][0] = *oldpal++;
550 table[i][3] = 255;
551 oldpal++;
552 }
553 qgl3DfxSetPaletteEXT((GLuint *)table);
554 is8bit = true;
555
556 } else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") &&
557 (qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL) {
558 char thePalette[256*3];
559 char *oldPalette, *newPalette;
560
561 Con_SafePrintf("... Using GL_EXT_shared_texture_palette\n");
562 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
563 oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
564 newPalette = thePalette;
565 for (i=0;i<256;i++) {
566 *newPalette++ = *oldPalette++;
567 *newPalette++ = *oldPalette++;
568 *newPalette++ = *oldPalette++;
569 oldPalette++;
570 }
571 qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
572 is8bit = true;
573
574 }
575
576 dlclose(prjobj);
577}
578
579static void Check_Gamma (unsigned char *pal)
580{
581 float f, inf;
582 unsigned char palette[768];
583 int i;
584
585 if ((i = COM_CheckParm("-gamma")) == 0) {
586 if ((gl_renderer && strstr(gl_renderer, "Voodoo")) ||
587 (gl_vendor && strstr(gl_vendor, "3Dfx")))
588 vid_gamma = 1;
589 else
590 vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware
591 } else
592 vid_gamma = Q_atof(com_argv[i+1]);
593
594 for (i=0 ; i<768 ; i++)
595 {
596 f = pow ( (pal[i]+1)/256.0 , vid_gamma );
597 inf = f*255 + 0.5;
598 if (inf < 0)
599 inf = 0;
600 if (inf > 255)
601 inf = 255;
602 palette[i] = inf;
603 }
604
605 memcpy (pal, palette, sizeof(palette));
606}
607
608void VID_Init(unsigned char *palette)
609{
610 int i;
611 GLint attribs[32];
612 char gldir[MAX_OSPATH];
613 int width = 640, height = 480;
614
615 Init_KBD();
616
617 Cvar_RegisterVariable (&vid_mode);
618 Cvar_RegisterVariable (&vid_redrawfull);
619 Cvar_RegisterVariable (&vid_waitforrefresh);
620 Cvar_RegisterVariable (&gl_ztrick);
621
622 vid.maxwarpwidth = WARP_WIDTH;
623 vid.maxwarpheight = WARP_HEIGHT;
624 vid.colormap = host_colormap;
625 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
626
627// interpret command-line params
628
629// set vid parameters
630 attribs[0] = FXMESA_DOUBLEBUFFER;
631 attribs[1] = FXMESA_ALPHA_SIZE;
632 attribs[2] = 1;
633 attribs[3] = FXMESA_DEPTH_SIZE;
634 attribs[4] = 1;
635 attribs[5] = FXMESA_NONE;
636
637 if ((i = COM_CheckParm("-width")) != 0)
638 width = atoi(com_argv[i+1]);
639 if ((i = COM_CheckParm("-height")) != 0)
640 height = atoi(com_argv[i+1]);
641
642 if ((i = COM_CheckParm("-conwidth")) != 0)
643 vid.conwidth = Q_atoi(com_argv[i+1]);
644 else
645 vid.conwidth = 640;
646
647 vid.conwidth &= 0xfff8; // make it a multiple of eight
648
649 if (vid.conwidth < 320)
650 vid.conwidth = 320;
651
652 // pick a conheight that matches with correct aspect
653 vid.conheight = vid.conwidth*3 / 4;
654
655 if ((i = COM_CheckParm("-conheight")) != 0)
656 vid.conheight = Q_atoi(com_argv[i+1]);
657 if (vid.conheight < 200)
658 vid.conheight = 200;
659
660 fc = fxMesaCreateContext(0, findres(&width, &height), GR_REFRESH_75Hz,
661 attribs);
662 if (!fc)
663 Sys_Error("Unable to create 3DFX context.\n");
664
665 InitSig(); // trap evil signals
666
667 scr_width = width;
668 scr_height = height;
669
670 fxMesaMakeCurrent(fc);
671
672 if (vid.conheight > height)
673 vid.conheight = height;
674 if (vid.conwidth > width)
675 vid.conwidth = width;
676 vid.width = vid.conwidth;
677 vid.height = vid.conheight;
678
679 vid.aspect = ((float)vid.height / (float)vid.width) *
680 (320.0 / 240.0);
681 vid.numpages = 2;
682
683 GL_Init();
684
685 sprintf (gldir, "%s/glquake", com_gamedir);
686 Sys_mkdir (gldir);
687
688 Check_Gamma(palette);
689 VID_SetPalette(palette);
690
691 // Check for 3DFX Extensions and initialize them.
692 VID_Init8bitPalette();
693
694 Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
695
696 vid.recalc_refdef = 1; // force a surface cache flush
697}
698
699void Sys_SendKeyEvents(void)
700{
701 if (UseKeyboard)
702 while (keyboard_update());
703}
704
705void Force_CenterView_f (void)
706{
707 cl.viewangles[PITCH] = 0;
708}
709
710
711void mousehandler(int buttonstate, int dx, int dy)
712{
713 mouse_buttonstate = buttonstate;
714 mx += dx;
715 my += dy;
716}
717
718void IN_Init(void)
719{
720
721 int mtype;
722 char *mousedev;
723 int mouserate;
724
725 if (UseMouse)
726 {
727
728 Cvar_RegisterVariable (&mouse_button_commands[0]);
729 Cvar_RegisterVariable (&mouse_button_commands[1]);
730 Cvar_RegisterVariable (&mouse_button_commands[2]);
731 Cmd_AddCommand ("force_centerview", Force_CenterView_f);
732
733 mouse_buttons = 3;
734
735 mtype = vga_getmousetype();
736
737 mousedev = "/dev/mouse";
738 if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV");
739 if (COM_CheckParm("-mdev"))
740 mousedev = com_argv[COM_CheckParm("-mdev")+1];
741
742 mouserate = 1200;
743 if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE"));
744 if (COM_CheckParm("-mrate"))
745 mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]);
746
747 if (mouse_init(mousedev, mtype, mouserate))
748 {
749 Con_Printf("No mouse found\n");
750 UseMouse = 0;
751 }
752 else
753 mouse_seteventhandler(mousehandler);
754
755 }
756
757}
758
759void IN_Shutdown(void)
760{
761 if (UseMouse)
762 mouse_close();
763}
764
765/*
766===========
767IN_Commands
768===========
769*/
770void IN_Commands (void)
771{
772 if (UseMouse && cls.state != ca_dedicated)
773 {
774 // poll mouse values
775 while (mouse_update())
776 ;
777
778 // perform button actions
779 if ((mouse_buttonstate & MOUSE_LEFTBUTTON) &&
780 !(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
781 Key_Event (K_MOUSE1, true);
782 else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) &&
783 (mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
784 Key_Event (K_MOUSE1, false);
785
786 if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
787 !(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
788 Key_Event (K_MOUSE2, true);
789 else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
790 (mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
791 Key_Event (K_MOUSE2, false);
792
793 if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
794 !(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
795 Key_Event (K_MOUSE3, true);
796 else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
797 (mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
798 Key_Event (K_MOUSE3, false);
799
800 mouse_oldbuttonstate = mouse_buttonstate;
801 }
802}
803
804/*
805===========
806IN_Move
807===========
808*/
809void IN_MouseMove (usercmd_t *cmd)
810{
811 if (!UseMouse)
812 return;
813
814 // poll mouse values
815 while (mouse_update())
816 ;
817
818 if (m_filter.value)
819 {
820 mouse_x = (mx + old_mouse_x) * 0.5;
821 mouse_y = (my + old_mouse_y) * 0.5;
822 }
823 else
824 {
825 mouse_x = mx;
826 mouse_y = my;
827 }
828 old_mouse_x = mx;
829 old_mouse_y = my;
830 mx = my = 0; // clear for next update
831
832 mouse_x *= sensitivity.value;
833 mouse_y *= sensitivity.value;
834
835// add mouse X/Y movement to cmd
836 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
837 cmd->sidemove += m_side.value * mouse_x;
838 else
839 cl.viewangles[YAW] -= m_yaw.value * mouse_x;
840
841 if (in_mlook.state & 1)
842 V_StopPitchDrift ();
843
844 if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
845 {
846 cl.viewangles[PITCH] += m_pitch.value * mouse_y;
847 if (cl.viewangles[PITCH] > 80)
848 cl.viewangles[PITCH] = 80;
849 if (cl.viewangles[PITCH] < -70)
850 cl.viewangles[PITCH] = -70;
851 }
852 else
853 {
854 if ((in_strafe.state & 1) && noclip_anglehack)
855 cmd->upmove -= m_forward.value * mouse_y;
856 else
857 cmd->forwardmove -= m_forward.value * mouse_y;
858 }
859}
860
861void IN_Move (usercmd_t *cmd)
862{
863 IN_MouseMove(cmd);
864}
865
866
diff --git a/apps/plugins/sdl/progs/quake/gl_vidlinuxglx.c b/apps/plugins/sdl/progs/quake/gl_vidlinuxglx.c
new file mode 100644
index 0000000000..400adb4678
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/gl_vidlinuxglx.c
@@ -0,0 +1,997 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include <termios.h>
21#include <sys/ioctl.h>
22#include <sys/stat.h>
23#include <sys/vt.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <signal.h>
27
28#include <dlfcn.h>
29
30#include "quakedef.h"
31
32#include <GL/glx.h>
33
34#include <X11/keysym.h>
35#include <X11/cursorfont.h>
36
37#include <X11/extensions/xf86dga.h>
38#include <X11/extensions/xf86vmode.h>
39
40#define WARP_WIDTH 320
41#define WARP_HEIGHT 200
42
43static Display *dpy = NULL;
44static int scrnum;
45static Window win;
46static GLXContext ctx = NULL;
47
48#define KEY_MASK (KeyPressMask | KeyReleaseMask)
49#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
50 PointerMotionMask | ButtonMotionMask )
51#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask )
52
53
54unsigned short d_8to16table[256];
55unsigned d_8to24table[256];
56unsigned char d_15to8table[65536];
57
58cvar_t vid_mode = {"vid_mode","0",false};
59
60static qboolean mouse_avail;
61static qboolean mouse_active;
62static int mx, my;
63static int old_mouse_x, old_mouse_y;
64
65static cvar_t in_mouse = {"in_mouse", "1", false};
66static cvar_t in_dgamouse = {"in_dgamouse", "1", false};
67static cvar_t m_filter = {"m_filter", "0"};
68
69qboolean dgamouse = false;
70qboolean vidmode_ext = false;
71
72static int win_x, win_y;
73
74static int scr_width, scr_height;
75
76static XF86VidModeModeInfo **vidmodes;
77static int default_dotclock_vidmode;
78static int num_vidmodes;
79static qboolean vidmode_active = false;
80
81/*-----------------------------------------------------------------------*/
82
83//int texture_mode = GL_NEAREST;
84//int texture_mode = GL_NEAREST_MIPMAP_NEAREST;
85//int texture_mode = GL_NEAREST_MIPMAP_LINEAR;
86int texture_mode = GL_LINEAR;
87//int texture_mode = GL_LINEAR_MIPMAP_NEAREST;
88//int texture_mode = GL_LINEAR_MIPMAP_LINEAR;
89
90int texture_extension_number = 1;
91
92float gldepthmin, gldepthmax;
93
94cvar_t gl_ztrick = {"gl_ztrick","1"};
95
96const char *gl_vendor;
97const char *gl_renderer;
98const char *gl_version;
99const char *gl_extensions;
100
101void (*qglColorTableEXT) (int, int, int, int, int, const void*);
102void (*qgl3DfxSetPaletteEXT) (GLuint *);
103
104static float vid_gamma = 1.0;
105
106qboolean is8bit = false;
107qboolean isPermedia = false;
108qboolean gl_mtexable = false;
109
110/*-----------------------------------------------------------------------*/
111void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
112{
113}
114
115void D_EndDirectRect (int x, int y, int width, int height)
116{
117}
118
119static int XLateKey(XKeyEvent *ev)
120{
121
122 int key;
123 char buf[64];
124 KeySym keysym;
125
126 key = 0;
127
128 XLookupString(ev, buf, sizeof buf, &keysym, 0);
129
130 switch(keysym)
131 {
132 case XK_KP_Page_Up:
133 case XK_Page_Up: key = K_PGUP; break;
134
135 case XK_KP_Page_Down:
136 case XK_Page_Down: key = K_PGDN; break;
137
138 case XK_KP_Home:
139 case XK_Home: key = K_HOME; break;
140
141 case XK_KP_End:
142 case XK_End: key = K_END; break;
143
144 case XK_KP_Left:
145 case XK_Left: key = K_LEFTARROW; break;
146
147 case XK_KP_Right:
148 case XK_Right: key = K_RIGHTARROW; break;
149
150 case XK_KP_Down:
151 case XK_Down: key = K_DOWNARROW; break;
152
153 case XK_KP_Up:
154 case XK_Up: key = K_UPARROW; break;
155
156 case XK_Escape: key = K_ESCAPE; break;
157
158 case XK_KP_Enter:
159 case XK_Return: key = K_ENTER; break;
160
161 case XK_Tab: key = K_TAB; break;
162
163 case XK_F1: key = K_F1; break;
164
165 case XK_F2: key = K_F2; break;
166
167 case XK_F3: key = K_F3; break;
168
169 case XK_F4: key = K_F4; break;
170
171 case XK_F5: key = K_F5; break;
172
173 case XK_F6: key = K_F6; break;
174
175 case XK_F7: key = K_F7; break;
176
177 case XK_F8: key = K_F8; break;
178
179 case XK_F9: key = K_F9; break;
180
181 case XK_F10: key = K_F10; break;
182
183 case XK_F11: key = K_F11; break;
184
185 case XK_F12: key = K_F12; break;
186
187 case XK_BackSpace: key = K_BACKSPACE; break;
188
189 case XK_KP_Delete:
190 case XK_Delete: key = K_DEL; break;
191
192 case XK_Pause: key = K_PAUSE; break;
193
194 case XK_Shift_L:
195 case XK_Shift_R: key = K_SHIFT; break;
196
197 case XK_Execute:
198 case XK_Control_L:
199 case XK_Control_R: key = K_CTRL; break;
200
201 case XK_Alt_L:
202 case XK_Meta_L:
203 case XK_Alt_R:
204 case XK_Meta_R: key = K_ALT; break;
205
206 case XK_KP_Begin: key = '5'; break;
207
208 case XK_KP_Insert:
209 case XK_Insert:key = K_INS; break;
210
211 case XK_KP_Multiply: key = '*'; break;
212 case XK_KP_Add: key = '+'; break;
213 case XK_KP_Subtract: key = '-'; break;
214 case XK_KP_Divide: key = '/'; break;
215
216#if 0
217 case 0x021: key = '1';break;/* [!] */
218 case 0x040: key = '2';break;/* [@] */
219 case 0x023: key = '3';break;/* [#] */
220 case 0x024: key = '4';break;/* [$] */
221 case 0x025: key = '5';break;/* [%] */
222 case 0x05e: key = '6';break;/* [^] */
223 case 0x026: key = '7';break;/* [&] */
224 case 0x02a: key = '8';break;/* [*] */
225 case 0x028: key = '9';;break;/* [(] */
226 case 0x029: key = '0';break;/* [)] */
227 case 0x05f: key = '-';break;/* [_] */
228 case 0x02b: key = '=';break;/* [+] */
229 case 0x07c: key = '\'';break;/* [|] */
230 case 0x07d: key = '[';break;/* [}] */
231 case 0x07b: key = ']';break;/* [{] */
232 case 0x022: key = '\'';break;/* ["] */
233 case 0x03a: key = ';';break;/* [:] */
234 case 0x03f: key = '/';break;/* [?] */
235 case 0x03e: key = '.';break;/* [>] */
236 case 0x03c: key = ',';break;/* [<] */
237#endif
238
239 default:
240 key = *(unsigned char*)buf;
241 if (key >= 'A' && key <= 'Z')
242 key = key - 'A' + 'a';
243 break;
244 }
245
246 return key;
247}
248
249static Cursor CreateNullCursor(Display *display, Window root)
250{
251 Pixmap cursormask;
252 XGCValues xgc;
253 GC gc;
254 XColor dummycolour;
255 Cursor cursor;
256
257 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
258 xgc.function = GXclear;
259 gc = XCreateGC(display, cursormask, GCFunction, &xgc);
260 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
261 dummycolour.pixel = 0;
262 dummycolour.red = 0;
263 dummycolour.flags = 04;
264 cursor = XCreatePixmapCursor(display, cursormask, cursormask,
265 &dummycolour,&dummycolour, 0,0);
266 XFreePixmap(display,cursormask);
267 XFreeGC(display,gc);
268 return cursor;
269}
270
271static void install_grabs(void)
272{
273
274// inviso cursor
275 XDefineCursor(dpy, win, CreateNullCursor(dpy, win));
276
277 XGrabPointer(dpy, win,
278 True,
279 0,
280 GrabModeAsync, GrabModeAsync,
281 win,
282 None,
283 CurrentTime);
284
285 if (in_dgamouse.value) {
286 int MajorVersion, MinorVersion;
287
288 if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
289 // unable to query, probalby not supported
290 Con_Printf( "Failed to detect XF86DGA Mouse\n" );
291 in_dgamouse.value = 0;
292 } else {
293 dgamouse = true;
294 XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse);
295 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
296 }
297 } else {
298 XWarpPointer(dpy, None, win,
299 0, 0, 0, 0,
300 vid.width / 2, vid.height / 2);
301 }
302
303 XGrabKeyboard(dpy, win,
304 False,
305 GrabModeAsync, GrabModeAsync,
306 CurrentTime);
307
308 mouse_active = true;
309
310// XSync(dpy, True);
311}
312
313static void uninstall_grabs(void)
314{
315 if (!dpy || !win)
316 return;
317
318 if (dgamouse) {
319 dgamouse = false;
320 XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0);
321 }
322
323 XUngrabPointer(dpy, CurrentTime);
324 XUngrabKeyboard(dpy, CurrentTime);
325
326// inviso cursor
327 XUndefineCursor(dpy, win);
328
329 mouse_active = false;
330}
331
332static void HandleEvents(void)
333{
334 XEvent event;
335 KeySym ks;
336 int b;
337 qboolean dowarp = false;
338 int mwx = vid.width/2;
339 int mwy = vid.height/2;
340
341 if (!dpy)
342 return;
343
344 while (XPending(dpy)) {
345 XNextEvent(dpy, &event);
346
347 switch (event.type) {
348 case KeyPress:
349 case KeyRelease:
350 Key_Event(XLateKey(&event.xkey), event.type == KeyPress);
351 break;
352
353 case MotionNotify:
354 if (mouse_active) {
355 if (dgamouse) {
356 mx += (event.xmotion.x + win_x) * 2;
357 my += (event.xmotion.y + win_y) * 2;
358 }
359 else
360 {
361 mx += ((int)event.xmotion.x - mwx) * 2;
362 my += ((int)event.xmotion.y - mwy) * 2;
363 mwx = event.xmotion.x;
364 mwy = event.xmotion.y;
365
366 if (mx || my)
367 dowarp = true;
368 }
369 }
370 break;
371
372 break;
373
374 case ButtonPress:
375 b=-1;
376 if (event.xbutton.button == 1)
377 b = 0;
378 else if (event.xbutton.button == 2)
379 b = 2;
380 else if (event.xbutton.button == 3)
381 b = 1;
382 if (b>=0)
383 Key_Event(K_MOUSE1 + b, true);
384 break;
385
386 case ButtonRelease:
387 b=-1;
388 if (event.xbutton.button == 1)
389 b = 0;
390 else if (event.xbutton.button == 2)
391 b = 2;
392 else if (event.xbutton.button == 3)
393 b = 1;
394 if (b>=0)
395 Key_Event(K_MOUSE1 + b, false);
396 break;
397
398 case CreateNotify :
399 win_x = event.xcreatewindow.x;
400 win_y = event.xcreatewindow.y;
401 break;
402
403 case ConfigureNotify :
404 win_x = event.xconfigure.x;
405 win_y = event.xconfigure.y;
406 break;
407 }
408 }
409
410 if (dowarp) {
411 /* move the mouse to the window center again */
412 XWarpPointer(dpy, None, win, 0, 0, 0, 0, vid.width / 2, vid.height / 2);
413 }
414
415}
416
417static void IN_DeactivateMouse( void )
418{
419 if (!mouse_avail || !dpy || !win)
420 return;
421
422 if (mouse_active) {
423 uninstall_grabs();
424 mouse_active = false;
425 }
426}
427
428static void IN_ActivateMouse( void )
429{
430 if (!mouse_avail || !dpy || !win)
431 return;
432
433 if (!mouse_active) {
434 mx = my = 0; // don't spazz
435 install_grabs();
436 mouse_active = true;
437 }
438}
439
440
441void VID_Shutdown(void)
442{
443 if (!ctx || !dpy)
444 return;
445 IN_DeactivateMouse();
446 if (dpy) {
447 if (ctx)
448 glXDestroyContext(dpy, ctx);
449 if (win)
450 XDestroyWindow(dpy, win);
451 if (vidmode_active)
452 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]);
453 XCloseDisplay(dpy);
454 }
455 vidmode_active = false;
456 dpy = NULL;
457 win = 0;
458 ctx = NULL;
459}
460
461void signal_handler(int sig)
462{
463 printf("Received signal %d, exiting...\n", sig);
464 Sys_Quit();
465 exit(0);
466}
467
468void InitSig(void)
469{
470 signal(SIGHUP, signal_handler);
471 signal(SIGINT, signal_handler);
472 signal(SIGQUIT, signal_handler);
473 signal(SIGILL, signal_handler);
474 signal(SIGTRAP, signal_handler);
475 signal(SIGIOT, signal_handler);
476 signal(SIGBUS, signal_handler);
477 signal(SIGFPE, signal_handler);
478 signal(SIGSEGV, signal_handler);
479 signal(SIGTERM, signal_handler);
480}
481
482void VID_ShiftPalette(unsigned char *p)
483{
484// VID_SetPalette(p);
485}
486
487void VID_SetPalette (unsigned char *palette)
488{
489 byte *pal;
490 unsigned r,g,b;
491 unsigned v;
492 int r1,g1,b1;
493 int j,k,l,m;
494 unsigned short i;
495 unsigned *table;
496 FILE *f;
497 char s[255];
498 int dist, bestdist;
499
500//
501// 8 8 8 encoding
502//
503 pal = palette;
504 table = d_8to24table;
505 for (i=0 ; i<256 ; i++)
506 {
507 r = pal[0];
508 g = pal[1];
509 b = pal[2];
510 pal += 3;
511
512 v = (255<<24) + (r<<0) + (g<<8) + (b<<16);
513 *table++ = v;
514 }
515 d_8to24table[255] &= 0xffffff; // 255 is transparent
516
517 for (i=0; i < (1<<15); i++) {
518 /* Maps
519 000000000000000
520 000000000011111 = Red = 0x1F
521 000001111100000 = Blue = 0x03E0
522 111110000000000 = Grn = 0x7C00
523 */
524 r = ((i & 0x1F) << 3)+4;
525 g = ((i & 0x03E0) >> 2)+4;
526 b = ((i & 0x7C00) >> 7)+4;
527 pal = (unsigned char *)d_8to24table;
528 for (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) {
529 r1 = (int)r - (int)pal[0];
530 g1 = (int)g - (int)pal[1];
531 b1 = (int)b - (int)pal[2];
532 dist = (r1*r1)+(g1*g1)+(b1*b1);
533 if (dist < bestdist) {
534 k=v;
535 bestdist = dist;
536 }
537 }
538 d_15to8table[i]=k;
539 }
540}
541
542void CheckMultiTextureExtensions(void)
543{
544 void *prjobj;
545
546 if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) {
547 Con_Printf("Found GL_SGIS_multitexture...\n");
548
549 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
550 Con_Printf("Unable to open symbol list for main program.\n");
551 return;
552 }
553
554 qglMTexCoord2fSGIS = (void *) dlsym(prjobj, "glMTexCoord2fSGIS");
555 qglSelectTextureSGIS = (void *) dlsym(prjobj, "glSelectTextureSGIS");
556
557 if (qglMTexCoord2fSGIS && qglSelectTextureSGIS) {
558 Con_Printf("Multitexture extensions found.\n");
559 gl_mtexable = true;
560 } else
561 Con_Printf("Symbol not found, disabled.\n");
562
563 dlclose(prjobj);
564 }
565}
566
567/*
568===============
569GL_Init
570===============
571*/
572void GL_Init (void)
573{
574 gl_vendor = glGetString (GL_VENDOR);
575 Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
576 gl_renderer = glGetString (GL_RENDERER);
577 Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
578
579 gl_version = glGetString (GL_VERSION);
580 Con_Printf ("GL_VERSION: %s\n", gl_version);
581 gl_extensions = glGetString (GL_EXTENSIONS);
582 Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
583
584// Con_Printf ("%s %s\n", gl_renderer, gl_version);
585
586 CheckMultiTextureExtensions ();
587
588 glClearColor (1,0,0,0);
589 glCullFace(GL_FRONT);
590 glEnable(GL_TEXTURE_2D);
591
592 glEnable(GL_ALPHA_TEST);
593 glAlphaFunc(GL_GREATER, 0.666);
594
595 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
596 glShadeModel (GL_FLAT);
597
598 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
599 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
600 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
601 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
602
603 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
604
605// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
606 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
607}
608
609/*
610=================
611GL_BeginRendering
612
613=================
614*/
615void GL_BeginRendering (int *x, int *y, int *width, int *height)
616{
617 extern cvar_t gl_clear;
618
619 *x = *y = 0;
620 *width = scr_width;
621 *height = scr_height;
622
623// if (!wglMakeCurrent( maindc, baseRC ))
624// Sys_Error ("wglMakeCurrent failed");
625
626// glViewport (*x, *y, *width, *height);
627}
628
629
630void GL_EndRendering (void)
631{
632 glFlush();
633 glXSwapBuffers(dpy, win);
634}
635
636qboolean VID_Is8bit(void)
637{
638 return is8bit;
639}
640
641void VID_Init8bitPalette(void)
642{
643 // Check for 8bit Extensions and initialize them.
644 int i;
645 void *prjobj;
646
647 if ((prjobj = dlopen(NULL, RTLD_LAZY)) == NULL) {
648 Con_Printf("Unable to open symbol list for main program.\n");
649 return;
650 }
651
652 if (strstr(gl_extensions, "3DFX_set_global_palette") &&
653 (qgl3DfxSetPaletteEXT = dlsym(prjobj, "gl3DfxSetPaletteEXT")) != NULL) {
654 GLubyte table[256][4];
655 char *oldpal;
656
657 Con_SafePrintf("8-bit GL extensions enabled.\n");
658 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
659 oldpal = (char *) d_8to24table; //d_8to24table3dfx;
660 for (i=0;i<256;i++) {
661 table[i][2] = *oldpal++;
662 table[i][1] = *oldpal++;
663 table[i][0] = *oldpal++;
664 table[i][3] = 255;
665 oldpal++;
666 }
667 qgl3DfxSetPaletteEXT((GLuint *)table);
668 is8bit = true;
669
670 } else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette") &&
671 (qglColorTableEXT = dlsym(prjobj, "glColorTableEXT")) != NULL) {
672 char thePalette[256*3];
673 char *oldPalette, *newPalette;
674
675 Con_SafePrintf("8-bit GL extensions enabled.\n");
676 glEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
677 oldPalette = (char *) d_8to24table; //d_8to24table3dfx;
678 newPalette = thePalette;
679 for (i=0;i<256;i++) {
680 *newPalette++ = *oldPalette++;
681 *newPalette++ = *oldPalette++;
682 *newPalette++ = *oldPalette++;
683 oldPalette++;
684 }
685 qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette);
686 is8bit = true;
687 }
688
689 dlclose(prjobj);
690}
691
692static void Check_Gamma (unsigned char *pal)
693{
694 float f, inf;
695 unsigned char palette[768];
696 int i;
697
698 if ((i = COM_CheckParm("-gamma")) == 0) {
699 if ((gl_renderer && strstr(gl_renderer, "Voodoo")) ||
700 (gl_vendor && strstr(gl_vendor, "3Dfx")))
701 vid_gamma = 1;
702 else
703 vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware
704 } else
705 vid_gamma = Q_atof(com_argv[i+1]);
706
707 for (i=0 ; i<768 ; i++)
708 {
709 f = pow ( (pal[i]+1)/256.0 , vid_gamma );
710 inf = f*255 + 0.5;
711 if (inf < 0)
712 inf = 0;
713 if (inf > 255)
714 inf = 255;
715 palette[i] = inf;
716 }
717
718 memcpy (pal, palette, sizeof(palette));
719}
720
721void VID_Init(unsigned char *palette)
722{
723 int i;
724 int attrib[] = {
725 GLX_RGBA,
726 GLX_RED_SIZE, 1,
727 GLX_GREEN_SIZE, 1,
728 GLX_BLUE_SIZE, 1,
729 GLX_DOUBLEBUFFER,
730 GLX_DEPTH_SIZE, 1,
731 None
732 };
733 char gldir[MAX_OSPATH];
734 int width = 640, height = 480;
735 XSetWindowAttributes attr;
736 unsigned long mask;
737 Window root;
738 XVisualInfo *visinfo;
739 qboolean fullscreen = true;
740 int MajorVersion, MinorVersion;
741 int actualWidth, actualHeight;
742
743 Cvar_RegisterVariable (&vid_mode);
744 Cvar_RegisterVariable (&in_mouse);
745 Cvar_RegisterVariable (&in_dgamouse);
746 Cvar_RegisterVariable (&m_filter);
747 Cvar_RegisterVariable (&gl_ztrick);
748
749 vid.maxwarpwidth = WARP_WIDTH;
750 vid.maxwarpheight = WARP_HEIGHT;
751 vid.colormap = host_colormap;
752 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
753
754// interpret command-line params
755
756// set vid parameters
757 if ((i = COM_CheckParm("-window")) != 0)
758 fullscreen = false;
759
760 if ((i = COM_CheckParm("-width")) != 0)
761 width = atoi(com_argv[i+1]);
762
763 if ((i = COM_CheckParm("-height")) != 0)
764 height = atoi(com_argv[i+1]);
765
766 if ((i = COM_CheckParm("-conwidth")) != 0)
767 vid.conwidth = Q_atoi(com_argv[i+1]);
768 else
769 vid.conwidth = 640;
770
771 vid.conwidth &= 0xfff8; // make it a multiple of eight
772
773 if (vid.conwidth < 320)
774 vid.conwidth = 320;
775
776 // pick a conheight that matches with correct aspect
777 vid.conheight = vid.conwidth*3 / 4;
778
779 if ((i = COM_CheckParm("-conheight")) != 0)
780 vid.conheight = Q_atoi(com_argv[i+1]);
781 if (vid.conheight < 200)
782 vid.conheight = 200;
783
784 if (!(dpy = XOpenDisplay(NULL))) {
785 fprintf(stderr, "Error couldn't open the X display\n");
786 exit(1);
787 }
788
789 scrnum = DefaultScreen(dpy);
790 root = RootWindow(dpy, scrnum);
791
792 // Get video mode list
793 MajorVersion = MinorVersion = 0;
794 if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) {
795 vidmode_ext = false;
796 } else {
797 Con_Printf("Using XFree86-VidModeExtension Version %d.%d\n", MajorVersion, MinorVersion);
798 vidmode_ext = true;
799 }
800
801 visinfo = glXChooseVisual(dpy, scrnum, attrib);
802 if (!visinfo) {
803 fprintf(stderr, "qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
804 exit(1);
805 }
806
807 if (vidmode_ext) {
808 int best_fit, best_dist, dist, x, y;
809
810 XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes);
811
812 // Are we going fullscreen? If so, let's change video mode
813 if (fullscreen) {
814 best_dist = 9999999;
815 best_fit = -1;
816
817 for (i = 0; i < num_vidmodes; i++) {
818 if (width > vidmodes[i]->hdisplay ||
819 height > vidmodes[i]->vdisplay)
820 continue;
821
822 x = width - vidmodes[i]->hdisplay;
823 y = height - vidmodes[i]->vdisplay;
824 dist = (x * x) + (y * y);
825 if (dist < best_dist) {
826 best_dist = dist;
827 best_fit = i;
828 }
829 }
830
831 if (best_fit != -1) {
832 actualWidth = vidmodes[best_fit]->hdisplay;
833 actualHeight = vidmodes[best_fit]->vdisplay;
834
835 // change to the mode
836 XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]);
837 vidmode_active = true;
838
839 // Move the viewport to top left
840 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
841 } else
842 fullscreen = 0;
843 }
844 }
845
846 /* window attributes */
847 attr.background_pixel = 0;
848 attr.border_pixel = 0;
849 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
850 attr.event_mask = X_MASK;
851 if (vidmode_active) {
852 mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
853 CWEventMask | CWOverrideRedirect;
854 attr.override_redirect = True;
855 attr.backing_store = NotUseful;
856 attr.save_under = False;
857 } else
858 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
859
860 win = XCreateWindow(dpy, root, 0, 0, width, height,
861 0, visinfo->depth, InputOutput,
862 visinfo->visual, mask, &attr);
863 XMapWindow(dpy, win);
864
865 if (vidmode_active) {
866 XMoveWindow(dpy, win, 0, 0);
867 XRaiseWindow(dpy, win);
868 XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0);
869 XFlush(dpy);
870 // Move the viewport to top left
871 XF86VidModeSetViewPort(dpy, scrnum, 0, 0);
872 }
873
874 XFlush(dpy);
875
876 ctx = glXCreateContext(dpy, visinfo, NULL, True);
877
878 glXMakeCurrent(dpy, win, ctx);
879
880 scr_width = width;
881 scr_height = height;
882
883 if (vid.conheight > height)
884 vid.conheight = height;
885 if (vid.conwidth > width)
886 vid.conwidth = width;
887 vid.width = vid.conwidth;
888 vid.height = vid.conheight;
889
890 vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
891 vid.numpages = 2;
892
893 InitSig(); // trap evil signals
894
895 GL_Init();
896
897 sprintf (gldir, "%s/glquake", com_gamedir);
898 Sys_mkdir (gldir);
899
900 VID_SetPalette(palette);
901
902 // Check for 3DFX Extensions and initialize them.
903 VID_Init8bitPalette();
904
905 Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height);
906
907 vid.recalc_refdef = 1; // force a surface cache flush
908}
909
910void Sys_SendKeyEvents(void)
911{
912 HandleEvents();
913}
914
915void Force_CenterView_f (void)
916{
917 cl.viewangles[PITCH] = 0;
918}
919
920void IN_Init(void)
921{
922}
923
924void IN_Shutdown(void)
925{
926}
927
928/*
929===========
930IN_Commands
931===========
932*/
933void IN_Commands (void)
934{
935 if (!dpy || !win)
936 return;
937
938 if (vidmode_active || key_dest == key_game)
939 IN_ActivateMouse();
940 else
941 IN_DeactivateMouse ();
942}
943
944/*
945===========
946IN_Move
947===========
948*/
949void IN_MouseMove (usercmd_t *cmd)
950{
951 if (!mouse_avail)
952 return;
953
954 if (m_filter.value)
955 {
956 mx = (mx + old_mouse_x) * 0.5;
957 my = (my + old_mouse_y) * 0.5;
958 }
959 old_mouse_x = mx;
960 old_mouse_y = my;
961
962 mx *= sensitivity.value;
963 my *= sensitivity.value;
964
965// add mouse X/Y movement to cmd
966 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
967 cmd->sidemove += m_side.value * mx;
968 else
969 cl.viewangles[YAW] -= m_yaw.value * mx;
970
971 if (in_mlook.state & 1)
972 V_StopPitchDrift ();
973
974 if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
975 {
976 cl.viewangles[PITCH] += m_pitch.value * my;
977 if (cl.viewangles[PITCH] > 80)
978 cl.viewangles[PITCH] = 80;
979 if (cl.viewangles[PITCH] < -70)
980 cl.viewangles[PITCH] = -70;
981 }
982 else
983 {
984 if ((in_strafe.state & 1) && noclip_anglehack)
985 cmd->upmove -= m_forward.value * my;
986 else
987 cmd->forwardmove -= m_forward.value * my;
988 }
989 mx = my = 0;
990}
991
992void IN_Move (usercmd_t *cmd)
993{
994 IN_MouseMove(cmd);
995}
996
997
diff --git a/apps/plugins/sdl/progs/quake/host.c b/apps/plugins/sdl/progs/quake/host.c
new file mode 100644
index 0000000000..9a5f7c29d6
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/host.c
@@ -0,0 +1,977 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// host.c -- coordinates spawning and killing of local servers
21
22#include "quakedef.h"
23#include "r_local.h"
24
25/*
26
27A server can allways be started, even if the system started out as a client
28to a remote system.
29
30A client can NOT be started if the system started as a dedicated server.
31
32Memory is cleared / released when a server or client begins, not when they end.
33
34*/
35
36quakeparms_t host_parms;
37
38qboolean host_initialized; // true if into command execution
39
40double host_frametime;
41double host_time;
42double realtime; // without any filtering or bounding
43double oldrealtime; // last frame run
44int host_framecount;
45
46int host_hunklevel;
47
48int minimum_memory;
49
50client_t *host_client; // current client
51
52jmp_buf host_abortserver;
53
54byte *host_basepal;
55byte *host_colormap;
56
57cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion
58cvar_t host_speeds = {"host_speeds","0"}; // set for running times
59
60cvar_t sys_ticrate = {"sys_ticrate","0.05"};
61cvar_t serverprofile = {"serverprofile","0"};
62
63cvar_t fraglimit = {"fraglimit","0",false,true};
64cvar_t timelimit = {"timelimit","0",false,true};
65cvar_t teamplay = {"teamplay","0",false,true};
66
67cvar_t samelevel = {"samelevel","0"};
68cvar_t noexit = {"noexit","0",false,true};
69
70#ifdef QUAKE2
71cvar_t developer = {"developer","1"}; // should be 0 for release!
72#else
73cvar_t developer = {"developer","0"};
74#endif
75
76cvar_t skill = {"skill","1"}; // 0 - 3
77cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2
78cvar_t coop = {"coop","0"}; // 0 or 1
79
80cvar_t pausable = {"pausable","1"};
81
82cvar_t temp1 = {"temp1","0"};
83
84
85/*
86================
87Host_EndGame
88================
89*/
90void Host_EndGame (char *message, ...)
91{
92 va_list argptr;
93 char string[1024];
94
95 va_start (argptr,message);
96 vsprintf (string,message,argptr);
97 va_end (argptr);
98 Con_DPrintf ("Host_EndGame: %s\n",string);
99
100 if (sv.active)
101 Host_ShutdownServer (false);
102
103 if (cls.state == ca_dedicated)
104 Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit
105
106 if (cls.demonum != -1)
107 CL_NextDemo ();
108 else
109 CL_Disconnect ();
110
111 longjmp (host_abortserver, 1);
112}
113
114/*
115================
116Host_Error
117
118This shuts down both the client and server
119================
120*/
121void Host_Error (char *error, ...)
122{
123 va_list argptr;
124 char string[1024];
125 static qboolean inerror = false;
126
127 if (inerror)
128 Sys_Error ("Host_Error: recursively entered");
129 inerror = true;
130
131 SCR_EndLoadingPlaque (); // reenable screen updates
132
133 va_start (argptr,error);
134 vsprintf (string,error,argptr);
135 va_end (argptr);
136 Con_Printf ("Host_Error: %s\n",string);
137
138 if (sv.active)
139 Host_ShutdownServer (false);
140
141 if (cls.state == ca_dedicated)
142 Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit
143
144 CL_Disconnect ();
145 cls.demonum = -1;
146
147 inerror = false;
148
149 longjmp (host_abortserver, 1);
150}
151
152/*
153================
154Host_FindMaxClients
155================
156*/
157void Host_FindMaxClients (void)
158{
159 int i;
160
161 svs.maxclients = 1;
162
163 i = COM_CheckParm ("-dedicated");
164 if (i)
165 {
166 cls.state = ca_dedicated;
167 if (i != (com_argc - 1))
168 {
169 svs.maxclients = Q_atoi (com_argv[i+1]);
170 }
171 else
172 svs.maxclients = 8;
173 }
174 else
175 cls.state = ca_disconnected;
176
177 i = COM_CheckParm ("-listen");
178 if (i)
179 {
180 if (cls.state == ca_dedicated)
181 Sys_Error ("Only one of -dedicated or -listen can be specified");
182 if (i != (com_argc - 1))
183 svs.maxclients = Q_atoi (com_argv[i+1]);
184 else
185 svs.maxclients = 8;
186 }
187 if (svs.maxclients < 1)
188 svs.maxclients = 8;
189 else if (svs.maxclients > MAX_SCOREBOARD)
190 svs.maxclients = MAX_SCOREBOARD;
191
192 svs.maxclientslimit = svs.maxclients;
193 if (svs.maxclientslimit < 4)
194 svs.maxclientslimit = 4;
195 svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
196
197 if (svs.maxclients > 1)
198 Cvar_SetValue ("deathmatch", 1.0);
199 else
200 Cvar_SetValue ("deathmatch", 0.0);
201}
202
203
204/*
205=======================
206Host_InitLocal
207======================
208*/
209void Host_InitLocal (void)
210{
211 Host_InitCommands ();
212
213 Cvar_RegisterVariable (&host_framerate);
214 Cvar_RegisterVariable (&host_speeds);
215
216 Cvar_RegisterVariable (&sys_ticrate);
217 Cvar_RegisterVariable (&serverprofile);
218
219 Cvar_RegisterVariable (&fraglimit);
220 Cvar_RegisterVariable (&timelimit);
221 Cvar_RegisterVariable (&teamplay);
222 Cvar_RegisterVariable (&samelevel);
223 Cvar_RegisterVariable (&noexit);
224 Cvar_RegisterVariable (&skill);
225 Cvar_RegisterVariable (&developer);
226 Cvar_RegisterVariable (&deathmatch);
227 Cvar_RegisterVariable (&coop);
228
229 Cvar_RegisterVariable (&pausable);
230
231 Cvar_RegisterVariable (&temp1);
232
233 Host_FindMaxClients ();
234
235 host_time = 1.0; // so a think at time 0 won't get called
236}
237
238
239/*
240===============
241Host_WriteConfiguration
242
243Writes key bindings and archived cvars to config.cfg
244===============
245*/
246void Host_WriteConfiguration (void)
247{
248 FILE *f;
249
250// dedicated servers initialize the host but don't parse and set the
251// config.cfg cvars
252 if (host_initialized & !isDedicated)
253 {
254 f = fopen (va("%s/config.cfg",com_gamedir), "w");
255 if (!f)
256 {
257 Con_Printf ("Couldn't write config.cfg.\n");
258 return;
259 }
260
261 Key_WriteBindings (f);
262 Cvar_WriteVariables (f);
263
264 fclose (f);
265 }
266}
267
268
269/*
270=================
271SV_ClientPrintf
272
273Sends text across to be displayed
274FIXME: make this just a stuffed echo?
275=================
276*/
277void SV_ClientPrintf (char *fmt, ...)
278{
279 va_list argptr;
280 char string[1024];
281
282 va_start (argptr,fmt);
283 vsprintf (string, fmt,argptr);
284 va_end (argptr);
285
286 MSG_WriteByte (&host_client->message, svc_print);
287 MSG_WriteString (&host_client->message, string);
288}
289
290/*
291=================
292SV_BroadcastPrintf
293
294Sends text to all active clients
295=================
296*/
297void SV_BroadcastPrintf (char *fmt, ...)
298{
299 va_list argptr;
300 char string[1024];
301 int i;
302
303 va_start (argptr,fmt);
304 vsprintf (string, fmt,argptr);
305 va_end (argptr);
306
307 for (i=0 ; i<svs.maxclients ; i++)
308 if (svs.clients[i].active && svs.clients[i].spawned)
309 {
310 MSG_WriteByte (&svs.clients[i].message, svc_print);
311 MSG_WriteString (&svs.clients[i].message, string);
312 }
313}
314
315/*
316=================
317Host_ClientCommands
318
319Send text over to the client to be executed
320=================
321*/
322void Host_ClientCommands (char *fmt, ...)
323{
324 va_list argptr;
325 char string[1024];
326
327 va_start (argptr,fmt);
328 vsprintf (string, fmt,argptr);
329 va_end (argptr);
330
331 MSG_WriteByte (&host_client->message, svc_stufftext);
332 MSG_WriteString (&host_client->message, string);
333}
334
335/*
336=====================
337SV_DropClient
338
339Called when the player is getting totally kicked off the host
340if (crash = true), don't bother sending signofs
341=====================
342*/
343void SV_DropClient (qboolean crash)
344{
345 int saveSelf;
346 int i;
347 client_t *client;
348
349 if (!crash)
350 {
351 // send any final messages (don't check for errors)
352 if (NET_CanSendMessage (host_client->netconnection))
353 {
354 MSG_WriteByte (&host_client->message, svc_disconnect);
355 NET_SendMessage (host_client->netconnection, &host_client->message);
356 }
357
358 if (host_client->edict && host_client->spawned)
359 {
360 // call the prog function for removing a client
361 // this will set the body to a dead frame, among other things
362 saveSelf = pr_global_struct->self;
363 pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
364 PR_ExecuteProgram (pr_global_struct->ClientDisconnect);
365 pr_global_struct->self = saveSelf;
366 }
367
368 Sys_Printf ("Client %s removed\n",host_client->name);
369 }
370
371// break the net connection
372 NET_Close (host_client->netconnection);
373 host_client->netconnection = NULL;
374
375// free the client (the body stays around)
376 host_client->active = false;
377 host_client->name[0] = 0;
378 host_client->old_frags = -999999;
379 net_activeconnections--;
380
381// send notification to all clients
382 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
383 {
384 if (!client->active)
385 continue;
386 MSG_WriteByte (&client->message, svc_updatename);
387 MSG_WriteByte (&client->message, host_client - svs.clients);
388 MSG_WriteString (&client->message, "");
389 MSG_WriteByte (&client->message, svc_updatefrags);
390 MSG_WriteByte (&client->message, host_client - svs.clients);
391 MSG_WriteShort (&client->message, 0);
392 MSG_WriteByte (&client->message, svc_updatecolors);
393 MSG_WriteByte (&client->message, host_client - svs.clients);
394 MSG_WriteByte (&client->message, 0);
395 }
396}
397
398/*
399==================
400Host_ShutdownServer
401
402This only happens at the end of a game, not between levels
403==================
404*/
405void Host_ShutdownServer(qboolean crash)
406{
407 int i;
408 int count;
409 sizebuf_t buf;
410 char message[4];
411 double start;
412
413 if (!sv.active)
414 return;
415
416 sv.active = false;
417
418// stop all client sounds immediately
419 if (cls.state == ca_connected)
420 CL_Disconnect ();
421
422// flush any pending messages - like the score!!!
423 start = Sys_FloatTime();
424 do
425 {
426 count = 0;
427 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
428 {
429 if (host_client->active && host_client->message.cursize)
430 {
431 if (NET_CanSendMessage (host_client->netconnection))
432 {
433 NET_SendMessage(host_client->netconnection, &host_client->message);
434 SZ_Clear (&host_client->message);
435 }
436 else
437 {
438 NET_GetMessage(host_client->netconnection);
439 count++;
440 }
441 }
442 }
443 if ((Sys_FloatTime() - start) > 3.0)
444 break;
445 }
446 while (count);
447
448// make sure all the clients know we're disconnecting
449 buf.data = message;
450 buf.maxsize = 4;
451 buf.cursize = 0;
452 MSG_WriteByte(&buf, svc_disconnect);
453 count = NET_SendToAll(&buf, 5);
454 if (count)
455 Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
456
457 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
458 if (host_client->active)
459 SV_DropClient(crash);
460
461//
462// clear structures
463//
464 memset (&sv, 0, sizeof(sv));
465 memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
466}
467
468
469/*
470================
471Host_ClearMemory
472
473This clears all the memory used by both the client and server, but does
474not reinitialize anything.
475================
476*/
477void Host_ClearMemory (void)
478{
479 Con_DPrintf ("Clearing memory\n");
480 D_FlushCaches ();
481 Mod_ClearAll ();
482 if (host_hunklevel)
483 Hunk_FreeToLowMark (host_hunklevel);
484
485 cls.signon = 0;
486 memset (&sv, 0, sizeof(sv));
487 memset (&cl, 0, sizeof(cl));
488}
489
490
491//============================================================================
492
493
494/*
495===================
496Host_FilterTime
497
498Returns false if the time is too short to run a frame
499===================
500*/
501qboolean Host_FilterTime (float time)
502{
503 realtime += time;
504
505 if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)
506 return false; // framerate is too high
507
508 host_frametime = realtime - oldrealtime;
509 oldrealtime = realtime;
510
511 if (host_framerate.value > 0)
512 host_frametime = host_framerate.value;
513 else
514 { // don't allow really long or short frames
515 if (host_frametime > 0.1)
516 host_frametime = 0.1;
517 if (host_frametime < 0.001)
518 host_frametime = 0.001;
519 }
520
521 return true;
522}
523
524
525/*
526===================
527Host_GetConsoleCommands
528
529Add them exactly as if they had been typed at the console
530===================
531*/
532void Host_GetConsoleCommands (void)
533{
534 char *cmd;
535
536 while (1)
537 {
538 cmd = Sys_ConsoleInput ();
539 if (!cmd)
540 break;
541 Cbuf_AddText (cmd);
542 }
543}
544
545
546/*
547==================
548Host_ServerFrame
549
550==================
551*/
552#ifdef FPS_20
553
554void _Host_ServerFrame (void)
555{
556// run the world state
557 pr_global_struct->frametime = host_frametime;
558
559// read client messages
560 SV_RunClients ();
561
562// move things around and think
563// always pause in single player if in console or menus
564 if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
565 SV_Physics ();
566}
567
568void Host_ServerFrame (void)
569{
570 float save_host_frametime;
571 float temp_host_frametime;
572
573// run the world state
574 pr_global_struct->frametime = host_frametime;
575
576// set the time and clear the general datagram
577 SV_ClearDatagram ();
578
579// check for new clients
580 SV_CheckForNewClients ();
581
582 temp_host_frametime = save_host_frametime = host_frametime;
583 while(temp_host_frametime > (1.0/72.0))
584 {
585 if (temp_host_frametime > 0.05)
586 host_frametime = 0.05;
587 else
588 host_frametime = temp_host_frametime;
589 temp_host_frametime -= host_frametime;
590 _Host_ServerFrame ();
591 }
592 host_frametime = save_host_frametime;
593
594// send all messages to the clients
595 SV_SendClientMessages ();
596}
597
598#else
599
600void Host_ServerFrame (void)
601{
602// run the world state
603 pr_global_struct->frametime = host_frametime;
604
605// set the time and clear the general datagram
606 SV_ClearDatagram ();
607
608// check for new clients
609 SV_CheckForNewClients ();
610
611// read client messages
612 SV_RunClients ();
613
614// move things around and think
615// always pause in single player if in console or menus
616 if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
617 SV_Physics ();
618
619// send all messages to the clients
620 SV_SendClientMessages ();
621}
622
623#endif
624
625
626/*
627==================
628Host_Frame
629
630Runs all active servers
631==================
632*/
633void _Host_Frame (float time)
634{
635 static double time1 = 0;
636 static double time2 = 0;
637 static double time3 = 0;
638 int pass1, pass2, pass3;
639
640 if (setjmp (host_abortserver) )
641 return; // something bad happened, or the server disconnected
642
643// keep the random time dependent
644 rand ();
645
646// decide the simulation time
647 if (!Host_FilterTime (time))
648 return; // don't run too fast, or packets will flood out
649
650// get new key events
651 Sys_SendKeyEvents ();
652
653// allow mice or other external controllers to add commands
654 IN_Commands ();
655
656// process console commands
657 Cbuf_Execute ();
658
659 NET_Poll();
660
661// if running the server locally, make intentions now
662 if (sv.active)
663 CL_SendCmd ();
664
665//-------------------
666//
667// server operations
668//
669//-------------------
670
671// check for commands typed to the host
672 Host_GetConsoleCommands ();
673
674 if (sv.active)
675 Host_ServerFrame ();
676
677//-------------------
678//
679// client operations
680//
681//-------------------
682
683// if running the server remotely, send intentions now after
684// the incoming messages have been read
685 if (!sv.active)
686 CL_SendCmd ();
687
688 host_time += host_frametime;
689
690// fetch results from server
691 if (cls.state == ca_connected)
692 {
693 CL_ReadFromServer ();
694 }
695
696// update video
697 if (host_speeds.value)
698 time1 = Sys_FloatTime ();
699
700 SCR_UpdateScreen ();
701
702 if (host_speeds.value)
703 time2 = Sys_FloatTime ();
704
705// update audio
706 if (cls.signon == SIGNONS)
707 {
708 S_Update (r_origin, vpn, vright, vup);
709 CL_DecayLights ();
710 }
711 else
712 S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
713
714 CDAudio_Update();
715
716 if (host_speeds.value)
717 {
718 pass1 = (time1 - time3)*1000;
719 time3 = Sys_FloatTime ();
720 pass2 = (time2 - time1)*1000;
721 pass3 = (time3 - time2)*1000;
722 Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
723 pass1+pass2+pass3, pass1, pass2, pass3);
724 }
725
726 host_framecount++;
727}
728
729void Host_Frame (float time)
730{
731 double time1, time2;
732 static double timetotal;
733 static int timecount;
734 int i, c, m;
735
736 if (!serverprofile.value)
737 {
738 _Host_Frame (time);
739 return;
740 }
741
742 time1 = Sys_FloatTime ();
743 _Host_Frame (time);
744 time2 = Sys_FloatTime ();
745
746 timetotal += time2 - time1;
747 timecount++;
748
749 if (timecount < 1000)
750 return;
751
752 m = timetotal*1000/timecount;
753 timecount = 0;
754 timetotal = 0;
755 c = 0;
756 for (i=0 ; i<svs.maxclients ; i++)
757 {
758 if (svs.clients[i].active)
759 c++;
760 }
761
762 Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m);
763}
764
765//============================================================================
766
767
768extern int vcrFile;
769#define VCR_SIGNATURE 0x56435231
770// "VCR1"
771
772void Host_InitVCR (quakeparms_t *parms)
773{
774 int i, len, n;
775 char *p;
776
777 if (COM_CheckParm("-playback"))
778 {
779 if (com_argc != 2)
780 Sys_Error("No other parameters allowed with -playback\n");
781
782 Sys_FileOpenRead("quake.vcr", &vcrFile);
783 if (vcrFile == -1)
784 Sys_Error("playback file not found\n");
785
786 Sys_FileRead (vcrFile, &i, sizeof(int));
787 if (i != VCR_SIGNATURE)
788 Sys_Error("Invalid signature in vcr file\n");
789
790 Sys_FileRead (vcrFile, &com_argc, sizeof(int));
791 com_argv = malloc(com_argc * sizeof(char *));
792 com_argv[0] = parms->argv[0];
793 for (i = 0; i < com_argc; i++)
794 {
795 Sys_FileRead (vcrFile, &len, sizeof(int));
796 p = malloc(len);
797 Sys_FileRead (vcrFile, p, len);
798 com_argv[i+1] = p;
799 }
800 com_argc++; /* add one for arg[0] */
801 parms->argc = com_argc;
802 parms->argv = com_argv;
803 }
804
805 if ( (n = COM_CheckParm("-record")) != 0)
806 {
807 vcrFile = Sys_FileOpenWrite("quake.vcr");
808
809 i = VCR_SIGNATURE;
810 Sys_FileWrite(vcrFile, &i, sizeof(int));
811 i = com_argc - 1;
812 Sys_FileWrite(vcrFile, &i, sizeof(int));
813 for (i = 1; i < com_argc; i++)
814 {
815 if (i == n)
816 {
817 len = 10;
818 Sys_FileWrite(vcrFile, &len, sizeof(int));
819 Sys_FileWrite(vcrFile, "-playback", len);
820 continue;
821 }
822 len = Q_strlen(com_argv[i]) + 1;
823 Sys_FileWrite(vcrFile, &len, sizeof(int));
824 Sys_FileWrite(vcrFile, com_argv[i], len);
825 }
826 }
827
828}
829
830/*
831====================
832Host_Init
833====================
834*/
835void Host_Init (quakeparms_t *parms)
836{
837
838 if (standard_quake)
839 minimum_memory = MINIMUM_MEMORY;
840 else
841 minimum_memory = MINIMUM_MEMORY_LEVELPAK;
842
843 if (COM_CheckParm ("-minmemory"))
844 parms->memsize = minimum_memory;
845
846 host_parms = *parms;
847
848 if (parms->memsize < minimum_memory)
849 Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000);
850
851 com_argc = parms->argc;
852 com_argv = parms->argv;
853
854 //printf("init 1");
855
856 Memory_Init (parms->membase, parms->memsize);
857 //printf("init 2");
858 Cbuf_Init ();
859 //printf("init 3");
860 Cmd_Init ();
861 //printf("init 4");
862 V_Init ();
863 //printf("init 5");
864 Chase_Init ();
865 //printf("init 6");
866 Host_InitVCR (parms);
867 //printf("init 7");
868 COM_Init (parms->basedir);
869 //printf("init 8");
870 Host_InitLocal ();
871 //printf("init 9");
872 W_LoadWadFile ("gfx.wad");
873 //printf("init 10");
874 Key_Init ();
875 Con_Init ();
876 M_Init ();
877 PR_Init ();
878 Mod_Init ();
879 NET_Init ();
880 //printf("init 11");
881 SV_Init ();
882 //printf("init 12");
883
884 Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
885 Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));
886
887 R_InitTextures (); // needed even for dedicated servers
888
889 //printf("init 13");
890 if (cls.state != ca_dedicated)
891 {
892 host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
893 if (!host_basepal)
894 Sys_Error ("Couldn't load gfx/palette.lmp");
895 host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
896 if (!host_colormap)
897 Sys_Error ("Couldn't load gfx/colormap.lmp");
898
899#ifndef _WIN32 // on non win32, mouse comes before video for security reasons
900 IN_Init ();
901#endif
902 VID_Init (host_basepal);
903
904 Draw_Init ();
905 SCR_Init ();
906 R_Init ();
907#ifndef _WIN32
908 // on Win32, sound initialization has to come before video initialization, so we
909 // can put up a popup if the sound hardware is in use
910 S_Init ();
911#else
912
913#ifdef GLQUAKE
914 // FIXME: doesn't use the new one-window approach yet
915 S_Init ();
916#endif
917
918#endif // _WIN32
919 CDAudio_Init ();
920 Sbar_Init ();
921 CL_Init ();
922#ifdef _WIN32 // on non win32, mouse comes before video for security reasons
923 IN_Init ();
924#endif
925 }
926
927 Cbuf_InsertText ("exec quake.rc\n");
928
929 Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
930 host_hunklevel = Hunk_LowMark ();
931
932 host_initialized = true;
933
934 Sys_Printf ("========Quake Initialized=========\n");
935
936 extern int enable_printf;
937 enable_printf = 0;
938}
939
940
941/*
942===============
943Host_Shutdown
944
945FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better
946to run quit through here before the final handoff to the sys code.
947===============
948*/
949void Host_Shutdown(void)
950{
951 static qboolean isdown = false;
952
953 if (isdown)
954 {
955 printf ("recursive shutdown\n");
956 return;
957 }
958 isdown = true;
959
960// keep Con_Printf from trying to update the screen
961 scr_disabled_for_loading = true;
962
963 Host_WriteConfiguration ();
964
965 CDAudio_Shutdown ();
966 NET_Shutdown ();
967 S_Shutdown();
968 IN_Shutdown ();
969
970 Sys_Shutdown();
971
972 if (cls.state != ca_dedicated)
973 {
974 VID_Shutdown();
975 }
976}
977
diff --git a/apps/plugins/sdl/progs/quake/host_cmd.c b/apps/plugins/sdl/progs/quake/host_cmd.c
new file mode 100644
index 0000000000..498eec0d3a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/host_cmd.c
@@ -0,0 +1,1931 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22
23extern cvar_t pausable;
24
25int current_skill;
26
27void Mod_Print (void);
28
29/*
30==================
31Host_Quit_f
32==================
33*/
34
35extern void M_Menu_Quit_f (void);
36
37void Host_Quit_f (void)
38{
39 if (key_dest != key_console && cls.state != ca_dedicated)
40 {
41 M_Menu_Quit_f ();
42 return;
43 }
44 CL_Disconnect ();
45 Host_ShutdownServer(false);
46
47 Sys_Quit ();
48}
49
50
51/*
52==================
53Host_Status_f
54==================
55*/
56void Host_Status_f (void)
57{
58 client_t *client;
59 int seconds;
60 int minutes;
61 int hours = 0;
62 int j;
63 void (*print) (char *fmt, ...);
64
65 if (cmd_source == src_command)
66 {
67 if (!sv.active)
68 {
69 Cmd_ForwardToServer ();
70 return;
71 }
72 print = Con_Printf;
73 }
74 else
75 print = SV_ClientPrintf;
76
77 print ("host: %s\n", Cvar_VariableString ("hostname"));
78 print ("version: %4.2f\n", VERSION);
79 if (tcpipAvailable)
80 print ("tcp/ip: %s\n", my_tcpip_address);
81 if (ipxAvailable)
82 print ("ipx: %s\n", my_ipx_address);
83 print ("map: %s\n", sv.name);
84 print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
85 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
86 {
87 if (!client->active)
88 continue;
89 seconds = (int)(net_time - client->netconnection->connecttime);
90 minutes = seconds / 60;
91 if (minutes)
92 {
93 seconds -= (minutes * 60);
94 hours = minutes / 60;
95 if (hours)
96 minutes -= (hours * 60);
97 }
98 else
99 hours = 0;
100 print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
101 print (" %s\n", client->netconnection->address);
102 }
103}
104
105
106/*
107==================
108Host_God_f
109
110Sets client to godmode
111==================
112*/
113void Host_God_f (void)
114{
115 if (cmd_source == src_command)
116 {
117 Cmd_ForwardToServer ();
118 return;
119 }
120
121 if (pr_global_struct->deathmatch && !host_client->privileged)
122 return;
123
124 sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
125 if (!((int)sv_player->v.flags & FL_GODMODE) )
126 SV_ClientPrintf ("godmode OFF\n");
127 else
128 SV_ClientPrintf ("godmode ON\n");
129}
130
131void Host_Notarget_f (void)
132{
133 if (cmd_source == src_command)
134 {
135 Cmd_ForwardToServer ();
136 return;
137 }
138
139 if (pr_global_struct->deathmatch && !host_client->privileged)
140 return;
141
142 sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;
143 if (!((int)sv_player->v.flags & FL_NOTARGET) )
144 SV_ClientPrintf ("notarget OFF\n");
145 else
146 SV_ClientPrintf ("notarget ON\n");
147}
148
149qboolean noclip_anglehack;
150
151void Host_Noclip_f (void)
152{
153 if (cmd_source == src_command)
154 {
155 Cmd_ForwardToServer ();
156 return;
157 }
158
159 if (pr_global_struct->deathmatch && !host_client->privileged)
160 return;
161
162 if (sv_player->v.movetype != MOVETYPE_NOCLIP)
163 {
164 noclip_anglehack = true;
165 sv_player->v.movetype = MOVETYPE_NOCLIP;
166 SV_ClientPrintf ("noclip ON\n");
167 }
168 else
169 {
170 noclip_anglehack = false;
171 sv_player->v.movetype = MOVETYPE_WALK;
172 SV_ClientPrintf ("noclip OFF\n");
173 }
174}
175
176/*
177==================
178Host_Fly_f
179
180Sets client to flymode
181==================
182*/
183void Host_Fly_f (void)
184{
185 if (cmd_source == src_command)
186 {
187 Cmd_ForwardToServer ();
188 return;
189 }
190
191 if (pr_global_struct->deathmatch && !host_client->privileged)
192 return;
193
194 if (sv_player->v.movetype != MOVETYPE_FLY)
195 {
196 sv_player->v.movetype = MOVETYPE_FLY;
197 SV_ClientPrintf ("flymode ON\n");
198 }
199 else
200 {
201 sv_player->v.movetype = MOVETYPE_WALK;
202 SV_ClientPrintf ("flymode OFF\n");
203 }
204}
205
206
207/*
208==================
209Host_Ping_f
210
211==================
212*/
213void Host_Ping_f (void)
214{
215 int i, j;
216 float total;
217 client_t *client;
218
219 if (cmd_source == src_command)
220 {
221 Cmd_ForwardToServer ();
222 return;
223 }
224
225 SV_ClientPrintf ("Client ping times:\n");
226 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
227 {
228 if (!client->active)
229 continue;
230 total = 0;
231 for (j=0 ; j<NUM_PING_TIMES ; j++)
232 total+=client->ping_times[j];
233 total /= NUM_PING_TIMES;
234 SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name);
235 }
236}
237
238/*
239===============================================================================
240
241SERVER TRANSITIONS
242
243===============================================================================
244*/
245
246
247/*
248======================
249Host_Map_f
250
251handle a
252map <servername>
253command from the console. Active clients are kicked off.
254======================
255*/
256void Host_Map_f (void)
257{
258 int i;
259 char name[MAX_QPATH];
260
261 if (cmd_source != src_command)
262 return;
263
264 cls.demonum = -1; // stop demo loop in case this fails
265
266 CL_Disconnect ();
267 Host_ShutdownServer(false);
268
269 key_dest = key_game; // remove console or menu
270 SCR_BeginLoadingPlaque ();
271
272 cls.mapstring[0] = 0;
273 for (i=0 ; i<Cmd_Argc() ; i++)
274 {
275 strcat (cls.mapstring, Cmd_Argv(i));
276 strcat (cls.mapstring, " ");
277 }
278 strcat (cls.mapstring, "\n");
279
280 svs.serverflags = 0; // haven't completed an episode yet
281 strcpy (name, Cmd_Argv(1));
282#ifdef QUAKE2
283 SV_SpawnServer (name, NULL);
284#else
285 SV_SpawnServer (name);
286#endif
287 if (!sv.active)
288 return;
289
290 if (cls.state != ca_dedicated)
291 {
292 strcpy (cls.spawnparms, "");
293
294 for (i=2 ; i<Cmd_Argc() ; i++)
295 {
296 strcat (cls.spawnparms, Cmd_Argv(i));
297 strcat (cls.spawnparms, " ");
298 }
299
300 Cmd_ExecuteString ("connect local", src_command);
301 }
302}
303
304/*
305==================
306Host_Changelevel_f
307
308Goes to a new map, taking all clients along
309==================
310*/
311void Host_Changelevel_f (void)
312{
313#ifdef QUAKE2
314 char level[MAX_QPATH];
315 char _startspot[MAX_QPATH];
316 char *startspot;
317
318 if (Cmd_Argc() < 2)
319 {
320 Con_Printf ("changelevel <levelname> : continue game on a new level\n");
321 return;
322 }
323 if (!sv.active || cls.demoplayback)
324 {
325 Con_Printf ("Only the server may changelevel\n");
326 return;
327 }
328
329 strcpy (level, Cmd_Argv(1));
330 if (Cmd_Argc() == 2)
331 startspot = NULL;
332 else
333 {
334 strcpy (_startspot, Cmd_Argv(2));
335 startspot = _startspot;
336 }
337
338 SV_SaveSpawnparms ();
339 SV_SpawnServer (level, startspot);
340#else
341 char level[MAX_QPATH];
342
343 if (Cmd_Argc() != 2)
344 {
345 Con_Printf ("changelevel <levelname> : continue game on a new level\n");
346 return;
347 }
348 if (!sv.active || cls.demoplayback)
349 {
350 Con_Printf ("Only the server may changelevel\n");
351 return;
352 }
353 SV_SaveSpawnparms ();
354 strcpy (level, Cmd_Argv(1));
355 SV_SpawnServer (level);
356#endif
357}
358
359/*
360==================
361Host_Restart_f
362
363Restarts the current server for a dead player
364==================
365*/
366void Host_Restart_f (void)
367{
368 char mapname[MAX_QPATH];
369#ifdef QUAKE2
370 char startspot[MAX_QPATH];
371#endif
372
373 if (cls.demoplayback || !sv.active)
374 return;
375
376 if (cmd_source != src_command)
377 return;
378 strcpy (mapname, sv.name); // must copy out, because it gets cleared
379 // in sv_spawnserver
380#ifdef QUAKE2
381 strcpy(startspot, sv.startspot);
382 SV_SpawnServer (mapname, startspot);
383#else
384 SV_SpawnServer (mapname);
385#endif
386}
387
388/*
389==================
390Host_Reconnect_f
391
392This command causes the client to wait for the signon messages again.
393This is sent just before a server changes levels
394==================
395*/
396void Host_Reconnect_f (void)
397{
398 SCR_BeginLoadingPlaque ();
399 cls.signon = 0; // need new connection messages
400}
401
402/*
403=====================
404Host_Connect_f
405
406User command to connect to server
407=====================
408*/
409void Host_Connect_f (void)
410{
411 char name[MAX_QPATH];
412
413 cls.demonum = -1; // stop demo loop in case this fails
414 if (cls.demoplayback)
415 {
416 CL_StopPlayback ();
417 CL_Disconnect ();
418 }
419 strcpy (name, Cmd_Argv(1));
420 CL_EstablishConnection (name);
421 Host_Reconnect_f ();
422}
423
424
425/*
426===============================================================================
427
428LOAD / SAVE GAME
429
430===============================================================================
431*/
432
433#define SAVEGAME_VERSION 5
434
435/*
436===============
437Host_SavegameComment
438
439Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current
440===============
441*/
442void Host_SavegameComment (char *text)
443{
444 int i;
445 char kills[20];
446
447 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
448 text[i] = ' ';
449 memcpy (text, cl.levelname, strlen(cl.levelname));
450 sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
451 memcpy (text+22, kills, strlen(kills));
452// convert space to _ to make stdio happy
453 for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
454 if (text[i] == ' ')
455 text[i] = '_';
456 text[SAVEGAME_COMMENT_LENGTH] = '\0';
457}
458
459
460/*
461===============
462Host_Savegame_f
463===============
464*/
465void Host_Savegame_f (void)
466{
467 char name[256];
468 FILE *f;
469 int i;
470 char comment[SAVEGAME_COMMENT_LENGTH+1];
471
472 if (cmd_source != src_command)
473 return;
474
475 if (!sv.active)
476 {
477 Con_Printf ("Not playing a local game.\n");
478 return;
479 }
480
481 if (cl.intermission)
482 {
483 Con_Printf ("Can't save in intermission.\n");
484 return;
485 }
486
487 if (svs.maxclients != 1)
488 {
489 Con_Printf ("Can't save multiplayer games.\n");
490 return;
491 }
492
493 if (Cmd_Argc() != 2)
494 {
495 Con_Printf ("save <savename> : save a game\n");
496 return;
497 }
498
499 if (strstr(Cmd_Argv(1), ".."))
500 {
501 Con_Printf ("Relative pathnames are not allowed.\n");
502 return;
503 }
504
505 for (i=0 ; i<svs.maxclients ; i++)
506 {
507 if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) )
508 {
509 Con_Printf ("Can't savegame with a dead player\n");
510 return;
511 }
512 }
513
514 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
515 COM_DefaultExtension (name, ".sav");
516
517 Con_Printf ("Saving game to %s...\n", name);
518 f = fopen (name, "w");
519 if (!f)
520 {
521 Con_Printf ("ERROR: couldn't open.\n");
522 return;
523 }
524
525 fprintf (f, "%i\n", SAVEGAME_VERSION);
526 Host_SavegameComment (comment);
527 fprintf (f, "%s\n", comment);
528 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
529 fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
530 fprintf (f, "%d\n", current_skill);
531 fprintf (f, "%s\n", sv.name);
532 fprintf (f, "%f\n",sv.time);
533
534// write the light styles
535
536 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
537 {
538 if (sv.lightstyles[i])
539 fprintf (f, "%s\n", sv.lightstyles[i]);
540 else
541 fprintf (f,"m\n");
542 }
543
544
545 ED_WriteGlobals (f);
546 for (i=0 ; i<sv.num_edicts ; i++)
547 {
548 ED_Write (f, EDICT_NUM(i));
549 fflush (f);
550 }
551 fclose (f);
552 Con_Printf ("done.\n");
553}
554
555
556/*
557===============
558Host_Loadgame_f
559===============
560*/
561void Host_Loadgame_f (void)
562{
563 char name[MAX_OSPATH];
564 FILE *f;
565 char mapname[MAX_QPATH];
566 float time, tfloat;
567 char str[32768], *start;
568 int i, r;
569 edict_t *ent;
570 int entnum;
571 int version;
572 float spawn_parms[NUM_SPAWN_PARMS];
573
574 if (cmd_source != src_command)
575 return;
576
577 if (Cmd_Argc() != 2)
578 {
579 Con_Printf ("load <savename> : load a game\n");
580 return;
581 }
582
583 cls.demonum = -1; // stop demo loop in case this fails
584
585 sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
586 COM_DefaultExtension (name, ".sav");
587
588// we can't call SCR_BeginLoadingPlaque, because too much stack space has
589// been used. The menu calls it before stuffing loadgame command
590// SCR_BeginLoadingPlaque ();
591
592 Con_Printf ("Loading game from %s...\n", name);
593 f = fopen (name, "r");
594 if (!f)
595 {
596 Con_Printf ("ERROR: couldn't open.\n");
597 return;
598 }
599
600 fscanf (f, "%i\n", &version);
601 if (version != SAVEGAME_VERSION)
602 {
603 fclose (f);
604 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
605 return;
606 }
607 fscanf (f, "%s\n", str);
608 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
609 fscanf (f, "%f\n", &spawn_parms[i]);
610// this silliness is so we can load 1.06 save files, which have float skill values
611 fscanf (f, "%f\n", &tfloat);
612 current_skill = (int)(tfloat + 0.1);
613 Cvar_SetValue ("skill", (float)current_skill);
614
615#ifdef QUAKE2
616 Cvar_SetValue ("deathmatch", 0);
617 Cvar_SetValue ("coop", 0);
618 Cvar_SetValue ("teamplay", 0);
619#endif
620
621 fscanf (f, "%s\n",mapname);
622 fscanf (f, "%f\n",&time);
623
624 CL_Disconnect_f ();
625
626#ifdef QUAKE2
627 SV_SpawnServer (mapname, NULL);
628#else
629 SV_SpawnServer (mapname);
630#endif
631 if (!sv.active)
632 {
633 Con_Printf ("Couldn't load map\n");
634 return;
635 }
636 sv.paused = true; // pause until all clients connect
637 sv.loadgame = true;
638
639// load the light styles
640
641 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
642 {
643 fscanf (f, "%s\n", str);
644 sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
645 strcpy (sv.lightstyles[i], str);
646 }
647
648// load the edicts out of the savegame file
649 entnum = -1; // -1 is the globals
650 bool done = false;
651 while (!done)
652 {
653 for (i=0 ; i<sizeof(str)-1 ; i++)
654 {
655 r = fgetc (f);
656 if (r == EOF || !r || r < 0)
657 {
658 if(r == EOF)
659 done = true;
660 break;
661 }
662 str[i] = r;
663 if (r == '}')
664 {
665 i++;
666 break;
667 }
668 LOGF("get char %d", r);
669 }
670 if (i == sizeof(str)-1)
671 Sys_Error ("Loadgame buffer overflow");
672 str[i] = 0;
673 start = str;
674 start = COM_Parse(str);
675 if (!com_token[0])
676 break; // end of file
677 if (strcmp(com_token,"{"))
678 Sys_Error ("First token isn't a brace");
679
680 if (entnum == -1)
681 { // parse the global vars
682 ED_ParseGlobals (start);
683 }
684 else
685 { // parse an edict
686
687 ent = EDICT_NUM(entnum);
688 memset (&ent->v, 0, progs->entityfields * 4);
689 ent->free = false;
690 ED_ParseEdict (start, ent);
691
692 // link it into the bsp tree
693 if (!ent->free)
694 SV_LinkEdict (ent, false);
695 }
696
697 entnum++;
698 }
699
700 sv.num_edicts = entnum;
701 sv.time = time;
702
703 fclose (f);
704
705 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
706 svs.clients->spawn_parms[i] = spawn_parms[i];
707
708 if (cls.state != ca_dedicated)
709 {
710 CL_EstablishConnection ("local");
711 Host_Reconnect_f ();
712 }
713}
714
715#ifdef QUAKE2
716void SaveGamestate()
717{
718 char name[256];
719 FILE *f;
720 int i;
721 char comment[SAVEGAME_COMMENT_LENGTH+1];
722 edict_t *ent;
723
724 sprintf (name, "%s/%s.gip", com_gamedir, sv.name);
725
726 Con_Printf ("Saving game to %s...\n", name);
727 f = fopen (name, "w");
728 if (!f)
729 {
730 Con_Printf ("ERROR: couldn't open.\n");
731 return;
732 }
733
734 fprintf (f, "%i\n", SAVEGAME_VERSION);
735 Host_SavegameComment (comment);
736 fprintf (f, "%s\n", comment);
737// for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
738// fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
739 fprintf (f, "%f\n", skill.value);
740 fprintf (f, "%s\n", sv.name);
741 fprintf (f, "%f\n", sv.time);
742
743// write the light styles
744
745 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
746 {
747 if (sv.lightstyles[i])
748 fprintf (f, "%s\n", sv.lightstyles[i]);
749 else
750 fprintf (f,"m\n");
751 }
752
753
754 for (i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
755 {
756 ent = EDICT_NUM(i);
757 if ((int)ent->v.flags & FL_ARCHIVE_OVERRIDE)
758 continue;
759 fprintf (f, "%i\n",i);
760 ED_Write (f, ent);
761 fflush (f);
762 }
763 fclose (f);
764 Con_Printf ("done.\n");
765}
766
767int LoadGamestate(char *level, char *startspot)
768{
769 char name[MAX_OSPATH];
770 FILE *f;
771 char mapname[MAX_QPATH];
772 float time, sk;
773 char str[32768], *start;
774 int i, r;
775 edict_t *ent;
776 int entnum;
777 int version;
778// float spawn_parms[NUM_SPAWN_PARMS];
779
780 sprintf (name, "%s/%s.gip", com_gamedir, level);
781
782 Con_Printf ("Loading game from %s...\n", name);
783 f = fopen (name, "r");
784 if (!f)
785 {
786 Con_Printf ("ERROR: couldn't open.\n");
787 return -1;
788 }
789
790 fscanf (f, "%i\n", &version);
791 if (version != SAVEGAME_VERSION)
792 {
793 fclose (f);
794 Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
795 return -1;
796 }
797 fscanf (f, "%s\n", str);
798 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
799 fscanf (f, "%f\n", &spawn_parms[i]);
800 fscanf (f, "%f\n", &sk);
801 Cvar_SetValue ("skill", sk);
802
803 fscanf (f, "%s\n",mapname);
804 fscanf (f, "%f\n",&time);
805
806 SV_SpawnServer (mapname, startspot);
807
808 if (!sv.active)
809 {
810 Con_Printf ("Couldn't load map\n");
811 return -1;
812 }
813
814// load the light styles
815 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
816 {
817 fscanf (f, "%s\n", str);
818 sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
819 strcpy (sv.lightstyles[i], str);
820 }
821
822// load the edicts out of the savegame file
823 while (!feof(f))
824 {
825 fscanf (f, "%i\n",&entnum);
826 for (i=0 ; i<sizeof(str)-1 ; i++)
827 {
828 r = fgetc (f);
829 if (r == EOF || !r)
830 break;
831 str[i] = r;
832 if (r == '}')
833 {
834 i++;
835 break;
836 }
837 }
838 if (i == sizeof(str)-1)
839 Sys_Error ("Loadgame buffer overflow");
840 str[i] = 0;
841 start = str;
842 start = COM_Parse(str);
843 if (!com_token[0])
844 break; // end of file
845 if (strcmp(com_token,"{"))
846 Sys_Error ("First token isn't a brace");
847
848 // parse an edict
849
850 ent = EDICT_NUM(entnum);
851 memset (&ent->v, 0, progs->entityfields * 4);
852 ent->free = false;
853 ED_ParseEdict (start, ent);
854
855 // link it into the bsp tree
856 if (!ent->free)
857 SV_LinkEdict (ent, false);
858 }
859
860// sv.num_edicts = entnum;
861 sv.time = time;
862 fclose (f);
863
864// for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
865// svs.clients->spawn_parms[i] = spawn_parms[i];
866
867 return 0;
868}
869
870// changing levels within a unit
871void Host_Changelevel2_f (void)
872{
873 char level[MAX_QPATH];
874 char _startspot[MAX_QPATH];
875 char *startspot;
876
877 if (Cmd_Argc() < 2)
878 {
879 Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n");
880 return;
881 }
882 if (!sv.active || cls.demoplayback)
883 {
884 Con_Printf ("Only the server may changelevel\n");
885 return;
886 }
887
888 strcpy (level, Cmd_Argv(1));
889 if (Cmd_Argc() == 2)
890 startspot = NULL;
891 else
892 {
893 strcpy (_startspot, Cmd_Argv(2));
894 startspot = _startspot;
895 }
896
897 SV_SaveSpawnparms ();
898
899 // save the current level's state
900 SaveGamestate ();
901
902 // try to restore the new level
903 if (LoadGamestate (level, startspot))
904 SV_SpawnServer (level, startspot);
905}
906#endif
907
908
909//============================================================================
910
911/*
912======================
913Host_Name_f
914======================
915*/
916void Host_Name_f (void)
917{
918 char *newName;
919
920 if (Cmd_Argc () == 1)
921 {
922 Con_Printf ("\"name\" is \"%s\"\n", cl_name.string);
923 return;
924 }
925 if (Cmd_Argc () == 2)
926 newName = Cmd_Argv(1);
927 else
928 newName = Cmd_Args();
929 newName[15] = 0;
930
931 if (cmd_source == src_command)
932 {
933 if (Q_strcmp(cl_name.string, newName) == 0)
934 return;
935 Cvar_Set ("_cl_name", newName);
936 if (cls.state == ca_connected)
937 Cmd_ForwardToServer ();
938 return;
939 }
940
941 if (host_client->name[0] && strcmp(host_client->name, "unconnected") )
942 if (Q_strcmp(host_client->name, newName) != 0)
943 Con_Printf ("%s renamed to %s\n", host_client->name, newName);
944 Q_strcpy (host_client->name, newName);
945 host_client->edict->v.netname = host_client->name - pr_strings;
946
947// send notification to all clients
948
949 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
950 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
951 MSG_WriteString (&sv.reliable_datagram, host_client->name);
952}
953
954
955void Host_Version_f (void)
956{
957 Con_Printf ("Version %4.2f\n", VERSION);
958 Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
959}
960
961#ifdef IDGODS
962void Host_Please_f (void)
963{
964 client_t *cl;
965 int j;
966
967 if (cmd_source != src_command)
968 return;
969
970 if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0)
971 {
972 j = Q_atof(Cmd_Argv(2)) - 1;
973 if (j < 0 || j >= svs.maxclients)
974 return;
975 if (!svs.clients[j].active)
976 return;
977 cl = &svs.clients[j];
978 if (cl->privileged)
979 {
980 cl->privileged = false;
981 cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
982 cl->edict->v.movetype = MOVETYPE_WALK;
983 noclip_anglehack = false;
984 }
985 else
986 cl->privileged = true;
987 }
988
989 if (Cmd_Argc () != 2)
990 return;
991
992 for (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++)
993 {
994 if (!cl->active)
995 continue;
996 if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0)
997 {
998 if (cl->privileged)
999 {
1000 cl->privileged = false;
1001 cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);
1002 cl->edict->v.movetype = MOVETYPE_WALK;
1003 noclip_anglehack = false;
1004 }
1005 else
1006 cl->privileged = true;
1007 break;
1008 }
1009 }
1010}
1011#endif
1012
1013
1014void Host_Say(qboolean teamonly)
1015{
1016 client_t *client;
1017 client_t *save;
1018 int j;
1019 char *p;
1020 unsigned char text[64];
1021 qboolean fromServer = false;
1022
1023 if (cmd_source == src_command)
1024 {
1025 if (cls.state == ca_dedicated)
1026 {
1027 fromServer = true;
1028 teamonly = false;
1029 }
1030 else
1031 {
1032 Cmd_ForwardToServer ();
1033 return;
1034 }
1035 }
1036
1037 if (Cmd_Argc () < 2)
1038 return;
1039
1040 save = host_client;
1041
1042 p = Cmd_Args();
1043// remove quotes if present
1044 if (*p == '"')
1045 {
1046 p++;
1047 p[Q_strlen(p)-1] = 0;
1048 }
1049
1050// turn on color set 1
1051 if (!fromServer)
1052 sprintf (text, "%c%s: ", 1, save->name);
1053 else
1054 sprintf (text, "%c<%s> ", 1, hostname.string);
1055
1056 j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator
1057 if (Q_strlen(p) > j)
1058 p[j] = 0;
1059
1060 strcat (text, p);
1061 strcat (text, "\n");
1062
1063 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
1064 {
1065 if (!client || !client->active || !client->spawned)
1066 continue;
1067 if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team)
1068 continue;
1069 host_client = client;
1070 SV_ClientPrintf("%s", text);
1071 }
1072 host_client = save;
1073
1074 Sys_Printf("%s", &text[1]);
1075}
1076
1077
1078void Host_Say_f(void)
1079{
1080 Host_Say(false);
1081}
1082
1083
1084void Host_Say_Team_f(void)
1085{
1086 Host_Say(true);
1087}
1088
1089
1090void Host_Tell_f(void)
1091{
1092 client_t *client;
1093 client_t *save;
1094 int j;
1095 char *p;
1096 char text[64];
1097
1098 if (cmd_source == src_command)
1099 {
1100 Cmd_ForwardToServer ();
1101 return;
1102 }
1103
1104 if (Cmd_Argc () < 3)
1105 return;
1106
1107 Q_strcpy(text, host_client->name);
1108 Q_strcat(text, ": ");
1109
1110 p = Cmd_Args();
1111
1112// remove quotes if present
1113 if (*p == '"')
1114 {
1115 p++;
1116 p[Q_strlen(p)-1] = 0;
1117 }
1118
1119// check length & truncate if necessary
1120 j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator
1121 if (Q_strlen(p) > j)
1122 p[j] = 0;
1123
1124 strcat (text, p);
1125 strcat (text, "\n");
1126
1127 save = host_client;
1128 for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)
1129 {
1130 if (!client->active || !client->spawned)
1131 continue;
1132 if (Q_strcasecmp(client->name, Cmd_Argv(1)))
1133 continue;
1134 host_client = client;
1135 SV_ClientPrintf("%s", text);
1136 break;
1137 }
1138 host_client = save;
1139}
1140
1141
1142/*
1143==================
1144Host_Color_f
1145==================
1146*/
1147void Host_Color_f(void)
1148{
1149 int top, bottom;
1150 int playercolor;
1151
1152 if (Cmd_Argc() == 1)
1153 {
1154 Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);
1155 Con_Printf ("color <0-13> [0-13]\n");
1156 return;
1157 }
1158
1159 if (Cmd_Argc() == 2)
1160 top = bottom = atoi(Cmd_Argv(1));
1161 else
1162 {
1163 top = atoi(Cmd_Argv(1));
1164 bottom = atoi(Cmd_Argv(2));
1165 }
1166
1167 top &= 15;
1168 if (top > 13)
1169 top = 13;
1170 bottom &= 15;
1171 if (bottom > 13)
1172 bottom = 13;
1173
1174 playercolor = top*16 + bottom;
1175
1176 if (cmd_source == src_command)
1177 {
1178 Cvar_SetValue ("_cl_color", playercolor);
1179 if (cls.state == ca_connected)
1180 Cmd_ForwardToServer ();
1181 return;
1182 }
1183
1184 host_client->colors = playercolor;
1185 host_client->edict->v.team = bottom + 1;
1186
1187// send notification to all clients
1188 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1189 MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
1190 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1191}
1192
1193/*
1194==================
1195Host_Kill_f
1196==================
1197*/
1198void Host_Kill_f (void)
1199{
1200 if (cmd_source == src_command)
1201 {
1202 Cmd_ForwardToServer ();
1203 return;
1204 }
1205
1206 if (sv_player->v.health <= 0)
1207 {
1208 SV_ClientPrintf ("Can't suicide -- allready dead!\n");
1209 return;
1210 }
1211
1212 pr_global_struct->time = sv.time;
1213 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1214 PR_ExecuteProgram (pr_global_struct->ClientKill);
1215}
1216
1217
1218/*
1219==================
1220Host_Pause_f
1221==================
1222*/
1223void Host_Pause_f (void)
1224{
1225
1226 if (cmd_source == src_command)
1227 {
1228 Cmd_ForwardToServer ();
1229 return;
1230 }
1231 if (!pausable.value)
1232 SV_ClientPrintf ("Pause not allowed.\n");
1233 else
1234 {
1235 sv.paused ^= 1;
1236
1237 if (sv.paused)
1238 {
1239 SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->v.netname);
1240 }
1241 else
1242 {
1243 SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->v.netname);
1244 }
1245
1246 // send notification to all clients
1247 MSG_WriteByte (&sv.reliable_datagram, svc_setpause);
1248 MSG_WriteByte (&sv.reliable_datagram, sv.paused);
1249 }
1250}
1251
1252//===========================================================================
1253
1254
1255/*
1256==================
1257Host_PreSpawn_f
1258==================
1259*/
1260void Host_PreSpawn_f (void)
1261{
1262 if (cmd_source == src_command)
1263 {
1264 Con_Printf ("prespawn is not valid from the console\n");
1265 return;
1266 }
1267
1268 if (host_client->spawned)
1269 {
1270 Con_Printf ("prespawn not valid -- allready spawned\n");
1271 return;
1272 }
1273
1274 SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);
1275 MSG_WriteByte (&host_client->message, svc_signonnum);
1276 MSG_WriteByte (&host_client->message, 2);
1277 host_client->sendsignon = true;
1278}
1279
1280/*
1281==================
1282Host_Spawn_f
1283==================
1284*/
1285void Host_Spawn_f (void)
1286{
1287 int i;
1288 client_t *client;
1289 edict_t *ent;
1290
1291 if (cmd_source == src_command)
1292 {
1293 Con_Printf ("spawn is not valid from the console\n");
1294 return;
1295 }
1296
1297 if (host_client->spawned)
1298 {
1299 Con_Printf ("Spawn not valid -- allready spawned\n");
1300 return;
1301 }
1302
1303// run the entrance script
1304 if (sv.loadgame)
1305 { // loaded games are fully inited allready
1306 // if this is the last client to be connected, unpause
1307 sv.paused = false;
1308 }
1309 else
1310 {
1311 // set up the edict
1312 ent = host_client->edict;
1313
1314 memset (&ent->v, 0, progs->entityfields * 4);
1315 ent->v.colormap = NUM_FOR_EDICT(ent);
1316 ent->v.team = (host_client->colors & 15) + 1;
1317 ent->v.netname = host_client->name - pr_strings;
1318
1319 // copy spawn parms out of the client_t
1320
1321 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1322 (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
1323
1324 // call the spawn function
1325
1326 pr_global_struct->time = sv.time;
1327 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1328 PR_ExecuteProgram (pr_global_struct->ClientConnect);
1329
1330 if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time)
1331 Sys_Printf ("%s entered the game\n", host_client->name);
1332
1333 PR_ExecuteProgram (pr_global_struct->PutClientInServer);
1334 }
1335
1336
1337// send all current names, colors, and frag counts
1338 SZ_Clear (&host_client->message);
1339
1340// send time of update
1341 MSG_WriteByte (&host_client->message, svc_time);
1342 MSG_WriteFloat (&host_client->message, sv.time);
1343
1344 for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
1345 {
1346 MSG_WriteByte (&host_client->message, svc_updatename);
1347 MSG_WriteByte (&host_client->message, i);
1348 MSG_WriteString (&host_client->message, client->name);
1349 MSG_WriteByte (&host_client->message, svc_updatefrags);
1350 MSG_WriteByte (&host_client->message, i);
1351 MSG_WriteShort (&host_client->message, client->old_frags);
1352 MSG_WriteByte (&host_client->message, svc_updatecolors);
1353 MSG_WriteByte (&host_client->message, i);
1354 MSG_WriteByte (&host_client->message, client->colors);
1355 }
1356
1357// send all current light styles
1358 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
1359 {
1360 MSG_WriteByte (&host_client->message, svc_lightstyle);
1361 MSG_WriteByte (&host_client->message, (char)i);
1362 MSG_WriteString (&host_client->message, sv.lightstyles[i]);
1363 }
1364
1365//
1366// send some stats
1367//
1368 MSG_WriteByte (&host_client->message, svc_updatestat);
1369 MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
1370 MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);
1371
1372 MSG_WriteByte (&host_client->message, svc_updatestat);
1373 MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
1374 MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);
1375
1376 MSG_WriteByte (&host_client->message, svc_updatestat);
1377 MSG_WriteByte (&host_client->message, STAT_SECRETS);
1378 MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);
1379
1380 MSG_WriteByte (&host_client->message, svc_updatestat);
1381 MSG_WriteByte (&host_client->message, STAT_MONSTERS);
1382 MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);
1383
1384
1385//
1386// send a fixangle
1387// Never send a roll angle, because savegames can catch the server
1388// in a state where it is expecting the client to correct the angle
1389// and it won't happen if the game was just loaded, so you wind up
1390// with a permanent head tilt
1391 ent = EDICT_NUM( 1 + (host_client - svs.clients) );
1392 MSG_WriteByte (&host_client->message, svc_setangle);
1393 for (i=0 ; i < 2 ; i++)
1394 MSG_WriteAngle (&host_client->message, ent->v.angles[i] );
1395 MSG_WriteAngle (&host_client->message, 0 );
1396
1397 SV_WriteClientdataToMessage (sv_player, &host_client->message);
1398
1399 MSG_WriteByte (&host_client->message, svc_signonnum);
1400 MSG_WriteByte (&host_client->message, 3);
1401 host_client->sendsignon = true;
1402}
1403
1404/*
1405==================
1406Host_Begin_f
1407==================
1408*/
1409void Host_Begin_f (void)
1410{
1411 if (cmd_source == src_command)
1412 {
1413 Con_Printf ("begin is not valid from the console\n");
1414 return;
1415 }
1416
1417 host_client->spawned = true;
1418}
1419
1420//===========================================================================
1421
1422
1423/*
1424==================
1425Host_Kick_f
1426
1427Kicks a user off of the server
1428==================
1429*/
1430void Host_Kick_f (void)
1431{
1432 char *who;
1433 char *message = NULL;
1434 client_t *save;
1435 int i;
1436 qboolean byNumber = false;
1437
1438 if (cmd_source == src_command)
1439 {
1440 if (!sv.active)
1441 {
1442 Cmd_ForwardToServer ();
1443 return;
1444 }
1445 }
1446 else if (pr_global_struct->deathmatch && !host_client->privileged)
1447 return;
1448
1449 save = host_client;
1450
1451 if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0)
1452 {
1453 i = Q_atof(Cmd_Argv(2)) - 1;
1454 if (i < 0 || i >= svs.maxclients)
1455 return;
1456 if (!svs.clients[i].active)
1457 return;
1458 host_client = &svs.clients[i];
1459 byNumber = true;
1460 }
1461 else
1462 {
1463 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
1464 {
1465 if (!host_client->active)
1466 continue;
1467 if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
1468 break;
1469 }
1470 }
1471
1472 if (i < svs.maxclients)
1473 {
1474 if (cmd_source == src_command)
1475 if (cls.state == ca_dedicated)
1476 who = "Console";
1477 else
1478 who = cl_name.string;
1479 else
1480 who = save->name;
1481
1482 // can't kick yourself!
1483 if (host_client == save)
1484 return;
1485
1486 if (Cmd_Argc() > 2)
1487 {
1488 message = COM_Parse(Cmd_Args());
1489 if (byNumber)
1490 {
1491 message++; // skip the #
1492 while (*message == ' ') // skip white space
1493 message++;
1494 message += Q_strlen(Cmd_Argv(2)); // skip the number
1495 }
1496 while (*message && *message == ' ')
1497 message++;
1498 }
1499 if (message)
1500 SV_ClientPrintf ("Kicked by %s: %s\n", who, message);
1501 else
1502 SV_ClientPrintf ("Kicked by %s\n", who);
1503 SV_DropClient (false);
1504 }
1505
1506 host_client = save;
1507}
1508
1509/*
1510===============================================================================
1511
1512DEBUGGING TOOLS
1513
1514===============================================================================
1515*/
1516
1517/*
1518==================
1519Host_Give_f
1520==================
1521*/
1522void Host_Give_f (void)
1523{
1524 char *t;
1525 int v, w;
1526 eval_t *val;
1527
1528 if (cmd_source == src_command)
1529 {
1530 Cmd_ForwardToServer ();
1531 return;
1532 }
1533
1534 if (pr_global_struct->deathmatch && !host_client->privileged)
1535 return;
1536
1537 t = Cmd_Argv(1);
1538 v = atoi (Cmd_Argv(2));
1539
1540 switch (t[0])
1541 {
1542 case '0':
1543 case '1':
1544 case '2':
1545 case '3':
1546 case '4':
1547 case '5':
1548 case '6':
1549 case '7':
1550 case '8':
1551 case '9':
1552 // MED 01/04/97 added hipnotic give stuff
1553 if (hipnotic)
1554 {
1555 if (t[0] == '6')
1556 {
1557 if (t[1] == 'a')
1558 sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;
1559 else
1560 sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;
1561 }
1562 else if (t[0] == '9')
1563 sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;
1564 else if (t[0] == '0')
1565 sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;
1566 else if (t[0] >= '2')
1567 sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
1568 }
1569 else
1570 {
1571 if (t[0] >= '2')
1572 sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));
1573 }
1574 break;
1575
1576 case 's':
1577 if (rogue)
1578 {
1579 val = GetEdictFieldValue(sv_player, "ammo_shells1");
1580 if (val)
1581 val->_float = v;
1582 }
1583
1584 sv_player->v.ammo_shells = v;
1585 break;
1586 case 'n':
1587 if (rogue)
1588 {
1589 val = GetEdictFieldValue(sv_player, "ammo_nails1");
1590 if (val)
1591 {
1592 val->_float = v;
1593 if (sv_player->v.weapon <= IT_LIGHTNING)
1594 sv_player->v.ammo_nails = v;
1595 }
1596 }
1597 else
1598 {
1599 sv_player->v.ammo_nails = v;
1600 }
1601 break;
1602 case 'l':
1603 if (rogue)
1604 {
1605 val = GetEdictFieldValue(sv_player, "ammo_lava_nails");
1606 if (val)
1607 {
1608 val->_float = v;
1609 if (sv_player->v.weapon > IT_LIGHTNING)
1610 sv_player->v.ammo_nails = v;
1611 }
1612 }
1613 break;
1614 case 'r':
1615 if (rogue)
1616 {
1617 val = GetEdictFieldValue(sv_player, "ammo_rockets1");
1618 if (val)
1619 {
1620 val->_float = v;
1621 if (sv_player->v.weapon <= IT_LIGHTNING)
1622 sv_player->v.ammo_rockets = v;
1623 }
1624 }
1625 else
1626 {
1627 sv_player->v.ammo_rockets = v;
1628 }
1629 break;
1630 case 'm':
1631 if (rogue)
1632 {
1633 val = GetEdictFieldValue(sv_player, "ammo_multi_rockets");
1634 if (val)
1635 {
1636 val->_float = v;
1637 if (sv_player->v.weapon > IT_LIGHTNING)
1638 sv_player->v.ammo_rockets = v;
1639 }
1640 }
1641 break;
1642 case 'h':
1643 sv_player->v.health = v;
1644 break;
1645 case 'c':
1646 if (rogue)
1647 {
1648 val = GetEdictFieldValue(sv_player, "ammo_cells1");
1649 if (val)
1650 {
1651 val->_float = v;
1652 if (sv_player->v.weapon <= IT_LIGHTNING)
1653 sv_player->v.ammo_cells = v;
1654 }
1655 }
1656 else
1657 {
1658 sv_player->v.ammo_cells = v;
1659 }
1660 break;
1661 case 'p':
1662 if (rogue)
1663 {
1664 val = GetEdictFieldValue(sv_player, "ammo_plasma");
1665 if (val)
1666 {
1667 val->_float = v;
1668 if (sv_player->v.weapon > IT_LIGHTNING)
1669 sv_player->v.ammo_cells = v;
1670 }
1671 }
1672 break;
1673 }
1674}
1675
1676edict_t *FindViewthing (void)
1677{
1678 int i;
1679 edict_t *e;
1680
1681 for (i=0 ; i<sv.num_edicts ; i++)
1682 {
1683 e = EDICT_NUM(i);
1684 if ( !strcmp (pr_strings + e->v.classname, "viewthing") )
1685 return e;
1686 }
1687 Con_Printf ("No viewthing on map\n");
1688 return NULL;
1689}
1690
1691/*
1692==================
1693Host_Viewmodel_f
1694==================
1695*/
1696void Host_Viewmodel_f (void)
1697{
1698 edict_t *e;
1699 model_t *m;
1700
1701 e = FindViewthing ();
1702 if (!e)
1703 return;
1704
1705 m = Mod_ForName (Cmd_Argv(1), false);
1706 if (!m)
1707 {
1708 Con_Printf ("Can't load %s\n", Cmd_Argv(1));
1709 return;
1710 }
1711
1712 e->v.frame = 0;
1713 cl.model_precache[(int)e->v.modelindex] = m;
1714}
1715
1716/*
1717==================
1718Host_Viewframe_f
1719==================
1720*/
1721void Host_Viewframe_f (void)
1722{
1723 edict_t *e;
1724 int f;
1725 model_t *m;
1726
1727 e = FindViewthing ();
1728 if (!e)
1729 return;
1730 m = cl.model_precache[(int)e->v.modelindex];
1731
1732 f = atoi(Cmd_Argv(1));
1733 if (f >= m->numframes)
1734 f = m->numframes-1;
1735
1736 e->v.frame = f;
1737}
1738
1739
1740void PrintFrameName (model_t *m, int frame)
1741{
1742 aliashdr_t *hdr;
1743 maliasframedesc_t *pframedesc;
1744
1745 hdr = (aliashdr_t *)Mod_Extradata (m);
1746 if (!hdr)
1747 return;
1748 pframedesc = &hdr->frames[frame];
1749
1750 Con_Printf ("frame %i: %s\n", frame, pframedesc->name);
1751}
1752
1753/*
1754==================
1755Host_Viewnext_f
1756==================
1757*/
1758void Host_Viewnext_f (void)
1759{
1760 edict_t *e;
1761 model_t *m;
1762
1763 e = FindViewthing ();
1764 if (!e)
1765 return;
1766 m = cl.model_precache[(int)e->v.modelindex];
1767
1768 e->v.frame = e->v.frame + 1;
1769 if (e->v.frame >= m->numframes)
1770 e->v.frame = m->numframes - 1;
1771
1772 PrintFrameName (m, e->v.frame);
1773}
1774
1775/*
1776==================
1777Host_Viewprev_f
1778==================
1779*/
1780void Host_Viewprev_f (void)
1781{
1782 edict_t *e;
1783 model_t *m;
1784
1785 e = FindViewthing ();
1786 if (!e)
1787 return;
1788
1789 m = cl.model_precache[(int)e->v.modelindex];
1790
1791 e->v.frame = e->v.frame - 1;
1792 if (e->v.frame < 0)
1793 e->v.frame = 0;
1794
1795 PrintFrameName (m, e->v.frame);
1796}
1797
1798/*
1799===============================================================================
1800
1801DEMO LOOP CONTROL
1802
1803===============================================================================
1804*/
1805
1806
1807/*
1808==================
1809Host_Startdemos_f
1810==================
1811*/
1812void Host_Startdemos_f (void)
1813{
1814 int i, c;
1815
1816 if (cls.state == ca_dedicated)
1817 {
1818 if (!sv.active)
1819 Cbuf_AddText ("map start\n");
1820 return;
1821 }
1822
1823 c = Cmd_Argc() - 1;
1824 if (c > MAX_DEMOS)
1825 {
1826 Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS);
1827 c = MAX_DEMOS;
1828 }
1829 Con_Printf ("%i demo(s) in loop\n", c);
1830
1831 for (i=1 ; i<c+1 ; i++)
1832 strncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1);
1833
1834 if (!sv.active && cls.demonum != -1 && !cls.demoplayback)
1835 {
1836 cls.demonum = 0;
1837 CL_NextDemo ();
1838 }
1839 else
1840 cls.demonum = -1;
1841}
1842
1843
1844/*
1845==================
1846Host_Demos_f
1847
1848Return to looping demos
1849==================
1850*/
1851void Host_Demos_f (void)
1852{
1853 if (cls.state == ca_dedicated)
1854 return;
1855 if (cls.demonum == -1)
1856 cls.demonum = 1;
1857 CL_Disconnect_f ();
1858 CL_NextDemo ();
1859}
1860
1861/*
1862==================
1863Host_Stopdemo_f
1864
1865Return to looping demos
1866==================
1867*/
1868void Host_Stopdemo_f (void)
1869{
1870 if (cls.state == ca_dedicated)
1871 return;
1872 if (!cls.demoplayback)
1873 return;
1874 CL_StopPlayback ();
1875 CL_Disconnect ();
1876}
1877
1878//=============================================================================
1879
1880/*
1881==================
1882Host_InitCommands
1883==================
1884*/
1885void Host_InitCommands (void)
1886{
1887 Cmd_AddCommand ("status", Host_Status_f);
1888 Cmd_AddCommand ("quit", Host_Quit_f);
1889 Cmd_AddCommand ("god", Host_God_f);
1890 Cmd_AddCommand ("notarget", Host_Notarget_f);
1891 Cmd_AddCommand ("fly", Host_Fly_f);
1892 Cmd_AddCommand ("map", Host_Map_f);
1893 Cmd_AddCommand ("restart", Host_Restart_f);
1894 Cmd_AddCommand ("changelevel", Host_Changelevel_f);
1895#ifdef QUAKE2
1896 Cmd_AddCommand ("changelevel2", Host_Changelevel2_f);
1897#endif
1898 Cmd_AddCommand ("connect", Host_Connect_f);
1899 Cmd_AddCommand ("reconnect", Host_Reconnect_f);
1900 Cmd_AddCommand ("name", Host_Name_f);
1901 Cmd_AddCommand ("noclip", Host_Noclip_f);
1902 Cmd_AddCommand ("version", Host_Version_f);
1903#ifdef IDGODS
1904 Cmd_AddCommand ("please", Host_Please_f);
1905#endif
1906 Cmd_AddCommand ("say", Host_Say_f);
1907 Cmd_AddCommand ("say_team", Host_Say_Team_f);
1908 Cmd_AddCommand ("tell", Host_Tell_f);
1909 Cmd_AddCommand ("color", Host_Color_f);
1910 Cmd_AddCommand ("kill", Host_Kill_f);
1911 Cmd_AddCommand ("pause", Host_Pause_f);
1912 Cmd_AddCommand ("spawn", Host_Spawn_f);
1913 Cmd_AddCommand ("begin", Host_Begin_f);
1914 Cmd_AddCommand ("prespawn", Host_PreSpawn_f);
1915 Cmd_AddCommand ("kick", Host_Kick_f);
1916 Cmd_AddCommand ("ping", Host_Ping_f);
1917 Cmd_AddCommand ("load", Host_Loadgame_f);
1918 Cmd_AddCommand ("save", Host_Savegame_f);
1919 Cmd_AddCommand ("give", Host_Give_f);
1920
1921 Cmd_AddCommand ("startdemos", Host_Startdemos_f);
1922 Cmd_AddCommand ("demos", Host_Demos_f);
1923 Cmd_AddCommand ("stopdemo", Host_Stopdemo_f);
1924
1925 Cmd_AddCommand ("viewmodel", Host_Viewmodel_f);
1926 Cmd_AddCommand ("viewframe", Host_Viewframe_f);
1927 Cmd_AddCommand ("viewnext", Host_Viewnext_f);
1928 Cmd_AddCommand ("viewprev", Host_Viewprev_f);
1929
1930 Cmd_AddCommand ("mcache", Mod_Print);
1931}
diff --git a/apps/plugins/sdl/progs/quake/in_null.c b/apps/plugins/sdl/progs/quake/in_null.c
new file mode 100644
index 0000000000..1c54ee4da2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/in_null.c
@@ -0,0 +1,39 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// in_null.c -- for systems without a mouse
21
22#include "quakedef.h"
23
24void IN_Init (void)
25{
26}
27
28void IN_Shutdown (void)
29{
30}
31
32void IN_Commands (void)
33{
34}
35
36void IN_Move (usercmd_t *cmd)
37{
38}
39
diff --git a/apps/plugins/sdl/progs/quake/input.h b/apps/plugins/sdl/progs/quake/input.h
new file mode 100644
index 0000000000..c3daa1700e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/input.h
@@ -0,0 +1,34 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// input.h -- external (non-keyboard) input devices
21
22void IN_Init (void);
23
24void IN_Shutdown (void);
25
26void IN_Commands (void);
27// oportunity for devices to stick commands on the script buffer
28
29void IN_Move (usercmd_t *cmd);
30// add additional movement on top of the keyboard move cmd
31
32void IN_ClearStates (void);
33// restores all button and position states to defaults
34
diff --git a/apps/plugins/sdl/progs/quake/keys.c b/apps/plugins/sdl/progs/quake/keys.c
new file mode 100644
index 0000000000..896bbaa795
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/keys.c
@@ -0,0 +1,804 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22/*
23
24key up events are sent even if in console mode
25
26*/
27
28
29#define MAXCMDLINE 256
30char key_lines[32][MAXCMDLINE];
31int key_linepos;
32int shift_down=false;
33int key_lastpress;
34
35int edit_line=0;
36int history_line=0;
37
38keydest_t key_dest;
39
40int key_count; // incremented every key event
41
42char *keybindings[256];
43qboolean consolekeys[256]; // if true, can't be rebound while in console
44qboolean menubound[256]; // if true, can't be rebound while in menu
45int keyshift[256]; // key to map to if shift held down in console
46int key_repeats[256]; // if > 1, it is autorepeating
47qboolean keydown[256];
48
49typedef struct
50{
51 char *name;
52 int keynum;
53} keyname_t;
54
55keyname_t keynames[] =
56{
57 {"TAB", K_TAB},
58 {"ENTER", K_ENTER},
59 {"ESCAPE", K_ESCAPE},
60 {"SPACE", K_SPACE},
61 {"BACKSPACE", K_BACKSPACE},
62 {"UPARROW", K_UPARROW},
63 {"DOWNARROW", K_DOWNARROW},
64 {"LEFTARROW", K_LEFTARROW},
65 {"RIGHTARROW", K_RIGHTARROW},
66
67 {"ALT", K_ALT},
68 {"CTRL", K_CTRL},
69 {"SHIFT", K_SHIFT},
70
71 {"F1", K_F1},
72 {"F2", K_F2},
73 {"F3", K_F3},
74 {"F4", K_F4},
75 {"F5", K_F5},
76 {"F6", K_F6},
77 {"F7", K_F7},
78 {"F8", K_F8},
79 {"F9", K_F9},
80 {"F10", K_F10},
81 {"F11", K_F11},
82 {"F12", K_F12},
83
84 {"INS", K_INS},
85 {"DEL", K_DEL},
86 {"PGDN", K_PGDN},
87 {"PGUP", K_PGUP},
88 {"HOME", K_HOME},
89 {"END", K_END},
90
91 {"MOUSE1", K_MOUSE1},
92 {"MOUSE2", K_MOUSE2},
93 {"MOUSE3", K_MOUSE3},
94
95 {"JOY1", K_JOY1},
96 {"JOY2", K_JOY2},
97 {"JOY3", K_JOY3},
98 {"JOY4", K_JOY4},
99
100 {"AUX1", K_AUX1},
101 {"AUX2", K_AUX2},
102 {"AUX3", K_AUX3},
103 {"AUX4", K_AUX4},
104 {"AUX5", K_AUX5},
105 {"AUX6", K_AUX6},
106 {"AUX7", K_AUX7},
107 {"AUX8", K_AUX8},
108 {"AUX9", K_AUX9},
109 {"AUX10", K_AUX10},
110 {"AUX11", K_AUX11},
111 {"AUX12", K_AUX12},
112 {"AUX13", K_AUX13},
113 {"AUX14", K_AUX14},
114 {"AUX15", K_AUX15},
115 {"AUX16", K_AUX16},
116 {"AUX17", K_AUX17},
117 {"AUX18", K_AUX18},
118 {"AUX19", K_AUX19},
119 {"AUX20", K_AUX20},
120 {"AUX21", K_AUX21},
121 {"AUX22", K_AUX22},
122 {"AUX23", K_AUX23},
123 {"AUX24", K_AUX24},
124 {"AUX25", K_AUX25},
125 {"AUX26", K_AUX26},
126 {"AUX27", K_AUX27},
127 {"AUX28", K_AUX28},
128 {"AUX29", K_AUX29},
129 {"AUX30", K_AUX30},
130 {"AUX31", K_AUX31},
131 {"AUX32", K_AUX32},
132
133 {"PAUSE", K_PAUSE},
134
135 {"MWHEELUP", K_MWHEELUP},
136 {"MWHEELDOWN", K_MWHEELDOWN},
137
138 {"SEMICOLON", ';'}, // because a raw semicolon seperates commands
139
140 {NULL,0}
141};
142
143/*
144==============================================================================
145
146 LINE TYPING INTO THE CONSOLE
147
148==============================================================================
149*/
150
151/* Rockbox hack */
152void rb_console(void)
153{
154 rb->kbd_input(key_lines[edit_line] + 1, MAXCMDLINE-1);
155}
156
157/*
158====================
159Key_Console
160
161Interactive line editing and console scrollback
162====================
163*/
164void Key_Console (int key)
165{
166 char *cmd;
167
168 if (key == K_ENTER)
169 {
170 Cbuf_AddText (key_lines[edit_line]+1); // skip the >
171 Cbuf_AddText ("\n");
172 Con_Printf ("%s\n",key_lines[edit_line]);
173 edit_line = (edit_line + 1) & 31;
174 history_line = edit_line;
175 key_lines[edit_line][0] = ']';
176 key_linepos = 1;
177 if (cls.state == ca_disconnected)
178 SCR_UpdateScreen (); // force an update, because the command
179 // may take some time
180 return;
181 }
182
183 if (key == K_TAB)
184 { // command completion
185 cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
186 if (!cmd)
187 cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
188 if (cmd)
189 {
190 Q_strcpy (key_lines[edit_line]+1, cmd);
191 key_linepos = Q_strlen(cmd)+1;
192 key_lines[edit_line][key_linepos] = ' ';
193 key_linepos++;
194 key_lines[edit_line][key_linepos] = 0;
195 return;
196 }
197 }
198
199 if (key == K_BACKSPACE || key == K_LEFTARROW)
200 {
201 if (key_linepos > 1)
202 key_linepos--;
203 return;
204 }
205
206 if (key == K_UPARROW)
207 {
208 do
209 {
210 history_line = (history_line - 1) & 31;
211 } while (history_line != edit_line
212 && !key_lines[history_line][1]);
213 if (history_line == edit_line)
214 history_line = (edit_line+1)&31;
215 Q_strcpy(key_lines[edit_line], key_lines[history_line]);
216 key_linepos = Q_strlen(key_lines[edit_line]);
217 return;
218 }
219
220 if (key == K_DOWNARROW)
221 {
222 if (history_line == edit_line) return;
223 do
224 {
225 history_line = (history_line + 1) & 31;
226 }
227 while (history_line != edit_line
228 && !key_lines[history_line][1]);
229 if (history_line == edit_line)
230 {
231 key_lines[edit_line][0] = ']';
232 key_linepos = 1;
233 }
234 else
235 {
236 Q_strcpy(key_lines[edit_line], key_lines[history_line]);
237 key_linepos = Q_strlen(key_lines[edit_line]);
238 }
239 return;
240 }
241
242 if (key == K_PGUP || key==K_MWHEELUP)
243 {
244 con_backscroll += 2;
245 if (con_backscroll > con_totallines - (vid.height>>3) - 1)
246 con_backscroll = con_totallines - (vid.height>>3) - 1;
247 return;
248 }
249
250 if (key == K_PGDN || key==K_MWHEELDOWN)
251 {
252 con_backscroll -= 2;
253 if (con_backscroll < 0)
254 con_backscroll = 0;
255 return;
256 }
257
258 if (key == K_HOME)
259 {
260 con_backscroll = con_totallines - (vid.height>>3) - 1;
261 return;
262 }
263
264 if (key == K_END)
265 {
266 con_backscroll = 0;
267 return;
268 }
269
270 if (key < 32 || key > 127)
271 return; // non printable
272
273 if (key_linepos < MAXCMDLINE-1)
274 {
275 key_lines[edit_line][key_linepos] = key;
276 key_linepos++;
277 key_lines[edit_line][key_linepos] = 0;
278 }
279
280}
281
282//============================================================================
283
284char chat_buffer[32];
285qboolean team_message = false;
286
287void Key_Message (int key)
288{
289 static int chat_bufferlen = 0;
290
291 if (key == K_ENTER)
292 {
293 if (team_message)
294 Cbuf_AddText ("say_team \"");
295 else
296 Cbuf_AddText ("say \"");
297 Cbuf_AddText(chat_buffer);
298 Cbuf_AddText("\"\n");
299
300 key_dest = key_game;
301 chat_bufferlen = 0;
302 chat_buffer[0] = 0;
303 return;
304 }
305
306 if (key == K_ESCAPE)
307 {
308 key_dest = key_game;
309 chat_bufferlen = 0;
310 chat_buffer[0] = 0;
311 return;
312 }
313
314 if (key < 32 || key > 127)
315 return; // non printable
316
317 if (key == K_BACKSPACE)
318 {
319 if (chat_bufferlen)
320 {
321 chat_bufferlen--;
322 chat_buffer[chat_bufferlen] = 0;
323 }
324 return;
325 }
326
327 if (chat_bufferlen == 31)
328 return; // all full
329
330 chat_buffer[chat_bufferlen++] = key;
331 chat_buffer[chat_bufferlen] = 0;
332}
333
334//============================================================================
335
336
337/*
338===================
339Key_StringToKeynum
340
341Returns a key number to be used to index keybindings[] by looking at
342the given string. Single ascii characters return themselves, while
343the K_* names are matched up.
344===================
345*/
346int Key_StringToKeynum (char *str)
347{
348 keyname_t *kn;
349
350 if (!str || !str[0])
351 return -1;
352 if (!str[1])
353 return str[0];
354
355 for (kn=keynames ; kn->name ; kn++)
356 {
357 if (!Q_strcasecmp(str,kn->name))
358 return kn->keynum;
359 }
360 return -1;
361}
362
363/*
364===================
365Key_KeynumToString
366
367Returns a string (either a single ascii char, or a K_* name) for the
368given keynum.
369FIXME: handle quote special (general escape sequence?)
370===================
371*/
372char *Key_KeynumToString (int keynum)
373{
374 keyname_t *kn;
375 static char tinystr[2];
376
377 if (keynum == -1)
378 return "<KEY NOT FOUND>";
379 if (keynum > 32 && keynum < 127)
380 { // printable ascii
381 tinystr[0] = keynum;
382 tinystr[1] = 0;
383 return tinystr;
384 }
385
386 for (kn=keynames ; kn->name ; kn++)
387 if (keynum == kn->keynum)
388 return kn->name;
389
390 return "<UNKNOWN KEYNUM>";
391}
392
393
394/*
395===================
396Key_SetBinding
397===================
398*/
399void Key_SetBinding (int keynum, char *binding)
400{
401 LOGF("binding %d -> %s\n", keynum, binding);
402
403 char *new;
404 int l;
405
406 if (keynum == -1)
407 return;
408
409// free old bindings
410 if (keybindings[keynum])
411 {
412 Z_Free (keybindings[keynum]);
413 keybindings[keynum] = NULL;
414 }
415
416// allocate memory for new binding
417 l = Q_strlen (binding);
418 new = Z_Malloc (l+1);
419 Q_strcpy (new, binding);
420 new[l] = 0;
421 keybindings[keynum] = new;
422}
423
424/*
425===================
426Key_Unbind_f
427===================
428*/
429void Key_Unbind_f (void)
430{
431 int b;
432
433 if (Cmd_Argc() != 2)
434 {
435 Con_Printf ("unbind <key> : remove commands from a key\n");
436 return;
437 }
438
439 b = Key_StringToKeynum (Cmd_Argv(1));
440 if (b==-1)
441 {
442 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
443 return;
444 }
445
446 Key_SetBinding (b, "");
447}
448
449void Key_Unbindall_f (void)
450{
451 int i;
452
453 for (i=0 ; i<256 ; i++)
454 if (keybindings[i])
455 Key_SetBinding (i, "");
456}
457
458int bind_nooverride = 0;
459
460/*
461===================
462Key_Bind_f
463===================
464*/
465void Key_Bind_f (void)
466{
467 int i, c, b;
468 char cmd[1024];
469
470 c = Cmd_Argc();
471
472 if (c != 2 && c != 3)
473 {
474 Con_Printf ("bind <key> [command] : attach a command to a key\n");
475 return;
476 }
477 b = Key_StringToKeynum (Cmd_Argv(1));
478 if (b==-1)
479 {
480 Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
481 return;
482 }
483
484 if (c == 2)
485 {
486 if (keybindings[b])
487 Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
488 else
489 Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
490 return;
491 }
492
493 bool overridden = false;
494
495 // Rockbox hack to set defaults
496 if(!bind_nooverride)
497 {
498 //rb->splashf(HZ, "overriding defaults");
499
500 switch(b)
501 {
502 case K_ENTER:
503 overridden = true;
504 strcpy(cmd, "+attack");
505 break;
506 case K_DOWNARROW:
507 overridden = true;
508 strcpy(cmd, "impulse 10; +jump; wait; -jump");
509 break;
510 case 'a':
511 overridden = true;
512 strcpy(cmd, "+moveleft");
513 break;
514 case 'd':
515 overridden = true;
516 strcpy(cmd, "+moveright");
517 break;
518 }
519 }
520
521 if(!overridden)
522 {
523// copy the rest of the command line
524 cmd[0] = 0; // start out with a null string
525 for (i=2 ; i< c ; i++)
526 {
527 if (i > 2)
528 strcat (cmd, " ");
529 strcat (cmd, Cmd_Argv(i));
530 }
531 }
532
533 Key_SetBinding (b, cmd);
534}
535
536/*
537============
538Key_WriteBindings
539
540Writes lines containing "bind key value"
541============
542*/
543void Key_WriteBindings (FILE *f)
544{
545 int i;
546
547 for (i=0 ; i<256 ; i++)
548 if (keybindings[i])
549 if (*keybindings[i])
550 fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
551}
552
553
554/*
555===================
556Key_Init
557===================
558*/
559void Key_Init (void)
560{
561 int i;
562
563 for (i=0 ; i<32 ; i++)
564 {
565 key_lines[i][0] = ']';
566 key_lines[i][1] = 0;
567 }
568 key_linepos = 1;
569
570//
571// init ascii characters in console mode
572//
573 for (i=32 ; i<128 ; i++)
574 consolekeys[i] = true;
575 consolekeys[K_ENTER] = true;
576 consolekeys[K_TAB] = true;
577 consolekeys[K_LEFTARROW] = true;
578 consolekeys[K_RIGHTARROW] = true;
579 consolekeys[K_UPARROW] = true;
580 consolekeys[K_DOWNARROW] = true;
581 consolekeys[K_BACKSPACE] = true;
582 consolekeys[K_PGUP] = true;
583 consolekeys[K_PGDN] = true;
584 consolekeys[K_SHIFT] = true;
585 consolekeys[K_MWHEELUP] = true;
586 consolekeys[K_MWHEELDOWN] = true;
587 consolekeys['`'] = false;
588 consolekeys['~'] = false;
589
590 for (i=0 ; i<256 ; i++)
591 keyshift[i] = i;
592 for (i='a' ; i<='z' ; i++)
593 keyshift[i] = i - 'a' + 'A';
594 keyshift['1'] = '!';
595 keyshift['2'] = '@';
596 keyshift['3'] = '#';
597 keyshift['4'] = '$';
598 keyshift['5'] = '%';
599 keyshift['6'] = '^';
600 keyshift['7'] = '&';
601 keyshift['8'] = '*';
602 keyshift['9'] = '(';
603 keyshift['0'] = ')';
604 keyshift['-'] = '_';
605 keyshift['='] = '+';
606 keyshift[','] = '<';
607 keyshift['.'] = '>';
608 keyshift['/'] = '?';
609 keyshift[';'] = ':';
610 keyshift['\''] = '"';
611 keyshift['['] = '{';
612 keyshift[']'] = '}';
613 keyshift['`'] = '~';
614 keyshift['\\'] = '|';
615
616 menubound[K_ESCAPE] = true;
617 for (i=0 ; i<12 ; i++)
618 menubound[K_F1+i] = true;
619
620//
621// register our functions
622//
623 Cmd_AddCommand ("bind",Key_Bind_f);
624 Cmd_AddCommand ("unbind",Key_Unbind_f);
625 Cmd_AddCommand ("unbindall",Key_Unbindall_f);
626
627
628}
629
630/*
631===================
632Key_Event
633
634Called by the system between frames for both key up and key down events
635Should NOT be called during an interrupt!
636===================
637*/
638void Key_Event (int key, qboolean down)
639{
640 char *kb;
641 char cmd[1024];
642
643 keydown[key] = down;
644
645 if (!down)
646 key_repeats[key] = 0;
647
648 key_lastpress = key;
649 key_count++;
650 if (key_count <= 0)
651 {
652 return; // just catching keys for Con_NotifyBox
653 }
654
655// update auto-repeat status
656 if (down)
657 {
658 key_repeats[key]++;
659 if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)
660 {
661 return; // ignore most autorepeats
662 }
663
664 if (key >= 200 && !keybindings[key])
665 Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
666 }
667
668 if (key == K_SHIFT)
669 shift_down = down;
670
671//
672// handle escape specialy, so the user can never unbind it
673//
674 if (key == K_ESCAPE)
675 {
676 if (!down)
677 return;
678 switch (key_dest)
679 {
680 case key_message:
681 Key_Message (key);
682 break;
683 case key_menu:
684 M_Keydown (key);
685 break;
686 case key_game:
687 case key_console:
688 M_ToggleMenu_f ();
689 break;
690 default:
691 Sys_Error ("Bad key_dest");
692 }
693 return;
694 }
695
696//
697// key up events only generate commands if the game key binding is
698// a button command (leading + sign). These will occur even in console mode,
699// to keep the character from continuing an action started before a console
700// switch. Button commands include the kenum as a parameter, so multiple
701// downs can be matched with ups
702//
703 if (!down)
704 {
705 kb = keybindings[key];
706 if (kb && kb[0] == '+')
707 {
708 sprintf (cmd, "-%s %i\n", kb+1, key);
709 Cbuf_AddText (cmd);
710 }
711 if (keyshift[key] != key)
712 {
713 kb = keybindings[keyshift[key]];
714 if (kb && kb[0] == '+')
715 {
716 sprintf (cmd, "-%s %i\n", kb+1, key);
717 Cbuf_AddText (cmd);
718 }
719 }
720 return;
721 }
722
723//
724// during demo playback, most keys bring up the main menu
725//
726 if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
727 {
728 M_ToggleMenu_f ();
729 return;
730 }
731
732//
733// if not a consolekey, send to the interpreter no matter what mode is
734//
735 if ( (key_dest == key_menu && menubound[key])
736 || (key_dest == key_console && !consolekeys[key])
737 || (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )
738 {
739 kb = keybindings[key];
740 if (kb)
741 {
742 if (kb[0] == '+')
743 { // button commands add keynum as a parm
744 sprintf (cmd, "%s %i\n", kb, key);
745 Cbuf_AddText (cmd);
746 }
747 else
748 {
749 Cbuf_AddText (kb);
750 Cbuf_AddText ("\n");
751 }
752 }
753 return;
754 }
755
756 if (!down)
757 return; // other systems only care about key down events
758
759 if (shift_down)
760 {
761 key = keyshift[key];
762 }
763
764 switch (key_dest)
765 {
766 case key_message:
767 Key_Message (key);
768 break;
769 case key_menu:
770 M_Keydown (key);
771 break;
772
773 case key_game:
774 case key_console:
775 if(key == K_ENTER)
776 {
777 rb_console();
778 Key_Console (K_ENTER);
779 }
780 else
781 Key_Console (key);
782 break;
783 default:
784 Sys_Error ("Bad key_dest");
785 }
786}
787
788
789/*
790===================
791Key_ClearStates
792===================
793*/
794void Key_ClearStates (void)
795{
796 int i;
797
798 for (i=0 ; i<256 ; i++)
799 {
800 keydown[i] = false;
801 key_repeats[i] = 0;
802 }
803}
804
diff --git a/apps/plugins/sdl/progs/quake/keys.h b/apps/plugins/sdl/progs/quake/keys.h
new file mode 100644
index 0000000000..ed26a8de81
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/keys.h
@@ -0,0 +1,134 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21//
22// these are the key numbers that should be passed to Key_Event
23//
24#define K_TAB 9
25#define K_ENTER 13
26#define K_ESCAPE 27
27#define K_SPACE 32
28
29// normal keys should be passed as lowercased ascii
30
31#define K_BACKSPACE 127
32#define K_UPARROW 128
33#define K_DOWNARROW 129
34#define K_LEFTARROW 130
35#define K_RIGHTARROW 131
36
37#define K_ALT 132
38#define K_CTRL 133
39#define K_SHIFT 134
40#define K_F1 135
41#define K_F2 136
42#define K_F3 137
43#define K_F4 138
44#define K_F5 139
45#define K_F6 140
46#define K_F7 141
47#define K_F8 142
48#define K_F9 143
49#define K_F10 144
50#define K_F11 145
51#define K_F12 146
52#define K_INS 147
53#define K_DEL 148
54#define K_PGDN 149
55#define K_PGUP 150
56#define K_HOME 151
57#define K_END 152
58
59#define K_PAUSE 255
60
61//
62// mouse buttons generate virtual keys
63//
64#define K_MOUSE1 200
65#define K_MOUSE2 201
66#define K_MOUSE3 202
67
68//
69// joystick buttons
70//
71#define K_JOY1 203
72#define K_JOY2 204
73#define K_JOY3 205
74#define K_JOY4 206
75
76//
77// aux keys are for multi-buttoned joysticks to generate so they can use
78// the normal binding process
79//
80#define K_AUX1 207
81#define K_AUX2 208
82#define K_AUX3 209
83#define K_AUX4 210
84#define K_AUX5 211
85#define K_AUX6 212
86#define K_AUX7 213
87#define K_AUX8 214
88#define K_AUX9 215
89#define K_AUX10 216
90#define K_AUX11 217
91#define K_AUX12 218
92#define K_AUX13 219
93#define K_AUX14 220
94#define K_AUX15 221
95#define K_AUX16 222
96#define K_AUX17 223
97#define K_AUX18 224
98#define K_AUX19 225
99#define K_AUX20 226
100#define K_AUX21 227
101#define K_AUX22 228
102#define K_AUX23 229
103#define K_AUX24 230
104#define K_AUX25 231
105#define K_AUX26 232
106#define K_AUX27 233
107#define K_AUX28 234
108#define K_AUX29 235
109#define K_AUX30 236
110#define K_AUX31 237
111#define K_AUX32 238
112
113// JACK: Intellimouse(c) Mouse Wheel Support
114
115#define K_MWHEELUP 239
116#define K_MWHEELDOWN 240
117
118
119
120typedef int keydest_t;
121enum {key_game, key_console, key_message, key_menu};
122
123extern keydest_t key_dest;
124extern char *keybindings[256];
125extern int key_repeats[256];
126extern int key_count; // incremented every key event
127extern int key_lastpress;
128
129void Key_Event (int key, qboolean down);
130void Key_Init (void);
131void Key_WriteBindings (FILE *f);
132void Key_SetBinding (int keynum, char *binding);
133void Key_ClearStates (void);
134
diff --git a/apps/plugins/sdl/progs/quake/mathlib.c b/apps/plugins/sdl/progs/quake/mathlib.c
new file mode 100644
index 0000000000..ddd5435089
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/mathlib.c
@@ -0,0 +1,550 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// mathlib.c -- math primitives
21
22#include <math.h>
23#include "quakedef.h"
24
25void Sys_Error (char *error, ...);
26
27vec3_t vec3_origin = {0,0,0};
28int nanmask = 255<<23;
29
30/*-----------------------------------------------------------------*/
31
32#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
33
34void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
35{
36 float d;
37 vec3_t n;
38 float inv_denom;
39
40 inv_denom = 1.0F / DotProduct( normal, normal );
41
42 d = DotProduct( normal, p ) * inv_denom;
43
44 n[0] = normal[0] * inv_denom;
45 n[1] = normal[1] * inv_denom;
46 n[2] = normal[2] * inv_denom;
47
48 dst[0] = p[0] - d * n[0];
49 dst[1] = p[1] - d * n[1];
50 dst[2] = p[2] - d * n[2];
51}
52
53/*
54** assumes "src" is normalized
55*/
56void PerpendicularVector( vec3_t dst, const vec3_t src )
57{
58 int pos;
59 int i;
60 float minelem = 1.0F;
61 vec3_t tempvec;
62
63 /*
64 ** find the smallest magnitude axially aligned vector
65 */
66 for ( pos = 0, i = 0; i < 3; i++ )
67 {
68 if ( fabs( src[i] ) < minelem )
69 {
70 pos = i;
71 minelem = fabs( src[i] );
72 }
73 }
74 tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
75 tempvec[pos] = 1.0F;
76
77 /*
78 ** project the point onto the plane defined by src
79 */
80 ProjectPointOnPlane( dst, tempvec, src );
81
82 /*
83 ** normalize the result
84 */
85 VectorNormalizeNoRet( dst );
86}
87
88#ifdef _WIN32
89#pragma optimize( "", off )
90#endif
91
92
93void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
94{
95 float m[3][3];
96 float im[3][3];
97 float zrot[3][3];
98 float tmpmat[3][3];
99 float rot[3][3];
100 int i;
101 vec3_t vr, vup, vf;
102
103 vf[0] = dir[0];
104 vf[1] = dir[1];
105 vf[2] = dir[2];
106
107 PerpendicularVector( vr, dir );
108 CrossProduct( vr, vf, vup );
109
110 m[0][0] = vr[0];
111 m[1][0] = vr[1];
112 m[2][0] = vr[2];
113
114 m[0][1] = vup[0];
115 m[1][1] = vup[1];
116 m[2][1] = vup[2];
117
118 m[0][2] = vf[0];
119 m[1][2] = vf[1];
120 m[2][2] = vf[2];
121
122 memcpy( im, m, sizeof( im ) );
123
124 im[0][1] = m[1][0];
125 im[0][2] = m[2][0];
126 im[1][0] = m[0][1];
127 im[1][2] = m[2][1];
128 im[2][0] = m[0][2];
129 im[2][1] = m[1][2];
130
131 memset( zrot, 0, sizeof( zrot ) );
132 zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
133
134 zrot[0][0] = cos( DEG2RAD( degrees ) );
135 zrot[0][1] = sin( DEG2RAD( degrees ) );
136 zrot[1][0] = -sin( DEG2RAD( degrees ) );
137 zrot[1][1] = cos( DEG2RAD( degrees ) );
138
139 R_ConcatRotations( m, zrot, tmpmat );
140 R_ConcatRotations( tmpmat, im, rot );
141
142 for ( i = 0; i < 3; i++ )
143 {
144 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
145 }
146}
147
148#ifdef _WIN32
149#pragma optimize( "", on )
150#endif
151
152/*-----------------------------------------------------------------*/
153
154
155float anglemod(float a)
156{
157#if 0
158 if (a >= 0)
159 a -= 360*(int)(a/360);
160 else
161 a += 360*( 1 + (int)(-a/360) );
162#endif
163 a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
164 return a;
165}
166
167/*
168==================
169BOPS_Error
170
171Split out like this for ASM to call.
172==================
173*/
174void BOPS_Error (void)
175{
176 Sys_Error ("BoxOnPlaneSide: Bad signbits");
177}
178
179
180#if !id386
181
182/*
183==================
184BoxOnPlaneSide
185
186Returns 1, 2, or 1 + 2
187==================
188*/
189int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p)
190{
191 float dist1, dist2;
192 int sides;
193
194#if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this
195 // function
196// fast axial cases
197 if (p->type < 3)
198 {
199 if (p->dist <= emins[p->type])
200 return 1;
201 if (p->dist >= emaxs[p->type])
202 return 2;
203 return 3;
204 }
205#endif
206
207// general case
208 switch (p->signbits)
209 {
210 case 0:
211dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
212dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
213 break;
214 case 1:
215dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
216dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
217 break;
218 case 2:
219dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
220dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
221 break;
222 case 3:
223dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
224dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
225 break;
226 case 4:
227dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
228dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
229 break;
230 case 5:
231dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
232dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
233 break;
234 case 6:
235dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
236dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
237 break;
238 case 7:
239dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
240dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
241 break;
242 default:
243 dist1 = dist2 = 0; // shut up compiler
244 BOPS_Error ();
245 break;
246 }
247
248#if 0
249 int i;
250 vec3_t corners[2];
251
252 for (i=0 ; i<3 ; i++)
253 {
254 if (plane->normal[i] < 0)
255 {
256 corners[0][i] = emins[i];
257 corners[1][i] = emaxs[i];
258 }
259 else
260 {
261 corners[1][i] = emins[i];
262 corners[0][i] = emaxs[i];
263 }
264 }
265 dist = DotProduct (plane->normal, corners[0]) - plane->dist;
266 dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
267 sides = 0;
268 if (dist1 >= 0)
269 sides = 1;
270 if (dist2 < 0)
271 sides |= 2;
272
273#endif
274
275 sides = 0;
276 if (dist1 >= p->dist)
277 sides = 1;
278 if (dist2 < p->dist)
279 sides |= 2;
280
281#ifdef PARANOID
282if (sides == 0)
283 Sys_Error ("BoxOnPlaneSide: sides==0");
284#endif
285
286 return sides;
287}
288
289#endif
290
291
292void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
293{
294 float angle;
295 float sr, sp, sy, cr, cp, cy;
296
297 angle = angles[YAW] * (M_PI*2 / 360);
298 sy = sin(angle);
299 cy = cos(angle);
300 angle = angles[PITCH] * (M_PI*2 / 360);
301 sp = sin(angle);
302 cp = cos(angle);
303 angle = angles[ROLL] * (M_PI*2 / 360);
304 sr = sin(angle);
305 cr = cos(angle);
306
307 forward[0] = cp*cy;
308 forward[1] = cp*sy;
309 forward[2] = -sp;
310 right[0] = (-1*sr*sp*cy+-1*cr*-sy);
311 right[1] = (-1*sr*sp*sy+-1*cr*cy);
312 right[2] = -1*sr*cp;
313 up[0] = (cr*sp*cy+-sr*-sy);
314 up[1] = (cr*sp*sy+-sr*cy);
315 up[2] = cr*cp;
316}
317
318int VectorCompare (vec3_t v1, vec3_t v2)
319{
320 int i;
321
322 for (i=0 ; i<3 ; i++)
323 if (v1[i] != v2[i])
324 return 0;
325
326 return 1;
327}
328
329void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
330{
331 vecc[0] = veca[0] + scale*vecb[0];
332 vecc[1] = veca[1] + scale*vecb[1];
333 vecc[2] = veca[2] + scale*vecb[2];
334}
335
336
337vec_t _DotProduct (vec3_t v1, vec3_t v2)
338{
339 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
340}
341
342void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
343{
344 out[0] = veca[0]-vecb[0];
345 out[1] = veca[1]-vecb[1];
346 out[2] = veca[2]-vecb[2];
347}
348
349void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
350{
351 out[0] = veca[0]+vecb[0];
352 out[1] = veca[1]+vecb[1];
353 out[2] = veca[2]+vecb[2];
354}
355
356void _VectorCopy (vec3_t in, vec3_t out)
357{
358 out[0] = in[0];
359 out[1] = in[1];
360 out[2] = in[2];
361}
362
363void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
364{
365 cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
366 cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
367 cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
368}
369
370vec_t Length(vec3_t v)
371{
372 int i;
373 float length;
374
375 length = 0;
376 for (i=0 ; i< 3 ; i++)
377 length += v[i]*v[i];
378 length = sqrt (length); // FIXME
379
380 return length;
381}
382
383
384int Q_log2(int val)
385{
386 int answer=0;
387 while (val>>=1)
388 answer++;
389 return answer;
390}
391
392
393/*
394================
395R_ConcatRotations
396================
397*/
398void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
399{
400 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
401 in1[0][2] * in2[2][0];
402 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
403 in1[0][2] * in2[2][1];
404 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
405 in1[0][2] * in2[2][2];
406 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
407 in1[1][2] * in2[2][0];
408 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
409 in1[1][2] * in2[2][1];
410 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
411 in1[1][2] * in2[2][2];
412 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
413 in1[2][2] * in2[2][0];
414 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
415 in1[2][2] * in2[2][1];
416 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
417 in1[2][2] * in2[2][2];
418}
419
420
421/*
422================
423R_ConcatTransforms
424================
425*/
426void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
427{
428 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
429 in1[0][2] * in2[2][0];
430 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
431 in1[0][2] * in2[2][1];
432 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
433 in1[0][2] * in2[2][2];
434 out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
435 in1[0][2] * in2[2][3] + in1[0][3];
436 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
437 in1[1][2] * in2[2][0];
438 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
439 in1[1][2] * in2[2][1];
440 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
441 in1[1][2] * in2[2][2];
442 out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
443 in1[1][2] * in2[2][3] + in1[1][3];
444 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
445 in1[2][2] * in2[2][0];
446 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
447 in1[2][2] * in2[2][1];
448 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
449 in1[2][2] * in2[2][2];
450 out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
451 in1[2][2] * in2[2][3] + in1[2][3];
452}
453
454
455/*
456===================
457FloorDivMod
458
459Returns mathematically correct (floor-based) quotient and remainder for
460numer and denom, both of which should contain no fractional part. The
461quotient must fit in 32 bits.
462====================
463*/
464
465void FloorDivMod (double numer, double denom, int *quotient,
466 int *rem)
467{
468 int q, r;
469 double x;
470
471#ifndef PARANOID
472 if (denom <= 0.0)
473 Sys_Error ("FloorDivMod: bad denominator %d\n", denom);
474
475// if ((floor(numer) != numer) || (floor(denom) != denom))
476// Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n",
477// numer, denom);
478#endif
479
480 if (numer >= 0.0)
481 {
482
483 x = floor(numer / denom);
484 q = (int)x;
485 r = (int)floor(numer - (x * denom));
486 }
487 else
488 {
489 //
490 // perform operations with positive values, and fix mod to make floor-based
491 //
492 x = floor(-numer / denom);
493 q = -(int)x;
494 r = (int)floor(-numer - (x * denom));
495 if (r != 0)
496 {
497 q--;
498 r = (int)denom - r;
499 }
500 }
501
502 *quotient = q;
503 *rem = r;
504}
505
506
507/*
508===================
509GreatestCommonDivisor
510====================
511*/
512int GreatestCommonDivisor (int i1, int i2)
513{
514 if (i1 > i2)
515 {
516 if (i2 == 0)
517 return (i1);
518 return GreatestCommonDivisor (i2, i1 % i2);
519 }
520 else
521 {
522 if (i1 == 0)
523 return (i2);
524 return GreatestCommonDivisor (i1, i2 % i1);
525 }
526}
527
528
529#if !id386
530
531// TODO: move to nonintel.c
532
533/*
534===================
535Invert24To16
536
537Inverts an 8.24 value to a 16.16 value
538====================
539*/
540
541fixed16_t Invert24To16(fixed16_t val)
542{
543 if (val < 256)
544 return (0xFFFFFFFF);
545
546 return (fixed16_t)
547 (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5);
548}
549
550#endif
diff --git a/apps/plugins/sdl/progs/quake/mathlib.h b/apps/plugins/sdl/progs/quake/mathlib.h
new file mode 100644
index 0000000000..b754966802
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/mathlib.h
@@ -0,0 +1,154 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// mathlib.h
21
22typedef float vec_t;
23typedef vec_t vec3_t[3];
24typedef vec_t vec5_t[5];
25
26typedef int fixed4_t;
27typedef int fixed8_t;
28typedef int fixed16_t;
29
30#ifndef M_PI
31#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
32#endif
33
34struct mplane_s;
35
36extern vec3_t vec3_origin;
37extern int nanmask;
38
39#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
40
41#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
42#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
43#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
44#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
45
46void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);
47
48vec_t _DotProduct (vec3_t v1, vec3_t v2);
49void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
50void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
51void _VectorCopy (vec3_t in, vec3_t out);
52
53int VectorCompare (vec3_t v1, vec3_t v2);
54vec_t Length (vec3_t v);
55void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
56//void VectorNormalizeNoRet (vec3_t v); // uses finvsqrt
57//float VectorNormalize (vec3_t v); // returns vector length
58
59static inline float InvSqrt( float number ) {
60 long i;
61 float x2, y;
62 const float threehalfs = 1.5F;
63
64 x2 = number * 0.5F;
65 y = number;
66 i = * ( long * ) &y; // evil floating point bit level hacking
67 i = 0x5f3759df - ( i >> 1 ); // what the fuck?
68 y = * ( float * ) &i;
69 y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
70// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
71
72 return y;
73}
74
75static inline void VectorNormalizeNoRet (vec3_t v)
76{
77 float length, ilength;
78
79 ilength = InvSqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
80
81 v[0] *= ilength;
82 v[1] *= ilength;
83 v[2] *= ilength;
84}
85
86static inline float VectorNormalize (vec3_t v)
87{
88 float length, ilength;
89
90 length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
91 length = sqrt (length); // FIXME
92
93 if (length)
94 {
95 ilength = 1/length;
96 v[0] *= ilength;
97 v[1] *= ilength;
98 v[2] *= ilength;
99 }
100
101 return length;
102
103}
104
105//void VectorInverse (vec3_t v);
106//void VectorScale (vec3_t in, vec_t scale, vec3_t out);
107
108
109static inline void VectorInverse (vec3_t v)
110{
111 v[0] = -v[0];
112 v[1] = -v[1];
113 v[2] = -v[2];
114}
115
116static inline void VectorScale (vec3_t in, vec_t scale, vec3_t out)
117{
118 out[0] = in[0]*scale;
119 out[1] = in[1]*scale;
120 out[2] = in[2]*scale;
121}
122
123
124int Q_log2(int val);
125
126void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
127void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
128
129void FloorDivMod (double numer, double denom, int *quotient,
130 int *rem);
131fixed16_t Invert24To16(fixed16_t val);
132int GreatestCommonDivisor (int i1, int i2);
133
134void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
135int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane);
136float anglemod(float a);
137
138
139
140#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
141 (((p)->type < 3)? \
142 ( \
143 ((p)->dist <= (emins)[(p)->type])? \
144 1 \
145 : \
146 ( \
147 ((p)->dist >= (emaxs)[(p)->type])?\
148 2 \
149 : \
150 3 \
151 ) \
152 ) \
153 : \
154 BoxOnPlaneSide( (emins), (emaxs), (p)))
diff --git a/apps/plugins/sdl/progs/quake/menu.c b/apps/plugins/sdl/progs/quake/menu.c
new file mode 100644
index 0000000000..8c67c8672d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/menu.c
@@ -0,0 +1,3234 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22#ifdef _WIN32
23#include "winquake.h"
24#endif
25
26void (*vid_menudrawfn)(void);
27void (*vid_menukeyfn)(int key);
28
29enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
30
31void M_Menu_Main_f (void);
32 void M_Menu_SinglePlayer_f (void);
33 void M_Menu_Load_f (void);
34 void M_Menu_Save_f (void);
35 void M_Menu_MultiPlayer_f (void);
36 void M_Menu_Setup_f (void);
37 void M_Menu_Net_f (void);
38 void M_Menu_Options_f (void);
39 void M_Menu_Keys_f (void);
40 void M_Menu_Video_f (void);
41 void M_Menu_Help_f (void);
42 void M_Menu_Quit_f (void);
43void M_Menu_SerialConfig_f (void);
44 void M_Menu_ModemConfig_f (void);
45void M_Menu_LanConfig_f (void);
46void M_Menu_GameOptions_f (void);
47void M_Menu_Search_f (void);
48void M_Menu_ServerList_f (void);
49
50void M_Main_Draw (void);
51 void M_SinglePlayer_Draw (void);
52 void M_Load_Draw (void);
53 void M_Save_Draw (void);
54 void M_MultiPlayer_Draw (void);
55 void M_Setup_Draw (void);
56 void M_Net_Draw (void);
57 void M_Options_Draw (void);
58 void M_Keys_Draw (void);
59 void M_Video_Draw (void);
60 void M_Help_Draw (void);
61 void M_Quit_Draw (void);
62void M_SerialConfig_Draw (void);
63 void M_ModemConfig_Draw (void);
64void M_LanConfig_Draw (void);
65void M_GameOptions_Draw (void);
66void M_Search_Draw (void);
67void M_ServerList_Draw (void);
68
69void M_Main_Key (int key);
70 void M_SinglePlayer_Key (int key);
71 void M_Load_Key (int key);
72 void M_Save_Key (int key);
73 void M_MultiPlayer_Key (int key);
74 void M_Setup_Key (int key);
75 void M_Net_Key (int key);
76 void M_Options_Key (int key);
77 void M_Keys_Key (int key);
78 void M_Video_Key (int key);
79 void M_Help_Key (int key);
80 void M_Quit_Key (int key);
81void M_SerialConfig_Key (int key);
82 void M_ModemConfig_Key (int key);
83void M_LanConfig_Key (int key);
84void M_GameOptions_Key (int key);
85void M_Search_Key (int key);
86void M_ServerList_Key (int key);
87
88qboolean m_entersound; // play after drawing a frame, so caching
89 // won't disrupt the sound
90qboolean m_recursiveDraw;
91
92int m_return_state;
93qboolean m_return_onerror;
94char m_return_reason [32];
95
96#define StartingGame (m_multiplayer_cursor == 1)
97#define JoiningGame (m_multiplayer_cursor == 0)
98#define SerialConfig (m_net_cursor == 0)
99#define DirectConfig (m_net_cursor == 1)
100#define IPXConfig (m_net_cursor == 2)
101#define TCPIPConfig (m_net_cursor == 3)
102
103void M_ConfigureNetSubsystem(void);
104
105/*
106================
107M_DrawCharacter
108
109Draws one solid graphics character
110================
111*/
112void M_DrawCharacter (int cx, int line, int num)
113{
114 Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
115}
116
117void M_Print (int cx, int cy, char *str)
118{
119 while (*str)
120 {
121 M_DrawCharacter (cx, cy, (*str)+128);
122 str++;
123 cx += 8;
124 }
125}
126
127void M_PrintWhite (int cx, int cy, char *str)
128{
129 while (*str)
130 {
131 M_DrawCharacter (cx, cy, *str);
132 str++;
133 cx += 8;
134 }
135}
136
137void M_DrawTransPic (int x, int y, qpic_t *pic)
138{
139 Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
140}
141
142void M_DrawPic (int x, int y, qpic_t *pic)
143{
144 Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
145}
146
147byte identityTable[256];
148byte translationTable[256];
149
150void M_BuildTranslationTable(int top, int bottom)
151{
152 int j;
153 byte *dest, *source;
154
155 for (j = 0; j < 256; j++)
156 identityTable[j] = j;
157 dest = translationTable;
158 source = identityTable;
159 memcpy (dest, source, 256);
160
161 if (top < 128) // the artists made some backwards ranges. sigh.
162 memcpy (dest + TOP_RANGE, source + top, 16);
163 else
164 for (j=0 ; j<16 ; j++)
165 dest[TOP_RANGE+j] = source[top+15-j];
166
167 if (bottom < 128)
168 memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
169 else
170 for (j=0 ; j<16 ; j++)
171 dest[BOTTOM_RANGE+j] = source[bottom+15-j];
172}
173
174
175void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
176{
177 Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
178}
179
180
181void M_DrawTextBox (int x, int y, int width, int lines)
182{
183 qpic_t *p;
184 int cx, cy;
185 int n;
186
187 // draw left side
188 cx = x;
189 cy = y;
190 p = Draw_CachePic ("gfx/box_tl.lmp");
191 M_DrawTransPic (cx, cy, p);
192 p = Draw_CachePic ("gfx/box_ml.lmp");
193 for (n = 0; n < lines; n++)
194 {
195 cy += 8;
196 M_DrawTransPic (cx, cy, p);
197 }
198 p = Draw_CachePic ("gfx/box_bl.lmp");
199 M_DrawTransPic (cx, cy+8, p);
200
201 // draw middle
202 cx += 8;
203 while (width > 0)
204 {
205 cy = y;
206 p = Draw_CachePic ("gfx/box_tm.lmp");
207 M_DrawTransPic (cx, cy, p);
208 p = Draw_CachePic ("gfx/box_mm.lmp");
209 for (n = 0; n < lines; n++)
210 {
211 cy += 8;
212 if (n == 1)
213 p = Draw_CachePic ("gfx/box_mm2.lmp");
214 M_DrawTransPic (cx, cy, p);
215 }
216 p = Draw_CachePic ("gfx/box_bm.lmp");
217 M_DrawTransPic (cx, cy+8, p);
218 width -= 2;
219 cx += 16;
220 }
221
222 // draw right side
223 cy = y;
224 p = Draw_CachePic ("gfx/box_tr.lmp");
225 M_DrawTransPic (cx, cy, p);
226 p = Draw_CachePic ("gfx/box_mr.lmp");
227 for (n = 0; n < lines; n++)
228 {
229 cy += 8;
230 M_DrawTransPic (cx, cy, p);
231 }
232 p = Draw_CachePic ("gfx/box_br.lmp");
233 M_DrawTransPic (cx, cy+8, p);
234}
235
236//=============================================================================
237
238int m_save_demonum;
239
240/*
241================
242M_ToggleMenu_f
243================
244*/
245void M_ToggleMenu_f (void)
246{
247 m_entersound = true;
248
249 if (key_dest == key_menu)
250 {
251 if (m_state != m_main)
252 {
253 M_Menu_Main_f ();
254 return;
255 }
256 key_dest = key_game;
257 m_state = m_none;
258 return;
259 }
260 if (key_dest == key_console)
261 {
262 Con_ToggleConsole_f ();
263 }
264 else
265 {
266 M_Menu_Main_f ();
267 }
268}
269
270
271//=============================================================================
272/* MAIN MENU */
273
274int m_main_cursor;
275#define MAIN_ITEMS 5
276
277
278void M_Menu_Main_f (void)
279{
280 if (key_dest != key_menu)
281 {
282 m_save_demonum = cls.demonum;
283 cls.demonum = -1;
284 }
285 key_dest = key_menu;
286 m_state = m_main;
287 m_entersound = true;
288}
289
290
291void M_Main_Draw (void)
292{
293 int f;
294 qpic_t *p;
295
296 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
297 p = Draw_CachePic ("gfx/ttl_main.lmp");
298 M_DrawPic ( (320-p->width)/2, 4, p);
299 M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
300
301 f = (int)(host_time * 10)%6;
302
303 M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
304}
305
306
307void M_Main_Key (int key)
308{
309 switch (key)
310 {
311 case K_ESCAPE:
312 key_dest = key_game;
313 m_state = m_none;
314 cls.demonum = m_save_demonum;
315 if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
316 CL_NextDemo ();
317 break;
318
319 case K_DOWNARROW:
320 S_LocalSound ("misc/menu1.wav");
321 if (++m_main_cursor >= MAIN_ITEMS)
322 m_main_cursor = 0;
323 break;
324
325 case K_UPARROW:
326 S_LocalSound ("misc/menu1.wav");
327 if (--m_main_cursor < 0)
328 m_main_cursor = MAIN_ITEMS - 1;
329 break;
330
331 case K_ENTER:
332 m_entersound = true;
333
334 switch (m_main_cursor)
335 {
336 case 0:
337 M_Menu_SinglePlayer_f ();
338 break;
339
340 case 1:
341 M_Menu_MultiPlayer_f ();
342 break;
343
344 case 2:
345 M_Menu_Options_f ();
346 break;
347
348 case 3:
349 M_Menu_Help_f ();
350 break;
351
352 case 4:
353 M_Menu_Quit_f ();
354 break;
355 }
356 }
357}
358
359//=============================================================================
360/* SINGLE PLAYER MENU */
361
362int m_singleplayer_cursor;
363#define SINGLEPLAYER_ITEMS 3
364
365
366void M_Menu_SinglePlayer_f (void)
367{
368 key_dest = key_menu;
369 m_state = m_singleplayer;
370 m_entersound = true;
371}
372
373
374void M_SinglePlayer_Draw (void)
375{
376 int f;
377 qpic_t *p;
378
379 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
380 p = Draw_CachePic ("gfx/ttl_sgl.lmp");
381 M_DrawPic ( (320-p->width)/2, 4, p);
382 M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
383
384 f = (int)(host_time * 10)%6;
385
386 M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
387}
388
389
390void M_SinglePlayer_Key (int key)
391{
392 switch (key)
393 {
394 case K_ESCAPE:
395 M_Menu_Main_f ();
396 break;
397
398 case K_DOWNARROW:
399 S_LocalSound ("misc/menu1.wav");
400 if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
401 m_singleplayer_cursor = 0;
402 break;
403
404 case K_UPARROW:
405 S_LocalSound ("misc/menu1.wav");
406 if (--m_singleplayer_cursor < 0)
407 m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
408 break;
409
410 case K_ENTER:
411 m_entersound = true;
412
413 switch (m_singleplayer_cursor)
414 {
415 case 0:
416 if (sv.active)
417 if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n"))
418 break;
419 key_dest = key_game;
420 if (sv.active)
421 Cbuf_AddText ("disconnect\n");
422 Cbuf_AddText ("maxplayers 1\n");
423 Cbuf_AddText ("map start\n");
424 break;
425
426 case 1:
427 M_Menu_Load_f ();
428 break;
429
430 case 2:
431 M_Menu_Save_f ();
432 break;
433 }
434 }
435}
436
437//=============================================================================
438/* LOAD/SAVE MENU */
439
440int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES
441
442#define MAX_SAVEGAMES 12
443char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
444int loadable[MAX_SAVEGAMES];
445
446void M_ScanSaves (void)
447{
448 int i, j;
449 char name[MAX_OSPATH];
450 FILE *f;
451 int version;
452
453 for (i=0 ; i<MAX_SAVEGAMES ; i++)
454 {
455 strcpy (m_filenames[i], "--- UNUSED SLOT ---");
456 loadable[i] = false;
457 sprintf (name, "%s/s%i.sav", com_gamedir, i);
458 f = fopen (name, "r");
459 if (!f)
460 continue;
461 fscanf (f, "%i\n", &version);
462 fscanf (f, "%s\n", name);
463 strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);
464
465 // change _ back to space
466 for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
467 if (m_filenames[i][j] == '_')
468 m_filenames[i][j] = ' ';
469 loadable[i] = true;
470 fclose (f);
471 }
472}
473
474void M_Menu_Load_f (void)
475{
476 m_entersound = true;
477 m_state = m_load;
478 key_dest = key_menu;
479 M_ScanSaves ();
480}
481
482
483void M_Menu_Save_f (void)
484{
485 if (!sv.active)
486 return;
487 if (cl.intermission)
488 return;
489 if (svs.maxclients != 1)
490 return;
491 m_entersound = true;
492 m_state = m_save;
493 key_dest = key_menu;
494 M_ScanSaves ();
495}
496
497
498void M_Load_Draw (void)
499{
500 int i;
501 qpic_t *p;
502
503 p = Draw_CachePic ("gfx/p_load.lmp");
504 M_DrawPic ( (320-p->width)/2, 4, p);
505
506 for (i=0 ; i< MAX_SAVEGAMES; i++)
507 M_Print (16, 32 + 8*i, m_filenames[i]);
508
509// line cursor
510 M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
511}
512
513
514void M_Save_Draw (void)
515{
516 int i;
517 qpic_t *p;
518
519 p = Draw_CachePic ("gfx/p_save.lmp");
520 M_DrawPic ( (320-p->width)/2, 4, p);
521
522 for (i=0 ; i<MAX_SAVEGAMES ; i++)
523 M_Print (16, 32 + 8*i, m_filenames[i]);
524
525// line cursor
526 M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
527}
528
529
530void M_Load_Key (int k)
531{
532 switch (k)
533 {
534 case K_ESCAPE:
535 M_Menu_SinglePlayer_f ();
536 break;
537
538 case K_ENTER:
539 S_LocalSound ("misc/menu2.wav");
540 if (!loadable[load_cursor])
541 return;
542 m_state = m_none;
543 key_dest = key_game;
544
545 // Host_Loadgame_f can't bring up the loading plaque because too much
546 // stack space has been used, so do it now
547 SCR_BeginLoadingPlaque ();
548
549 // issue the load command
550 Cbuf_AddText (va ("load s%i\n", load_cursor) );
551 return;
552
553 case K_UPARROW:
554 case K_LEFTARROW:
555 S_LocalSound ("misc/menu1.wav");
556 load_cursor--;
557 if (load_cursor < 0)
558 load_cursor = MAX_SAVEGAMES-1;
559 break;
560
561 case K_DOWNARROW:
562 case K_RIGHTARROW:
563 S_LocalSound ("misc/menu1.wav");
564 load_cursor++;
565 if (load_cursor >= MAX_SAVEGAMES)
566 load_cursor = 0;
567 break;
568 }
569}
570
571
572void M_Save_Key (int k)
573{
574 switch (k)
575 {
576 case K_ESCAPE:
577 M_Menu_SinglePlayer_f ();
578 break;
579
580 case K_ENTER:
581 m_state = m_none;
582 key_dest = key_game;
583 Cbuf_AddText (va("save s%i\n", load_cursor));
584 return;
585
586 case K_UPARROW:
587 case K_LEFTARROW:
588 S_LocalSound ("misc/menu1.wav");
589 load_cursor--;
590 if (load_cursor < 0)
591 load_cursor = MAX_SAVEGAMES-1;
592 break;
593
594 case K_DOWNARROW:
595 case K_RIGHTARROW:
596 S_LocalSound ("misc/menu1.wav");
597 load_cursor++;
598 if (load_cursor >= MAX_SAVEGAMES)
599 load_cursor = 0;
600 break;
601 }
602}
603
604//=============================================================================
605/* MULTIPLAYER MENU */
606
607int m_multiplayer_cursor;
608#define MULTIPLAYER_ITEMS 3
609
610
611void M_Menu_MultiPlayer_f (void)
612{
613 key_dest = key_menu;
614 m_state = m_multiplayer;
615 m_entersound = true;
616}
617
618
619void M_MultiPlayer_Draw (void)
620{
621 int f;
622 qpic_t *p;
623
624 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
625 p = Draw_CachePic ("gfx/p_multi.lmp");
626 M_DrawPic ( (320-p->width)/2, 4, p);
627 M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
628
629 f = (int)(host_time * 10)%6;
630
631 M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
632
633 if (serialAvailable || ipxAvailable || tcpipAvailable)
634 return;
635 M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
636}
637
638
639void M_MultiPlayer_Key (int key)
640{
641 switch (key)
642 {
643 case K_ESCAPE:
644 M_Menu_Main_f ();
645 break;
646
647 case K_DOWNARROW:
648 S_LocalSound ("misc/menu1.wav");
649 if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
650 m_multiplayer_cursor = 0;
651 break;
652
653 case K_UPARROW:
654 S_LocalSound ("misc/menu1.wav");
655 if (--m_multiplayer_cursor < 0)
656 m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
657 break;
658
659 case K_ENTER:
660 m_entersound = true;
661 switch (m_multiplayer_cursor)
662 {
663 case 0:
664 if (serialAvailable || ipxAvailable || tcpipAvailable)
665 M_Menu_Net_f ();
666 break;
667
668 case 1:
669 if (serialAvailable || ipxAvailable || tcpipAvailable)
670 M_Menu_Net_f ();
671 break;
672
673 case 2:
674 M_Menu_Setup_f ();
675 break;
676 }
677 }
678}
679
680//=============================================================================
681/* SETUP MENU */
682
683int setup_cursor = 4;
684int setup_cursor_table[] = {40, 56, 80, 104, 140};
685
686char setup_hostname[16];
687char setup_myname[16];
688int setup_oldtop;
689int setup_oldbottom;
690int setup_top;
691int setup_bottom;
692
693#define NUM_SETUP_CMDS 5
694
695void M_Menu_Setup_f (void)
696{
697 key_dest = key_menu;
698 m_state = m_setup;
699 m_entersound = true;
700 Q_strcpy(setup_myname, cl_name.string);
701 Q_strcpy(setup_hostname, hostname.string);
702 setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
703 setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
704}
705
706
707void M_Setup_Draw (void)
708{
709 qpic_t *p;
710
711 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
712 p = Draw_CachePic ("gfx/p_multi.lmp");
713 M_DrawPic ( (320-p->width)/2, 4, p);
714
715 M_Print (64, 40, "Hostname");
716 M_DrawTextBox (160, 32, 16, 1);
717 M_Print (168, 40, setup_hostname);
718
719 M_Print (64, 56, "Your name");
720 M_DrawTextBox (160, 48, 16, 1);
721 M_Print (168, 56, setup_myname);
722
723 M_Print (64, 80, "Shirt color");
724 M_Print (64, 104, "Pants color");
725
726 M_DrawTextBox (64, 140-8, 14, 1);
727 M_Print (72, 140, "Accept Changes");
728
729 p = Draw_CachePic ("gfx/bigbox.lmp");
730 M_DrawTransPic (160, 64, p);
731 p = Draw_CachePic ("gfx/menuplyr.lmp");
732 M_BuildTranslationTable(setup_top*16, setup_bottom*16);
733 M_DrawTransPicTranslate (172, 72, p);
734
735 M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
736
737 if (setup_cursor == 0)
738 M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
739
740 if (setup_cursor == 1)
741 M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
742}
743
744
745void M_Setup_Key (int k)
746{
747 int l;
748
749 switch (k)
750 {
751 case K_ESCAPE:
752 M_Menu_MultiPlayer_f ();
753 break;
754
755 case K_UPARROW:
756 S_LocalSound ("misc/menu1.wav");
757 setup_cursor--;
758 if (setup_cursor < 0)
759 setup_cursor = NUM_SETUP_CMDS-1;
760 break;
761
762 case K_DOWNARROW:
763 S_LocalSound ("misc/menu1.wav");
764 setup_cursor++;
765 if (setup_cursor >= NUM_SETUP_CMDS)
766 setup_cursor = 0;
767 break;
768
769 case K_LEFTARROW:
770 if (setup_cursor < 2)
771 return;
772 S_LocalSound ("misc/menu3.wav");
773 if (setup_cursor == 2)
774 setup_top = setup_top - 1;
775 if (setup_cursor == 3)
776 setup_bottom = setup_bottom - 1;
777 break;
778 case K_RIGHTARROW:
779 if (setup_cursor < 2)
780 return;
781forward:
782 S_LocalSound ("misc/menu3.wav");
783 if (setup_cursor == 2)
784 setup_top = setup_top + 1;
785 if (setup_cursor == 3)
786 setup_bottom = setup_bottom + 1;
787 break;
788
789 case K_ENTER:
790 if (setup_cursor == 0 || setup_cursor == 1)
791 return;
792
793 if (setup_cursor == 2 || setup_cursor == 3)
794 goto forward;
795
796 // setup_cursor == 4 (OK)
797 if (Q_strcmp(cl_name.string, setup_myname) != 0)
798 Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
799 if (Q_strcmp(hostname.string, setup_hostname) != 0)
800 Cvar_Set("hostname", setup_hostname);
801 if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
802 Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
803 m_entersound = true;
804 M_Menu_MultiPlayer_f ();
805 break;
806
807 case K_BACKSPACE:
808 if (setup_cursor == 0)
809 {
810 if (strlen(setup_hostname))
811 setup_hostname[strlen(setup_hostname)-1] = 0;
812 }
813
814 if (setup_cursor == 1)
815 {
816 if (strlen(setup_myname))
817 setup_myname[strlen(setup_myname)-1] = 0;
818 }
819 break;
820
821 default:
822 if (k < 32 || k > 127)
823 break;
824 if (setup_cursor == 0)
825 {
826 l = strlen(setup_hostname);
827 if (l < 15)
828 {
829 setup_hostname[l+1] = 0;
830 setup_hostname[l] = k;
831 }
832 }
833 if (setup_cursor == 1)
834 {
835 l = strlen(setup_myname);
836 if (l < 15)
837 {
838 setup_myname[l+1] = 0;
839 setup_myname[l] = k;
840 }
841 }
842 }
843
844 if (setup_top > 13)
845 setup_top = 0;
846 if (setup_top < 0)
847 setup_top = 13;
848 if (setup_bottom > 13)
849 setup_bottom = 0;
850 if (setup_bottom < 0)
851 setup_bottom = 13;
852}
853
854//=============================================================================
855/* NET MENU */
856
857int m_net_cursor;
858int m_net_items;
859int m_net_saveHeight;
860
861char *net_helpMessage [] =
862{
863/* .........1.........2.... */
864 " ",
865 " Two computers connected",
866 " through two modems. ",
867 " ",
868
869 " ",
870 " Two computers connected",
871 " by a null-modem cable. ",
872 " ",
873
874 " Novell network LANs ",
875 " or Windows 95 DOS-box. ",
876 " ",
877 "(LAN=Local Area Network)",
878
879 " Commonly used to play ",
880 " over the Internet, but ",
881 " also used on a Local ",
882 " Area Network. "
883};
884
885void M_Menu_Net_f (void)
886{
887 key_dest = key_menu;
888 m_state = m_net;
889 m_entersound = true;
890 m_net_items = 4;
891
892 if (m_net_cursor >= m_net_items)
893 m_net_cursor = 0;
894 m_net_cursor--;
895 M_Net_Key (K_DOWNARROW);
896}
897
898
899void M_Net_Draw (void)
900{
901 int f;
902 qpic_t *p;
903
904 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
905 p = Draw_CachePic ("gfx/p_multi.lmp");
906 M_DrawPic ( (320-p->width)/2, 4, p);
907
908 f = 32;
909
910 if (serialAvailable)
911 {
912 p = Draw_CachePic ("gfx/netmen1.lmp");
913 }
914 else
915 {
916#ifdef _WIN32
917 p = NULL;
918#else
919 p = Draw_CachePic ("gfx/dim_modm.lmp");
920#endif
921 }
922
923 if (p)
924 M_DrawTransPic (72, f, p);
925
926 f += 19;
927
928 if (serialAvailable)
929 {
930 p = Draw_CachePic ("gfx/netmen2.lmp");
931 }
932 else
933 {
934#ifdef _WIN32
935 p = NULL;
936#else
937 p = Draw_CachePic ("gfx/dim_drct.lmp");
938#endif
939 }
940
941 if (p)
942 M_DrawTransPic (72, f, p);
943
944 f += 19;
945 if (ipxAvailable)
946 p = Draw_CachePic ("gfx/netmen3.lmp");
947 else
948 p = Draw_CachePic ("gfx/dim_ipx.lmp");
949 M_DrawTransPic (72, f, p);
950
951 f += 19;
952 if (tcpipAvailable)
953 p = Draw_CachePic ("gfx/netmen4.lmp");
954 else
955 p = Draw_CachePic ("gfx/dim_tcp.lmp");
956 M_DrawTransPic (72, f, p);
957
958 if (m_net_items == 5) // JDC, could just be removed
959 {
960 f += 19;
961 p = Draw_CachePic ("gfx/netmen5.lmp");
962 M_DrawTransPic (72, f, p);
963 }
964
965 f = (320-26*8)/2;
966 M_DrawTextBox (f, 134, 24, 4);
967 f += 8;
968 M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
969 M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
970 M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
971 M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
972
973 f = (int)(host_time * 10)%6;
974 M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
975}
976
977
978void M_Net_Key (int k)
979{
980again:
981 switch (k)
982 {
983 case K_ESCAPE:
984 M_Menu_MultiPlayer_f ();
985 break;
986
987 case K_DOWNARROW:
988 S_LocalSound ("misc/menu1.wav");
989 if (++m_net_cursor >= m_net_items)
990 m_net_cursor = 0;
991 break;
992
993 case K_UPARROW:
994 S_LocalSound ("misc/menu1.wav");
995 if (--m_net_cursor < 0)
996 m_net_cursor = m_net_items - 1;
997 break;
998
999 case K_ENTER:
1000 m_entersound = true;
1001
1002 switch (m_net_cursor)
1003 {
1004 case 0:
1005 M_Menu_SerialConfig_f ();
1006 break;
1007
1008 case 1:
1009 M_Menu_SerialConfig_f ();
1010 break;
1011
1012 case 2:
1013 M_Menu_LanConfig_f ();
1014 break;
1015
1016 case 3:
1017 M_Menu_LanConfig_f ();
1018 break;
1019
1020 case 4:
1021// multiprotocol
1022 break;
1023 }
1024 }
1025
1026 if (m_net_cursor == 0 && !serialAvailable)
1027 goto again;
1028 if (m_net_cursor == 1 && !serialAvailable)
1029 goto again;
1030 if (m_net_cursor == 2 && !ipxAvailable)
1031 goto again;
1032 if (m_net_cursor == 3 && !tcpipAvailable)
1033 goto again;
1034}
1035
1036//=============================================================================
1037/* OPTIONS MENU */
1038
1039#ifdef _WIN32
1040#define OPTIONS_ITEMS 14
1041#else
1042#define OPTIONS_ITEMS 13
1043#endif
1044
1045#define SLIDER_RANGE 10
1046
1047int options_cursor;
1048
1049void M_Menu_Options_f (void)
1050{
1051 key_dest = key_menu;
1052 m_state = m_options;
1053 m_entersound = true;
1054
1055#ifdef _WIN32
1056 if ((options_cursor == 13) && (modestate != MS_WINDOWED))
1057 {
1058 options_cursor = 0;
1059 }
1060#endif
1061}
1062
1063
1064void M_AdjustSliders (int dir)
1065{
1066 S_LocalSound ("misc/menu3.wav");
1067
1068 switch (options_cursor)
1069 {
1070 case 3: // screen size
1071 scr_viewsize.value += dir * 10;
1072 if (scr_viewsize.value < 30)
1073 scr_viewsize.value = 30;
1074 if (scr_viewsize.value > 120)
1075 scr_viewsize.value = 120;
1076 Cvar_SetValue ("viewsize", scr_viewsize.value);
1077 break;
1078 case 4: // gamma
1079 v_gamma.value -= dir * 0.05;
1080 if (v_gamma.value < 0.5)
1081 v_gamma.value = 0.5;
1082 if (v_gamma.value > 1)
1083 v_gamma.value = 1;
1084 Cvar_SetValue ("gamma", v_gamma.value);
1085 break;
1086 case 5: // mouse speed
1087 sensitivity.value += dir * 0.5;
1088 if (sensitivity.value < 1)
1089 sensitivity.value = 1;
1090 if (sensitivity.value > 11)
1091 sensitivity.value = 11;
1092 Cvar_SetValue ("sensitivity", sensitivity.value);
1093 break;
1094 case 6: // music volume
1095#ifdef _WIN32
1096 bgmvolume.value += dir * 1.0;
1097#else
1098 bgmvolume.value += dir * 0.1;
1099#endif
1100 if (bgmvolume.value < 0)
1101 bgmvolume.value = 0;
1102 if (bgmvolume.value > 1)
1103 bgmvolume.value = 1;
1104 Cvar_SetValue ("bgmvolume", bgmvolume.value);
1105 break;
1106 case 7: // sfx volume
1107 volume.value += dir * 0.1;
1108 if (volume.value < 0)
1109 volume.value = 0;
1110 if (volume.value > 1)
1111 volume.value = 1;
1112 Cvar_SetValue ("volume", volume.value);
1113 break;
1114
1115 case 8: // allways run
1116 if (cl_forwardspeed.value > 200)
1117 {
1118 Cvar_SetValue ("cl_forwardspeed", 200);
1119 Cvar_SetValue ("cl_backspeed", 200);
1120 }
1121 else
1122 {
1123 Cvar_SetValue ("cl_forwardspeed", 400);
1124 Cvar_SetValue ("cl_backspeed", 400);
1125 }
1126 break;
1127
1128 case 9: // invert mouse
1129 Cvar_SetValue ("m_pitch", -m_pitch.value);
1130 break;
1131
1132 case 10: // lookspring
1133 Cvar_SetValue ("lookspring", !lookspring.value);
1134 break;
1135
1136 case 11: // lookstrafe
1137 Cvar_SetValue ("lookstrafe", !lookstrafe.value);
1138 break;
1139
1140#ifdef _WIN32
1141 case 13: // _windowed_mouse
1142 Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
1143 break;
1144#endif
1145 }
1146}
1147
1148
1149void M_DrawSlider (int x, int y, float range)
1150{
1151 int i;
1152
1153 if (range < 0)
1154 range = 0;
1155 if (range > 1)
1156 range = 1;
1157 M_DrawCharacter (x-8, y, 128);
1158 for (i=0 ; i<SLIDER_RANGE ; i++)
1159 M_DrawCharacter (x + i*8, y, 129);
1160 M_DrawCharacter (x+i*8, y, 130);
1161 M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
1162}
1163
1164void M_DrawCheckbox (int x, int y, int on)
1165{
1166#if 0
1167 if (on)
1168 M_DrawCharacter (x, y, 131);
1169 else
1170 M_DrawCharacter (x, y, 129);
1171#endif
1172 if (on)
1173 M_Print (x, y, "on");
1174 else
1175 M_Print (x, y, "off");
1176}
1177
1178void M_Options_Draw (void)
1179{
1180 float r;
1181 qpic_t *p;
1182
1183 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1184 p = Draw_CachePic ("gfx/p_option.lmp");
1185 M_DrawPic ( (320-p->width)/2, 4, p);
1186
1187 M_Print (16, 32, " Customize controls");
1188 M_Print (16, 40, " Go to console");
1189 M_Print (16, 48, " Reset to defaults");
1190
1191 M_Print (16, 56, " Screen size");
1192 r = (scr_viewsize.value - 30) / (120 - 30);
1193 M_DrawSlider (220, 56, r);
1194
1195 M_Print (16, 64, " Brightness");
1196 r = (1.0 - v_gamma.value) / 0.5;
1197 M_DrawSlider (220, 64, r);
1198
1199 M_Print (16, 72, " Mouse Speed");
1200 r = (sensitivity.value - 1)/10;
1201 M_DrawSlider (220, 72, r);
1202
1203 M_Print (16, 80, " CD Music Volume");
1204 r = bgmvolume.value;
1205 M_DrawSlider (220, 80, r);
1206
1207 M_Print (16, 88, " Sound Volume");
1208 r = volume.value;
1209 M_DrawSlider (220, 88, r);
1210
1211 M_Print (16, 96, " Always Run");
1212 M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
1213
1214 M_Print (16, 104, " Invert Mouse");
1215 M_DrawCheckbox (220, 104, m_pitch.value < 0);
1216
1217 M_Print (16, 112, " Lookspring");
1218 M_DrawCheckbox (220, 112, lookspring.value);
1219
1220 M_Print (16, 120, " Lookstrafe");
1221 M_DrawCheckbox (220, 120, lookstrafe.value);
1222
1223 if (vid_menudrawfn)
1224 M_Print (16, 128, " Video Options");
1225
1226#ifdef _WIN32
1227 if (modestate == MS_WINDOWED)
1228 {
1229 M_Print (16, 136, " Use Mouse");
1230 M_DrawCheckbox (220, 136, _windowed_mouse.value);
1231 }
1232#endif
1233
1234// cursor
1235 M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
1236}
1237
1238
1239void M_Options_Key (int k)
1240{
1241 switch (k)
1242 {
1243 case K_ESCAPE:
1244 M_Menu_Main_f ();
1245 break;
1246
1247 case K_ENTER:
1248 m_entersound = true;
1249 switch (options_cursor)
1250 {
1251 case 0:
1252 M_Menu_Keys_f ();
1253 break;
1254 case 1:
1255 m_state = m_none;
1256 Con_ToggleConsole_f ();
1257 break;
1258 case 2:
1259 Cbuf_AddText ("exec default.cfg\n");
1260 break;
1261 case 12:
1262 M_Menu_Video_f ();
1263 break;
1264 default:
1265 M_AdjustSliders (1);
1266 break;
1267 }
1268 return;
1269
1270 case K_UPARROW:
1271 S_LocalSound ("misc/menu1.wav");
1272 options_cursor--;
1273 if (options_cursor < 0)
1274 options_cursor = OPTIONS_ITEMS-1;
1275 break;
1276
1277 case K_DOWNARROW:
1278 S_LocalSound ("misc/menu1.wav");
1279 options_cursor++;
1280 if (options_cursor >= OPTIONS_ITEMS)
1281 options_cursor = 0;
1282 break;
1283
1284 case K_LEFTARROW:
1285 M_AdjustSliders (-1);
1286 break;
1287
1288 case K_RIGHTARROW:
1289 M_AdjustSliders (1);
1290 break;
1291 }
1292
1293 if (options_cursor == 12 && vid_menudrawfn == NULL)
1294 {
1295 if (k == K_UPARROW)
1296 options_cursor = 11;
1297 else
1298 options_cursor = 0;
1299 }
1300
1301#ifdef _WIN32
1302 if ((options_cursor == 13) && (modestate != MS_WINDOWED))
1303 {
1304 if (k == K_UPARROW)
1305 options_cursor = 12;
1306 else
1307 options_cursor = 0;
1308 }
1309#endif
1310}
1311
1312//=============================================================================
1313/* KEYS MENU */
1314
1315char *bindnames[][2] =
1316{
1317{"+attack", "attack"},
1318{"impulse 10", "change weapon"},
1319{"+jump", "jump / swim up"},
1320{"+forward", "walk forward"},
1321{"+back", "backpedal"},
1322{"+left", "turn left"},
1323{"+right", "turn right"},
1324{"+speed", "run"},
1325{"+moveleft", "step left"},
1326{"+moveright", "step right"},
1327{"+strafe", "sidestep"},
1328{"+lookup", "look up"},
1329{"+lookdown", "look down"},
1330{"centerview", "center view"},
1331{"+mlook", "mouse look"},
1332{"+klook", "keyboard look"},
1333{"+moveup", "swim up"},
1334{"+movedown", "swim down"}
1335};
1336
1337#define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0]))
1338
1339int keys_cursor;
1340int bind_grab;
1341extern int bind_nooverride;
1342
1343void M_Menu_Keys_f (void)
1344{
1345 key_dest = key_menu;
1346 m_state = m_keys;
1347 m_entersound = true;
1348 bind_nooverride = 1; // don't override binds
1349}
1350
1351
1352void M_FindKeysForCommand (char *command, int *twokeys)
1353{
1354 int count;
1355 int j;
1356 int l;
1357 char *b;
1358
1359 twokeys[0] = twokeys[1] = -1;
1360 l = strlen(command);
1361 count = 0;
1362
1363 for (j=0 ; j<256 ; j++)
1364 {
1365 b = keybindings[j];
1366 if (!b)
1367 continue;
1368 if (!strncmp (b, command, l) )
1369 {
1370 twokeys[count] = j;
1371 count++;
1372 if (count == 2)
1373 break;
1374 }
1375 }
1376}
1377
1378void M_UnbindCommand (char *command)
1379{
1380 int j;
1381 int l;
1382 char *b;
1383
1384 l = strlen(command);
1385
1386 for (j=0 ; j<256 ; j++)
1387 {
1388 b = keybindings[j];
1389 if (!b)
1390 continue;
1391 if (!strncmp (b, command, l) )
1392 Key_SetBinding (j, "");
1393 }
1394}
1395
1396
1397void M_Keys_Draw (void)
1398{
1399 int i, l;
1400 int keys[2];
1401 char *name;
1402 int x, y;
1403 qpic_t *p;
1404
1405 p = Draw_CachePic ("gfx/ttl_cstm.lmp");
1406 M_DrawPic ( (320-p->width)/2, 4, p);
1407
1408 if (bind_grab)
1409 M_Print (12, 32, "Press a key or button for this action");
1410 else
1411 M_Print (18, 32, "Enter to change, backspace to clear");
1412
1413// search for known bindings
1414 for (i=0 ; i<NUMCOMMANDS ; i++)
1415 {
1416 y = 48 + 8*i;
1417
1418 M_Print (16, y, bindnames[i][1]);
1419
1420 l = strlen (bindnames[i][0]);
1421
1422 M_FindKeysForCommand (bindnames[i][0], keys);
1423
1424 if (keys[0] == -1)
1425 {
1426 M_Print (140, y, "???");
1427 }
1428 else
1429 {
1430 name = Key_KeynumToString (keys[0]);
1431 M_Print (140, y, name);
1432 x = strlen(name) * 8;
1433 if (keys[1] != -1)
1434 {
1435 M_Print (140 + x + 8, y, "or");
1436 M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
1437 }
1438 }
1439 }
1440
1441 if (bind_grab)
1442 M_DrawCharacter (130, 48 + keys_cursor*8, '=');
1443 else
1444 M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
1445}
1446
1447
1448void M_Keys_Key (int k)
1449{
1450 char cmd[80];
1451 int keys[2];
1452
1453 if (bind_grab)
1454 { // defining a key
1455 S_LocalSound ("misc/menu1.wav");
1456 if (k == K_ESCAPE)
1457 {
1458 bind_grab = false;
1459 }
1460 else if (k != '`')
1461 {
1462 sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
1463 Cbuf_InsertText (cmd);
1464 }
1465
1466 bind_grab = false;
1467 return;
1468 }
1469
1470 switch (k)
1471 {
1472 case K_ESCAPE:
1473 M_Menu_Options_f ();
1474 break;
1475
1476 case K_LEFTARROW:
1477 case K_UPARROW:
1478 S_LocalSound ("misc/menu1.wav");
1479 keys_cursor--;
1480 if (keys_cursor < 0)
1481 keys_cursor = NUMCOMMANDS-1;
1482 break;
1483
1484 case K_DOWNARROW:
1485 case K_RIGHTARROW:
1486 S_LocalSound ("misc/menu1.wav");
1487 keys_cursor++;
1488 if (keys_cursor >= NUMCOMMANDS)
1489 keys_cursor = 0;
1490 break;
1491
1492 case K_ENTER: // go into bind mode
1493 M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
1494 S_LocalSound ("misc/menu2.wav");
1495 if (keys[1] != -1)
1496 M_UnbindCommand (bindnames[keys_cursor][0]);
1497 bind_grab = true;
1498 break;
1499
1500 case K_BACKSPACE: // delete bindings
1501 case K_DEL: // delete bindings
1502 S_LocalSound ("misc/menu2.wav");
1503 M_UnbindCommand (bindnames[keys_cursor][0]);
1504 break;
1505 }
1506}
1507
1508//=============================================================================
1509/* VIDEO MENU */
1510
1511void M_Menu_Video_f (void)
1512{
1513 key_dest = key_menu;
1514 m_state = m_video;
1515 m_entersound = true;
1516}
1517
1518
1519void M_Video_Draw (void)
1520{
1521 (*vid_menudrawfn) ();
1522}
1523
1524
1525void M_Video_Key (int key)
1526{
1527 (*vid_menukeyfn) (key);
1528}
1529
1530//=============================================================================
1531/* HELP MENU */
1532
1533int help_page;
1534#define NUM_HELP_PAGES 6
1535
1536
1537void M_Menu_Help_f (void)
1538{
1539 key_dest = key_menu;
1540 m_state = m_help;
1541 m_entersound = true;
1542 help_page = 0;
1543}
1544
1545
1546
1547void M_Help_Draw (void)
1548{
1549 M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
1550}
1551
1552
1553void M_Help_Key (int key)
1554{
1555 switch (key)
1556 {
1557 case K_ESCAPE:
1558 M_Menu_Main_f ();
1559 break;
1560
1561 case K_UPARROW:
1562 case K_RIGHTARROW:
1563 m_entersound = true;
1564 if (++help_page >= NUM_HELP_PAGES)
1565 help_page = 0;
1566 break;
1567
1568 case K_DOWNARROW:
1569 case K_LEFTARROW:
1570 m_entersound = true;
1571 if (--help_page < 0)
1572 help_page = NUM_HELP_PAGES-1;
1573 break;
1574 }
1575
1576}
1577
1578//=============================================================================
1579/* QUIT MENU */
1580
1581int msgNumber;
1582int m_quit_prevstate;
1583qboolean wasInMenus;
1584
1585#ifndef _WIN32
1586char *quitMessage [] =
1587{
1588/* .........1.........2.... */
1589 " Are you gonna quit ",
1590 " this game just like ",
1591 " everything else? ",
1592 " ",
1593
1594 " Milord, methinks that ",
1595 " thou art a lowly ",
1596 " quitter. Is this true? ",
1597 " ",
1598
1599 " Do I need to bust your ",
1600 " face open for trying ",
1601 " to quit? ",
1602 " ",
1603
1604 " Man, I oughta smack you",
1605 " for trying to quit! ",
1606 " Press Y to get ",
1607 " smacked out. ",
1608
1609 " Press Y to quit like a ",
1610 " big loser in life. ",
1611 " Press N to stay proud ",
1612 " and successful! ",
1613
1614 " If you press Y to ",
1615 " quit, I will summon ",
1616 " Satan all over your ",
1617 " hard drive! ",
1618
1619 " Um, Asmodeus dislikes ",
1620 " his children trying to ",
1621 " quit. Press Y to return",
1622 " to your Tinkertoys. ",
1623
1624 " If you quit now, I'll ",
1625 " throw a blanket-party ",
1626 " for you next time! ",
1627 " "
1628};
1629#endif
1630
1631void M_Menu_Quit_f (void)
1632{
1633 if (m_state == m_quit)
1634 return;
1635 wasInMenus = (key_dest == key_menu);
1636 key_dest = key_menu;
1637 m_quit_prevstate = m_state;
1638 m_state = m_quit;
1639 m_entersound = true;
1640 msgNumber = rand()&7;
1641}
1642
1643
1644void M_Quit_Key (int key)
1645{
1646 switch (key)
1647 {
1648 case K_ESCAPE:
1649 case 'n':
1650 case 'N':
1651 if (wasInMenus)
1652 {
1653 m_state = m_quit_prevstate;
1654 m_entersound = true;
1655 }
1656 else
1657 {
1658 key_dest = key_game;
1659 m_state = m_none;
1660 }
1661 break;
1662
1663 case K_ENTER:
1664 case 'Y':
1665 case 'y':
1666 key_dest = key_console;
1667 Host_Quit_f ();
1668 break;
1669
1670 default:
1671 break;
1672 }
1673
1674}
1675
1676
1677void M_Quit_Draw (void)
1678{
1679 if (wasInMenus)
1680 {
1681 m_state = m_quit_prevstate;
1682 m_recursiveDraw = true;
1683 M_Draw ();
1684 m_state = m_quit;
1685 }
1686
1687#ifdef _WIN32
1688 M_DrawTextBox (0, 0, 38, 23);
1689 M_PrintWhite (16, 12, " Quake version 1.09 by id Software\n\n");
1690 M_PrintWhite (16, 28, "Programming Art \n");
1691 M_Print (16, 36, " John Carmack Adrian Carmack\n");
1692 M_Print (16, 44, " Michael Abrash Kevin Cloud\n");
1693 M_Print (16, 52, " John Cash Paul Steed\n");
1694 M_Print (16, 60, " Dave 'Zoid' Kirsch\n");
1695 M_PrintWhite (16, 68, "Design Biz\n");
1696 M_Print (16, 76, " John Romero Jay Wilbur\n");
1697 M_Print (16, 84, " Sandy Petersen Mike Wilson\n");
1698 M_Print (16, 92, " American McGee Donna Jackson\n");
1699 M_Print (16, 100, " Tim Willits Todd Hollenshead\n");
1700 M_PrintWhite (16, 108, "Support Projects\n");
1701 M_Print (16, 116, " Barrett Alexander Shawn Green\n");
1702 M_PrintWhite (16, 124, "Sound Effects\n");
1703 M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
1704 M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
1705 M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
1706 M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
1707 M_PrintWhite (16, 164, "registered trademark licensed to\n");
1708 M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
1709 M_PrintWhite (16, 180, "reserved. Press y to exit\n");
1710#else
1711 M_DrawTextBox (56, 76, 24, 4);
1712 M_Print (64, 84, quitMessage[msgNumber*4+0]);
1713 M_Print (64, 92, quitMessage[msgNumber*4+1]);
1714 M_Print (64, 100, quitMessage[msgNumber*4+2]);
1715 M_Print (64, 108, quitMessage[msgNumber*4+3]);
1716#endif
1717}
1718
1719//=============================================================================
1720
1721/* SERIAL CONFIG MENU */
1722
1723int serialConfig_cursor;
1724int serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
1725#define NUM_SERIALCONFIG_CMDS 6
1726
1727static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8};
1728static int ISA_IRQs[] = {4,3,4,3};
1729int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
1730
1731int serialConfig_comport;
1732int serialConfig_irq ;
1733int serialConfig_baud;
1734char serialConfig_phone[16];
1735
1736void M_Menu_SerialConfig_f (void)
1737{
1738 int n;
1739 int port;
1740 int baudrate;
1741 qboolean useModem;
1742
1743 key_dest = key_menu;
1744 m_state = m_serialconfig;
1745 m_entersound = true;
1746 if (JoiningGame && SerialConfig)
1747 serialConfig_cursor = 4;
1748 else
1749 serialConfig_cursor = 5;
1750
1751 (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
1752
1753 // map uart's port to COMx
1754 for (n = 0; n < 4; n++)
1755 if (ISA_uarts[n] == port)
1756 break;
1757 if (n == 4)
1758 {
1759 n = 0;
1760 serialConfig_irq = 4;
1761 }
1762 serialConfig_comport = n + 1;
1763
1764 // map baudrate to index
1765 for (n = 0; n < 6; n++)
1766 if (serialConfig_baudrate[n] == baudrate)
1767 break;
1768 if (n == 6)
1769 n = 5;
1770 serialConfig_baud = n;
1771
1772 m_return_onerror = false;
1773 m_return_reason[0] = 0;
1774}
1775
1776
1777void M_SerialConfig_Draw (void)
1778{
1779 qpic_t *p;
1780 int basex;
1781 char *startJoin;
1782 char *directModem;
1783
1784 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
1785 p = Draw_CachePic ("gfx/p_multi.lmp");
1786 basex = (320-p->width)/2;
1787 M_DrawPic (basex, 4, p);
1788
1789 if (StartingGame)
1790 startJoin = "New Game";
1791 else
1792 startJoin = "Join Game";
1793 if (SerialConfig)
1794 directModem = "Modem";
1795 else
1796 directModem = "Direct Connect";
1797 M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
1798 basex += 8;
1799
1800 M_Print (basex, serialConfig_cursor_table[0], "Port");
1801 M_DrawTextBox (160, 40, 4, 1);
1802 M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
1803
1804 M_Print (basex, serialConfig_cursor_table[1], "IRQ");
1805 M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
1806 M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
1807
1808 M_Print (basex, serialConfig_cursor_table[2], "Baud");
1809 M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
1810 M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
1811
1812 if (SerialConfig)
1813 {
1814 M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
1815 if (JoiningGame)
1816 {
1817 M_Print (basex, serialConfig_cursor_table[4], "Phone number");
1818 M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
1819 M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
1820 }
1821 }
1822
1823 if (JoiningGame)
1824 {
1825 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
1826 M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
1827 }
1828 else
1829 {
1830 M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
1831 M_Print (basex+8, serialConfig_cursor_table[5], "OK");
1832 }
1833
1834 M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
1835
1836 if (serialConfig_cursor == 4)
1837 M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
1838
1839 if (*m_return_reason)
1840 M_PrintWhite (basex, 148, m_return_reason);
1841}
1842
1843
1844void M_SerialConfig_Key (int key)
1845{
1846 int l;
1847
1848 switch (key)
1849 {
1850 case K_ESCAPE:
1851 M_Menu_Net_f ();
1852 break;
1853
1854 case K_UPARROW:
1855 S_LocalSound ("misc/menu1.wav");
1856 serialConfig_cursor--;
1857 if (serialConfig_cursor < 0)
1858 serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
1859 break;
1860
1861 case K_DOWNARROW:
1862 S_LocalSound ("misc/menu1.wav");
1863 serialConfig_cursor++;
1864 if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
1865 serialConfig_cursor = 0;
1866 break;
1867
1868 case K_LEFTARROW:
1869 if (serialConfig_cursor > 2)
1870 break;
1871 S_LocalSound ("misc/menu3.wav");
1872
1873 if (serialConfig_cursor == 0)
1874 {
1875 serialConfig_comport--;
1876 if (serialConfig_comport == 0)
1877 serialConfig_comport = 4;
1878 serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1879 }
1880
1881 if (serialConfig_cursor == 1)
1882 {
1883 serialConfig_irq--;
1884 if (serialConfig_irq == 6)
1885 serialConfig_irq = 5;
1886 if (serialConfig_irq == 1)
1887 serialConfig_irq = 7;
1888 }
1889
1890 if (serialConfig_cursor == 2)
1891 {
1892 serialConfig_baud--;
1893 if (serialConfig_baud < 0)
1894 serialConfig_baud = 5;
1895 }
1896
1897 break;
1898
1899 case K_RIGHTARROW:
1900 if (serialConfig_cursor > 2)
1901 break;
1902forward:
1903 S_LocalSound ("misc/menu3.wav");
1904
1905 if (serialConfig_cursor == 0)
1906 {
1907 serialConfig_comport++;
1908 if (serialConfig_comport > 4)
1909 serialConfig_comport = 1;
1910 serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
1911 }
1912
1913 if (serialConfig_cursor == 1)
1914 {
1915 serialConfig_irq++;
1916 if (serialConfig_irq == 6)
1917 serialConfig_irq = 7;
1918 if (serialConfig_irq == 8)
1919 serialConfig_irq = 2;
1920 }
1921
1922 if (serialConfig_cursor == 2)
1923 {
1924 serialConfig_baud++;
1925 if (serialConfig_baud > 5)
1926 serialConfig_baud = 0;
1927 }
1928
1929 break;
1930
1931 case K_ENTER:
1932 if (serialConfig_cursor < 3)
1933 goto forward;
1934
1935 m_entersound = true;
1936
1937 if (serialConfig_cursor == 3)
1938 {
1939 (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1940
1941 M_Menu_ModemConfig_f ();
1942 break;
1943 }
1944
1945 if (serialConfig_cursor == 4)
1946 {
1947 serialConfig_cursor = 5;
1948 break;
1949 }
1950
1951 // serialConfig_cursor == 5 (OK/CONNECT)
1952 (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
1953
1954 M_ConfigureNetSubsystem ();
1955
1956 if (StartingGame)
1957 {
1958 M_Menu_GameOptions_f ();
1959 break;
1960 }
1961
1962 m_return_state = m_state;
1963 m_return_onerror = true;
1964 key_dest = key_game;
1965 m_state = m_none;
1966
1967 if (SerialConfig)
1968 Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
1969 else
1970 Cbuf_AddText ("connect\n");
1971 break;
1972
1973 case K_BACKSPACE:
1974 if (serialConfig_cursor == 4)
1975 {
1976 if (strlen(serialConfig_phone))
1977 serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
1978 }
1979 break;
1980
1981 default:
1982 if (key < 32 || key > 127)
1983 break;
1984 if (serialConfig_cursor == 4)
1985 {
1986 l = strlen(serialConfig_phone);
1987 if (l < 15)
1988 {
1989 serialConfig_phone[l+1] = 0;
1990 serialConfig_phone[l] = key;
1991 }
1992 }
1993 }
1994
1995 if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
1996 if (key == K_UPARROW)
1997 serialConfig_cursor = 2;
1998 else
1999 serialConfig_cursor = 5;
2000
2001 if (SerialConfig && StartingGame && serialConfig_cursor == 4)
2002 if (key == K_UPARROW)
2003 serialConfig_cursor = 3;
2004 else
2005 serialConfig_cursor = 5;
2006}
2007
2008//=============================================================================
2009/* MODEM CONFIG MENU */
2010
2011int modemConfig_cursor;
2012int modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
2013#define NUM_MODEMCONFIG_CMDS 5
2014
2015char modemConfig_dialing;
2016char modemConfig_clear [16];
2017char modemConfig_init [32];
2018char modemConfig_hangup [16];
2019
2020void M_Menu_ModemConfig_f (void)
2021{
2022 key_dest = key_menu;
2023 m_state = m_modemconfig;
2024 m_entersound = true;
2025 (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
2026}
2027
2028
2029void M_ModemConfig_Draw (void)
2030{
2031 qpic_t *p;
2032 int basex;
2033
2034 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2035 p = Draw_CachePic ("gfx/p_multi.lmp");
2036 basex = (320-p->width)/2;
2037 M_DrawPic (basex, 4, p);
2038 basex += 8;
2039
2040 if (modemConfig_dialing == 'P')
2041 M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
2042 else
2043 M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
2044
2045 M_Print (basex, modemConfig_cursor_table[1], "Clear");
2046 M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
2047 M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
2048 if (modemConfig_cursor == 1)
2049 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
2050
2051 M_Print (basex, modemConfig_cursor_table[2], "Init");
2052 M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
2053 M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
2054 if (modemConfig_cursor == 2)
2055 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
2056
2057 M_Print (basex, modemConfig_cursor_table[3], "Hangup");
2058 M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
2059 M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
2060 if (modemConfig_cursor == 3)
2061 M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
2062
2063 M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
2064 M_Print (basex+8, modemConfig_cursor_table[4], "OK");
2065
2066 M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
2067}
2068
2069
2070void M_ModemConfig_Key (int key)
2071{
2072 int l;
2073
2074 switch (key)
2075 {
2076 case K_ESCAPE:
2077 M_Menu_SerialConfig_f ();
2078 break;
2079
2080 case K_UPARROW:
2081 S_LocalSound ("misc/menu1.wav");
2082 modemConfig_cursor--;
2083 if (modemConfig_cursor < 0)
2084 modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
2085 break;
2086
2087 case K_DOWNARROW:
2088 S_LocalSound ("misc/menu1.wav");
2089 modemConfig_cursor++;
2090 if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
2091 modemConfig_cursor = 0;
2092 break;
2093
2094 case K_LEFTARROW:
2095 case K_RIGHTARROW:
2096 if (modemConfig_cursor == 0)
2097 {
2098 if (modemConfig_dialing == 'P')
2099 modemConfig_dialing = 'T';
2100 else
2101 modemConfig_dialing = 'P';
2102 S_LocalSound ("misc/menu1.wav");
2103 }
2104 break;
2105
2106 case K_ENTER:
2107 if (modemConfig_cursor == 0)
2108 {
2109 if (modemConfig_dialing == 'P')
2110 modemConfig_dialing = 'T';
2111 else
2112 modemConfig_dialing = 'P';
2113 m_entersound = true;
2114 }
2115
2116 if (modemConfig_cursor == 4)
2117 {
2118 (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
2119 m_entersound = true;
2120 M_Menu_SerialConfig_f ();
2121 }
2122 break;
2123
2124 case K_BACKSPACE:
2125 if (modemConfig_cursor == 1)
2126 {
2127 if (strlen(modemConfig_clear))
2128 modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
2129 }
2130
2131 if (modemConfig_cursor == 2)
2132 {
2133 if (strlen(modemConfig_init))
2134 modemConfig_init[strlen(modemConfig_init)-1] = 0;
2135 }
2136
2137 if (modemConfig_cursor == 3)
2138 {
2139 if (strlen(modemConfig_hangup))
2140 modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
2141 }
2142 break;
2143
2144 default:
2145 if (key < 32 || key > 127)
2146 break;
2147
2148 if (modemConfig_cursor == 1)
2149 {
2150 l = strlen(modemConfig_clear);
2151 if (l < 15)
2152 {
2153 modemConfig_clear[l+1] = 0;
2154 modemConfig_clear[l] = key;
2155 }
2156 }
2157
2158 if (modemConfig_cursor == 2)
2159 {
2160 l = strlen(modemConfig_init);
2161 if (l < 29)
2162 {
2163 modemConfig_init[l+1] = 0;
2164 modemConfig_init[l] = key;
2165 }
2166 }
2167
2168 if (modemConfig_cursor == 3)
2169 {
2170 l = strlen(modemConfig_hangup);
2171 if (l < 15)
2172 {
2173 modemConfig_hangup[l+1] = 0;
2174 modemConfig_hangup[l] = key;
2175 }
2176 }
2177 }
2178}
2179
2180//=============================================================================
2181/* LAN CONFIG MENU */
2182
2183int lanConfig_cursor = -1;
2184int lanConfig_cursor_table [] = {72, 92, 124};
2185#define NUM_LANCONFIG_CMDS 3
2186
2187int lanConfig_port;
2188char lanConfig_portname[6];
2189char lanConfig_joinname[22];
2190
2191void M_Menu_LanConfig_f (void)
2192{
2193 key_dest = key_menu;
2194 m_state = m_lanconfig;
2195 m_entersound = true;
2196 if (lanConfig_cursor == -1)
2197 {
2198 if (JoiningGame && TCPIPConfig)
2199 lanConfig_cursor = 2;
2200 else
2201 lanConfig_cursor = 1;
2202 }
2203 if (StartingGame && lanConfig_cursor == 2)
2204 lanConfig_cursor = 1;
2205 lanConfig_port = DEFAULTnet_hostport;
2206 sprintf(lanConfig_portname, "%u", lanConfig_port);
2207
2208 m_return_onerror = false;
2209 m_return_reason[0] = 0;
2210}
2211
2212
2213void M_LanConfig_Draw (void)
2214{
2215 qpic_t *p;
2216 int basex;
2217 char *startJoin;
2218 char *protocol;
2219
2220 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2221 p = Draw_CachePic ("gfx/p_multi.lmp");
2222 basex = (320-p->width)/2;
2223 M_DrawPic (basex, 4, p);
2224
2225 if (StartingGame)
2226 startJoin = "New Game";
2227 else
2228 startJoin = "Join Game";
2229 if (IPXConfig)
2230 protocol = "IPX";
2231 else
2232 protocol = "TCP/IP";
2233 M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
2234 basex += 8;
2235
2236 M_Print (basex, 52, "Address:");
2237 if (IPXConfig)
2238 M_Print (basex+9*8, 52, my_ipx_address);
2239 else
2240 M_Print (basex+9*8, 52, my_tcpip_address);
2241
2242 M_Print (basex, lanConfig_cursor_table[0], "Port");
2243 M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
2244 M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
2245
2246 if (JoiningGame)
2247 {
2248 M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
2249 M_Print (basex, 108, "Join game at:");
2250 M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
2251 M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
2252 }
2253 else
2254 {
2255 M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
2256 M_Print (basex+8, lanConfig_cursor_table[1], "OK");
2257 }
2258
2259 M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
2260
2261 if (lanConfig_cursor == 0)
2262 M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
2263
2264 if (lanConfig_cursor == 2)
2265 M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
2266
2267 if (*m_return_reason)
2268 M_PrintWhite (basex, 148, m_return_reason);
2269}
2270
2271
2272void M_LanConfig_Key (int key)
2273{
2274 int l;
2275
2276 switch (key)
2277 {
2278 case K_ESCAPE:
2279 M_Menu_Net_f ();
2280 break;
2281
2282 case K_UPARROW:
2283 S_LocalSound ("misc/menu1.wav");
2284 lanConfig_cursor--;
2285 if (lanConfig_cursor < 0)
2286 lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
2287 break;
2288
2289 case K_DOWNARROW:
2290 S_LocalSound ("misc/menu1.wav");
2291 lanConfig_cursor++;
2292 if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
2293 lanConfig_cursor = 0;
2294 break;
2295
2296 case K_ENTER:
2297 if (lanConfig_cursor == 0)
2298 break;
2299
2300 m_entersound = true;
2301
2302 M_ConfigureNetSubsystem ();
2303
2304 if (lanConfig_cursor == 1)
2305 {
2306 if (StartingGame)
2307 {
2308 M_Menu_GameOptions_f ();
2309 break;
2310 }
2311 M_Menu_Search_f();
2312 break;
2313 }
2314
2315 if (lanConfig_cursor == 2)
2316 {
2317 m_return_state = m_state;
2318 m_return_onerror = true;
2319 key_dest = key_game;
2320 m_state = m_none;
2321 Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
2322 break;
2323 }
2324
2325 break;
2326
2327 case K_BACKSPACE:
2328 if (lanConfig_cursor == 0)
2329 {
2330 if (strlen(lanConfig_portname))
2331 lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
2332 }
2333
2334 if (lanConfig_cursor == 2)
2335 {
2336 if (strlen(lanConfig_joinname))
2337 lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
2338 }
2339 break;
2340
2341 default:
2342 if (key < 32 || key > 127)
2343 break;
2344
2345 if (lanConfig_cursor == 2)
2346 {
2347 l = strlen(lanConfig_joinname);
2348 if (l < 21)
2349 {
2350 lanConfig_joinname[l+1] = 0;
2351 lanConfig_joinname[l] = key;
2352 }
2353 }
2354
2355 if (key < '0' || key > '9')
2356 break;
2357 if (lanConfig_cursor == 0)
2358 {
2359 l = strlen(lanConfig_portname);
2360 if (l < 5)
2361 {
2362 lanConfig_portname[l+1] = 0;
2363 lanConfig_portname[l] = key;
2364 }
2365 }
2366 }
2367
2368 if (StartingGame && lanConfig_cursor == 2)
2369 if (key == K_UPARROW)
2370 lanConfig_cursor = 1;
2371 else
2372 lanConfig_cursor = 0;
2373
2374 l = Q_atoi(lanConfig_portname);
2375 if (l > 65535)
2376 l = lanConfig_port;
2377 else
2378 lanConfig_port = l;
2379 sprintf(lanConfig_portname, "%u", lanConfig_port);
2380}
2381
2382//=============================================================================
2383/* GAME OPTIONS MENU */
2384
2385typedef struct
2386{
2387 char *name;
2388 char *description;
2389} level_t;
2390
2391level_t levels[] =
2392{
2393 {"start", "Entrance"}, // 0
2394
2395 {"e1m1", "Slipgate Complex"}, // 1
2396 {"e1m2", "Castle of the Damned"},
2397 {"e1m3", "The Necropolis"},
2398 {"e1m4", "The Grisly Grotto"},
2399 {"e1m5", "Gloom Keep"},
2400 {"e1m6", "The Door To Chthon"},
2401 {"e1m7", "The House of Chthon"},
2402 {"e1m8", "Ziggurat Vertigo"},
2403
2404 {"e2m1", "The Installation"}, // 9
2405 {"e2m2", "Ogre Citadel"},
2406 {"e2m3", "Crypt of Decay"},
2407 {"e2m4", "The Ebon Fortress"},
2408 {"e2m5", "The Wizard's Manse"},
2409 {"e2m6", "The Dismal Oubliette"},
2410 {"e2m7", "Underearth"},
2411
2412 {"e3m1", "Termination Central"}, // 16
2413 {"e3m2", "The Vaults of Zin"},
2414 {"e3m3", "The Tomb of Terror"},
2415 {"e3m4", "Satan's Dark Delight"},
2416 {"e3m5", "Wind Tunnels"},
2417 {"e3m6", "Chambers of Torment"},
2418 {"e3m7", "The Haunted Halls"},
2419
2420 {"e4m1", "The Sewage System"}, // 23
2421 {"e4m2", "The Tower of Despair"},
2422 {"e4m3", "The Elder God Shrine"},
2423 {"e4m4", "The Palace of Hate"},
2424 {"e4m5", "Hell's Atrium"},
2425 {"e4m6", "The Pain Maze"},
2426 {"e4m7", "Azure Agony"},
2427 {"e4m8", "The Nameless City"},
2428
2429 {"end", "Shub-Niggurath's Pit"}, // 31
2430
2431 {"dm1", "Place of Two Deaths"}, // 32
2432 {"dm2", "Claustrophobopolis"},
2433 {"dm3", "The Abandoned Base"},
2434 {"dm4", "The Bad Place"},
2435 {"dm5", "The Cistern"},
2436 {"dm6", "The Dark Zone"}
2437};
2438
2439//MED 01/06/97 added hipnotic levels
2440level_t hipnoticlevels[] =
2441{
2442 {"start", "Command HQ"}, // 0
2443
2444 {"hip1m1", "The Pumping Station"}, // 1
2445 {"hip1m2", "Storage Facility"},
2446 {"hip1m3", "The Lost Mine"},
2447 {"hip1m4", "Research Facility"},
2448 {"hip1m5", "Military Complex"},
2449
2450 {"hip2m1", "Ancient Realms"}, // 6
2451 {"hip2m2", "The Black Cathedral"},
2452 {"hip2m3", "The Catacombs"},
2453 {"hip2m4", "The Crypt"},
2454 {"hip2m5", "Mortum's Keep"},
2455 {"hip2m6", "The Gremlin's Domain"},
2456
2457 {"hip3m1", "Tur Torment"}, // 12
2458 {"hip3m2", "Pandemonium"},
2459 {"hip3m3", "Limbo"},
2460 {"hip3m4", "The Gauntlet"},
2461
2462 {"hipend", "Armagon's Lair"}, // 16
2463
2464 {"hipdm1", "The Edge of Oblivion"} // 17
2465};
2466
2467//PGM 01/07/97 added rogue levels
2468//PGM 03/02/97 added dmatch level
2469level_t roguelevels[] =
2470{
2471 {"start", "Split Decision"},
2472 {"r1m1", "Deviant's Domain"},
2473 {"r1m2", "Dread Portal"},
2474 {"r1m3", "Judgement Call"},
2475 {"r1m4", "Cave of Death"},
2476 {"r1m5", "Towers of Wrath"},
2477 {"r1m6", "Temple of Pain"},
2478 {"r1m7", "Tomb of the Overlord"},
2479 {"r2m1", "Tempus Fugit"},
2480 {"r2m2", "Elemental Fury I"},
2481 {"r2m3", "Elemental Fury II"},
2482 {"r2m4", "Curse of Osiris"},
2483 {"r2m5", "Wizard's Keep"},
2484 {"r2m6", "Blood Sacrifice"},
2485 {"r2m7", "Last Bastion"},
2486 {"r2m8", "Source of Evil"},
2487 {"ctf1", "Division of Change"}
2488};
2489
2490typedef struct
2491{
2492 char *description;
2493 int firstLevel;
2494 int levels;
2495} episode_t;
2496
2497episode_t episodes[] =
2498{
2499 {"Welcome to Quake", 0, 1},
2500 {"Doomed Dimension", 1, 8},
2501 {"Realm of Black Magic", 9, 7},
2502 {"Netherworld", 16, 7},
2503 {"The Elder World", 23, 8},
2504 {"Final Level", 31, 1},
2505 {"Deathmatch Arena", 32, 6}
2506};
2507
2508//MED 01/06/97 added hipnotic episodes
2509episode_t hipnoticepisodes[] =
2510{
2511 {"Scourge of Armagon", 0, 1},
2512 {"Fortress of the Dead", 1, 5},
2513 {"Dominion of Darkness", 6, 6},
2514 {"The Rift", 12, 4},
2515 {"Final Level", 16, 1},
2516 {"Deathmatch Arena", 17, 1}
2517};
2518
2519//PGM 01/07/97 added rogue episodes
2520//PGM 03/02/97 added dmatch episode
2521episode_t rogueepisodes[] =
2522{
2523 {"Introduction", 0, 1},
2524 {"Hell's Fortress", 1, 7},
2525 {"Corridors of Time", 8, 8},
2526 {"Deathmatch Arena", 16, 1}
2527};
2528
2529int startepisode;
2530int startlevel;
2531int maxplayers;
2532qboolean m_serverInfoMessage = false;
2533double m_serverInfoMessageTime;
2534
2535void M_Menu_GameOptions_f (void)
2536{
2537 key_dest = key_menu;
2538 m_state = m_gameoptions;
2539 m_entersound = true;
2540 if (maxplayers == 0)
2541 maxplayers = svs.maxclients;
2542 if (maxplayers < 2)
2543 maxplayers = svs.maxclientslimit;
2544}
2545
2546
2547int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
2548#define NUM_GAMEOPTIONS 9
2549int gameoptions_cursor;
2550
2551void M_GameOptions_Draw (void)
2552{
2553 qpic_t *p;
2554 int x;
2555
2556 M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
2557 p = Draw_CachePic ("gfx/p_multi.lmp");
2558 M_DrawPic ( (320-p->width)/2, 4, p);
2559
2560 M_DrawTextBox (152, 32, 10, 1);
2561 M_Print (160, 40, "begin game");
2562
2563 M_Print (0, 56, " Max players");
2564 M_Print (160, 56, va("%i", maxplayers) );
2565
2566 M_Print (0, 64, " Game Type");
2567 if (coop.value)
2568 M_Print (160, 64, "Cooperative");
2569 else
2570 M_Print (160, 64, "Deathmatch");
2571
2572 M_Print (0, 72, " Teamplay");
2573 if (rogue)
2574 {
2575 char *msg;
2576
2577 switch((int)teamplay.value)
2578 {
2579 case 1: msg = "No Friendly Fire"; break;
2580 case 2: msg = "Friendly Fire"; break;
2581 case 3: msg = "Tag"; break;
2582 case 4: msg = "Capture the Flag"; break;
2583 case 5: msg = "One Flag CTF"; break;
2584 case 6: msg = "Three Team CTF"; break;
2585 default: msg = "Off"; break;
2586 }
2587 M_Print (160, 72, msg);
2588 }
2589 else
2590 {
2591 char *msg;
2592
2593 switch((int)teamplay.value)
2594 {
2595 case 1: msg = "No Friendly Fire"; break;
2596 case 2: msg = "Friendly Fire"; break;
2597 default: msg = "Off"; break;
2598 }
2599 M_Print (160, 72, msg);
2600 }
2601
2602 M_Print (0, 80, " Skill");
2603 if (skill.value == 0)
2604 M_Print (160, 80, "Easy difficulty");
2605 else if (skill.value == 1)
2606 M_Print (160, 80, "Normal difficulty");
2607 else if (skill.value == 2)
2608 M_Print (160, 80, "Hard difficulty");
2609 else
2610 M_Print (160, 80, "Nightmare difficulty");
2611
2612 M_Print (0, 88, " Frag Limit");
2613 if (fraglimit.value == 0)
2614 M_Print (160, 88, "none");
2615 else
2616 M_Print (160, 88, va("%i frags", (int)fraglimit.value));
2617
2618 M_Print (0, 96, " Time Limit");
2619 if (timelimit.value == 0)
2620 M_Print (160, 96, "none");
2621 else
2622 M_Print (160, 96, va("%i minutes", (int)timelimit.value));
2623
2624 M_Print (0, 112, " Episode");
2625 //MED 01/06/97 added hipnotic episodes
2626 if (hipnotic)
2627 M_Print (160, 112, hipnoticepisodes[startepisode].description);
2628 //PGM 01/07/97 added rogue episodes
2629 else if (rogue)
2630 M_Print (160, 112, rogueepisodes[startepisode].description);
2631 else
2632 M_Print (160, 112, episodes[startepisode].description);
2633
2634 M_Print (0, 120, " Level");
2635 //MED 01/06/97 added hipnotic episodes
2636 if (hipnotic)
2637 {
2638 M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
2639 M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
2640 }
2641 //PGM 01/07/97 added rogue episodes
2642 else if (rogue)
2643 {
2644 M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
2645 M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
2646 }
2647 else
2648 {
2649 M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
2650 M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
2651 }
2652
2653// line cursor
2654 M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
2655
2656 if (m_serverInfoMessage)
2657 {
2658 if ((realtime - m_serverInfoMessageTime) < 5.0)
2659 {
2660 x = (320-26*8)/2;
2661 M_DrawTextBox (x, 138, 24, 4);
2662 x += 8;
2663 M_Print (x, 146, " More than 4 players ");
2664 M_Print (x, 154, " requires using command ");
2665 M_Print (x, 162, "line parameters; please ");
2666 M_Print (x, 170, " see techinfo.txt. ");
2667 }
2668 else
2669 {
2670 m_serverInfoMessage = false;
2671 }
2672 }
2673}
2674
2675
2676void M_NetStart_Change (int dir)
2677{
2678 int count;
2679
2680 switch (gameoptions_cursor)
2681 {
2682 case 1:
2683 maxplayers += dir;
2684 if (maxplayers > svs.maxclientslimit)
2685 {
2686 maxplayers = svs.maxclientslimit;
2687 m_serverInfoMessage = true;
2688 m_serverInfoMessageTime = realtime;
2689 }
2690 if (maxplayers < 2)
2691 maxplayers = 2;
2692 break;
2693
2694 case 2:
2695 Cvar_SetValue ("coop", coop.value ? 0 : 1);
2696 break;
2697
2698 case 3:
2699 if (rogue)
2700 count = 6;
2701 else
2702 count = 2;
2703
2704 Cvar_SetValue ("teamplay", teamplay.value + dir);
2705 if (teamplay.value > count)
2706 Cvar_SetValue ("teamplay", 0);
2707 else if (teamplay.value < 0)
2708 Cvar_SetValue ("teamplay", count);
2709 break;
2710
2711 case 4:
2712 Cvar_SetValue ("skill", skill.value + dir);
2713 if (skill.value > 3)
2714 Cvar_SetValue ("skill", 0);
2715 if (skill.value < 0)
2716 Cvar_SetValue ("skill", 3);
2717 break;
2718
2719 case 5:
2720 Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
2721 if (fraglimit.value > 100)
2722 Cvar_SetValue ("fraglimit", 0);
2723 if (fraglimit.value < 0)
2724 Cvar_SetValue ("fraglimit", 100);
2725 break;
2726
2727 case 6:
2728 Cvar_SetValue ("timelimit", timelimit.value + dir*5);
2729 if (timelimit.value > 60)
2730 Cvar_SetValue ("timelimit", 0);
2731 if (timelimit.value < 0)
2732 Cvar_SetValue ("timelimit", 60);
2733 break;
2734
2735 case 7:
2736 startepisode += dir;
2737 //MED 01/06/97 added hipnotic count
2738 if (hipnotic)
2739 count = 6;
2740 //PGM 01/07/97 added rogue count
2741 //PGM 03/02/97 added 1 for dmatch episode
2742 else if (rogue)
2743 count = 4;
2744 else if (registered.value)
2745 count = 7;
2746 else
2747 count = 2;
2748
2749 if (startepisode < 0)
2750 startepisode = count - 1;
2751
2752 if (startepisode >= count)
2753 startepisode = 0;
2754
2755 startlevel = 0;
2756 break;
2757
2758 case 8:
2759 startlevel += dir;
2760 //MED 01/06/97 added hipnotic episodes
2761 if (hipnotic)
2762 count = hipnoticepisodes[startepisode].levels;
2763 //PGM 01/06/97 added hipnotic episodes
2764 else if (rogue)
2765 count = rogueepisodes[startepisode].levels;
2766 else
2767 count = episodes[startepisode].levels;
2768
2769 if (startlevel < 0)
2770 startlevel = count - 1;
2771
2772 if (startlevel >= count)
2773 startlevel = 0;
2774 break;
2775 }
2776}
2777
2778void M_GameOptions_Key (int key)
2779{
2780 switch (key)
2781 {
2782 case K_ESCAPE:
2783 M_Menu_Net_f ();
2784 break;
2785
2786 case K_UPARROW:
2787 S_LocalSound ("misc/menu1.wav");
2788 gameoptions_cursor--;
2789 if (gameoptions_cursor < 0)
2790 gameoptions_cursor = NUM_GAMEOPTIONS-1;
2791 break;
2792
2793 case K_DOWNARROW:
2794 S_LocalSound ("misc/menu1.wav");
2795 gameoptions_cursor++;
2796 if (gameoptions_cursor >= NUM_GAMEOPTIONS)
2797 gameoptions_cursor = 0;
2798 break;
2799
2800 case K_LEFTARROW:
2801 if (gameoptions_cursor == 0)
2802 break;
2803 S_LocalSound ("misc/menu3.wav");
2804 M_NetStart_Change (-1);
2805 break;
2806
2807 case K_RIGHTARROW:
2808 if (gameoptions_cursor == 0)
2809 break;
2810 S_LocalSound ("misc/menu3.wav");
2811 M_NetStart_Change (1);
2812 break;
2813
2814 case K_ENTER:
2815 S_LocalSound ("misc/menu2.wav");
2816 if (gameoptions_cursor == 0)
2817 {
2818 if (sv.active)
2819 Cbuf_AddText ("disconnect\n");
2820 Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined
2821 Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
2822 SCR_BeginLoadingPlaque ();
2823
2824 if (hipnotic)
2825 Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
2826 else if (rogue)
2827 Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
2828 else
2829 Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
2830
2831 return;
2832 }
2833
2834 M_NetStart_Change (1);
2835 break;
2836 }
2837}
2838
2839//=============================================================================
2840/* SEARCH MENU */
2841
2842qboolean searchComplete = false;
2843double searchCompleteTime;
2844
2845void M_Menu_Search_f (void)
2846{
2847 key_dest = key_menu;
2848 m_state = m_search;
2849 m_entersound = false;
2850 slistSilent = true;
2851 slistLocal = false;
2852 searchComplete = false;
2853 NET_Slist_f();
2854
2855}
2856
2857
2858void M_Search_Draw (void)
2859{
2860 qpic_t *p;
2861 int x;
2862
2863 p = Draw_CachePic ("gfx/p_multi.lmp");
2864 M_DrawPic ( (320-p->width)/2, 4, p);
2865 x = (320/2) - ((12*8)/2) + 4;
2866 M_DrawTextBox (x-8, 32, 12, 1);
2867 M_Print (x, 40, "Searching...");
2868
2869 if(slistInProgress)
2870 {
2871 NET_Poll();
2872 return;
2873 }
2874
2875 if (! searchComplete)
2876 {
2877 searchComplete = true;
2878 searchCompleteTime = realtime;
2879 }
2880
2881 if (hostCacheCount)
2882 {
2883 M_Menu_ServerList_f ();
2884 return;
2885 }
2886
2887 M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
2888 if ((realtime - searchCompleteTime) < 3.0)
2889 return;
2890
2891 M_Menu_LanConfig_f ();
2892}
2893
2894
2895void M_Search_Key (int key)
2896{
2897}
2898
2899//=============================================================================
2900/* SLIST MENU */
2901
2902int slist_cursor;
2903qboolean slist_sorted;
2904
2905void M_Menu_ServerList_f (void)
2906{
2907 key_dest = key_menu;
2908 m_state = m_slist;
2909 m_entersound = true;
2910 slist_cursor = 0;
2911 m_return_onerror = false;
2912 m_return_reason[0] = 0;
2913 slist_sorted = false;
2914}
2915
2916
2917void M_ServerList_Draw (void)
2918{
2919 int n;
2920 char string [64];
2921 qpic_t *p;
2922
2923 if (!slist_sorted)
2924 {
2925 if (hostCacheCount > 1)
2926 {
2927 int i,j;
2928 hostcache_t temp;
2929 for (i = 0; i < hostCacheCount; i++)
2930 for (j = i+1; j < hostCacheCount; j++)
2931 if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
2932 {
2933 Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
2934 Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
2935 Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
2936 }
2937 }
2938 slist_sorted = true;
2939 }
2940
2941 p = Draw_CachePic ("gfx/p_multi.lmp");
2942 M_DrawPic ( (320-p->width)/2, 4, p);
2943 for (n = 0; n < hostCacheCount; n++)
2944 {
2945 if (hostcache[n].maxusers)
2946 sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
2947 else
2948 sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
2949 M_Print (16, 32 + 8*n, string);
2950 }
2951 M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
2952
2953 if (*m_return_reason)
2954 M_PrintWhite (16, 148, m_return_reason);
2955}
2956
2957
2958void M_ServerList_Key (int k)
2959{
2960 switch (k)
2961 {
2962 case K_ESCAPE:
2963 M_Menu_LanConfig_f ();
2964 break;
2965
2966 case K_SPACE:
2967 M_Menu_Search_f ();
2968 break;
2969
2970 case K_UPARROW:
2971 case K_LEFTARROW:
2972 S_LocalSound ("misc/menu1.wav");
2973 slist_cursor--;
2974 if (slist_cursor < 0)
2975 slist_cursor = hostCacheCount - 1;
2976 break;
2977
2978 case K_DOWNARROW:
2979 case K_RIGHTARROW:
2980 S_LocalSound ("misc/menu1.wav");
2981 slist_cursor++;
2982 if (slist_cursor >= hostCacheCount)
2983 slist_cursor = 0;
2984 break;
2985
2986 case K_ENTER:
2987 S_LocalSound ("misc/menu2.wav");
2988 m_return_state = m_state;
2989 m_return_onerror = true;
2990 slist_sorted = false;
2991 key_dest = key_game;
2992 m_state = m_none;
2993 Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
2994 break;
2995
2996 default:
2997 break;
2998 }
2999
3000}
3001
3002//=============================================================================
3003/* Menu Subsystem */
3004
3005
3006void M_Init (void)
3007{
3008 Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
3009
3010 Cmd_AddCommand ("menu_main", M_Menu_Main_f);
3011 Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
3012 Cmd_AddCommand ("menu_load", M_Menu_Load_f);
3013 Cmd_AddCommand ("menu_save", M_Menu_Save_f);
3014 Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
3015 Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
3016 Cmd_AddCommand ("menu_options", M_Menu_Options_f);
3017 Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
3018 Cmd_AddCommand ("menu_video", M_Menu_Video_f);
3019 Cmd_AddCommand ("help", M_Menu_Help_f);
3020 Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
3021}
3022
3023
3024void M_Draw (void)
3025{
3026 if (m_state == m_none || key_dest != key_menu)
3027 return;
3028
3029 if (!m_recursiveDraw)
3030 {
3031 scr_copyeverything = 1;
3032
3033 if (scr_con_current)
3034 {
3035 Draw_ConsoleBackground (vid.height);
3036 VID_UnlockBuffer ();
3037 S_ExtraUpdate ();
3038 VID_LockBuffer ();
3039 }
3040 else
3041 Draw_FadeScreen ();
3042
3043 scr_fullupdate = 0;
3044 }
3045 else
3046 {
3047 m_recursiveDraw = false;
3048 }
3049
3050 switch (m_state)
3051 {
3052 case m_none:
3053 break;
3054
3055 case m_main:
3056 M_Main_Draw ();
3057 break;
3058
3059 case m_singleplayer:
3060 M_SinglePlayer_Draw ();
3061 break;
3062
3063 case m_load:
3064 M_Load_Draw ();
3065 break;
3066
3067 case m_save:
3068 M_Save_Draw ();
3069 break;
3070
3071 case m_multiplayer:
3072 M_MultiPlayer_Draw ();
3073 break;
3074
3075 case m_setup:
3076 M_Setup_Draw ();
3077 break;
3078
3079 case m_net:
3080 M_Net_Draw ();
3081 break;
3082
3083 case m_options:
3084 M_Options_Draw ();
3085 break;
3086
3087 case m_keys:
3088 M_Keys_Draw ();
3089 break;
3090
3091 case m_video:
3092 M_Video_Draw ();
3093 break;
3094
3095 case m_help:
3096 M_Help_Draw ();
3097 break;
3098
3099 case m_quit:
3100 M_Quit_Draw ();
3101 break;
3102
3103 case m_serialconfig:
3104 M_SerialConfig_Draw ();
3105 break;
3106
3107 case m_modemconfig:
3108 M_ModemConfig_Draw ();
3109 break;
3110
3111 case m_lanconfig:
3112 M_LanConfig_Draw ();
3113 break;
3114
3115 case m_gameoptions:
3116 M_GameOptions_Draw ();
3117 break;
3118
3119 case m_search:
3120 M_Search_Draw ();
3121 break;
3122
3123 case m_slist:
3124 M_ServerList_Draw ();
3125 break;
3126 }
3127
3128 if (m_entersound)
3129 {
3130 S_LocalSound ("misc/menu2.wav");
3131 m_entersound = false;
3132 }
3133
3134 VID_UnlockBuffer ();
3135 S_ExtraUpdate ();
3136 VID_LockBuffer ();
3137}
3138
3139
3140void M_Keydown (int key)
3141{
3142 switch (m_state)
3143 {
3144 case m_none:
3145 return;
3146
3147 case m_main:
3148 M_Main_Key (key);
3149 return;
3150
3151 case m_singleplayer:
3152 M_SinglePlayer_Key (key);
3153 return;
3154
3155 case m_load:
3156 M_Load_Key (key);
3157 return;
3158
3159 case m_save:
3160 M_Save_Key (key);
3161 return;
3162
3163 case m_multiplayer:
3164 M_MultiPlayer_Key (key);
3165 return;
3166
3167 case m_setup:
3168 M_Setup_Key (key);
3169 return;
3170
3171 case m_net:
3172 M_Net_Key (key);
3173 return;
3174
3175 case m_options:
3176 M_Options_Key (key);
3177 return;
3178
3179 case m_keys:
3180 M_Keys_Key (key);
3181 return;
3182
3183 case m_video:
3184 M_Video_Key (key);
3185 return;
3186
3187 case m_help:
3188 M_Help_Key (key);
3189 return;
3190
3191 case m_quit:
3192 M_Quit_Key (key);
3193 return;
3194
3195 case m_serialconfig:
3196 M_SerialConfig_Key (key);
3197 return;
3198
3199 case m_modemconfig:
3200 M_ModemConfig_Key (key);
3201 return;
3202
3203 case m_lanconfig:
3204 M_LanConfig_Key (key);
3205 return;
3206
3207 case m_gameoptions:
3208 M_GameOptions_Key (key);
3209 return;
3210
3211 case m_search:
3212 M_Search_Key (key);
3213 break;
3214
3215 case m_slist:
3216 M_ServerList_Key (key);
3217 return;
3218 }
3219}
3220
3221
3222void M_ConfigureNetSubsystem(void)
3223{
3224// enable/disable net systems to match desired config
3225
3226 Cbuf_AddText ("stopdemo\n");
3227 if (SerialConfig || DirectConfig)
3228 {
3229 Cbuf_AddText ("com1 enable\n");
3230 }
3231
3232 if (IPXConfig || TCPIPConfig)
3233 net_hostport = lanConfig_port;
3234}
diff --git a/apps/plugins/sdl/progs/quake/menu.h b/apps/plugins/sdl/progs/quake/menu.h
new file mode 100644
index 0000000000..616de3f848
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/menu.h
@@ -0,0 +1,38 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21//
22// the net drivers should just set the apropriate bits in m_activenet,
23// instead of having the menu code look through their internal tables
24//
25#define MNET_IPX 1
26#define MNET_TCP 2
27
28extern int m_activenet;
29
30//
31// menus
32//
33void M_Init (void);
34void M_Keydown (int key);
35void M_Draw (void);
36void M_ToggleMenu_f (void);
37
38
diff --git a/apps/plugins/sdl/progs/quake/model.c b/apps/plugins/sdl/progs/quake/model.c
new file mode 100644
index 0000000000..57fdfec993
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/model.c
@@ -0,0 +1,1874 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// models.c -- model loading and caching
21
22// models are the only shared resource between a client and server running
23// on the same machine.
24
25#include "quakedef.h"
26#include "r_local.h"
27
28model_t *loadmodel;
29char loadname[32]; // for hunk tags
30
31void Mod_LoadSpriteModel (model_t *mod, void *buffer);
32void Mod_LoadBrushModel (model_t *mod, void *buffer);
33void Mod_LoadAliasModel (model_t *mod, void *buffer);
34model_t *Mod_LoadModel (model_t *mod, qboolean crash);
35
36byte mod_novis[MAX_MAP_LEAFS/8];
37
38#define MAX_MOD_KNOWN 256
39model_t mod_known[MAX_MOD_KNOWN];
40int mod_numknown;
41
42// values for model_t's needload
43#define NL_PRESENT 0
44#define NL_NEEDS_LOADED 1
45#define NL_UNREFERENCED 2
46
47/*
48===============
49Mod_Init
50===============
51*/
52void Mod_Init (void)
53{
54 memset (mod_novis, 0xff, sizeof(mod_novis));
55}
56
57/*
58===============
59Mod_Extradata
60
61Caches the data if needed
62===============
63*/
64void *Mod_Extradata (model_t *mod)
65{
66 void *r;
67
68 r = Cache_Check (&mod->cache);
69 if (r)
70 return r;
71
72 Mod_LoadModel (mod, true);
73
74 if (!mod->cache.data)
75 Sys_Error ("Mod_Extradata: caching failed");
76 return mod->cache.data;
77}
78
79/*
80===============
81Mod_PointInLeaf
82===============
83*/
84mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
85{
86 mnode_t *node;
87 float d;
88 mplane_t *plane;
89
90 if (!model || !model->nodes)
91 Sys_Error ("Mod_PointInLeaf: bad model");
92
93 node = model->nodes;
94 while (1)
95 {
96 if (node->contents < 0)
97 return (mleaf_t *)node;
98 plane = node->plane;
99 d = DotProduct (p,plane->normal) - plane->dist;
100 if (d > 0)
101 node = node->children[0];
102 else
103 node = node->children[1];
104 }
105
106 return NULL; // never reached
107}
108
109
110/*
111===================
112Mod_DecompressVis
113===================
114*/
115byte *Mod_DecompressVis (byte *in, model_t *model)
116{
117 static byte decompressed[MAX_MAP_LEAFS/8];
118 int c;
119 byte *out;
120 int row;
121
122 row = (model->numleafs+7)>>3;
123 out = decompressed;
124
125 if (!in)
126 { // no vis info, so make all visible
127 while (row)
128 {
129 *out++ = 0xff;
130 row--;
131 }
132 return decompressed;
133 }
134
135 do
136 {
137 if (*in)
138 {
139 *out++ = *in++;
140 continue;
141 }
142
143 c = in[1];
144 in += 2;
145 while (c)
146 {
147 *out++ = 0;
148 c--;
149 }
150 } while (out - decompressed < row);
151
152 return decompressed;
153}
154
155byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
156{
157 if (leaf == model->leafs)
158 return mod_novis;
159 return Mod_DecompressVis (leaf->compressed_vis, model);
160}
161
162/*
163===================
164Mod_ClearAll
165===================
166*/
167void Mod_ClearAll (void)
168{
169 int i;
170 model_t *mod;
171
172
173 for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) {
174 mod->needload = NL_UNREFERENCED;
175//FIX FOR CACHE_ALLOC ERRORS:
176 if (mod->type == mod_sprite) mod->cache.data = NULL;
177 }
178}
179
180/*
181==================
182Mod_FindName
183
184==================
185*/
186model_t *Mod_FindName (char *name)
187{
188 int i;
189 model_t *mod;
190 model_t *avail = NULL;
191
192 if (!name[0])
193 Sys_Error ("Mod_ForName: NULL name");
194
195//
196// search the currently loaded models
197//
198 for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
199 {
200 if (!strcmp (mod->name, name) )
201 break;
202 if (mod->needload == NL_UNREFERENCED)
203 if (!avail || mod->type != mod_alias)
204 avail = mod;
205 }
206
207 if (i == mod_numknown)
208 {
209 if (mod_numknown == MAX_MOD_KNOWN)
210 {
211 if (avail)
212 {
213 mod = avail;
214 if (mod->type == mod_alias)
215 if (Cache_Check (&mod->cache))
216 Cache_Free (&mod->cache);
217 }
218 else
219 Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
220 }
221 else
222 mod_numknown++;
223 strcpy (mod->name, name);
224 mod->needload = NL_NEEDS_LOADED;
225 }
226
227 return mod;
228}
229
230/*
231==================
232Mod_TouchModel
233
234==================
235*/
236void Mod_TouchModel (char *name)
237{
238 model_t *mod;
239
240 mod = Mod_FindName (name);
241
242 if (mod->needload == NL_PRESENT)
243 {
244 if (mod->type == mod_alias)
245 Cache_Check (&mod->cache);
246 }
247}
248
249/*
250==================
251Mod_LoadModel
252
253Loads a model into the cache
254==================
255*/
256model_t *Mod_LoadModel (model_t *mod, qboolean crash)
257{
258 unsigned *buf;
259 byte stackbuf[1024]; // avoid dirtying the cache heap
260
261 if (mod->type == mod_alias)
262 {
263 if (Cache_Check (&mod->cache))
264 {
265 mod->needload = NL_PRESENT;
266 return mod;
267 }
268 }
269 else
270 {
271 if (mod->needload == NL_PRESENT)
272 return mod;
273 }
274
275//
276// because the world is so huge, load it one piece at a time
277//
278
279//
280// load the file
281//
282 buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf));
283 if (!buf)
284 {
285 if (crash)
286 Sys_Error ("Mod_NumForName: %s not found", mod->name);
287 return NULL;
288 }
289
290//
291// allocate a new model
292//
293 COM_FileBase (mod->name, loadname);
294
295 loadmodel = mod;
296
297//
298// fill it in
299//
300
301// call the apropriate loader
302 mod->needload = NL_PRESENT;
303
304 switch (LittleLong(*(unsigned *)buf))
305 {
306 case IDPOLYHEADER:
307 Mod_LoadAliasModel (mod, buf);
308 break;
309
310 case IDSPRITEHEADER:
311 Mod_LoadSpriteModel (mod, buf);
312 break;
313
314 default:
315 Mod_LoadBrushModel (mod, buf);
316 break;
317 }
318
319 return mod;
320}
321
322/*
323==================
324Mod_ForName
325
326Loads in a model for the given name
327==================
328*/
329model_t *Mod_ForName (char *name, qboolean crash)
330{
331 model_t *mod;
332
333 mod = Mod_FindName (name);
334
335 return Mod_LoadModel (mod, crash);
336}
337
338
339/*
340===============================================================================
341
342 BRUSHMODEL LOADING
343
344===============================================================================
345*/
346
347byte *mod_base;
348
349
350/*
351=================
352Mod_LoadTextures
353=================
354*/
355void Mod_LoadTextures (lump_t *l)
356{
357 int i, j, pixels, num, max, altmax;
358 miptex_t *mt;
359 texture_t *tx, *tx2;
360 texture_t *anims[10];
361 texture_t *altanims[10];
362 dmiptexlump_t *m;
363
364 if (!l->filelen)
365 {
366 loadmodel->textures = NULL;
367 return;
368 }
369 m = (dmiptexlump_t *)(mod_base + l->fileofs);
370
371 m->nummiptex = LittleLong (m->nummiptex);
372
373 loadmodel->numtextures = m->nummiptex;
374 loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
375
376 for (i=0 ; i<m->nummiptex ; i++)
377 {
378 m->dataofs[i] = LittleLong(m->dataofs[i]);
379 if (m->dataofs[i] == -1)
380 continue;
381 mt = (miptex_t *)((byte *)m + m->dataofs[i]);
382 mt->width = LittleLong (mt->width);
383 mt->height = LittleLong (mt->height);
384 for (j=0 ; j<MIPLEVELS ; j++)
385 mt->offsets[j] = LittleLong (mt->offsets[j]);
386
387 if ( (mt->width & 15) || (mt->height & 15) )
388 Sys_Error ("Texture %s is not 16 aligned", mt->name);
389 pixels = mt->width*mt->height/64*85;
390 tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
391 loadmodel->textures[i] = tx;
392
393 memcpy (tx->name, mt->name, sizeof(tx->name));
394 tx->width = mt->width;
395 tx->height = mt->height;
396 for (j=0 ; j<MIPLEVELS ; j++)
397 tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
398 // the pixels immediately follow the structures
399 memcpy ( tx+1, mt+1, pixels);
400
401 if (!Q_strncmp(mt->name,"sky",3))
402 R_InitSky (tx);
403 }
404
405//
406// sequence the animations
407//
408 for (i=0 ; i<m->nummiptex ; i++)
409 {
410 tx = loadmodel->textures[i];
411 if (!tx || tx->name[0] != '+')
412 continue;
413 if (tx->anim_next)
414 continue; // allready sequenced
415
416 // find the number of frames in the animation
417 memset (anims, 0, sizeof(anims));
418 memset (altanims, 0, sizeof(altanims));
419
420 max = tx->name[1];
421 altmax = 0;
422 if (max >= 'a' && max <= 'z')
423 max -= 'a' - 'A';
424 if (max >= '0' && max <= '9')
425 {
426 max -= '0';
427 altmax = 0;
428 anims[max] = tx;
429 max++;
430 }
431 else if (max >= 'A' && max <= 'J')
432 {
433 altmax = max - 'A';
434 max = 0;
435 altanims[altmax] = tx;
436 altmax++;
437 }
438 else
439 Sys_Error ("Bad animating texture %s", tx->name);
440
441 for (j=i+1 ; j<m->nummiptex ; j++)
442 {
443 tx2 = loadmodel->textures[j];
444 if (!tx2 || tx2->name[0] != '+')
445 continue;
446 if (strcmp (tx2->name+2, tx->name+2))
447 continue;
448
449 num = tx2->name[1];
450 if (num >= 'a' && num <= 'z')
451 num -= 'a' - 'A';
452 if (num >= '0' && num <= '9')
453 {
454 num -= '0';
455 anims[num] = tx2;
456 if (num+1 > max)
457 max = num + 1;
458 }
459 else if (num >= 'A' && num <= 'J')
460 {
461 num = num - 'A';
462 altanims[num] = tx2;
463 if (num+1 > altmax)
464 altmax = num+1;
465 }
466 else
467 Sys_Error ("Bad animating texture %s", tx->name);
468 }
469
470#define ANIM_CYCLE 2
471 // link them all together
472 for (j=0 ; j<max ; j++)
473 {
474 tx2 = anims[j];
475 if (!tx2)
476 Sys_Error ("Missing frame %i of %s",j, tx->name);
477 tx2->anim_total = max * ANIM_CYCLE;
478 tx2->anim_min = j * ANIM_CYCLE;
479 tx2->anim_max = (j+1) * ANIM_CYCLE;
480 tx2->anim_next = anims[ (j+1)%max ];
481 if (altmax)
482 tx2->alternate_anims = altanims[0];
483 }
484 for (j=0 ; j<altmax ; j++)
485 {
486 tx2 = altanims[j];
487 if (!tx2)
488 Sys_Error ("Missing frame %i of %s",j, tx->name);
489 tx2->anim_total = altmax * ANIM_CYCLE;
490 tx2->anim_min = j * ANIM_CYCLE;
491 tx2->anim_max = (j+1) * ANIM_CYCLE;
492 tx2->anim_next = altanims[ (j+1)%altmax ];
493 if (max)
494 tx2->alternate_anims = anims[0];
495 }
496 }
497}
498
499/*
500=================
501Mod_LoadLighting
502=================
503*/
504void Mod_LoadLighting (lump_t *l)
505{
506 if (!l->filelen)
507 {
508 loadmodel->lightdata = NULL;
509 return;
510 }
511 loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
512 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
513}
514
515
516/*
517=================
518Mod_LoadVisibility
519=================
520*/
521void Mod_LoadVisibility (lump_t *l)
522{
523 if (!l->filelen)
524 {
525 loadmodel->visdata = NULL;
526 return;
527 }
528 loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);
529 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
530}
531
532
533/*
534=================
535Mod_LoadEntities
536=================
537*/
538void Mod_LoadEntities (lump_t *l)
539{
540 if (!l->filelen)
541 {
542 loadmodel->entities = NULL;
543 return;
544 }
545 loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);
546 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
547}
548
549
550/*
551=================
552Mod_LoadVertexes
553=================
554*/
555void Mod_LoadVertexes (lump_t *l)
556{
557 dvertex_t *in;
558 mvertex_t *out;
559 int i, count;
560
561 in = (void *)(mod_base + l->fileofs);
562 if (l->filelen % sizeof(*in))
563 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
564 count = l->filelen / sizeof(*in);
565 out = Hunk_AllocName ( count*sizeof(*out), loadname);
566
567 loadmodel->vertexes = out;
568 loadmodel->numvertexes = count;
569
570 for ( i=0 ; i<count ; i++, in++, out++)
571 {
572 out->position[0] = LittleFloat (in->point[0]);
573 out->position[1] = LittleFloat (in->point[1]);
574 out->position[2] = LittleFloat (in->point[2]);
575 }
576}
577
578/*
579=================
580Mod_LoadSubmodels
581=================
582*/
583void Mod_LoadSubmodels (lump_t *l)
584{
585 dmodel_t *in;
586 dmodel_t *out;
587 int i, j, count;
588
589 in = (void *)(mod_base + l->fileofs);
590 if (l->filelen % sizeof(*in))
591 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
592 count = l->filelen / sizeof(*in);
593 out = Hunk_AllocName ( count*sizeof(*out), loadname);
594
595 loadmodel->submodels = out;
596 loadmodel->numsubmodels = count;
597
598 for ( i=0 ; i<count ; i++, in++, out++)
599 {
600 for (j=0 ; j<3 ; j++)
601 { // spread the mins / maxs by a pixel
602 out->mins[j] = LittleFloat (in->mins[j]) - 1;
603 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
604 out->origin[j] = LittleFloat (in->origin[j]);
605 }
606 for (j=0 ; j<MAX_MAP_HULLS ; j++)
607 out->headnode[j] = LittleLong (in->headnode[j]);
608 out->visleafs = LittleLong (in->visleafs);
609 out->firstface = LittleLong (in->firstface);
610 out->numfaces = LittleLong (in->numfaces);
611 }
612}
613
614/*
615=================
616Mod_LoadEdges
617=================
618*/
619void Mod_LoadEdges (lump_t *l)
620{
621 dedge_t *in;
622 medge_t *out;
623 int i, count;
624
625 in = (void *)(mod_base + l->fileofs);
626 if (l->filelen % sizeof(*in))
627 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
628 count = l->filelen / sizeof(*in);
629 out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);
630
631 loadmodel->edges = out;
632 loadmodel->numedges = count;
633
634 for ( i=0 ; i<count ; i++, in++, out++)
635 {
636 out->v[0] = (unsigned short)LittleShort(in->v[0]);
637 out->v[1] = (unsigned short)LittleShort(in->v[1]);
638 }
639}
640
641/*
642=================
643Mod_LoadTexinfo
644=================
645*/
646void Mod_LoadTexinfo (lump_t *l)
647{
648 texinfo_t *in;
649 mtexinfo_t *out;
650 int i, j, count;
651 int miptex;
652 float len1, len2;
653
654 in = (void *)(mod_base + l->fileofs);
655 if (l->filelen % sizeof(*in))
656 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
657 count = l->filelen / sizeof(*in);
658 out = Hunk_AllocName ( count*sizeof(*out), loadname);
659
660 loadmodel->texinfo = out;
661 loadmodel->numtexinfo = count;
662
663 for ( i=0 ; i<count ; i++, in++, out++)
664 {
665 for (j=0 ; j<8 ; j++)
666 out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
667 len1 = Length (out->vecs[0]);
668 len2 = Length (out->vecs[1]);
669 len1 = (len1 + len2)/2;
670 if (len1 < 0.32)
671 out->mipadjust = 4;
672 else if (len1 < 0.49)
673 out->mipadjust = 3;
674 else if (len1 < 0.99)
675 out->mipadjust = 2;
676 else
677 out->mipadjust = 1;
678#if 0
679 if (len1 + len2 < 0.001)
680 out->mipadjust = 1; // don't crash
681 else
682 out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
683#endif
684
685 miptex = LittleLong (in->miptex);
686 out->flags = LittleLong (in->flags);
687
688 if (!loadmodel->textures)
689 {
690 out->texture = r_notexture_mip; // checkerboard texture
691 out->flags = 0;
692 }
693 else
694 {
695 if (miptex >= loadmodel->numtextures)
696 Sys_Error ("miptex >= loadmodel->numtextures");
697 out->texture = loadmodel->textures[miptex];
698 if (!out->texture)
699 {
700 out->texture = r_notexture_mip; // texture not found
701 out->flags = 0;
702 }
703 }
704 }
705}
706
707/*
708================
709CalcSurfaceExtents
710
711Fills in s->texturemins[] and s->extents[]
712================
713*/
714void CalcSurfaceExtents (msurface_t *s)
715{
716 float mins[2], maxs[2], val;
717 int i,j, e;
718 mvertex_t *v;
719 mtexinfo_t *tex;
720 int bmins[2], bmaxs[2];
721
722 mins[0] = mins[1] = 999999;
723 maxs[0] = maxs[1] = -99999;
724
725 tex = s->texinfo;
726
727 for (i=0 ; i<s->numedges ; i++)
728 {
729 e = loadmodel->surfedges[s->firstedge+i];
730 if (e >= 0)
731 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
732 else
733 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
734
735 for (j=0 ; j<2 ; j++)
736 {
737 val = v->position[0] * tex->vecs[j][0] +
738 v->position[1] * tex->vecs[j][1] +
739 v->position[2] * tex->vecs[j][2] +
740 tex->vecs[j][3];
741 if (val < mins[j])
742 mins[j] = val;
743 if (val > maxs[j])
744 maxs[j] = val;
745 }
746 }
747
748 for (i=0 ; i<2 ; i++)
749 {
750 bmins[i] = floor(mins[i]/16);
751 bmaxs[i] = ceil(maxs[i]/16);
752
753 s->texturemins[i] = bmins[i] * 16;
754 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
755 if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256)
756 Sys_Error ("Bad surface extents");
757 }
758}
759
760
761/*
762=================
763Mod_LoadFaces
764=================
765*/
766void Mod_LoadFaces (lump_t *l)
767{
768 dface_t *in;
769 msurface_t *out;
770 int i, count, surfnum;
771 int planenum, side;
772
773 in = (void *)(mod_base + l->fileofs);
774 if (l->filelen % sizeof(*in))
775 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
776 count = l->filelen / sizeof(*in);
777 out = Hunk_AllocName ( count*sizeof(*out), loadname);
778
779 loadmodel->surfaces = out;
780 loadmodel->numsurfaces = count;
781
782 for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
783 {
784 out->firstedge = LittleLong(in->firstedge);
785 out->numedges = LittleShort(in->numedges);
786 out->flags = 0;
787
788 planenum = LittleShort(in->planenum);
789 side = LittleShort(in->side);
790 if (side)
791 out->flags |= SURF_PLANEBACK;
792
793 out->plane = loadmodel->planes + planenum;
794
795 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
796
797 CalcSurfaceExtents (out);
798
799 // lighting info
800
801 for (i=0 ; i<MAXLIGHTMAPS ; i++)
802 out->styles[i] = in->styles[i];
803 i = LittleLong(in->lightofs);
804 if (i == -1)
805 out->samples = NULL;
806 else
807 out->samples = loadmodel->lightdata + i;
808
809 // set the drawing flags flag
810
811 if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky
812 {
813 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
814 continue;
815 }
816
817 if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent
818 {
819 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
820 for (i=0 ; i<2 ; i++)
821 {
822 out->extents[i] = 16384;
823 out->texturemins[i] = -8192;
824 }
825 continue;
826 }
827 }
828}
829
830
831/*
832=================
833Mod_SetParent
834=================
835*/
836void Mod_SetParent (mnode_t *node, mnode_t *parent)
837{
838 node->parent = parent;
839 if (node->contents < 0)
840 return;
841 Mod_SetParent (node->children[0], node);
842 Mod_SetParent (node->children[1], node);
843}
844
845/*
846=================
847Mod_LoadNodes
848=================
849*/
850void Mod_LoadNodes (lump_t *l)
851{
852 int i, j, count, p;
853 dnode_t *in;
854 mnode_t *out;
855
856 in = (void *)(mod_base + l->fileofs);
857 if (l->filelen % sizeof(*in))
858 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
859 count = l->filelen / sizeof(*in);
860 out = Hunk_AllocName ( count*sizeof(*out), loadname);
861
862 loadmodel->nodes = out;
863 loadmodel->numnodes = count;
864
865 for ( i=0 ; i<count ; i++, in++, out++)
866 {
867 for (j=0 ; j<3 ; j++)
868 {
869 out->minmaxs[j] = LittleShort (in->mins[j]);
870 out->minmaxs[3+j] = LittleShort (in->maxs[j]);
871 }
872
873 p = LittleLong(in->planenum);
874 out->plane = loadmodel->planes + p;
875
876 out->firstsurface = LittleShort (in->firstface);
877 out->numsurfaces = LittleShort (in->numfaces);
878
879 for (j=0 ; j<2 ; j++)
880 {
881 p = LittleShort (in->children[j]);
882 if (p >= 0)
883 out->children[j] = loadmodel->nodes + p;
884 else
885 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
886 }
887 }
888
889 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
890}
891
892/*
893=================
894Mod_LoadLeafs
895=================
896*/
897void Mod_LoadLeafs (lump_t *l)
898{
899 dleaf_t *in;
900 mleaf_t *out;
901 int i, j, count, p;
902
903 in = (void *)(mod_base + l->fileofs);
904 if (l->filelen % sizeof(*in))
905 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
906 count = l->filelen / sizeof(*in);
907 out = Hunk_AllocName ( count*sizeof(*out), loadname);
908
909 loadmodel->leafs = out;
910 loadmodel->numleafs = count;
911
912 for ( i=0 ; i<count ; i++, in++, out++)
913 {
914 for (j=0 ; j<3 ; j++)
915 {
916 out->minmaxs[j] = LittleShort (in->mins[j]);
917 out->minmaxs[3+j] = LittleShort (in->maxs[j]);
918 }
919
920 p = LittleLong(in->contents);
921 out->contents = p;
922
923 out->firstmarksurface = loadmodel->marksurfaces +
924 LittleShort(in->firstmarksurface);
925 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
926
927 p = LittleLong(in->visofs);
928 if (p == -1)
929 out->compressed_vis = NULL;
930 else
931 out->compressed_vis = loadmodel->visdata + p;
932 out->efrags = NULL;
933
934 for (j=0 ; j<4 ; j++)
935 out->ambient_sound_level[j] = in->ambient_level[j];
936 }
937}
938
939/*
940=================
941Mod_LoadClipnodes
942=================
943*/
944void Mod_LoadClipnodes (lump_t *l)
945{
946 dclipnode_t *in, *out;
947 int i, count;
948 hull_t *hull;
949
950 in = (void *)(mod_base + l->fileofs);
951 if (l->filelen % sizeof(*in))
952 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
953 count = l->filelen / sizeof(*in);
954 out = Hunk_AllocName ( count*sizeof(*out), loadname);
955
956 loadmodel->clipnodes = out;
957 loadmodel->numclipnodes = count;
958
959 hull = &loadmodel->hulls[1];
960 hull->clipnodes = out;
961 hull->firstclipnode = 0;
962 hull->lastclipnode = count-1;
963 hull->planes = loadmodel->planes;
964 hull->clip_mins[0] = -16;
965 hull->clip_mins[1] = -16;
966 hull->clip_mins[2] = -24;
967 hull->clip_maxs[0] = 16;
968 hull->clip_maxs[1] = 16;
969 hull->clip_maxs[2] = 32;
970
971 hull = &loadmodel->hulls[2];
972 hull->clipnodes = out;
973 hull->firstclipnode = 0;
974 hull->lastclipnode = count-1;
975 hull->planes = loadmodel->planes;
976 hull->clip_mins[0] = -32;
977 hull->clip_mins[1] = -32;
978 hull->clip_mins[2] = -24;
979 hull->clip_maxs[0] = 32;
980 hull->clip_maxs[1] = 32;
981 hull->clip_maxs[2] = 64;
982
983 for (i=0 ; i<count ; i++, out++, in++)
984 {
985 out->planenum = LittleLong(in->planenum);
986 out->children[0] = LittleShort(in->children[0]);
987 out->children[1] = LittleShort(in->children[1]);
988 }
989}
990
991/*
992=================
993Mod_MakeHull0
994
995Deplicate the drawing hull structure as a clipping hull
996=================
997*/
998void Mod_MakeHull0 (void)
999{
1000 mnode_t *in, *child;
1001 dclipnode_t *out;
1002 int i, j, count;
1003 hull_t *hull;
1004
1005 hull = &loadmodel->hulls[0];
1006
1007 in = loadmodel->nodes;
1008 count = loadmodel->numnodes;
1009 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1010
1011 hull->clipnodes = out;
1012 hull->firstclipnode = 0;
1013 hull->lastclipnode = count-1;
1014 hull->planes = loadmodel->planes;
1015
1016 for (i=0 ; i<count ; i++, out++, in++)
1017 {
1018 out->planenum = in->plane - loadmodel->planes;
1019 for (j=0 ; j<2 ; j++)
1020 {
1021 child = in->children[j];
1022 if (child->contents < 0)
1023 out->children[j] = child->contents;
1024 else
1025 out->children[j] = child - loadmodel->nodes;
1026 }
1027 }
1028}
1029
1030/*
1031=================
1032Mod_LoadMarksurfaces
1033=================
1034*/
1035void Mod_LoadMarksurfaces (lump_t *l)
1036{
1037 int i, j, count;
1038 short *in;
1039 msurface_t **out;
1040
1041 in = (void *)(mod_base + l->fileofs);
1042 if (l->filelen % sizeof(*in))
1043 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1044 count = l->filelen / sizeof(*in);
1045 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1046
1047 loadmodel->marksurfaces = out;
1048 loadmodel->nummarksurfaces = count;
1049
1050 for ( i=0 ; i<count ; i++)
1051 {
1052 j = LittleShort(in[i]);
1053 if (j >= loadmodel->numsurfaces)
1054 Sys_Error ("Mod_ParseMarksurfaces: bad surface number");
1055 out[i] = loadmodel->surfaces + j;
1056 }
1057}
1058
1059/*
1060=================
1061Mod_LoadSurfedges
1062=================
1063*/
1064void Mod_LoadSurfedges (lump_t *l)
1065{
1066 int i, count;
1067 int *in, *out;
1068
1069 in = (void *)(mod_base + l->fileofs);
1070 if (l->filelen % sizeof(*in))
1071 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1072 count = l->filelen / sizeof(*in);
1073 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1074
1075 loadmodel->surfedges = out;
1076 loadmodel->numsurfedges = count;
1077
1078 for ( i=0 ; i<count ; i++)
1079 out[i] = LittleLong (in[i]);
1080}
1081
1082/*
1083=================
1084Mod_LoadPlanes
1085=================
1086*/
1087void Mod_LoadPlanes (lump_t *l)
1088{
1089 int i, j;
1090 mplane_t *out;
1091 dplane_t *in;
1092 int count;
1093 int bits;
1094
1095 in = (void *)(mod_base + l->fileofs);
1096 if (l->filelen % sizeof(*in))
1097 Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1098 count = l->filelen / sizeof(*in);
1099 out = Hunk_AllocName ( count*2*sizeof(*out), loadname);
1100
1101 loadmodel->planes = out;
1102 loadmodel->numplanes = count;
1103
1104 for ( i=0 ; i<count ; i++, in++, out++)
1105 {
1106 bits = 0;
1107 for (j=0 ; j<3 ; j++)
1108 {
1109 out->normal[j] = LittleFloat (in->normal[j]);
1110 if (out->normal[j] < 0)
1111 bits |= 1<<j;
1112 }
1113
1114 out->dist = LittleFloat (in->dist);
1115 out->type = LittleLong (in->type);
1116 out->signbits = bits;
1117 }
1118}
1119
1120/*
1121=================
1122RadiusFromBounds
1123=================
1124*/
1125float RadiusFromBounds (vec3_t mins, vec3_t maxs)
1126{
1127 int i;
1128 vec3_t corner;
1129
1130 for (i=0 ; i<3 ; i++)
1131 {
1132 corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
1133 }
1134
1135 return Length (corner);
1136}
1137
1138/*
1139=================
1140Mod_LoadBrushModel
1141=================
1142*/
1143void Mod_LoadBrushModel (model_t *mod, void *buffer)
1144{
1145 int i, j;
1146 dheader_t *header;
1147 dmodel_t *bm;
1148
1149 loadmodel->type = mod_brush;
1150
1151 header = (dheader_t *)buffer;
1152
1153 i = LittleLong (header->version);
1154 if (i != BSPVERSION)
1155 rb->splashf (HZ, "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
1156
1157// swap all the lumps
1158 mod_base = (byte *)header;
1159
1160 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1161 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1162
1163// load into heap
1164
1165 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1166 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1167 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1168 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1169 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1170 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1171 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1172 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1173 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1174 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1175 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1176 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1177 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1178 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1179 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1180
1181 Mod_MakeHull0 ();
1182
1183 mod->numframes = 2; // regular and alternate animation
1184 mod->flags = 0;
1185
1186//
1187// set up the submodels (FIXME: this is confusing)
1188//
1189 for (i=0 ; i<mod->numsubmodels ; i++)
1190 {
1191 bm = &mod->submodels[i];
1192
1193 mod->hulls[0].firstclipnode = bm->headnode[0];
1194 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1195 {
1196 mod->hulls[j].firstclipnode = bm->headnode[j];
1197 mod->hulls[j].lastclipnode = mod->numclipnodes-1;
1198 }
1199
1200 mod->firstmodelsurface = bm->firstface;
1201 mod->nummodelsurfaces = bm->numfaces;
1202
1203 VectorCopy (bm->maxs, mod->maxs);
1204 VectorCopy (bm->mins, mod->mins);
1205 mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1206
1207 mod->numleafs = bm->visleafs;
1208
1209 if (i < mod->numsubmodels-1)
1210 { // duplicate the basic information
1211 char name[10];
1212
1213 sprintf (name, "*%i", i+1);
1214 loadmodel = Mod_FindName (name);
1215 *loadmodel = *mod;
1216 strcpy (loadmodel->name, name);
1217 mod = loadmodel;
1218 }
1219 }
1220}
1221
1222/*
1223==============================================================================
1224
1225ALIAS MODELS
1226
1227==============================================================================
1228*/
1229
1230/*
1231=================
1232Mod_LoadAliasFrame
1233=================
1234*/
1235void * Mod_LoadAliasFrame (void * pin, int *pframeindex, int numv,
1236 trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
1237{
1238 trivertx_t *pframe, *pinframe;
1239 int i, j;
1240 daliasframe_t *pdaliasframe;
1241
1242 pdaliasframe = (daliasframe_t *)pin;
1243
1244 strcpy (name, pdaliasframe->name);
1245
1246 for (i=0 ; i<3 ; i++)
1247 {
1248 // these are byte values, so we don't have to worry about
1249 // endianness
1250 pbboxmin->v[i] = pdaliasframe->bboxmin.v[i];
1251 pbboxmax->v[i] = pdaliasframe->bboxmax.v[i];
1252 }
1253
1254 pinframe = (trivertx_t *)(pdaliasframe + 1);
1255 pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname);
1256
1257 *pframeindex = (byte *)pframe - (byte *)pheader;
1258
1259 for (j=0 ; j<numv ; j++)
1260 {
1261 int k;
1262
1263 // these are all byte values, so no need to deal with endianness
1264 pframe[j].lightnormalindex = pinframe[j].lightnormalindex;
1265
1266 for (k=0 ; k<3 ; k++)
1267 {
1268 pframe[j].v[k] = pinframe[j].v[k];
1269 }
1270 }
1271
1272 pinframe += numv;
1273
1274 return (void *)pinframe;
1275}
1276
1277
1278/*
1279=================
1280Mod_LoadAliasGroup
1281=================
1282*/
1283void * Mod_LoadAliasGroup (void * pin, int *pframeindex, int numv,
1284 trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
1285{
1286 daliasgroup_t *pingroup;
1287 maliasgroup_t *paliasgroup;
1288 int i, numframes;
1289 daliasinterval_t *pin_intervals;
1290 float *poutintervals;
1291 void *ptemp;
1292
1293 pingroup = (daliasgroup_t *)pin;
1294
1295 numframes = LittleLong (pingroup->numframes);
1296
1297 paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) +
1298 (numframes - 1) * sizeof (paliasgroup->frames[0]), loadname);
1299
1300 paliasgroup->numframes = numframes;
1301
1302 for (i=0 ; i<3 ; i++)
1303 {
1304 // these are byte values, so we don't have to worry about endianness
1305 pbboxmin->v[i] = pingroup->bboxmin.v[i];
1306 pbboxmax->v[i] = pingroup->bboxmax.v[i];
1307 }
1308
1309 *pframeindex = (byte *)paliasgroup - (byte *)pheader;
1310
1311 pin_intervals = (daliasinterval_t *)(pingroup + 1);
1312
1313 poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
1314
1315 paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader;
1316
1317 for (i=0 ; i<numframes ; i++)
1318 {
1319 *poutintervals = LittleFloat (pin_intervals->interval);
1320 if (*poutintervals <= 0.0)
1321 Sys_Error ("Mod_LoadAliasGroup: interval<=0");
1322
1323 poutintervals++;
1324 pin_intervals++;
1325 }
1326
1327 ptemp = (void *)pin_intervals;
1328
1329 for (i=0 ; i<numframes ; i++)
1330 {
1331 ptemp = Mod_LoadAliasFrame (ptemp,
1332 &paliasgroup->frames[i].frame,
1333 numv,
1334 &paliasgroup->frames[i].bboxmin,
1335 &paliasgroup->frames[i].bboxmax,
1336 pheader, name);
1337 }
1338
1339 return ptemp;
1340}
1341
1342
1343/*
1344=================
1345Mod_LoadAliasSkin
1346=================
1347*/
1348void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize,
1349 aliashdr_t *pheader)
1350{
1351 int i;
1352 byte *pskin, *pinskin;
1353 unsigned short *pusskin;
1354
1355 pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
1356 pinskin = (byte *)pin;
1357 *pskinindex = (byte *)pskin - (byte *)pheader;
1358
1359 if (r_pixbytes == 1)
1360 {
1361 Q_memcpy (pskin, pinskin, skinsize);
1362 }
1363 else if (r_pixbytes == 2)
1364 {
1365 pusskin = (unsigned short *)pskin;
1366
1367 for (i=0 ; i<skinsize ; i++)
1368 pusskin[i] = d_8to16table[pinskin[i]];
1369 }
1370 else
1371 {
1372 Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n",
1373 r_pixbytes);
1374 }
1375
1376 pinskin += skinsize;
1377
1378 return ((void *)pinskin);
1379}
1380
1381
1382/*
1383=================
1384Mod_LoadAliasSkinGroup
1385=================
1386*/
1387void * Mod_LoadAliasSkinGroup (void * pin, int *pskinindex, int skinsize,
1388 aliashdr_t *pheader)
1389{
1390 daliasskingroup_t *pinskingroup;
1391 maliasskingroup_t *paliasskingroup;
1392 int i, numskins;
1393 daliasskininterval_t *pinskinintervals;
1394 float *poutskinintervals;
1395 void *ptemp;
1396
1397 pinskingroup = (daliasskingroup_t *)pin;
1398
1399 numskins = LittleLong (pinskingroup->numskins);
1400
1401 paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) +
1402 (numskins - 1) * sizeof (paliasskingroup->skindescs[0]),
1403 loadname);
1404
1405 paliasskingroup->numskins = numskins;
1406
1407 *pskinindex = (byte *)paliasskingroup - (byte *)pheader;
1408
1409 pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
1410
1411 poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname);
1412
1413 paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader;
1414
1415 for (i=0 ; i<numskins ; i++)
1416 {
1417 *poutskinintervals = LittleFloat (pinskinintervals->interval);
1418 if (*poutskinintervals <= 0)
1419 Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");
1420
1421 poutskinintervals++;
1422 pinskinintervals++;
1423 }
1424
1425 ptemp = (void *)pinskinintervals;
1426
1427 for (i=0 ; i<numskins ; i++)
1428 {
1429 ptemp = Mod_LoadAliasSkin (ptemp,
1430 &paliasskingroup->skindescs[i].skin, skinsize, pheader);
1431 }
1432
1433 return ptemp;
1434}
1435
1436
1437/*
1438=================
1439Mod_LoadAliasModel
1440=================
1441*/
1442void Mod_LoadAliasModel (model_t *mod, void *buffer)
1443{
1444 int i;
1445 mdl_t *pmodel, *pinmodel;
1446 stvert_t *pstverts, *pinstverts;
1447 aliashdr_t *pheader;
1448 mtriangle_t *ptri;
1449 dtriangle_t *pintriangles;
1450 int version, numframes, numskins;
1451 int size;
1452 daliasframetype_t *pframetype;
1453 daliasskintype_t *pskintype;
1454 maliasskindesc_t *pskindesc;
1455 int skinsize;
1456 int start, end, total;
1457
1458 start = Hunk_LowMark ();
1459
1460 pinmodel = (mdl_t *)buffer;
1461
1462 version = LittleLong (pinmodel->version);
1463 if (version != ALIAS_VERSION)
1464 Sys_Error ("%s has wrong version number (%i should be %i)",
1465 mod->name, version, ALIAS_VERSION);
1466
1467//
1468// allocate space for a working header, plus all the data except the frames,
1469// skin and group info
1470//
1471 size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) *
1472 sizeof (pheader->frames[0]) +
1473 sizeof (mdl_t) +
1474 LittleLong (pinmodel->numverts) * sizeof (stvert_t) +
1475 LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);
1476
1477 pheader = Hunk_AllocName (size, loadname);
1478 pmodel = (mdl_t *) ((byte *)&pheader[1] +
1479 (LittleLong (pinmodel->numframes) - 1) *
1480 sizeof (pheader->frames[0]));
1481
1482// mod->cache.data = pheader;
1483 mod->flags = LittleLong (pinmodel->flags);
1484
1485//
1486// endian-adjust and copy the data, starting with the alias model header
1487//
1488 pmodel->boundingradius = LittleFloat (pinmodel->boundingradius);
1489 pmodel->numskins = LittleLong (pinmodel->numskins);
1490 pmodel->skinwidth = LittleLong (pinmodel->skinwidth);
1491 pmodel->skinheight = LittleLong (pinmodel->skinheight);
1492
1493 if (pmodel->skinheight > MAX_LBM_HEIGHT)
1494 Sys_Error ("model %s has a skin taller than %d", mod->name,
1495 MAX_LBM_HEIGHT);
1496
1497 pmodel->numverts = LittleLong (pinmodel->numverts);
1498
1499 if (pmodel->numverts <= 0)
1500 Sys_Error ("model %s has no vertices", mod->name);
1501
1502 if (pmodel->numverts > MAXALIASVERTS)
1503 Sys_Error ("model %s has too many vertices", mod->name);
1504
1505 pmodel->numtris = LittleLong (pinmodel->numtris);
1506
1507 if (pmodel->numtris <= 0)
1508 Sys_Error ("model %s has no triangles", mod->name);
1509
1510 pmodel->numframes = LittleLong (pinmodel->numframes);
1511 pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
1512 mod->synctype = LittleLong (pinmodel->synctype);
1513 mod->numframes = pmodel->numframes;
1514
1515 for (i=0 ; i<3 ; i++)
1516 {
1517 pmodel->scale[i] = LittleFloat (pinmodel->scale[i]);
1518 pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
1519 pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
1520 }
1521
1522 numskins = pmodel->numskins;
1523 numframes = pmodel->numframes;
1524
1525 if (pmodel->skinwidth & 0x03)
1526 Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");
1527
1528 pheader->model = (byte *)pmodel - (byte *)pheader;
1529
1530//
1531// load the skins
1532//
1533 skinsize = pmodel->skinheight * pmodel->skinwidth;
1534
1535 if (numskins < 1)
1536 Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
1537
1538 pskintype = (daliasskintype_t *)&pinmodel[1];
1539
1540 pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
1541 loadname);
1542
1543 pheader->skindesc = (byte *)pskindesc - (byte *)pheader;
1544
1545 for (i=0 ; i<numskins ; i++)
1546 {
1547 aliasskintype_t skintype;
1548
1549 skintype = LittleLong (pskintype->type);
1550 pskindesc[i].type = skintype;
1551
1552 if (skintype == ALIAS_SKIN_SINGLE)
1553 {
1554 pskintype = (daliasskintype_t *)
1555 Mod_LoadAliasSkin (pskintype + 1,
1556 &pskindesc[i].skin,
1557 skinsize, pheader);
1558 }
1559 else
1560 {
1561 pskintype = (daliasskintype_t *)
1562 Mod_LoadAliasSkinGroup (pskintype + 1,
1563 &pskindesc[i].skin,
1564 skinsize, pheader);
1565 }
1566 }
1567
1568//
1569// set base s and t vertices
1570//
1571 pstverts = (stvert_t *)&pmodel[1];
1572 pinstverts = (stvert_t *)pskintype;
1573
1574 pheader->stverts = (byte *)pstverts - (byte *)pheader;
1575
1576 for (i=0 ; i<pmodel->numverts ; i++)
1577 {
1578 pstverts[i].onseam = LittleLong (pinstverts[i].onseam);
1579 // put s and t in 16.16 format
1580 pstverts[i].s = LittleLong (pinstverts[i].s) << 16;
1581 pstverts[i].t = LittleLong (pinstverts[i].t) << 16;
1582 }
1583
1584//
1585// set up the triangles
1586//
1587 ptri = (mtriangle_t *)&pstverts[pmodel->numverts];
1588 pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts];
1589
1590 pheader->triangles = (byte *)ptri - (byte *)pheader;
1591
1592 for (i=0 ; i<pmodel->numtris ; i++)
1593 {
1594 int j;
1595
1596 ptri[i].facesfront = LittleLong (pintriangles[i].facesfront);
1597
1598 for (j=0 ; j<3 ; j++)
1599 {
1600 ptri[i].vertindex[j] =
1601 LittleLong (pintriangles[i].vertindex[j]);
1602 }
1603 }
1604
1605//
1606// load the frames
1607//
1608 if (numframes < 1)
1609 Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
1610
1611 pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris];
1612
1613 for (i=0 ; i<numframes ; i++)
1614 {
1615 aliasframetype_t frametype;
1616
1617 frametype = LittleLong (pframetype->type);
1618 pheader->frames[i].type = frametype;
1619
1620 if (frametype == ALIAS_SINGLE)
1621 {
1622 pframetype = (daliasframetype_t *)
1623 Mod_LoadAliasFrame (pframetype + 1,
1624 &pheader->frames[i].frame,
1625 pmodel->numverts,
1626 &pheader->frames[i].bboxmin,
1627 &pheader->frames[i].bboxmax,
1628 pheader, pheader->frames[i].name);
1629 }
1630 else
1631 {
1632 pframetype = (daliasframetype_t *)
1633 Mod_LoadAliasGroup (pframetype + 1,
1634 &pheader->frames[i].frame,
1635 pmodel->numverts,
1636 &pheader->frames[i].bboxmin,
1637 &pheader->frames[i].bboxmax,
1638 pheader, pheader->frames[i].name);
1639 }
1640 }
1641
1642 mod->type = mod_alias;
1643
1644// FIXME: do this right
1645 mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;
1646 mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;
1647
1648//
1649// move the complete, relocatable alias model to the cache
1650//
1651 end = Hunk_LowMark ();
1652 total = end - start;
1653
1654 Cache_Alloc (&mod->cache, total, loadname);
1655 if (!mod->cache.data)
1656 return;
1657 memcpy (mod->cache.data, pheader, total);
1658
1659 Hunk_FreeToLowMark (start);
1660}
1661
1662//=============================================================================
1663
1664/*
1665=================
1666Mod_LoadSpriteFrame
1667=================
1668*/
1669void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe)
1670{
1671 dspriteframe_t *pinframe;
1672 mspriteframe_t *pspriteframe;
1673 int i, width, height, size, origin[2];
1674 unsigned short *ppixout;
1675 byte *ppixin;
1676
1677 pinframe = (dspriteframe_t *)pin;
1678
1679 width = LittleLong (pinframe->width);
1680 height = LittleLong (pinframe->height);
1681 size = width * height;
1682
1683 pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes,
1684 loadname);
1685
1686 Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size);
1687 *ppframe = pspriteframe;
1688
1689 pspriteframe->width = width;
1690 pspriteframe->height = height;
1691 origin[0] = LittleLong (pinframe->origin[0]);
1692 origin[1] = LittleLong (pinframe->origin[1]);
1693
1694 pspriteframe->up = origin[1];
1695 pspriteframe->down = origin[1] - height;
1696 pspriteframe->left = origin[0];
1697 pspriteframe->right = width + origin[0];
1698
1699 if (r_pixbytes == 1)
1700 {
1701 Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size);
1702 }
1703 else if (r_pixbytes == 2)
1704 {
1705 ppixin = (byte *)(pinframe + 1);
1706 ppixout = (unsigned short *)&pspriteframe->pixels[0];
1707
1708 for (i=0 ; i<size ; i++)
1709 ppixout[i] = d_8to16table[ppixin[i]];
1710 }
1711 else
1712 {
1713 Sys_Error ("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n",
1714 r_pixbytes);
1715 }
1716
1717 return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
1718}
1719
1720
1721/*
1722=================
1723Mod_LoadSpriteGroup
1724=================
1725*/
1726void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe)
1727{
1728 dspritegroup_t *pingroup;
1729 mspritegroup_t *pspritegroup;
1730 int i, numframes;
1731 dspriteinterval_t *pin_intervals;
1732 float *poutintervals;
1733 void *ptemp;
1734
1735 pingroup = (dspritegroup_t *)pin;
1736
1737 numframes = LittleLong (pingroup->numframes);
1738
1739 pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
1740 (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
1741
1742 pspritegroup->numframes = numframes;
1743
1744 *ppframe = (mspriteframe_t *)pspritegroup;
1745
1746 pin_intervals = (dspriteinterval_t *)(pingroup + 1);
1747
1748 poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
1749
1750 pspritegroup->intervals = poutintervals;
1751
1752 for (i=0 ; i<numframes ; i++)
1753 {
1754 *poutintervals = LittleFloat (pin_intervals->interval);
1755 if (*poutintervals <= 0.0)
1756 Sys_Error ("Mod_LoadSpriteGroup: interval<=0");
1757
1758 poutintervals++;
1759 pin_intervals++;
1760 }
1761
1762 ptemp = (void *)pin_intervals;
1763
1764 for (i=0 ; i<numframes ; i++)
1765 {
1766 ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i]);
1767 }
1768
1769 return ptemp;
1770}
1771
1772
1773/*
1774=================
1775Mod_LoadSpriteModel
1776=================
1777*/
1778void Mod_LoadSpriteModel (model_t *mod, void *buffer)
1779{
1780 int i;
1781 int version;
1782 dsprite_t *pin;
1783 msprite_t *psprite;
1784 int numframes;
1785 int size;
1786 dspriteframetype_t *pframetype;
1787
1788 pin = (dsprite_t *)buffer;
1789
1790 version = LittleLong (pin->version);
1791 if (version != SPRITE_VERSION)
1792 Sys_Error ("%s has wrong version number "
1793 "(%i should be %i)", mod->name, version, SPRITE_VERSION);
1794
1795 numframes = LittleLong (pin->numframes);
1796
1797 size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames);
1798
1799 psprite = Hunk_AllocName (size, loadname);
1800
1801 mod->cache.data = psprite;
1802
1803 psprite->type = LittleLong (pin->type);
1804 psprite->maxwidth = LittleLong (pin->width);
1805 psprite->maxheight = LittleLong (pin->height);
1806 psprite->beamlength = LittleFloat (pin->beamlength);
1807 mod->synctype = LittleLong (pin->synctype);
1808 psprite->numframes = numframes;
1809
1810 mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
1811 mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;
1812 mod->mins[2] = -psprite->maxheight/2;
1813 mod->maxs[2] = psprite->maxheight/2;
1814
1815//
1816// load the frames
1817//
1818 if (numframes < 1)
1819 Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
1820
1821 mod->numframes = numframes;
1822 mod->flags = 0;
1823
1824 pframetype = (dspriteframetype_t *)(pin + 1);
1825
1826 for (i=0 ; i<numframes ; i++)
1827 {
1828 spriteframetype_t frametype;
1829
1830 frametype = LittleLong (pframetype->type);
1831 psprite->frames[i].type = frametype;
1832
1833 if (frametype == SPR_SINGLE)
1834 {
1835 pframetype = (dspriteframetype_t *)
1836 Mod_LoadSpriteFrame (pframetype + 1,
1837 &psprite->frames[i].frameptr);
1838 }
1839 else
1840 {
1841 pframetype = (dspriteframetype_t *)
1842 Mod_LoadSpriteGroup (pframetype + 1,
1843 &psprite->frames[i].frameptr);
1844 }
1845 }
1846
1847 mod->type = mod_sprite;
1848}
1849
1850//=============================================================================
1851
1852/*
1853================
1854Mod_Print
1855================
1856*/
1857void Mod_Print (void)
1858{
1859 int i;
1860 model_t *mod;
1861
1862 Con_Printf ("Cached models:\n");
1863 for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
1864 {
1865 Con_Printf ("%8p : %s",mod->cache.data, mod->name);
1866 if (mod->needload & NL_UNREFERENCED)
1867 Con_Printf (" (!R)");
1868 if (mod->needload & NL_NEEDS_LOADED)
1869 Con_Printf (" (!P)");
1870 Con_Printf ("\n");
1871 }
1872}
1873
1874
diff --git a/apps/plugins/sdl/progs/quake/model.h b/apps/plugins/sdl/progs/quake/model.h
new file mode 100644
index 0000000000..899010f0fb
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/model.h
@@ -0,0 +1,383 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#ifndef __MODEL__
22#define __MODEL__
23
24#include "modelgen.h"
25#include "spritegn.h"
26
27/*
28
29d*_t structures are on-disk representations
30m*_t structures are in-memory
31
32*/
33
34/*
35==============================================================================
36
37BRUSH MODELS
38
39==============================================================================
40*/
41
42
43//
44// in memory representation
45//
46// !!! if this is changed, it must be changed in asm_draw.h too !!!
47typedef struct
48{
49 vec3_t position;
50} mvertex_t;
51
52#define SIDE_FRONT 0
53#define SIDE_BACK 1
54#define SIDE_ON 2
55
56
57// plane_t structure
58// !!! if this is changed, it must be changed in asm_i386.h too !!!
59typedef struct mplane_s
60{
61 vec3_t normal;
62 float dist;
63 byte type; // for texture axis selection and fast side tests
64 byte signbits; // signx + signy<<1 + signz<<1
65 byte pad[2];
66} mplane_t;
67
68typedef struct texture_s
69{
70 char name[16];
71 unsigned width, height;
72 int anim_total; // total tenths in sequence ( 0 = no)
73 int anim_min, anim_max; // time for this frame min <=time< max
74 struct texture_s *anim_next; // in the animation sequence
75 struct texture_s *alternate_anims; // bmodels in frmae 1 use these
76 unsigned offsets[MIPLEVELS]; // four mip maps stored
77} texture_t;
78
79
80#define SURF_PLANEBACK 2
81#define SURF_DRAWSKY 4
82#define SURF_DRAWSPRITE 8
83#define SURF_DRAWTURB 0x10
84#define SURF_DRAWTILED 0x20
85#define SURF_DRAWBACKGROUND 0x40
86
87// !!! if this is changed, it must be changed in asm_draw.h too !!!
88typedef struct
89{
90 unsigned short v[2];
91 unsigned int cachededgeoffset;
92} medge_t;
93
94typedef struct
95{
96 float vecs[2][4];
97 float mipadjust;
98 texture_t *texture;
99 int flags;
100} mtexinfo_t;
101
102typedef struct msurface_s
103{
104 int visframe; // should be drawn when node is crossed
105
106 int dlightframe;
107 int dlightbits;
108
109 mplane_t *plane;
110 int flags;
111
112 int firstedge; // look up in model->surfedges[], negative numbers
113 int numedges; // are backwards edges
114
115// surface generation data
116 struct surfcache_s *cachespots[MIPLEVELS];
117
118 short texturemins[2];
119 short extents[2];
120
121 mtexinfo_t *texinfo;
122
123// lighting info
124 byte styles[MAXLIGHTMAPS];
125 byte *samples; // [numstyles*surfsize]
126} msurface_t;
127
128typedef struct mnode_s
129{
130// common with leaf
131 int contents; // 0, to differentiate from leafs
132 int visframe; // node needs to be traversed if current
133
134 short minmaxs[6]; // for bounding box culling
135
136 struct mnode_s *parent;
137
138// node specific
139 mplane_t *plane;
140 struct mnode_s *children[2];
141
142 unsigned short firstsurface;
143 unsigned short numsurfaces;
144} mnode_t;
145
146
147
148typedef struct mleaf_s
149{
150// common with node
151 int contents; // wil be a negative contents number
152 int visframe; // node needs to be traversed if current
153
154 short minmaxs[6]; // for bounding box culling
155
156 struct mnode_s *parent;
157
158// leaf specific
159 byte *compressed_vis;
160 efrag_t *efrags;
161
162 msurface_t **firstmarksurface;
163 int nummarksurfaces;
164 int key; // BSP sequence number for leaf's contents
165 byte ambient_sound_level[NUM_AMBIENTS];
166} mleaf_t;
167
168// !!! if this is changed, it must be changed in asm_i386.h too !!!
169typedef struct
170{
171 dclipnode_t *clipnodes;
172 mplane_t *planes;
173 int firstclipnode;
174 int lastclipnode;
175 vec3_t clip_mins;
176 vec3_t clip_maxs;
177} hull_t;
178
179/*
180==============================================================================
181
182SPRITE MODELS
183
184==============================================================================
185*/
186
187
188// FIXME: shorten these?
189typedef struct mspriteframe_s
190{
191 int width;
192 int height;
193 void *pcachespot; // remove?
194 float up, down, left, right;
195 byte pixels[4];
196} mspriteframe_t;
197
198typedef struct
199{
200 int numframes;
201 float *intervals;
202 mspriteframe_t *frames[1];
203} mspritegroup_t;
204
205typedef struct
206{
207 spriteframetype_t type;
208 mspriteframe_t *frameptr;
209} mspriteframedesc_t;
210
211typedef struct
212{
213 int type;
214 int maxwidth;
215 int maxheight;
216 int numframes;
217 float beamlength; // remove?
218 void *cachespot; // remove?
219 mspriteframedesc_t frames[1];
220} msprite_t;
221
222
223/*
224==============================================================================
225
226ALIAS MODELS
227
228Alias models are position independent, so the cache manager can move them.
229==============================================================================
230*/
231
232typedef struct
233{
234 aliasframetype_t type;
235 trivertx_t bboxmin;
236 trivertx_t bboxmax;
237 int frame;
238 char name[16];
239} maliasframedesc_t;
240
241typedef struct
242{
243 aliasskintype_t type;
244 void *pcachespot;
245 int skin;
246} maliasskindesc_t;
247
248typedef struct
249{
250 trivertx_t bboxmin;
251 trivertx_t bboxmax;
252 int frame;
253} maliasgroupframedesc_t;
254
255typedef struct
256{
257 int numframes;
258 int intervals;
259 maliasgroupframedesc_t frames[1];
260} maliasgroup_t;
261
262typedef struct
263{
264 int numskins;
265 int intervals;
266 maliasskindesc_t skindescs[1];
267} maliasskingroup_t;
268
269// !!! if this is changed, it must be changed in asm_draw.h too !!!
270typedef struct mtriangle_s {
271 int facesfront;
272 int vertindex[3];
273} mtriangle_t;
274
275typedef struct {
276 int model;
277 int stverts;
278 int skindesc;
279 int triangles;
280 maliasframedesc_t frames[1];
281} aliashdr_t;
282
283//===================================================================
284
285//
286// Whole model
287//
288
289typedef int modtype_t;
290enum {mod_brush, mod_sprite, mod_alias};
291
292#define EF_ROCKET 1 // leave a trail
293#define EF_GRENADE 2 // leave a trail
294#define EF_GIB 4 // leave a trail
295#define EF_ROTATE 8 // rotate (bonus items)
296#define EF_TRACER 16 // green split trail
297#define EF_ZOMGIB 32 // small blood trail
298#define EF_TRACER2 64 // orange split trail + rotate
299#define EF_TRACER3 128 // purple trail
300
301typedef struct model_s
302{
303 char name[MAX_QPATH];
304 qboolean needload; // bmodels and sprites don't cache normally
305
306 modtype_t type;
307 int numframes;
308 synctype_t synctype;
309
310 int flags;
311
312//
313// volume occupied by the model
314//
315 vec3_t mins, maxs;
316 float radius;
317
318//
319// brush model
320//
321 int firstmodelsurface, nummodelsurfaces;
322
323 int numsubmodels;
324 dmodel_t *submodels;
325
326 int numplanes;
327 mplane_t *planes;
328
329 int numleafs; // number of visible leafs, not counting 0
330 mleaf_t *leafs;
331
332 int numvertexes;
333 mvertex_t *vertexes;
334
335 int numedges;
336 medge_t *edges;
337
338 int numnodes;
339 mnode_t *nodes;
340
341 int numtexinfo;
342 mtexinfo_t *texinfo;
343
344 int numsurfaces;
345 msurface_t *surfaces;
346
347 int numsurfedges;
348 int *surfedges;
349
350 int numclipnodes;
351 dclipnode_t *clipnodes;
352
353 int nummarksurfaces;
354 msurface_t **marksurfaces;
355
356 hull_t hulls[MAX_MAP_HULLS];
357
358 int numtextures;
359 texture_t **textures;
360
361 byte *visdata;
362 byte *lightdata;
363 char *entities;
364
365//
366// additional model data
367//
368 cache_user_t cache; // only access through Mod_Extradata
369
370} model_t;
371
372//============================================================================
373
374void Mod_Init (void);
375void Mod_ClearAll (void);
376model_t *Mod_ForName (char *name, qboolean crash);
377void *Mod_Extradata (model_t *mod); // handles caching
378void Mod_TouchModel (char *name);
379
380mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
381byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model);
382
383#endif // __MODEL__
diff --git a/apps/plugins/sdl/progs/quake/modelgen.h b/apps/plugins/sdl/progs/quake/modelgen.h
new file mode 100644
index 0000000000..631232f76e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/modelgen.h
@@ -0,0 +1,137 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// modelgen.h: header file for model generation program
22//
23
24// *********************************************************
25// * This file must be identical in the modelgen directory *
26// * and in the Quake directory, because it's used to *
27// * pass data from one to the other via model files. *
28// *********************************************************
29
30#ifdef INCLUDELIBS
31
32#include <stdlib.h>
33#include <stdio.h>
34#include <math.h>
35#include <string.h>
36
37#include "cmdlib.h"
38#include "scriplib.h"
39#include "trilib.h"
40#include "lbmlib.h"
41#include "mathlib.h"
42
43#endif
44
45#define ALIAS_VERSION 6
46
47#define ALIAS_ONSEAM 0x0020
48
49// must match definition in spritegn.h
50#ifndef SYNCTYPE_T
51#define SYNCTYPE_T
52typedef int synctype_t;
53enum {ST_SYNC=0, ST_RAND };
54#endif
55
56typedef int aliasframetype_t;
57enum { ALIAS_SINGLE=0, ALIAS_GROUP };
58
59typedef int aliasskintype_t;
60enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP };
61
62typedef struct {
63 int ident;
64 int version;
65 vec3_t scale;
66 vec3_t scale_origin;
67 float boundingradius;
68 vec3_t eyeposition;
69 int numskins;
70 int skinwidth;
71 int skinheight;
72 int numverts;
73 int numtris;
74 int numframes;
75 synctype_t synctype;
76 int flags;
77 float size;
78} mdl_t;
79
80// TODO: could be shorts
81
82typedef struct {
83 int onseam;
84 int s;
85 int t;
86} stvert_t;
87
88typedef struct dtriangle_s {
89 int facesfront;
90 int vertindex[3];
91} dtriangle_t;
92
93#define DT_FACES_FRONT 0x0010
94
95// This mirrors trivert_t in trilib.h, is present so Quake knows how to
96// load this data
97
98typedef struct {
99 byte v[3];
100 byte lightnormalindex;
101} trivertx_t;
102
103typedef struct {
104 trivertx_t bboxmin; // lightnormal isn't used
105 trivertx_t bboxmax; // lightnormal isn't used
106 char name[16]; // frame name from grabbing
107} daliasframe_t;
108
109typedef struct {
110 int numframes;
111 trivertx_t bboxmin; // lightnormal isn't used
112 trivertx_t bboxmax; // lightnormal isn't used
113} daliasgroup_t;
114
115typedef struct {
116 int numskins;
117} daliasskingroup_t;
118
119typedef struct {
120 float interval;
121} daliasinterval_t;
122
123typedef struct {
124 float interval;
125} daliasskininterval_t;
126
127typedef struct {
128 aliasframetype_t type;
129} daliasframetype_t;
130
131typedef struct {
132 aliasskintype_t type;
133} daliasskintype_t;
134
135#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I')
136 // little-endian "IDPO"
137
diff --git a/apps/plugins/sdl/progs/quake/mpdosock.h b/apps/plugins/sdl/progs/quake/mpdosock.h
new file mode 100644
index 0000000000..75171f4d69
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/mpdosock.h
@@ -0,0 +1,797 @@
1/* WINSOCK.H--definitions to be used with the WINSOCK.DLL
2 * Copyright (c) 1993-1995, Microsoft Corp. All rights reserved.
3 *
4 * This header file corresponds to version 1.1 of the Windows Sockets specification.
5 *
6 * This file includes parts which are Copyright (c) 1982-1986 Regents
7 * of the University of California. All rights reserved. The
8 * Berkeley Software License Agreement specifies the terms and
9 * conditions for redistribution.
10 *
11 */
12
13#ifndef _WINSOCKAPI_
14#define _WINSOCKAPI_
15
16#define FAR
17#define PASCAL
18
19/*
20 * Basic system type definitions, taken from the BSD file sys/types.h.
21 */
22typedef unsigned char u_char;
23typedef unsigned short u_short;
24typedef unsigned int u_int;
25typedef unsigned long u_long;
26
27/*
28 * The new type to be used in all
29 * instances which refer to sockets.
30 */
31typedef u_int SOCKET;
32
33// FIXME
34#if 0
35/*
36 * Select uses arrays of SOCKETs. These macros manipulate such
37 * arrays. FD_SETSIZE may be defined by the user before including
38 * this file, but the default here should be >= 64.
39 *
40 * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
41 * INCLUDED IN WINSOCK.H EXACTLY AS SHOWN HERE.
42 */
43#ifndef FD_SETSIZE
44#define FD_SETSIZE 64
45#endif /* FD_SETSIZE */
46
47typedef struct fd_set {
48 u_int fd_count; /* how many are SET? */
49 SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
50} fd_set;
51
52#ifdef __cplusplus
53extern "C" {
54#endif
55
56extern int PASCAL FAR __WSAFDIsSet(SOCKET, fd_set FAR *);
57
58#ifdef __cplusplus
59}
60#endif
61
62
63#define FD_CLR(fd, set) do { \
64 u_int __i; \
65 for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \
66 if (((fd_set FAR *)(set))->fd_array[__i] == fd) { \
67 while (__i < ((fd_set FAR *)(set))->fd_count-1) { \
68 ((fd_set FAR *)(set))->fd_array[__i] = \
69 ((fd_set FAR *)(set))->fd_array[__i+1]; \
70 __i++; \
71 } \
72 ((fd_set FAR *)(set))->fd_count--; \
73 break; \
74 } \
75 } \
76} while(0)
77
78#define FD_SET(fd, set) do { \
79 if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) \
80 ((fd_set FAR *)(set))->fd_array[((fd_set FAR *)(set))->fd_count++]=(fd);\
81} while(0)
82
83#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)
84
85#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
86
87/*
88 * Structure used in select() call, taken from the BSD file sys/time.h.
89 */
90struct timeval {
91 long tv_sec; /* seconds */
92 long tv_usec; /* and microseconds */
93};
94
95/*
96 * Operations on timevals.
97 *
98 * NB: timercmp does not work for >= or <=.
99 */
100#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
101#define timercmp(tvp, uvp, cmp) \
102 ((tvp)->tv_sec cmp (uvp)->tv_sec || \
103 (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
104#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
105#endif
106
107/*
108 * Commands for ioctlsocket(), taken from the BSD file fcntl.h.
109 *
110 *
111 * Ioctl's have the command encoded in the lower word,
112 * and the size of any in or out parameters in the upper
113 * word. The high 2 bits of the upper word are used
114 * to encode the in/out status of the parameter; for now
115 * we restrict parameters to at most 128 bytes.
116 */
117#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
118#define IOC_VOID 0x20000000 /* no parameters */
119#define IOC_OUT 0x40000000 /* copy out parameters */
120#define IOC_IN 0x80000000 /* copy in parameters */
121#define IOC_INOUT (IOC_IN|IOC_OUT)
122 /* 0x20000000 distinguishes new &
123 old ioctl's */
124#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
125
126#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
127
128#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
129
130#define FIONREAD _IOR('f', 127, u_long) /* get # bytes to read */
131#define FIONBIO _IOW('f', 126, u_long) /* set/clear non-blocking i/o */
132#define FIOASYNC _IOW('f', 125, u_long) /* set/clear async i/o */
133
134/* Socket I/O Controls */
135#define SIOCSHIWAT _IOW('s', 0, u_long) /* set high watermark */
136#define SIOCGHIWAT _IOR('s', 1, u_long) /* get high watermark */
137#define SIOCSLOWAT _IOW('s', 2, u_long) /* set low watermark */
138#define SIOCGLOWAT _IOR('s', 3, u_long) /* get low watermark */
139#define SIOCATMARK _IOR('s', 7, u_long) /* at oob mark? */
140
141/*
142 * Structures returned by network data base library, taken from the
143 * BSD file netdb.h. All addresses are supplied in host order, and
144 * returned in network order (suitable for use in system calls).
145 */
146
147struct hostent {
148 char FAR * h_name; /* official name of host */
149 char FAR * FAR * h_aliases; /* alias list */
150 short h_addrtype; /* host address type */
151 short h_length; /* length of address */
152 char FAR * FAR * h_addr_list; /* list of addresses */
153#define h_addr h_addr_list[0] /* address, for backward compat */
154};
155
156/*
157 * It is assumed here that a network number
158 * fits in 32 bits.
159 */
160struct netent {
161 char FAR * n_name; /* official name of net */
162 char FAR * FAR * n_aliases; /* alias list */
163 short n_addrtype; /* net address type */
164 u_long n_net; /* network # */
165};
166
167struct servent {
168 char FAR * s_name; /* official service name */
169 char FAR * FAR * s_aliases; /* alias list */
170 short s_port; /* port # */
171 char FAR * s_proto; /* protocol to use */
172};
173
174struct protoent {
175 char FAR * p_name; /* official protocol name */
176 char FAR * FAR * p_aliases; /* alias list */
177 short p_proto; /* protocol # */
178};
179
180/*
181 * Constants and structures defined by the internet system,
182 * Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
183 */
184
185/*
186 * Protocols
187 */
188#define IPPROTO_IP 0 /* dummy for IP */
189#define IPPROTO_ICMP 1 /* control message protocol */
190#define IPPROTO_GGP 2 /* gateway^2 (deprecated) */
191#define IPPROTO_TCP 6 /* tcp */
192#define IPPROTO_PUP 12 /* pup */
193#define IPPROTO_UDP 17 /* user datagram protocol */
194#define IPPROTO_IDP 22 /* xns idp */
195#define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */
196
197#define IPPROTO_RAW 255 /* raw IP packet */
198#define IPPROTO_MAX 256
199
200/*
201 * Port/socket numbers: network standard functions
202 */
203#define IPPORT_ECHO 7
204#define IPPORT_DISCARD 9
205#define IPPORT_SYSTAT 11
206#define IPPORT_DAYTIME 13
207#define IPPORT_NETSTAT 15
208#define IPPORT_FTP 21
209#define IPPORT_TELNET 23
210#define IPPORT_SMTP 25
211#define IPPORT_TIMESERVER 37
212#define IPPORT_NAMESERVER 42
213#define IPPORT_WHOIS 43
214#define IPPORT_MTP 57
215
216/*
217 * Port/socket numbers: host specific functions
218 */
219#define IPPORT_TFTP 69
220#define IPPORT_RJE 77
221#define IPPORT_FINGER 79
222#define IPPORT_TTYLINK 87
223#define IPPORT_SUPDUP 95
224
225/*
226 * UNIX TCP sockets
227 */
228#define IPPORT_EXECSERVER 512
229#define IPPORT_LOGINSERVER 513
230#define IPPORT_CMDSERVER 514
231#define IPPORT_EFSSERVER 520
232
233/*
234 * UNIX UDP sockets
235 */
236#define IPPORT_BIFFUDP 512
237#define IPPORT_WHOSERVER 513
238#define IPPORT_ROUTESERVER 520
239 /* 520+1 also used */
240
241/*
242 * Ports < IPPORT_RESERVED are reserved for
243 * privileged processes (e.g. root).
244 */
245#define IPPORT_RESERVED 1024
246
247/*
248 * Link numbers
249 */
250#define IMPLINK_IP 155
251#define IMPLINK_LOWEXPER 156
252#define IMPLINK_HIGHEXPER 158
253
254/*
255 * Internet address (old style... should be updated)
256 */
257struct in_addr {
258 union {
259 struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
260 struct { u_short s_w1,s_w2; } S_un_w;
261 u_long S_addr;
262 } S_un;
263#define s_addr S_un.S_addr
264 /* can be used for most tcp & ip code */
265#define s_host S_un.S_un_b.s_b2
266 /* host on imp */
267#define s_net S_un.S_un_b.s_b1
268 /* network */
269#define s_imp S_un.S_un_w.s_w2
270 /* imp */
271#define s_impno S_un.S_un_b.s_b4
272 /* imp # */
273#define s_lh S_un.S_un_b.s_b3
274 /* logical host */
275};
276
277/*
278 * Definitions of bits in internet address integers.
279 * On subnets, the decomposition of addresses to host and net parts
280 * is done according to subnet mask, not the masks here.
281 */
282#define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0)
283#define IN_CLASSA_NET 0xff000000
284#define IN_CLASSA_NSHIFT 24
285#define IN_CLASSA_HOST 0x00ffffff
286#define IN_CLASSA_MAX 128
287
288#define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000)
289#define IN_CLASSB_NET 0xffff0000
290#define IN_CLASSB_NSHIFT 16
291#define IN_CLASSB_HOST 0x0000ffff
292#define IN_CLASSB_MAX 65536
293
294#define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000)
295#define IN_CLASSC_NET 0xffffff00
296#define IN_CLASSC_NSHIFT 8
297#define IN_CLASSC_HOST 0x000000ff
298
299#define INADDR_ANY (u_long)0x00000000
300#define INADDR_LOOPBACK 0x7f000001
301#define INADDR_BROADCAST (u_long)0xffffffff
302#define INADDR_NONE 0xffffffff
303
304/*
305 * Socket address, internet style.
306 */
307struct sockaddr_in {
308 short sin_family;
309 u_short sin_port;
310 struct in_addr sin_addr;
311 char sin_zero[8];
312};
313
314#define WSADESCRIPTION_LEN 256
315#define WSASYS_STATUS_LEN 128
316
317
318/*
319 * Options for use with [gs]etsockopt at the IP level.
320 */
321#define IP_OPTIONS 1 /* set/get IP per-packet options */
322#define IP_MULTICAST_IF 2 /* set/get IP multicast interface */
323#define IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */
324#define IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */
325#define IP_ADD_MEMBERSHIP 5 /* add an IP group membership */
326#define IP_DROP_MEMBERSHIP 6 /* drop an IP group membership */
327
328#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */
329#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */
330#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */
331
332/*
333 * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
334 */
335struct ip_mreq {
336 struct in_addr imr_multiaddr; /* IP multicast address of group */
337 struct in_addr imr_interface; /* local IP address of interface */
338};
339
340/*
341 * Definitions related to sockets: types, address families, options,
342 * taken from the BSD file sys/socket.h.
343 */
344
345/*
346 * This is used instead of -1, since the
347 * SOCKET type is unsigned.
348 */
349#define INVALID_SOCKET (SOCKET)(~0)
350#define SOCKET_ERROR (-1)
351
352/*
353 * Types
354 */
355#define SOCK_STREAM 1 /* stream socket */
356#define SOCK_DGRAM 2 /* datagram socket */
357#define SOCK_RAW 3 /* raw-protocol interface */
358#define SOCK_RDM 4 /* reliably-delivered message */
359#define SOCK_SEQPACKET 5 /* sequenced packet stream */
360
361/*
362 * Option flags per-socket.
363 */
364#define SO_DEBUG 0x0001 /* turn on debugging info recording */
365#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
366#define SO_REUSEADDR 0x0004 /* allow local address reuse */
367#define SO_KEEPALIVE 0x0008 /* keep connections alive */
368#define SO_DONTROUTE 0x0010 /* just use interface addresses */
369#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
370#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
371#define SO_LINGER 0x0080 /* linger on close if data present */
372#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
373
374#define SO_DONTLINGER (u_int)(~SO_LINGER)
375
376/*
377 * Additional options.
378 */
379#define SO_SNDBUF 0x1001 /* send buffer size */
380#define SO_RCVBUF 0x1002 /* receive buffer size */
381#define SO_SNDLOWAT 0x1003 /* send low-water mark */
382#define SO_RCVLOWAT 0x1004 /* receive low-water mark */
383#define SO_SNDTIMEO 0x1005 /* send timeout */
384#define SO_RCVTIMEO 0x1006 /* receive timeout */
385#define SO_ERROR 0x1007 /* get error status and clear */
386#define SO_TYPE 0x1008 /* get socket type */
387
388/*
389 * Options for connect and disconnect data and options. Used only by
390 * non-TCP/IP transports such as DECNet, OSI TP4, etc.
391 */
392#define SO_CONNDATA 0x7000
393#define SO_CONNOPT 0x7001
394#define SO_DISCDATA 0x7002
395#define SO_DISCOPT 0x7003
396#define SO_CONNDATALEN 0x7004
397#define SO_CONNOPTLEN 0x7005
398#define SO_DISCDATALEN 0x7006
399#define SO_DISCOPTLEN 0x7007
400
401/*
402 * Option for opening sockets for synchronous access.
403 */
404#define SO_OPENTYPE 0x7008
405
406#define SO_SYNCHRONOUS_ALERT 0x10
407#define SO_SYNCHRONOUS_NONALERT 0x20
408
409/*
410 * Other NT-specific options.
411 */
412#define SO_MAXDG 0x7009
413#define SO_MAXPATHDG 0x700A
414
415/*
416 * TCP options.
417 */
418#define TCP_NODELAY 0x0001
419#define TCP_BSDURGENT 0x7000
420
421/*
422 * Address families.
423 */
424#define AF_UNSPEC 0 /* unspecified */
425#define AF_UNIX 1 /* local to host (pipes, portals) */
426#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
427#define AF_IMPLINK 3 /* arpanet imp addresses */
428#define AF_PUP 4 /* pup protocols: e.g. BSP */
429#define AF_CHAOS 5 /* mit CHAOS protocols */
430#define AF_IPX 6 /* IPX and SPX */
431#define AF_NS 6 /* XEROX NS protocols */
432#define AF_ISO 7 /* ISO protocols */
433#define AF_OSI AF_ISO /* OSI is ISO */
434#define AF_ECMA 8 /* european computer manufacturers */
435#define AF_DATAKIT 9 /* datakit protocols */
436#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
437#define AF_SNA 11 /* IBM SNA */
438#define AF_DECnet 12 /* DECnet */
439#define AF_DLI 13 /* Direct data link interface */
440#define AF_LAT 14 /* LAT */
441#define AF_HYLINK 15 /* NSC Hyperchannel */
442#define AF_APPLETALK 16 /* AppleTalk */
443#define AF_NETBIOS 17 /* NetBios-style addresses */
444#define AF_VOICEVIEW 18 /* VoiceView */
445
446#define AF_MAX 19
447
448/*
449 * Structure used by kernel to store most
450 * addresses.
451 */
452struct sockaddr {
453 u_short sa_family; /* address family */
454 char sa_data[14]; /* up to 14 bytes of direct address */
455};
456
457/*
458 * Structure used by kernel to pass protocol
459 * information in raw sockets.
460 */
461struct sockproto {
462 u_short sp_family; /* address family */
463 u_short sp_protocol; /* protocol */
464};
465
466/*
467 * Protocol families, same as address families for now.
468 */
469#define PF_UNSPEC AF_UNSPEC
470#define PF_UNIX AF_UNIX
471#define PF_INET AF_INET
472#define PF_IMPLINK AF_IMPLINK
473#define PF_PUP AF_PUP
474#define PF_CHAOS AF_CHAOS
475#define PF_NS AF_NS
476#define PF_IPX AF_IPX
477#define PF_ISO AF_ISO
478#define PF_OSI AF_OSI
479#define PF_ECMA AF_ECMA
480#define PF_DATAKIT AF_DATAKIT
481#define PF_CCITT AF_CCITT
482#define PF_SNA AF_SNA
483#define PF_DECnet AF_DECnet
484#define PF_DLI AF_DLI
485#define PF_LAT AF_LAT
486#define PF_HYLINK AF_HYLINK
487#define PF_APPLETALK AF_APPLETALK
488#define PF_VOICEVIEW AF_VOICEVIEW
489
490#define PF_MAX AF_MAX
491
492/*
493 * Structure used for manipulating linger option.
494 */
495struct linger {
496 u_short l_onoff; /* option on/off */
497 u_short l_linger; /* linger time */
498};
499
500/*
501 * Level number for (get/set)sockopt() to apply to socket itself.
502 */
503#define SOL_SOCKET 0xffff /* options for socket level */
504
505/*
506 * Maximum queue length specifiable by listen.
507 */
508#define SOMAXCONN 5
509
510#define MSG_OOB 0x1 /* process out-of-band data */
511#define MSG_PEEK 0x2 /* peek at incoming message */
512#define MSG_DONTROUTE 0x4 /* send without using routing tables */
513
514#define MSG_MAXIOVLEN 16
515
516#define MSG_PARTIAL 0x8000 /* partial send or recv for message xport */
517
518/*
519 * Define constant based on rfc883, used by gethostbyxxxx() calls.
520 */
521#define MAXGETHOSTSTRUCT 1024
522
523/*
524 * Define flags to be used with the WSAAsyncSelect() call.
525 */
526#define FD_READ 0x01
527#define FD_WRITE 0x02
528#define FD_OOB 0x04
529#define FD_ACCEPT 0x08
530#define FD_CONNECT 0x10
531#define FD_CLOSE 0x20
532
533/*
534 * All Windows Sockets error constants are biased by WSABASEERR from
535 * the "normal"
536 */
537#define WSABASEERR 10000
538/*
539 * Windows Sockets definitions of regular Microsoft C error constants
540 */
541#define WSAEINTR (WSABASEERR+4)
542#define WSAEBADF (WSABASEERR+9)
543#define WSAEACCES (WSABASEERR+13)
544#define WSAEFAULT (WSABASEERR+14)
545#define WSAEINVAL (WSABASEERR+22)
546#define WSAEMFILE (WSABASEERR+24)
547
548/*
549 * Windows Sockets definitions of regular Berkeley error constants
550 */
551#define WSAEWOULDBLOCK (WSABASEERR+35)
552#define WSAEINPROGRESS (WSABASEERR+36)
553#define WSAEALREADY (WSABASEERR+37)
554#define WSAENOTSOCK (WSABASEERR+38)
555#define WSAEDESTADDRREQ (WSABASEERR+39)
556#define WSAEMSGSIZE (WSABASEERR+40)
557#define WSAEPROTOTYPE (WSABASEERR+41)
558#define WSAENOPROTOOPT (WSABASEERR+42)
559#define WSAEPROTONOSUPPORT (WSABASEERR+43)
560#define WSAESOCKTNOSUPPORT (WSABASEERR+44)
561#define WSAEOPNOTSUPP (WSABASEERR+45)
562#define WSAEPFNOSUPPORT (WSABASEERR+46)
563#define WSAEAFNOSUPPORT (WSABASEERR+47)
564#define WSAEADDRINUSE (WSABASEERR+48)
565#define WSAEADDRNOTAVAIL (WSABASEERR+49)
566#define WSAENETDOWN (WSABASEERR+50)
567#define WSAENETUNREACH (WSABASEERR+51)
568#define WSAENETRESET (WSABASEERR+52)
569#define WSAECONNABORTED (WSABASEERR+53)
570#define WSAECONNRESET (WSABASEERR+54)
571#define WSAENOBUFS (WSABASEERR+55)
572#define WSAEISCONN (WSABASEERR+56)
573#define WSAENOTCONN (WSABASEERR+57)
574#define WSAESHUTDOWN (WSABASEERR+58)
575#define WSAETOOMANYREFS (WSABASEERR+59)
576#define WSAETIMEDOUT (WSABASEERR+60)
577#define WSAECONNREFUSED (WSABASEERR+61)
578#define WSAELOOP (WSABASEERR+62)
579#define WSAENAMETOOLONG (WSABASEERR+63)
580#define WSAEHOSTDOWN (WSABASEERR+64)
581#define WSAEHOSTUNREACH (WSABASEERR+65)
582#define WSAENOTEMPTY (WSABASEERR+66)
583#define WSAEPROCLIM (WSABASEERR+67)
584#define WSAEUSERS (WSABASEERR+68)
585#define WSAEDQUOT (WSABASEERR+69)
586#define WSAESTALE (WSABASEERR+70)
587#define WSAEREMOTE (WSABASEERR+71)
588
589#define WSAEDISCON (WSABASEERR+101)
590
591/*
592 * Extended Windows Sockets error constant definitions
593 */
594#define WSASYSNOTREADY (WSABASEERR+91)
595#define WSAVERNOTSUPPORTED (WSABASEERR+92)
596#define WSANOTINITIALISED (WSABASEERR+93)
597
598/*
599 * Error return codes from gethostbyname() and gethostbyaddr()
600 * (when using the resolver). Note that these errors are
601 * retrieved via WSAGetLastError() and must therefore follow
602 * the rules for avoiding clashes with error numbers from
603 * specific implementations or language run-time systems.
604 * For this reason the codes are based at WSABASEERR+1001.
605 * Note also that [WSA]NO_ADDRESS is defined only for
606 * compatibility purposes.
607 */
608
609#define h_errno WSAGetLastError()
610
611/* Authoritative Answer: Host not found */
612#define WSAHOST_NOT_FOUND (WSABASEERR+1001)
613#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
614
615/* Non-Authoritative: Host not found, or SERVERFAIL */
616#define WSATRY_AGAIN (WSABASEERR+1002)
617#define TRY_AGAIN WSATRY_AGAIN
618
619/* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
620#define WSANO_RECOVERY (WSABASEERR+1003)
621#define NO_RECOVERY WSANO_RECOVERY
622
623/* Valid name, no data record of requested type */
624#define WSANO_DATA (WSABASEERR+1004)
625#define NO_DATA WSANO_DATA
626
627/* no address, look for MX record */
628#define WSANO_ADDRESS WSANO_DATA
629#define NO_ADDRESS WSANO_ADDRESS
630
631/*
632 * Windows Sockets errors redefined as regular Berkeley error constants.
633 * These are commented out in Windows NT to avoid conflicts with errno.h.
634 * Use the WSA constants instead.
635 */
636#if 0
637#define EWOULDBLOCK WSAEWOULDBLOCK
638#define EINPROGRESS WSAEINPROGRESS
639#define EALREADY WSAEALREADY
640#define ENOTSOCK WSAENOTSOCK
641#define EDESTADDRREQ WSAEDESTADDRREQ
642#define EMSGSIZE WSAEMSGSIZE
643#define EPROTOTYPE WSAEPROTOTYPE
644#define ENOPROTOOPT WSAENOPROTOOPT
645#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
646#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
647#define EOPNOTSUPP WSAEOPNOTSUPP
648#define EPFNOSUPPORT WSAEPFNOSUPPORT
649#define EAFNOSUPPORT WSAEAFNOSUPPORT
650#define EADDRINUSE WSAEADDRINUSE
651#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
652#define ENETDOWN WSAENETDOWN
653#define ENETUNREACH WSAENETUNREACH
654#define ENETRESET WSAENETRESET
655#define ECONNABORTED WSAECONNABORTED
656#define ECONNRESET WSAECONNRESET
657#define ENOBUFS WSAENOBUFS
658#define EISCONN WSAEISCONN
659#define ENOTCONN WSAENOTCONN
660#define ESHUTDOWN WSAESHUTDOWN
661#define ETOOMANYREFS WSAETOOMANYREFS
662#define ETIMEDOUT WSAETIMEDOUT
663#define ECONNREFUSED WSAECONNREFUSED
664#define ELOOP WSAELOOP
665#define ENAMETOOLONG WSAENAMETOOLONG
666#define EHOSTDOWN WSAEHOSTDOWN
667#define EHOSTUNREACH WSAEHOSTUNREACH
668#define ENOTEMPTY WSAENOTEMPTY
669#define EPROCLIM WSAEPROCLIM
670#define EUSERS WSAEUSERS
671#define EDQUOT WSAEDQUOT
672#define ESTALE WSAESTALE
673#define EREMOTE WSAEREMOTE
674#endif
675
676/* Socket function prototypes */
677
678#ifdef __cplusplus
679extern "C" {
680#endif
681
682SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr,
683 int FAR *addrlen);
684
685int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);
686
687int PASCAL FAR closesocket (SOCKET s);
688
689int PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen);
690
691int PASCAL FAR ioctlsocket (SOCKET s, long cmd, u_long FAR *argp);
692
693int PASCAL FAR getpeername (SOCKET s, struct sockaddr FAR *name,
694 int FAR * namelen);
695
696int PASCAL FAR getsockname (SOCKET s, struct sockaddr FAR *name,
697 int FAR * namelen);
698
699int PASCAL FAR getsockopt (SOCKET s, int level, int optname,
700 char FAR * optval, int FAR *optlen);
701
702u_long PASCAL FAR htonl (u_long hostlong);
703
704u_short PASCAL FAR htons (u_short hostshort);
705
706unsigned long PASCAL FAR inet_addr (const char FAR * cp);
707
708char FAR * PASCAL FAR inet_ntoa (struct in_addr in);
709
710int PASCAL FAR listen (SOCKET s, int backlog);
711
712u_long PASCAL FAR ntohl (u_long netlong);
713
714u_short PASCAL FAR ntohs (u_short netshort);
715
716int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags);
717
718int PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,
719 struct sockaddr FAR *from, int FAR * fromlen);
720
721#if 0
722int PASCAL FAR select (int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
723 fd_set FAR *exceptfds, const struct timeval FAR *timeout);
724#endif
725
726int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags);
727
728int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,
729 const struct sockaddr FAR *to, int tolen);
730
731int PASCAL FAR setsockopt (SOCKET s, int level, int optname,
732 const char FAR * optval, int optlen);
733
734int PASCAL FAR shutdown (SOCKET s, int how);
735
736SOCKET PASCAL FAR socket (int af, int type, int protocol);
737
738/* Database function prototypes */
739
740struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr,
741 int len, int type);
742
743struct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name);
744
745int PASCAL FAR gethostname (char FAR * name, int namelen);
746
747struct servent FAR * PASCAL FAR getservbyport(int port, const char FAR * proto);
748
749struct servent FAR * PASCAL FAR getservbyname(const char FAR * name,
750 const char FAR * proto);
751
752struct protoent FAR * PASCAL FAR getprotobynumber(int proto);
753
754struct protoent FAR * PASCAL FAR getprotobyname(const char FAR * name);
755
756#ifdef __cplusplus
757}
758#endif
759
760/* Microsoft Windows Extended data types */
761typedef struct sockaddr SOCKADDR;
762typedef struct sockaddr *PSOCKADDR;
763typedef struct sockaddr FAR *LPSOCKADDR;
764
765typedef struct sockaddr_in SOCKADDR_IN;
766typedef struct sockaddr_in *PSOCKADDR_IN;
767typedef struct sockaddr_in FAR *LPSOCKADDR_IN;
768
769typedef struct linger LINGER;
770typedef struct linger *PLINGER;
771typedef struct linger FAR *LPLINGER;
772
773typedef struct in_addr IN_ADDR;
774typedef struct in_addr *PIN_ADDR;
775typedef struct in_addr FAR *LPIN_ADDR;
776
777typedef struct fd_set FD_SET;
778typedef struct fd_set *PFD_SET;
779typedef struct fd_set FAR *LPFD_SET;
780
781typedef struct hostent HOSTENT;
782typedef struct hostent *PHOSTENT;
783typedef struct hostent FAR *LPHOSTENT;
784
785typedef struct servent SERVENT;
786typedef struct servent *PSERVENT;
787typedef struct servent FAR *LPSERVENT;
788
789typedef struct protoent PROTOENT;
790typedef struct protoent *PPROTOENT;
791typedef struct protoent FAR *LPPROTOENT;
792
793typedef struct timeval TIMEVAL;
794typedef struct timeval *PTIMEVAL;
795typedef struct timeval FAR *LPTIMEVAL;
796
797#endif /* _WINSOCKAPI_ */
diff --git a/apps/plugins/sdl/progs/quake/net.h b/apps/plugins/sdl/progs/quake/net.h
new file mode 100644
index 0000000000..af461256b6
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net.h
@@ -0,0 +1,337 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net.h -- quake's interface to the networking layer
21
22struct qsockaddr
23{
24 short sa_family;
25 unsigned char sa_data[14];
26};
27
28
29#define NET_NAMELEN 64
30
31#define NET_MAXMESSAGE 8192
32#define NET_HEADERSIZE (2 * sizeof(unsigned int))
33#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE)
34
35// NetHeader flags
36#define NETFLAG_LENGTH_MASK 0x0000ffff
37#define NETFLAG_DATA 0x00010000
38#define NETFLAG_ACK 0x00020000
39#define NETFLAG_NAK 0x00040000
40#define NETFLAG_EOM 0x00080000
41#define NETFLAG_UNRELIABLE 0x00100000
42#define NETFLAG_CTL 0x80000000
43
44
45#define NET_PROTOCOL_VERSION 3
46
47// This is the network info/connection protocol. It is used to find Quake
48// servers, get info about them, and connect to them. Once connected, the
49// Quake game protocol (documented elsewhere) is used.
50//
51//
52// General notes:
53// game_name is currently always "QUAKE", but is there so this same protocol
54// can be used for future games as well; can you say Quake2?
55//
56// CCREQ_CONNECT
57// string game_name "QUAKE"
58// byte net_protocol_version NET_PROTOCOL_VERSION
59//
60// CCREQ_SERVER_INFO
61// string game_name "QUAKE"
62// byte net_protocol_version NET_PROTOCOL_VERSION
63//
64// CCREQ_PLAYER_INFO
65// byte player_number
66//
67// CCREQ_RULE_INFO
68// string rule
69//
70//
71//
72// CCREP_ACCEPT
73// long port
74//
75// CCREP_REJECT
76// string reason
77//
78// CCREP_SERVER_INFO
79// string server_address
80// string host_name
81// string level_name
82// byte current_players
83// byte max_players
84// byte protocol_version NET_PROTOCOL_VERSION
85//
86// CCREP_PLAYER_INFO
87// byte player_number
88// string name
89// long colors
90// long frags
91// long connect_time
92// string address
93//
94// CCREP_RULE_INFO
95// string rule
96// string value
97
98// note:
99// There are two address forms used above. The short form is just a
100// port number. The address that goes along with the port is defined as
101// "whatever address you receive this reponse from". This lets us use
102// the host OS to solve the problem of multiple host addresses (possibly
103// with no routing between them); the host will use the right address
104// when we reply to the inbound connection request. The long from is
105// a full address and port in a string. It is used for returning the
106// address of a server that is not running locally.
107
108#define CCREQ_CONNECT 0x01
109#define CCREQ_SERVER_INFO 0x02
110#define CCREQ_PLAYER_INFO 0x03
111#define CCREQ_RULE_INFO 0x04
112
113#define CCREP_ACCEPT 0x81
114#define CCREP_REJECT 0x82
115#define CCREP_SERVER_INFO 0x83
116#define CCREP_PLAYER_INFO 0x84
117#define CCREP_RULE_INFO 0x85
118
119typedef struct qsocket_s
120{
121 struct qsocket_s *next;
122 double connecttime;
123 double lastMessageTime;
124 double lastSendTime;
125
126 qboolean disconnected;
127 qboolean canSend;
128 qboolean sendNext;
129
130 int driver;
131 int landriver;
132 int socket;
133 void *driverdata;
134
135 unsigned int ackSequence;
136 unsigned int sendSequence;
137 unsigned int unreliableSendSequence;
138 int sendMessageLength;
139 byte sendMessage [NET_MAXMESSAGE];
140
141 unsigned int receiveSequence;
142 unsigned int unreliableReceiveSequence;
143 int receiveMessageLength;
144 byte receiveMessage [NET_MAXMESSAGE];
145
146 struct qsockaddr addr;
147 char address[NET_NAMELEN];
148
149} qsocket_t;
150
151extern qsocket_t *net_activeSockets;
152extern qsocket_t *net_freeSockets;
153extern int net_numsockets;
154
155typedef struct
156{
157 char *name;
158 qboolean initialized;
159 int controlSock;
160 int (*Init) (void);
161 void (*Shutdown) (void);
162 void (*Listen) (qboolean state);
163 int (*OpenSocket) (int port);
164 int (*CloseSocket) (int socket);
165 int (*Connect) (int socket, struct qsockaddr *addr);
166 int (*CheckNewConnections) (void);
167 int (*Read) (int socket, byte *buf, int len, struct qsockaddr *addr);
168 int (*Write) (int socket, byte *buf, int len, struct qsockaddr *addr);
169 int (*Broadcast) (int socket, byte *buf, int len);
170 char * (*AddrToString) (struct qsockaddr *addr);
171 int (*StringToAddr) (char *string, struct qsockaddr *addr);
172 int (*GetSocketAddr) (int socket, struct qsockaddr *addr);
173 int (*GetNameFromAddr) (struct qsockaddr *addr, char *name);
174 int (*GetAddrFromName) (char *name, struct qsockaddr *addr);
175 int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);
176 int (*GetSocketPort) (struct qsockaddr *addr);
177 int (*SetSocketPort) (struct qsockaddr *addr, int port);
178} net_landriver_t;
179
180#define MAX_NET_DRIVERS 8
181extern int net_numlandrivers;
182extern net_landriver_t net_landrivers[MAX_NET_DRIVERS];
183
184typedef struct
185{
186 char *name;
187 qboolean initialized;
188 int (*Init) (void);
189 void (*Listen) (qboolean state);
190 void (*SearchForHosts) (qboolean xmit);
191 qsocket_t *(*Connect) (char *host);
192 qsocket_t *(*CheckNewConnections) (void);
193 int (*QGetMessage) (qsocket_t *sock);
194 int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data);
195 int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);
196 qboolean (*CanSendMessage) (qsocket_t *sock);
197 qboolean (*CanSendUnreliableMessage) (qsocket_t *sock);
198 void (*Close) (qsocket_t *sock);
199 void (*Shutdown) (void);
200 int controlSock;
201} net_driver_t;
202
203extern int net_numdrivers;
204extern net_driver_t net_drivers[MAX_NET_DRIVERS];
205
206extern int DEFAULTnet_hostport;
207extern int net_hostport;
208
209extern int net_driverlevel;
210extern cvar_t hostname;
211extern char playername[];
212extern int playercolor;
213
214extern int messagesSent;
215extern int messagesReceived;
216extern int unreliableMessagesSent;
217extern int unreliableMessagesReceived;
218
219qsocket_t *NET_NewQSocket (void);
220void NET_FreeQSocket(qsocket_t *);
221double SetNetTime(void);
222
223
224#define HOSTCACHESIZE 8
225
226typedef struct
227{
228 char name[16];
229 char map[16];
230 char cname[32];
231 int users;
232 int maxusers;
233 int driver;
234 int ldriver;
235 struct qsockaddr addr;
236} hostcache_t;
237
238extern int hostCacheCount;
239extern hostcache_t hostcache[HOSTCACHESIZE];
240
241#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__)
242#ifndef htonl
243extern unsigned long htonl (unsigned long hostlong);
244#endif
245#ifndef htons
246extern unsigned short htons (unsigned short hostshort);
247#endif
248#ifndef ntohl
249extern unsigned long ntohl (unsigned long netlong);
250#endif
251#ifndef ntohs
252extern unsigned short ntohs (unsigned short netshort);
253#endif
254#endif
255
256#ifdef IDGODS
257qboolean IsID(struct qsockaddr *addr);
258#endif
259
260//============================================================================
261//
262// public network functions
263//
264//============================================================================
265
266extern double net_time;
267extern sizebuf_t net_message;
268extern int net_activeconnections;
269
270void NET_Init (void);
271void NET_Shutdown (void);
272
273struct qsocket_s *NET_CheckNewConnections (void);
274// returns a new connection number if there is one pending, else -1
275
276struct qsocket_s *NET_Connect (char *host);
277// called by client to connect to a host. Returns -1 if not able to
278
279qboolean NET_CanSendMessage (qsocket_t *sock);
280// Returns true or false if the given qsocket can currently accept a
281// message to be transmitted.
282
283int NET_GetMessage (struct qsocket_s *sock);
284// returns data in net_message sizebuf
285// returns 0 if no data is waiting
286// returns 1 if a message was received
287// returns 2 if an unreliable message was received
288// returns -1 if the connection died
289
290int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data);
291int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data);
292// returns 0 if the message connot be delivered reliably, but the connection
293// is still considered valid
294// returns 1 if the message was sent properly
295// returns -1 if the connection died
296
297int NET_SendToAll(sizebuf_t *data, int blocktime);
298// This is a reliable *blocking* send to all attached clients.
299
300
301void NET_Close (struct qsocket_s *sock);
302// if a dead connection is returned by a get or send function, this function
303// should be called when it is convenient
304
305// Server calls when a client is kicked off for a game related misbehavior
306// like an illegal protocal conversation. Client calls when disconnecting
307// from a server.
308// A netcon_t number will not be reused until this function is called for it
309
310void NET_Poll(void);
311
312
313typedef struct _PollProcedure
314{
315 struct _PollProcedure *next;
316 double nextTime;
317 void (*procedure)();
318 void *arg;
319} PollProcedure;
320
321void SchedulePollProcedure(PollProcedure *pp, double timeOffset);
322
323extern qboolean serialAvailable;
324extern qboolean ipxAvailable;
325extern qboolean tcpipAvailable;
326extern char my_ipx_address[NET_NAMELEN];
327extern char my_tcpip_address[NET_NAMELEN];
328extern void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
329extern void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
330extern void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
331extern void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
332
333extern qboolean slistInProgress;
334extern qboolean slistSilent;
335extern qboolean slistLocal;
336
337void NET_Slist_f (void);
diff --git a/apps/plugins/sdl/progs/quake/net_bsd.c b/apps/plugins/sdl/progs/quake/net_bsd.c
new file mode 100644
index 0000000000..79d62f859b
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_bsd.c
@@ -0,0 +1,93 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22#include "net_loop.h"
23#include "net_dgrm.h"
24
25net_driver_t net_drivers[MAX_NET_DRIVERS] =
26{
27 {
28 "Loopback",
29 false,
30 Loop_Init,
31 Loop_Listen,
32 Loop_SearchForHosts,
33 Loop_Connect,
34 Loop_CheckNewConnections,
35 Loop_GetMessage,
36 Loop_SendMessage,
37 Loop_SendUnreliableMessage,
38 Loop_CanSendMessage,
39 Loop_CanSendUnreliableMessage,
40 Loop_Close,
41 Loop_Shutdown
42 }
43 ,
44 {
45 "Datagram",
46 false,
47 Datagram_Init,
48 Datagram_Listen,
49 Datagram_SearchForHosts,
50 Datagram_Connect,
51 Datagram_CheckNewConnections,
52 Datagram_GetMessage,
53 Datagram_SendMessage,
54 Datagram_SendUnreliableMessage,
55 Datagram_CanSendMessage,
56 Datagram_CanSendUnreliableMessage,
57 Datagram_Close,
58 Datagram_Shutdown
59 }
60};
61
62int net_numdrivers = 2;
63
64#include "net_udp.h"
65
66net_landriver_t net_landrivers[MAX_NET_DRIVERS] =
67{
68 {
69 "UDP",
70 false,
71 0,
72 UDP_Init,
73 UDP_Shutdown,
74 UDP_Listen,
75 UDP_OpenSocket,
76 UDP_CloseSocket,
77 UDP_Connect,
78 UDP_CheckNewConnections,
79 UDP_Read,
80 UDP_Write,
81 UDP_Broadcast,
82 UDP_AddrToString,
83 UDP_StringToAddr,
84 UDP_GetSocketAddr,
85 UDP_GetNameFromAddr,
86 UDP_GetAddrFromName,
87 UDP_AddrCompare,
88 UDP_GetSocketPort,
89 UDP_SetSocketPort
90 }
91};
92
93int net_numlandrivers = 1;
diff --git a/apps/plugins/sdl/progs/quake/net_bw.h b/apps/plugins/sdl/progs/quake/net_bw.h
new file mode 100644
index 0000000000..341c49ae61
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_bw.h
@@ -0,0 +1,39 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_bw.h
21
22int BW_Init (void);
23void BW_Shutdown (void);
24void BW_Listen (qboolean state);
25int BW_OpenSocket (int port);
26int BW_CloseSocket (int socket);
27int BW_Connect (int socket, struct qsockaddr *addr);
28int BW_CheckNewConnections (void);
29int BW_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
30int BW_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
31int BW_Broadcast (int socket, byte *buf, int len);
32char *BW_AddrToString (struct qsockaddr *addr);
33int BW_StringToAddr (char *string, struct qsockaddr *addr);
34int BW_GetSocketAddr (int socket, struct qsockaddr *addr);
35int BW_GetNameFromAddr (struct qsockaddr *addr, char *name);
36int BW_GetAddrFromName (char *name, struct qsockaddr *addr);
37int BW_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
38int BW_GetSocketPort (struct qsockaddr *addr);
39int BW_SetSocketPort (struct qsockaddr *addr, int port);
diff --git a/apps/plugins/sdl/progs/quake/net_dgrm.c b/apps/plugins/sdl/progs/quake/net_dgrm.c
new file mode 100644
index 0000000000..a293b77b9f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_dgrm.c
@@ -0,0 +1,1390 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_dgrm.c
21
22// This is enables a simple IP banning mechanism
23#define BAN_TEST
24
25#ifdef BAN_TEST
26#if defined(_WIN32)
27#include <windows.h>
28#elif defined (NeXT)
29#include <sys/socket.h>
30#include <arpa/inet.h>
31#else
32#define AF_INET 2 /* internet */
33struct in_addr
34{
35 union
36 {
37 struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
38 struct { unsigned short s_w1,s_w2; } S_un_w;
39 unsigned long S_addr;
40 } S_un;
41};
42#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
43struct sockaddr_in
44{
45 short sin_family;
46 unsigned short sin_port;
47 struct in_addr sin_addr;
48 char sin_zero[8];
49};
50char *inet_ntoa(struct in_addr in);
51unsigned long inet_addr(const char *cp);
52#endif
53#endif // BAN_TEST
54
55#include "quakedef.h"
56#include "net_dgrm.h"
57
58// these two macros are to make the code more readable
59#define sfunc net_landrivers[sock->landriver]
60#define dfunc net_landrivers[net_landriverlevel]
61
62static int net_landriverlevel;
63
64/* statistic counters */
65int packetsSent = 0;
66int packetsReSent = 0;
67int packetsReceived = 0;
68int receivedDuplicateCount = 0;
69int shortPacketCount = 0;
70int droppedDatagrams;
71
72static int myDriverLevel;
73
74struct
75{
76 unsigned int length;
77 unsigned int sequence;
78 byte data[MAX_DATAGRAM];
79} packetBuffer;
80
81extern int m_return_state;
82extern int m_state;
83extern qboolean m_return_onerror;
84extern char m_return_reason[32];
85
86
87#ifdef DEBUG
88char *StrAddr (struct qsockaddr *addr)
89{
90 static char buf[34];
91 byte *p = (byte *)addr;
92 int n;
93
94 for (n = 0; n < 16; n++)
95 sprintf (buf + n * 2, "%02x", *p++);
96 return buf;
97}
98#endif
99
100
101#ifdef BAN_TEST
102unsigned long banAddr = 0x00000000;
103unsigned long banMask = 0xffffffff;
104
105void NET_Ban_f (void)
106{
107 char addrStr [32];
108 char maskStr [32];
109 void (*print) (char *fmt, ...);
110
111 if (cmd_source == src_command)
112 {
113 if (!sv.active)
114 {
115 Cmd_ForwardToServer ();
116 return;
117 }
118 print = Con_Printf;
119 }
120 else
121 {
122 if (pr_global_struct->deathmatch && !host_client->privileged)
123 return;
124 print = SV_ClientPrintf;
125 }
126
127 switch (Cmd_Argc ())
128 {
129 case 1:
130 if (((struct in_addr *)&banAddr)->s_addr)
131 {
132 Q_strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));
133 Q_strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));
134 print("Banning %s [%s]\n", addrStr, maskStr);
135 }
136 else
137 print("Banning not active\n");
138 break;
139
140 case 2:
141 if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)
142 banAddr = 0x00000000;
143 else
144 banAddr = inet_addr(Cmd_Argv(1));
145 banMask = 0xffffffff;
146 break;
147
148 case 3:
149 banAddr = inet_addr(Cmd_Argv(1));
150 banMask = inet_addr(Cmd_Argv(2));
151 break;
152
153 default:
154 print("BAN ip_address [mask]\n");
155 break;
156 }
157}
158#endif
159
160
161int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)
162{
163 unsigned int packetLen;
164 unsigned int dataLen;
165 unsigned int eom;
166
167#ifdef DEBUG
168 if (data->cursize == 0)
169 Sys_Error("Datagram_SendMessage: zero length message\n");
170
171 if (data->cursize > NET_MAXMESSAGE)
172 Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
173
174 if (sock->canSend == false)
175 Sys_Error("SendMessage: called with canSend == false\n");
176#endif
177
178 Q_memcpy(sock->sendMessage, data->data, data->cursize);
179 sock->sendMessageLength = data->cursize;
180
181 if (data->cursize <= MAX_DATAGRAM)
182 {
183 dataLen = data->cursize;
184 eom = NETFLAG_EOM;
185 }
186 else
187 {
188 dataLen = MAX_DATAGRAM;
189 eom = 0;
190 }
191 packetLen = NET_HEADERSIZE + dataLen;
192
193 packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
194 packetBuffer.sequence = BigLong(sock->sendSequence++);
195 Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
196
197 sock->canSend = false;
198
199 if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
200 return -1;
201
202 sock->lastSendTime = net_time;
203 packetsSent++;
204 return 1;
205}
206
207
208int SendMessageNext (qsocket_t *sock)
209{
210 unsigned int packetLen;
211 unsigned int dataLen;
212 unsigned int eom;
213
214 if (sock->sendMessageLength <= MAX_DATAGRAM)
215 {
216 dataLen = sock->sendMessageLength;
217 eom = NETFLAG_EOM;
218 }
219 else
220 {
221 dataLen = MAX_DATAGRAM;
222 eom = 0;
223 }
224 packetLen = NET_HEADERSIZE + dataLen;
225
226 packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
227 packetBuffer.sequence = BigLong(sock->sendSequence++);
228 Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
229
230 sock->sendNext = false;
231
232 if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
233 return -1;
234
235 sock->lastSendTime = net_time;
236 packetsSent++;
237 return 1;
238}
239
240
241int ReSendMessage (qsocket_t *sock)
242{
243 unsigned int packetLen;
244 unsigned int dataLen;
245 unsigned int eom;
246
247 if (sock->sendMessageLength <= MAX_DATAGRAM)
248 {
249 dataLen = sock->sendMessageLength;
250 eom = NETFLAG_EOM;
251 }
252 else
253 {
254 dataLen = MAX_DATAGRAM;
255 eom = 0;
256 }
257 packetLen = NET_HEADERSIZE + dataLen;
258
259 packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
260 packetBuffer.sequence = BigLong(sock->sendSequence - 1);
261 Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);
262
263 sock->sendNext = false;
264
265 if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
266 return -1;
267
268 sock->lastSendTime = net_time;
269 packetsReSent++;
270 return 1;
271}
272
273
274qboolean Datagram_CanSendMessage (qsocket_t *sock)
275{
276 if (sock->sendNext)
277 SendMessageNext (sock);
278
279 return sock->canSend;
280}
281
282
283qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock)
284{
285 return true;
286}
287
288
289int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
290{
291 int packetLen;
292
293#ifdef DEBUG
294 if (data->cursize == 0)
295 Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
296
297 if (data->cursize > MAX_DATAGRAM)
298 Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
299#endif
300
301 packetLen = NET_HEADERSIZE + data->cursize;
302
303 packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);
304 packetBuffer.sequence = BigLong(sock->unreliableSendSequence++);
305 Q_memcpy (packetBuffer.data, data->data, data->cursize);
306
307 if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
308 return -1;
309
310 packetsSent++;
311 return 1;
312}
313
314
315int Datagram_GetMessage (qsocket_t *sock)
316{
317 unsigned int length;
318 unsigned int flags;
319 int ret = 0;
320 struct qsockaddr readaddr;
321 unsigned int sequence;
322 unsigned int count;
323
324 if (!sock->canSend)
325 if ((net_time - sock->lastSendTime) > 1.0)
326 ReSendMessage (sock);
327
328 while(1)
329 {
330 length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);
331
332// if ((rand() & 255) > 220)
333// continue;
334
335 if (length == 0)
336 break;
337
338 if (length == -1)
339 {
340 Con_Printf("Read error\n");
341 return -1;
342 }
343
344 if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
345 {
346#ifdef DEBUG
347 Con_DPrintf("Forged packet received\n");
348 Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
349 Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
350#endif
351 continue;
352 }
353
354 if (length < NET_HEADERSIZE)
355 {
356 shortPacketCount++;
357 continue;
358 }
359
360 length = BigLong(packetBuffer.length);
361 flags = length & (~NETFLAG_LENGTH_MASK);
362 length &= NETFLAG_LENGTH_MASK;
363
364 if (flags & NETFLAG_CTL)
365 continue;
366
367 sequence = BigLong(packetBuffer.sequence);
368 packetsReceived++;
369
370 if (flags & NETFLAG_UNRELIABLE)
371 {
372 if (sequence < sock->unreliableReceiveSequence)
373 {
374 Con_DPrintf("Got a stale datagram\n");
375 ret = 0;
376 break;
377 }
378 if (sequence != sock->unreliableReceiveSequence)
379 {
380 count = sequence - sock->unreliableReceiveSequence;
381 droppedDatagrams += count;
382 Con_DPrintf("Dropped %u datagram(s)\n", count);
383 }
384 sock->unreliableReceiveSequence = sequence + 1;
385
386 length -= NET_HEADERSIZE;
387
388 SZ_Clear (&net_message);
389 SZ_Write (&net_message, packetBuffer.data, length);
390
391 ret = 2;
392 break;
393 }
394
395 if (flags & NETFLAG_ACK)
396 {
397 if (sequence != (sock->sendSequence - 1))
398 {
399 Con_DPrintf("Stale ACK received\n");
400 continue;
401 }
402 if (sequence == sock->ackSequence)
403 {
404 sock->ackSequence++;
405 if (sock->ackSequence != sock->sendSequence)
406 Con_DPrintf("ack sequencing error\n");
407 }
408 else
409 {
410 Con_DPrintf("Duplicate ACK received\n");
411 continue;
412 }
413 sock->sendMessageLength -= MAX_DATAGRAM;
414 if (sock->sendMessageLength > 0)
415 {
416 Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);
417 sock->sendNext = true;
418 }
419 else
420 {
421 sock->sendMessageLength = 0;
422 sock->canSend = true;
423 }
424 continue;
425 }
426
427 if (flags & NETFLAG_DATA)
428 {
429 packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);
430 packetBuffer.sequence = BigLong(sequence);
431 sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);
432
433 if (sequence != sock->receiveSequence)
434 {
435 receivedDuplicateCount++;
436 continue;
437 }
438 sock->receiveSequence++;
439
440 length -= NET_HEADERSIZE;
441
442 if (flags & NETFLAG_EOM)
443 {
444 SZ_Clear(&net_message);
445 SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);
446 SZ_Write(&net_message, packetBuffer.data, length);
447 sock->receiveMessageLength = 0;
448
449 ret = 1;
450 break;
451 }
452
453 Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);
454 sock->receiveMessageLength += length;
455 continue;
456 }
457 }
458
459 if (sock->sendNext)
460 SendMessageNext (sock);
461
462 return ret;
463}
464
465
466void PrintStats(qsocket_t *s)
467{
468 Con_Printf("canSend = %4u \n", s->canSend);
469 Con_Printf("sendSeq = %4u ", s->sendSequence);
470 Con_Printf("recvSeq = %4u \n", s->receiveSequence);
471 Con_Printf("\n");
472}
473
474void NET_Stats_f (void)
475{
476 qsocket_t *s;
477
478 if (Cmd_Argc () == 1)
479 {
480 Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent);
481 Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived);
482 Con_Printf("reliable messages sent = %i\n", messagesSent);
483 Con_Printf("reliable messages received = %i\n", messagesReceived);
484 Con_Printf("packetsSent = %i\n", packetsSent);
485 Con_Printf("packetsReSent = %i\n", packetsReSent);
486 Con_Printf("packetsReceived = %i\n", packetsReceived);
487 Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount);
488 Con_Printf("shortPacketCount = %i\n", shortPacketCount);
489 Con_Printf("droppedDatagrams = %i\n", droppedDatagrams);
490 }
491 else if (Q_strcmp(Cmd_Argv(1), "*") == 0)
492 {
493 for (s = net_activeSockets; s; s = s->next)
494 PrintStats(s);
495 for (s = net_freeSockets; s; s = s->next)
496 PrintStats(s);
497 }
498 else
499 {
500 for (s = net_activeSockets; s; s = s->next)
501 if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
502 break;
503 if (s == NULL)
504 for (s = net_freeSockets; s; s = s->next)
505 if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
506 break;
507 if (s == NULL)
508 return;
509 PrintStats(s);
510 }
511}
512
513
514static qboolean testInProgress = false;
515static int testPollCount;
516static int testDriver;
517static int testSocket;
518
519static void Test_Poll(void);
520PollProcedure testPollProcedure = {NULL, 0.0, Test_Poll};
521
522static void Test_Poll(void)
523{
524 struct qsockaddr clientaddr;
525 int control;
526 int len;
527 char name[32];
528 char address[64];
529 int colors;
530 int frags;
531 int connectTime;
532 byte playerNumber;
533
534 net_landriverlevel = testDriver;
535
536 while (1)
537 {
538 len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
539 if (len < sizeof(int))
540 break;
541
542 net_message.cursize = len;
543
544 MSG_BeginReading ();
545 control = BigLong(*((int *)net_message.data));
546 MSG_ReadLong();
547 if (control == -1)
548 break;
549 if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
550 break;
551 if ((control & NETFLAG_LENGTH_MASK) != len)
552 break;
553
554 if (MSG_ReadByte() != CCREP_PLAYER_INFO)
555 Sys_Error("Unexpected repsonse to Player Info request\n");
556
557 playerNumber = MSG_ReadByte();
558 Q_strcpy(name, MSG_ReadString());
559 colors = MSG_ReadLong();
560 frags = MSG_ReadLong();
561 connectTime = MSG_ReadLong();
562 Q_strcpy(address, MSG_ReadString());
563
564 Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);
565 }
566
567 testPollCount--;
568 if (testPollCount)
569 {
570 SchedulePollProcedure(&testPollProcedure, 0.1);
571 }
572 else
573 {
574 dfunc.CloseSocket(testSocket);
575 testInProgress = false;
576 }
577}
578
579static void Test_f (void)
580{
581 char *host;
582 int n;
583 int max = MAX_SCOREBOARD;
584 struct qsockaddr sendaddr;
585
586 if (testInProgress)
587 return;
588
589 host = Cmd_Argv (1);
590
591 if (host && hostCacheCount)
592 {
593 for (n = 0; n < hostCacheCount; n++)
594 if (Q_strcasecmp (host, hostcache[n].name) == 0)
595 {
596 if (hostcache[n].driver != myDriverLevel)
597 continue;
598 net_landriverlevel = hostcache[n].ldriver;
599 max = hostcache[n].maxusers;
600 Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
601 break;
602 }
603 if (n < hostCacheCount)
604 goto JustDoIt;
605 }
606
607 for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
608 {
609 if (!net_landrivers[net_landriverlevel].initialized)
610 continue;
611
612 // see if we can resolve the host name
613 if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
614 break;
615 }
616 if (net_landriverlevel == net_numlandrivers)
617 return;
618
619JustDoIt:
620 testSocket = dfunc.OpenSocket(0);
621 if (testSocket == -1)
622 return;
623
624 testInProgress = true;
625 testPollCount = 20;
626 testDriver = net_landriverlevel;
627
628 for (n = 0; n < max; n++)
629 {
630 SZ_Clear(&net_message);
631 // save space for the header, filled in later
632 MSG_WriteLong(&net_message, 0);
633 MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);
634 MSG_WriteByte(&net_message, n);
635 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
636 dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);
637 }
638 SZ_Clear(&net_message);
639 SchedulePollProcedure(&testPollProcedure, 0.1);
640}
641
642
643static qboolean test2InProgress = false;
644static int test2Driver;
645static int test2Socket;
646
647static void Test2_Poll(void);
648PollProcedure test2PollProcedure = {NULL, 0.0, Test2_Poll};
649
650static void Test2_Poll(void)
651{
652 struct qsockaddr clientaddr;
653 int control;
654 int len;
655 char name[256];
656 char value[256];
657
658 net_landriverlevel = test2Driver;
659 name[0] = 0;
660
661 len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
662 if (len < sizeof(int))
663 goto Reschedule;
664
665 net_message.cursize = len;
666
667 MSG_BeginReading ();
668 control = BigLong(*((int *)net_message.data));
669 MSG_ReadLong();
670 if (control == -1)
671 goto Error;
672 if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
673 goto Error;
674 if ((control & NETFLAG_LENGTH_MASK) != len)
675 goto Error;
676
677 if (MSG_ReadByte() != CCREP_RULE_INFO)
678 goto Error;
679
680 Q_strcpy(name, MSG_ReadString());
681 if (name[0] == 0)
682 goto Done;
683 Q_strcpy(value, MSG_ReadString());
684
685 Con_Printf("%-16.16s %-16.16s\n", name, value);
686
687 SZ_Clear(&net_message);
688 // save space for the header, filled in later
689 MSG_WriteLong(&net_message, 0);
690 MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
691 MSG_WriteString(&net_message, name);
692 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
693 dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);
694 SZ_Clear(&net_message);
695
696Reschedule:
697 SchedulePollProcedure(&test2PollProcedure, 0.05);
698 return;
699
700Error:
701 Con_Printf("Unexpected repsonse to Rule Info request\n");
702Done:
703 dfunc.CloseSocket(test2Socket);
704 test2InProgress = false;
705 return;
706}
707
708static void Test2_f (void)
709{
710 char *host;
711 int n;
712 struct qsockaddr sendaddr;
713
714 if (test2InProgress)
715 return;
716
717 host = Cmd_Argv (1);
718
719 if (host && hostCacheCount)
720 {
721 for (n = 0; n < hostCacheCount; n++)
722 if (Q_strcasecmp (host, hostcache[n].name) == 0)
723 {
724 if (hostcache[n].driver != myDriverLevel)
725 continue;
726 net_landriverlevel = hostcache[n].ldriver;
727 Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));
728 break;
729 }
730 if (n < hostCacheCount)
731 goto JustDoIt;
732 }
733
734 for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
735 {
736 if (!net_landrivers[net_landriverlevel].initialized)
737 continue;
738
739 // see if we can resolve the host name
740 if (dfunc.GetAddrFromName(host, &sendaddr) != -1)
741 break;
742 }
743 if (net_landriverlevel == net_numlandrivers)
744 return;
745
746JustDoIt:
747 test2Socket = dfunc.OpenSocket(0);
748 if (test2Socket == -1)
749 return;
750
751 test2InProgress = true;
752 test2Driver = net_landriverlevel;
753
754 SZ_Clear(&net_message);
755 // save space for the header, filled in later
756 MSG_WriteLong(&net_message, 0);
757 MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
758 MSG_WriteString(&net_message, "");
759 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
760 dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);
761 SZ_Clear(&net_message);
762 SchedulePollProcedure(&test2PollProcedure, 0.05);
763}
764
765
766int Datagram_Init (void)
767{
768 int i;
769 int csock;
770
771 myDriverLevel = net_driverlevel;
772 Cmd_AddCommand ("net_stats", NET_Stats_f);
773
774 if (COM_CheckParm("-nolan"))
775 return -1;
776
777 for (i = 0; i < net_numlandrivers; i++)
778 {
779 csock = net_landrivers[i].Init ();
780 if (csock == -1)
781 continue;
782 net_landrivers[i].initialized = true;
783 net_landrivers[i].controlSock = csock;
784 }
785
786#ifdef BAN_TEST
787 Cmd_AddCommand ("ban", NET_Ban_f);
788#endif
789 Cmd_AddCommand ("test", Test_f);
790 Cmd_AddCommand ("test2", Test2_f);
791
792 return 0;
793}
794
795
796void Datagram_Shutdown (void)
797{
798 int i;
799
800//
801// shutdown the lan drivers
802//
803 for (i = 0; i < net_numlandrivers; i++)
804 {
805 if (net_landrivers[i].initialized)
806 {
807 net_landrivers[i].Shutdown ();
808 net_landrivers[i].initialized = false;
809 }
810 }
811}
812
813
814void Datagram_Close (qsocket_t *sock)
815{
816 sfunc.CloseSocket(sock->socket);
817}
818
819
820void Datagram_Listen (qboolean state)
821{
822 int i;
823
824 for (i = 0; i < net_numlandrivers; i++)
825 if (net_landrivers[i].initialized)
826 net_landrivers[i].Listen (state);
827}
828
829
830static qsocket_t *_Datagram_CheckNewConnections (void)
831{
832 struct qsockaddr clientaddr;
833 struct qsockaddr newaddr;
834 int newsock;
835 int acceptsock;
836 qsocket_t *sock;
837 qsocket_t *s;
838 int len;
839 int command;
840 int control;
841 int ret;
842
843 acceptsock = dfunc.CheckNewConnections();
844 if (acceptsock == -1)
845 return NULL;
846
847 SZ_Clear(&net_message);
848
849 len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
850 if (len < sizeof(int))
851 return NULL;
852 net_message.cursize = len;
853
854 MSG_BeginReading ();
855 control = BigLong(*((int *)net_message.data));
856 MSG_ReadLong();
857 if (control == -1)
858 return NULL;
859 if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
860 return NULL;
861 if ((control & NETFLAG_LENGTH_MASK) != len)
862 return NULL;
863
864 command = MSG_ReadByte();
865 if (command == CCREQ_SERVER_INFO)
866 {
867 if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
868 return NULL;
869
870 SZ_Clear(&net_message);
871 // save space for the header, filled in later
872 MSG_WriteLong(&net_message, 0);
873 MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
874 dfunc.GetSocketAddr(acceptsock, &newaddr);
875 MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
876 MSG_WriteString(&net_message, hostname.string);
877 MSG_WriteString(&net_message, sv.name);
878 MSG_WriteByte(&net_message, net_activeconnections);
879 MSG_WriteByte(&net_message, svs.maxclients);
880 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
881 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
882 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
883 SZ_Clear(&net_message);
884 return NULL;
885 }
886
887 if (command == CCREQ_PLAYER_INFO)
888 {
889 int playerNumber;
890 int activeNumber;
891 int clientNumber;
892 client_t *client;
893
894 playerNumber = MSG_ReadByte();
895 activeNumber = -1;
896 for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)
897 {
898 if (client->active)
899 {
900 activeNumber++;
901 if (activeNumber == playerNumber)
902 break;
903 }
904 }
905 if (clientNumber == svs.maxclients)
906 return NULL;
907
908 SZ_Clear(&net_message);
909 // save space for the header, filled in later
910 MSG_WriteLong(&net_message, 0);
911 MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
912 MSG_WriteByte(&net_message, playerNumber);
913 MSG_WriteString(&net_message, client->name);
914 MSG_WriteLong(&net_message, client->colors);
915 MSG_WriteLong(&net_message, (int)client->edict->v.frags);
916 MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
917 MSG_WriteString(&net_message, client->netconnection->address);
918 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
919 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
920 SZ_Clear(&net_message);
921
922 return NULL;
923 }
924
925 if (command == CCREQ_RULE_INFO)
926 {
927 char *prevCvarName;
928 cvar_t *var;
929
930 // find the search start location
931 prevCvarName = MSG_ReadString();
932 if (*prevCvarName)
933 {
934 var = Cvar_FindVar (prevCvarName);
935 if (!var)
936 return NULL;
937 var = var->next;
938 }
939 else
940 var = cvar_vars;
941
942 // search for the next server cvar
943 while (var)
944 {
945 if (var->server)
946 break;
947 var = var->next;
948 }
949
950 // send the response
951
952 SZ_Clear(&net_message);
953 // save space for the header, filled in later
954 MSG_WriteLong(&net_message, 0);
955 MSG_WriteByte(&net_message, CCREP_RULE_INFO);
956 if (var)
957 {
958 MSG_WriteString(&net_message, var->name);
959 MSG_WriteString(&net_message, var->string);
960 }
961 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
962 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
963 SZ_Clear(&net_message);
964
965 return NULL;
966 }
967
968 if (command != CCREQ_CONNECT)
969 return NULL;
970
971 if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0)
972 return NULL;
973
974 if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
975 {
976 SZ_Clear(&net_message);
977 // save space for the header, filled in later
978 MSG_WriteLong(&net_message, 0);
979 MSG_WriteByte(&net_message, CCREP_REJECT);
980 MSG_WriteString(&net_message, "Incompatible version.\n");
981 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
982 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
983 SZ_Clear(&net_message);
984 return NULL;
985 }
986
987#ifdef BAN_TEST
988 // check for a ban
989 if (clientaddr.sa_family == AF_INET)
990 {
991 unsigned long testAddr;
992 testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
993 if ((testAddr & banMask) == banAddr)
994 {
995 SZ_Clear(&net_message);
996 // save space for the header, filled in later
997 MSG_WriteLong(&net_message, 0);
998 MSG_WriteByte(&net_message, CCREP_REJECT);
999 MSG_WriteString(&net_message, "You have been banned.\n");
1000 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1001 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1002 SZ_Clear(&net_message);
1003 return NULL;
1004 }
1005 }
1006#endif
1007
1008 // see if this guy is already connected
1009 for (s = net_activeSockets; s; s = s->next)
1010 {
1011 if (s->driver != net_driverlevel)
1012 continue;
1013 ret = dfunc.AddrCompare(&clientaddr, &s->addr);
1014 if (ret >= 0)
1015 {
1016 // is this a duplicate connection reqeust?
1017 if (ret == 0 && net_time - s->connecttime < 2.0)
1018 {
1019 // yes, so send a duplicate reply
1020 SZ_Clear(&net_message);
1021 // save space for the header, filled in later
1022 MSG_WriteLong(&net_message, 0);
1023 MSG_WriteByte(&net_message, CCREP_ACCEPT);
1024 dfunc.GetSocketAddr(s->socket, &newaddr);
1025 MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1026 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1027 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1028 SZ_Clear(&net_message);
1029 return NULL;
1030 }
1031 // it's somebody coming back in from a crash/disconnect
1032 // so close the old qsocket and let their retry get them back in
1033 NET_Close(s);
1034 return NULL;
1035 }
1036 }
1037
1038 // allocate a QSocket
1039 sock = NET_NewQSocket ();
1040 if (sock == NULL)
1041 {
1042 // no room; try to let him know
1043 SZ_Clear(&net_message);
1044 // save space for the header, filled in later
1045 MSG_WriteLong(&net_message, 0);
1046 MSG_WriteByte(&net_message, CCREP_REJECT);
1047 MSG_WriteString(&net_message, "Server is full.\n");
1048 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1049 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1050 SZ_Clear(&net_message);
1051 return NULL;
1052 }
1053
1054 // allocate a network socket
1055 newsock = dfunc.OpenSocket(0);
1056 if (newsock == -1)
1057 {
1058 NET_FreeQSocket(sock);
1059 return NULL;
1060 }
1061
1062 // connect to the client
1063 if (dfunc.Connect (newsock, &clientaddr) == -1)
1064 {
1065 dfunc.CloseSocket(newsock);
1066 NET_FreeQSocket(sock);
1067 return NULL;
1068 }
1069
1070 // everything is allocated, just fill in the details
1071 sock->socket = newsock;
1072 sock->landriver = net_landriverlevel;
1073 sock->addr = clientaddr;
1074 Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));
1075
1076 // send him back the info about the server connection he has been allocated
1077 SZ_Clear(&net_message);
1078 // save space for the header, filled in later
1079 MSG_WriteLong(&net_message, 0);
1080 MSG_WriteByte(&net_message, CCREP_ACCEPT);
1081 dfunc.GetSocketAddr(newsock, &newaddr);
1082 MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
1083// MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
1084 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1085 dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
1086 SZ_Clear(&net_message);
1087
1088 return sock;
1089}
1090
1091qsocket_t *Datagram_CheckNewConnections (void)
1092{
1093 qsocket_t *ret = NULL;
1094
1095 for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1096 if (net_landrivers[net_landriverlevel].initialized)
1097 if ((ret = _Datagram_CheckNewConnections ()) != NULL)
1098 break;
1099 return ret;
1100}
1101
1102
1103static void _Datagram_SearchForHosts (qboolean xmit)
1104{
1105 int ret;
1106 int n;
1107 int i;
1108 struct qsockaddr readaddr;
1109 struct qsockaddr myaddr;
1110 int control;
1111
1112 dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
1113 if (xmit)
1114 {
1115 SZ_Clear(&net_message);
1116 // save space for the header, filled in later
1117 MSG_WriteLong(&net_message, 0);
1118 MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
1119 MSG_WriteString(&net_message, "QUAKE");
1120 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1121 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1122 dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
1123 SZ_Clear(&net_message);
1124 }
1125
1126 while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
1127 {
1128 if (ret < sizeof(int))
1129 continue;
1130 net_message.cursize = ret;
1131
1132 // don't answer our own query
1133 if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
1134 continue;
1135
1136 // is the cache full?
1137 if (hostCacheCount == HOSTCACHESIZE)
1138 continue;
1139
1140 MSG_BeginReading ();
1141 control = BigLong(*((int *)net_message.data));
1142 MSG_ReadLong();
1143 if (control == -1)
1144 continue;
1145 if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
1146 continue;
1147 if ((control & NETFLAG_LENGTH_MASK) != ret)
1148 continue;
1149
1150 if (MSG_ReadByte() != CCREP_SERVER_INFO)
1151 continue;
1152
1153 dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
1154 // search the cache for this server
1155 for (n = 0; n < hostCacheCount; n++)
1156 if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
1157 break;
1158
1159 // is it already there?
1160 if (n < hostCacheCount)
1161 continue;
1162
1163 // add it
1164 hostCacheCount++;
1165 Q_strcpy(hostcache[n].name, MSG_ReadString());
1166 Q_strcpy(hostcache[n].map, MSG_ReadString());
1167 hostcache[n].users = MSG_ReadByte();
1168 hostcache[n].maxusers = MSG_ReadByte();
1169 if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
1170 {
1171 Q_strcpy(hostcache[n].cname, hostcache[n].name);
1172 hostcache[n].cname[14] = 0;
1173 Q_strcpy(hostcache[n].name, "*");
1174 Q_strcat(hostcache[n].name, hostcache[n].cname);
1175 }
1176 Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
1177 hostcache[n].driver = net_driverlevel;
1178 hostcache[n].ldriver = net_landriverlevel;
1179 Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
1180
1181 // check for a name conflict
1182 for (i = 0; i < hostCacheCount; i++)
1183 {
1184 if (i == n)
1185 continue;
1186 if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
1187 {
1188 i = Q_strlen(hostcache[n].name);
1189 if (i < 15 && hostcache[n].name[i-1] > '8')
1190 {
1191 hostcache[n].name[i] = '0';
1192 hostcache[n].name[i+1] = 0;
1193 }
1194 else
1195 hostcache[n].name[i-1]++;
1196 i = -1;
1197 }
1198 }
1199 }
1200}
1201
1202void Datagram_SearchForHosts (qboolean xmit)
1203{
1204 for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1205 {
1206 if (hostCacheCount == HOSTCACHESIZE)
1207 break;
1208 if (net_landrivers[net_landriverlevel].initialized)
1209 _Datagram_SearchForHosts (xmit);
1210 }
1211}
1212
1213
1214static qsocket_t *_Datagram_Connect (char *host)
1215{
1216 struct qsockaddr sendaddr;
1217 struct qsockaddr readaddr;
1218 qsocket_t *sock;
1219 int newsock;
1220 int ret;
1221 int reps;
1222 double start_time;
1223 int control;
1224 char *reason;
1225
1226 // see if we can resolve the host name
1227 if (dfunc.GetAddrFromName(host, &sendaddr) == -1)
1228 return NULL;
1229
1230 newsock = dfunc.OpenSocket (0);
1231 if (newsock == -1)
1232 return NULL;
1233
1234 sock = NET_NewQSocket ();
1235 if (sock == NULL)
1236 goto ErrorReturn2;
1237 sock->socket = newsock;
1238 sock->landriver = net_landriverlevel;
1239
1240 // connect to the host
1241 if (dfunc.Connect (newsock, &sendaddr) == -1)
1242 goto ErrorReturn;
1243
1244 // send the connection request
1245 Con_Printf("trying...\n"); SCR_UpdateScreen ();
1246 start_time = net_time;
1247
1248 for (reps = 0; reps < 3; reps++)
1249 {
1250 SZ_Clear(&net_message);
1251 // save space for the header, filled in later
1252 MSG_WriteLong(&net_message, 0);
1253 MSG_WriteByte(&net_message, CCREQ_CONNECT);
1254 MSG_WriteString(&net_message, "QUAKE");
1255 MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
1256 *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
1257 dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);
1258 SZ_Clear(&net_message);
1259 do
1260 {
1261 ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);
1262 // if we got something, validate it
1263 if (ret > 0)
1264 {
1265 // is it from the right place?
1266 if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
1267 {
1268#ifdef DEBUG
1269 Con_Printf("wrong reply address\n");
1270 Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
1271 Con_Printf("Received: %s\n", StrAddr (&readaddr));
1272 SCR_UpdateScreen ();
1273#endif
1274 ret = 0;
1275 continue;
1276 }
1277
1278 if (ret < sizeof(int))
1279 {
1280 ret = 0;
1281 continue;
1282 }
1283
1284 net_message.cursize = ret;
1285 MSG_BeginReading ();
1286
1287 control = BigLong(*((int *)net_message.data));
1288 MSG_ReadLong();
1289 if (control == -1)
1290 {
1291 ret = 0;
1292 continue;
1293 }
1294 if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
1295 {
1296 ret = 0;
1297 continue;
1298 }
1299 if ((control & NETFLAG_LENGTH_MASK) != ret)
1300 {
1301 ret = 0;
1302 continue;
1303 }
1304 }
1305 }
1306 while (ret == 0 && (SetNetTime() - start_time) < 2.5);
1307 if (ret)
1308 break;
1309 Con_Printf("still trying...\n"); SCR_UpdateScreen ();
1310 start_time = SetNetTime();
1311 }
1312
1313 if (ret == 0)
1314 {
1315 reason = "No Response";
1316 Con_Printf("%s\n", reason);
1317 Q_strcpy(m_return_reason, reason);
1318 goto ErrorReturn;
1319 }
1320
1321 if (ret == -1)
1322 {
1323 reason = "Network Error";
1324 Con_Printf("%s\n", reason);
1325 Q_strcpy(m_return_reason, reason);
1326 goto ErrorReturn;
1327 }
1328
1329 ret = MSG_ReadByte();
1330 if (ret == CCREP_REJECT)
1331 {
1332 reason = MSG_ReadString();
1333 Con_Printf(reason);
1334 Q_strncpy(m_return_reason, reason, 31);
1335 goto ErrorReturn;
1336 }
1337
1338 if (ret == CCREP_ACCEPT)
1339 {
1340 Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
1341 dfunc.SetSocketPort (&sock->addr, MSG_ReadLong());
1342 }
1343 else
1344 {
1345 reason = "Bad Response";
1346 Con_Printf("%s\n", reason);
1347 Q_strcpy(m_return_reason, reason);
1348 goto ErrorReturn;
1349 }
1350
1351 dfunc.GetNameFromAddr (&sendaddr, sock->address);
1352
1353 Con_Printf ("Connection accepted\n");
1354 sock->lastMessageTime = SetNetTime();
1355
1356 // switch the connection to the specified address
1357 if (dfunc.Connect (newsock, &sock->addr) == -1)
1358 {
1359 reason = "Connect to Game failed";
1360 Con_Printf("%s\n", reason);
1361 Q_strcpy(m_return_reason, reason);
1362 goto ErrorReturn;
1363 }
1364
1365 m_return_onerror = false;
1366 return sock;
1367
1368ErrorReturn:
1369 NET_FreeQSocket(sock);
1370ErrorReturn2:
1371 dfunc.CloseSocket(newsock);
1372 if (m_return_onerror)
1373 {
1374 key_dest = key_menu;
1375 m_state = m_return_state;
1376 m_return_onerror = false;
1377 }
1378 return NULL;
1379}
1380
1381qsocket_t *Datagram_Connect (char *host)
1382{
1383 qsocket_t *ret = NULL;
1384
1385 for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
1386 if (net_landrivers[net_landriverlevel].initialized)
1387 if ((ret = _Datagram_Connect (host)) != NULL)
1388 break;
1389 return ret;
1390}
diff --git a/apps/plugins/sdl/progs/quake/net_dgrm.h b/apps/plugins/sdl/progs/quake/net_dgrm.h
new file mode 100644
index 0000000000..da052e7011
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_dgrm.h
@@ -0,0 +1,34 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_dgrm.h
21
22
23int Datagram_Init (void);
24void Datagram_Listen (qboolean state);
25void Datagram_SearchForHosts (qboolean xmit);
26qsocket_t *Datagram_Connect (char *host);
27qsocket_t *Datagram_CheckNewConnections (void);
28int Datagram_GetMessage (qsocket_t *sock);
29int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data);
30int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
31qboolean Datagram_CanSendMessage (qsocket_t *sock);
32qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock);
33void Datagram_Close (qsocket_t *sock);
34void Datagram_Shutdown (void);
diff --git a/apps/plugins/sdl/progs/quake/net_loop.c b/apps/plugins/sdl/progs/quake/net_loop.c
new file mode 100644
index 0000000000..35aa370d95
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_loop.c
@@ -0,0 +1,245 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_loop.c
21
22#include "quakedef.h"
23#include "net_loop.h"
24
25qboolean localconnectpending = false;
26qsocket_t *loop_client = NULL;
27qsocket_t *loop_server = NULL;
28
29int Loop_Init (void)
30{
31 if (cls.state == ca_dedicated)
32 return -1;
33 return 0;
34}
35
36
37void Loop_Shutdown (void)
38{
39}
40
41
42void Loop_Listen (qboolean state)
43{
44}
45
46
47void Loop_SearchForHosts (qboolean xmit)
48{
49 if (!sv.active)
50 return;
51
52 hostCacheCount = 1;
53 if (Q_strcmp(hostname.string, "UNNAMED") == 0)
54 Q_strcpy(hostcache[0].name, "local");
55 else
56 Q_strcpy(hostcache[0].name, hostname.string);
57 Q_strcpy(hostcache[0].map, sv.name);
58 hostcache[0].users = net_activeconnections;
59 hostcache[0].maxusers = svs.maxclients;
60 hostcache[0].driver = net_driverlevel;
61 Q_strcpy(hostcache[0].cname, "local");
62}
63
64
65qsocket_t *Loop_Connect (char *host)
66{
67 if (Q_strcmp(host,"local") != 0)
68 return NULL;
69
70 localconnectpending = true;
71
72 if (!loop_client)
73 {
74 if ((loop_client = NET_NewQSocket ()) == NULL)
75 {
76 Con_Printf("Loop_Connect: no qsocket available\n");
77 return NULL;
78 }
79 Q_strcpy (loop_client->address, "localhost");
80 }
81 loop_client->receiveMessageLength = 0;
82 loop_client->sendMessageLength = 0;
83 loop_client->canSend = true;
84
85 if (!loop_server)
86 {
87 if ((loop_server = NET_NewQSocket ()) == NULL)
88 {
89 Con_Printf("Loop_Connect: no qsocket available\n");
90 return NULL;
91 }
92 Q_strcpy (loop_server->address, "LOCAL");
93 }
94 loop_server->receiveMessageLength = 0;
95 loop_server->sendMessageLength = 0;
96 loop_server->canSend = true;
97
98 loop_client->driverdata = (void *)loop_server;
99 loop_server->driverdata = (void *)loop_client;
100
101 return loop_client;
102}
103
104
105qsocket_t *Loop_CheckNewConnections (void)
106{
107 if (!localconnectpending)
108 return NULL;
109
110 localconnectpending = false;
111 loop_server->sendMessageLength = 0;
112 loop_server->receiveMessageLength = 0;
113 loop_server->canSend = true;
114 loop_client->sendMessageLength = 0;
115 loop_client->receiveMessageLength = 0;
116 loop_client->canSend = true;
117 return loop_server;
118}
119
120
121static int IntAlign(int value)
122{
123 return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
124}
125
126
127int Loop_GetMessage (qsocket_t *sock)
128{
129 int ret;
130 int length;
131
132 if (sock->receiveMessageLength == 0)
133 return 0;
134
135 ret = sock->receiveMessage[0];
136 length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
137 // alignment byte skipped here
138 SZ_Clear (&net_message);
139 SZ_Write (&net_message, &sock->receiveMessage[4], length);
140
141 length = IntAlign(length + 4);
142 sock->receiveMessageLength -= length;
143
144 if (sock->receiveMessageLength)
145 Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);
146
147 if (sock->driverdata && ret == 1)
148 ((qsocket_t *)sock->driverdata)->canSend = true;
149
150 return ret;
151}
152
153
154int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)
155{
156 byte *buffer;
157 int *bufferLength;
158
159 if (!sock->driverdata)
160 return -1;
161
162 bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
163
164 if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)
165 Sys_Error("Loop_SendMessage: overflow\n");
166
167 buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
168
169 // message type
170 *buffer++ = 1;
171
172 // length
173 *buffer++ = data->cursize & 0xff;
174 *buffer++ = data->cursize >> 8;
175
176 // align
177 buffer++;
178
179 // message
180 Q_memcpy(buffer, data->data, data->cursize);
181 *bufferLength = IntAlign(*bufferLength + data->cursize + 4);
182
183 sock->canSend = false;
184 return 1;
185}
186
187
188int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
189{
190 byte *buffer;
191 int *bufferLength;
192
193 if (!sock->driverdata)
194 return -1;
195
196 bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;
197
198 if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE)
199 return 0;
200
201 buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;
202
203 // message type
204 *buffer++ = 2;
205
206 // length
207 *buffer++ = data->cursize & 0xff;
208 *buffer++ = data->cursize >> 8;
209
210 // align
211 buffer++;
212
213 // message
214 Q_memcpy(buffer, data->data, data->cursize);
215 *bufferLength = IntAlign(*bufferLength + data->cursize + 4);
216 return 1;
217}
218
219
220qboolean Loop_CanSendMessage (qsocket_t *sock)
221{
222 if (!sock->driverdata)
223 return false;
224 return sock->canSend;
225}
226
227
228qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock)
229{
230 return true;
231}
232
233
234void Loop_Close (qsocket_t *sock)
235{
236 if (sock->driverdata)
237 ((qsocket_t *)sock->driverdata)->driverdata = NULL;
238 sock->receiveMessageLength = 0;
239 sock->sendMessageLength = 0;
240 sock->canSend = true;
241 if (sock == loop_client)
242 loop_client = NULL;
243 else
244 loop_server = NULL;
245}
diff --git a/apps/plugins/sdl/progs/quake/net_loop.h b/apps/plugins/sdl/progs/quake/net_loop.h
new file mode 100644
index 0000000000..90cdb2c50d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_loop.h
@@ -0,0 +1,33 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_loop.h
21
22int Loop_Init (void);
23void Loop_Listen (qboolean state);
24void Loop_SearchForHosts (qboolean xmit);
25qsocket_t *Loop_Connect (char *host);
26qsocket_t *Loop_CheckNewConnections (void);
27int Loop_GetMessage (qsocket_t *sock);
28int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data);
29int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);
30qboolean Loop_CanSendMessage (qsocket_t *sock);
31qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock);
32void Loop_Close (qsocket_t *sock);
33void Loop_Shutdown (void);
diff --git a/apps/plugins/sdl/progs/quake/net_main.c b/apps/plugins/sdl/progs/quake/net_main.c
new file mode 100644
index 0000000000..5f5d2cf1ad
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_main.c
@@ -0,0 +1,997 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_main.c
21
22#include "quakedef.h"
23#include "net_vcr.h"
24
25qsocket_t *net_activeSockets = NULL;
26qsocket_t *net_freeSockets = NULL;
27int net_numsockets = 0;
28
29qboolean serialAvailable = false;
30qboolean ipxAvailable = false;
31qboolean tcpipAvailable = false;
32
33int net_hostport;
34int DEFAULTnet_hostport = 26000;
35
36char my_ipx_address[NET_NAMELEN];
37char my_tcpip_address[NET_NAMELEN];
38
39void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
40void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
41void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
42void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
43
44static qboolean listening = false;
45
46qboolean slistInProgress = false;
47qboolean slistSilent = false;
48qboolean slistLocal = true;
49static double slistStartTime;
50static int slistLastShown;
51
52static void Slist_Send(void);
53static void Slist_Poll(void);
54PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
55PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
56
57
58sizebuf_t net_message;
59int net_activeconnections = 0;
60
61int messagesSent = 0;
62int messagesReceived = 0;
63int unreliableMessagesSent = 0;
64int unreliableMessagesReceived = 0;
65
66cvar_t net_messagetimeout = {"net_messagetimeout","300"};
67cvar_t hostname = {"hostname", "UNNAMED"};
68
69qboolean configRestored = false;
70cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
71cvar_t config_com_irq = {"_config_com_irq", "4", true};
72cvar_t config_com_baud = {"_config_com_baud", "57600", true};
73cvar_t config_com_modem = {"_config_com_modem", "1", true};
74cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
75cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
76cvar_t config_modem_init = {"_config_modem_init", "", true};
77cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
78
79#ifdef IDGODS
80cvar_t idgods = {"idgods", "0"};
81#endif
82
83int vcrFile = -1;
84qboolean recording = false;
85
86// these two macros are to make the code more readable
87#define sfunc net_drivers[sock->driver]
88#define dfunc net_drivers[net_driverlevel]
89
90int net_driverlevel;
91
92
93double net_time;
94
95double SetNetTime(void)
96{
97 net_time = Sys_FloatTime();
98 return net_time;
99}
100
101
102/*
103===================
104NET_NewQSocket
105
106Called by drivers when a new communications endpoint is required
107The sequence and buffer fields will be filled in properly
108===================
109*/
110qsocket_t *NET_NewQSocket (void)
111{
112 qsocket_t *sock;
113
114 if (net_freeSockets == NULL)
115 return NULL;
116
117 if (net_activeconnections >= svs.maxclients)
118 return NULL;
119
120 // get one from free list
121 sock = net_freeSockets;
122 net_freeSockets = sock->next;
123
124 // add it to active list
125 sock->next = net_activeSockets;
126 net_activeSockets = sock;
127
128 sock->disconnected = false;
129 sock->connecttime = net_time;
130 Q_strcpy (sock->address,"UNSET ADDRESS");
131 sock->driver = net_driverlevel;
132 sock->socket = 0;
133 sock->driverdata = NULL;
134 sock->canSend = true;
135 sock->sendNext = false;
136 sock->lastMessageTime = net_time;
137 sock->ackSequence = 0;
138 sock->sendSequence = 0;
139 sock->unreliableSendSequence = 0;
140 sock->sendMessageLength = 0;
141 sock->receiveSequence = 0;
142 sock->unreliableReceiveSequence = 0;
143 sock->receiveMessageLength = 0;
144
145 return sock;
146}
147
148
149void NET_FreeQSocket(qsocket_t *sock)
150{
151 qsocket_t *s;
152
153 // remove it from active list
154 if (sock == net_activeSockets)
155 net_activeSockets = net_activeSockets->next;
156 else
157 {
158 for (s = net_activeSockets; s; s = s->next)
159 if (s->next == sock)
160 {
161 s->next = sock->next;
162 break;
163 }
164 if (!s)
165 Sys_Error ("NET_FreeQSocket: not active\n");
166 }
167
168 // add it to free list
169 sock->next = net_freeSockets;
170 net_freeSockets = sock;
171 sock->disconnected = true;
172}
173
174
175static void NET_Listen_f (void)
176{
177 if (Cmd_Argc () != 2)
178 {
179 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
180 return;
181 }
182
183 listening = Q_atoi(Cmd_Argv(1)) ? true : false;
184
185 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
186 {
187 if (net_drivers[net_driverlevel].initialized == false)
188 continue;
189 dfunc.Listen (listening);
190 }
191}
192
193
194static void MaxPlayers_f (void)
195{
196 int n;
197
198 if (Cmd_Argc () != 2)
199 {
200 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
201 return;
202 }
203
204 if (sv.active)
205 {
206 Con_Printf ("maxplayers can not be changed while a server is running.\n");
207 return;
208 }
209
210 n = Q_atoi(Cmd_Argv(1));
211 if (n < 1)
212 n = 1;
213 if (n > svs.maxclientslimit)
214 {
215 n = svs.maxclientslimit;
216 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
217 }
218
219 if ((n == 1) && listening)
220 Cbuf_AddText ("listen 0\n");
221
222 if ((n > 1) && (!listening))
223 Cbuf_AddText ("listen 1\n");
224
225 svs.maxclients = n;
226 if (n == 1)
227 Cvar_Set ("deathmatch", "0");
228 else
229 Cvar_Set ("deathmatch", "1");
230}
231
232
233static void NET_Port_f (void)
234{
235 int n;
236
237 if (Cmd_Argc () != 2)
238 {
239 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
240 return;
241 }
242
243 n = Q_atoi(Cmd_Argv(1));
244 if (n < 1 || n > 65534)
245 {
246 Con_Printf ("Bad value, must be between 1 and 65534\n");
247 return;
248 }
249
250 DEFAULTnet_hostport = n;
251 net_hostport = n;
252
253 if (listening)
254 {
255 // force a change to the new port
256 Cbuf_AddText ("listen 0\n");
257 Cbuf_AddText ("listen 1\n");
258 }
259}
260
261
262static void PrintSlistHeader(void)
263{
264 Con_Printf("Server Map Users\n");
265 Con_Printf("--------------- --------------- -----\n");
266 slistLastShown = 0;
267}
268
269
270static void PrintSlist(void)
271{
272 int n;
273
274 for (n = slistLastShown; n < hostCacheCount; n++)
275 {
276 if (hostcache[n].maxusers)
277 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
278 else
279 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
280 }
281 slistLastShown = n;
282}
283
284
285static void PrintSlistTrailer(void)
286{
287 if (hostCacheCount)
288 Con_Printf("== end list ==\n\n");
289 else
290 Con_Printf("No Quake servers found.\n\n");
291}
292
293
294void NET_Slist_f (void)
295{
296 if (slistInProgress)
297 return;
298
299 if (! slistSilent)
300 {
301 Con_Printf("Looking for Quake servers...\n");
302 PrintSlistHeader();
303 }
304
305 slistInProgress = true;
306 slistStartTime = Sys_FloatTime();
307
308 SchedulePollProcedure(&slistSendProcedure, 0.0);
309 SchedulePollProcedure(&slistPollProcedure, 0.1);
310
311 hostCacheCount = 0;
312}
313
314
315static void Slist_Send(void)
316{
317 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
318 {
319 if (!slistLocal && net_driverlevel == 0)
320 continue;
321 if (net_drivers[net_driverlevel].initialized == false)
322 continue;
323 dfunc.SearchForHosts (true);
324 }
325
326 if ((Sys_FloatTime() - slistStartTime) < 0.5)
327 SchedulePollProcedure(&slistSendProcedure, 0.75);
328}
329
330
331static void Slist_Poll(void)
332{
333 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
334 {
335 if (!slistLocal && net_driverlevel == 0)
336 continue;
337 if (net_drivers[net_driverlevel].initialized == false)
338 continue;
339 dfunc.SearchForHosts (false);
340 }
341
342 if (! slistSilent)
343 PrintSlist();
344
345 if ((Sys_FloatTime() - slistStartTime) < 1.5)
346 {
347 SchedulePollProcedure(&slistPollProcedure, 0.1);
348 return;
349 }
350
351 if (! slistSilent)
352 PrintSlistTrailer();
353 slistInProgress = false;
354 slistSilent = false;
355 slistLocal = true;
356}
357
358
359/*
360===================
361NET_Connect
362===================
363*/
364
365int hostCacheCount = 0;
366hostcache_t hostcache[HOSTCACHESIZE];
367
368qsocket_t *NET_Connect (char *host)
369{
370 qsocket_t *ret;
371 int n;
372 int numdrivers = net_numdrivers;
373
374 SetNetTime();
375
376 if (host && *host == 0)
377 host = NULL;
378
379 if (host)
380 {
381 if (Q_strcasecmp (host, "local") == 0)
382 {
383 numdrivers = 1;
384 goto JustDoIt;
385 }
386
387 if (hostCacheCount)
388 {
389 for (n = 0; n < hostCacheCount; n++)
390 if (Q_strcasecmp (host, hostcache[n].name) == 0)
391 {
392 host = hostcache[n].cname;
393 break;
394 }
395 if (n < hostCacheCount)
396 goto JustDoIt;
397 }
398 }
399
400 slistSilent = host ? true : false;
401 NET_Slist_f ();
402
403 while(slistInProgress)
404 NET_Poll();
405
406 if (host == NULL)
407 {
408 if (hostCacheCount != 1)
409 return NULL;
410 host = hostcache[0].cname;
411 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
412 }
413
414 if (hostCacheCount)
415 for (n = 0; n < hostCacheCount; n++)
416 if (Q_strcasecmp (host, hostcache[n].name) == 0)
417 {
418 host = hostcache[n].cname;
419 break;
420 }
421
422JustDoIt:
423 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
424 {
425 if (net_drivers[net_driverlevel].initialized == false)
426 continue;
427 ret = dfunc.Connect (host);
428 if (ret)
429 return ret;
430 }
431
432 if (host)
433 {
434 Con_Printf("\n");
435 PrintSlistHeader();
436 PrintSlist();
437 PrintSlistTrailer();
438 }
439
440 return NULL;
441}
442
443
444/*
445===================
446NET_CheckNewConnections
447===================
448*/
449
450struct
451{
452 double time;
453 int op;
454 long session;
455} vcrConnect;
456
457qsocket_t *NET_CheckNewConnections (void)
458{
459 qsocket_t *ret;
460
461 SetNetTime();
462
463 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
464 {
465 if (net_drivers[net_driverlevel].initialized == false)
466 continue;
467 if (net_driverlevel && listening == false)
468 continue;
469 ret = dfunc.CheckNewConnections ();
470 if (ret)
471 {
472 if (recording)
473 {
474 vcrConnect.time = host_time;
475 vcrConnect.op = VCR_OP_CONNECT;
476 vcrConnect.session = (long)ret;
477 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
478 Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
479 }
480 return ret;
481 }
482 }
483
484 if (recording)
485 {
486 vcrConnect.time = host_time;
487 vcrConnect.op = VCR_OP_CONNECT;
488 vcrConnect.session = 0;
489 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
490 }
491
492 return NULL;
493}
494
495/*
496===================
497NET_Close
498===================
499*/
500void NET_Close (qsocket_t *sock)
501{
502 if (!sock)
503 return;
504
505 if (sock->disconnected)
506 return;
507
508 SetNetTime();
509
510 // call the driver_Close function
511 sfunc.Close (sock);
512
513 NET_FreeQSocket(sock);
514}
515
516
517/*
518=================
519NET_GetMessage
520
521If there is a complete message, return it in net_message
522
523returns 0 if no data is waiting
524returns 1 if a message was received
525returns -1 if connection is invalid
526=================
527*/
528
529struct
530{
531 double time;
532 int op;
533 long session;
534 int ret;
535 int len;
536} vcrGetMessage;
537
538extern void PrintStats(qsocket_t *s);
539
540int NET_GetMessage (qsocket_t *sock)
541{
542 int ret;
543
544 if (!sock)
545 return -1;
546
547 if (sock->disconnected)
548 {
549 Con_Printf("NET_GetMessage: disconnected socket\n");
550 return -1;
551 }
552
553 SetNetTime();
554
555 ret = sfunc.QGetMessage(sock);
556
557 // see if this connection has timed out
558 if (ret == 0 && sock->driver)
559 {
560 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
561 {
562 NET_Close(sock);
563 return -1;
564 }
565 }
566
567
568 if (ret > 0)
569 {
570 if (sock->driver)
571 {
572 sock->lastMessageTime = net_time;
573 if (ret == 1)
574 messagesReceived++;
575 else if (ret == 2)
576 unreliableMessagesReceived++;
577 }
578
579 if (recording)
580 {
581 vcrGetMessage.time = host_time;
582 vcrGetMessage.op = VCR_OP_GETMESSAGE;
583 vcrGetMessage.session = (long)sock;
584 vcrGetMessage.ret = ret;
585 vcrGetMessage.len = net_message.cursize;
586 Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
587 Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
588 }
589 }
590 else
591 {
592 if (recording)
593 {
594 vcrGetMessage.time = host_time;
595 vcrGetMessage.op = VCR_OP_GETMESSAGE;
596 vcrGetMessage.session = (long)sock;
597 vcrGetMessage.ret = ret;
598 Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
599 }
600 }
601
602 return ret;
603}
604
605
606/*
607==================
608NET_SendMessage
609
610Try to send a complete length+message unit over the reliable stream.
611returns 0 if the message cannot be delivered reliably, but the connection
612 is still considered valid
613returns 1 if the message was sent properly
614returns -1 if the connection died
615==================
616*/
617struct
618{
619 double time;
620 int op;
621 long session;
622 int r;
623} vcrSendMessage;
624
625int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
626{
627 int r;
628
629 if (!sock)
630 return -1;
631
632 if (sock->disconnected)
633 {
634 Con_Printf("NET_SendMessage: disconnected socket\n");
635 return -1;
636 }
637
638 SetNetTime();
639 r = sfunc.QSendMessage(sock, data);
640 if (r == 1 && sock->driver)
641 messagesSent++;
642
643 if (recording)
644 {
645 vcrSendMessage.time = host_time;
646 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
647 vcrSendMessage.session = (long)sock;
648 vcrSendMessage.r = r;
649 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
650 }
651
652 return r;
653}
654
655
656int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
657{
658 int r;
659
660 if (!sock)
661 return -1;
662
663 if (sock->disconnected)
664 {
665 Con_Printf("NET_SendMessage: disconnected socket\n");
666 return -1;
667 }
668
669 SetNetTime();
670 r = sfunc.SendUnreliableMessage(sock, data);
671 if (r == 1 && sock->driver)
672 unreliableMessagesSent++;
673
674 if (recording)
675 {
676 vcrSendMessage.time = host_time;
677 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
678 vcrSendMessage.session = (long)sock;
679 vcrSendMessage.r = r;
680 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
681 }
682
683 return r;
684}
685
686
687/*
688==================
689NET_CanSendMessage
690
691Returns true or false if the given qsocket can currently accept a
692message to be transmitted.
693==================
694*/
695qboolean NET_CanSendMessage (qsocket_t *sock)
696{
697 int r;
698
699 if (!sock)
700 return false;
701
702 if (sock->disconnected)
703 return false;
704
705 SetNetTime();
706
707 r = sfunc.CanSendMessage(sock);
708
709 if (recording)
710 {
711 vcrSendMessage.time = host_time;
712 vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
713 vcrSendMessage.session = (long)sock;
714 vcrSendMessage.r = r;
715 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
716 }
717
718 return r;
719}
720
721
722int NET_SendToAll(sizebuf_t *data, int blocktime)
723{
724 double start;
725 int i;
726 int count = 0;
727 qboolean state1 [MAX_SCOREBOARD];
728 qboolean state2 [MAX_SCOREBOARD];
729
730 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
731 {
732 if (!host_client->netconnection)
733 continue;
734 if (host_client->active)
735 {
736 if (host_client->netconnection->driver == 0)
737 {
738 NET_SendMessage(host_client->netconnection, data);
739 state1[i] = true;
740 state2[i] = true;
741 continue;
742 }
743 count++;
744 state1[i] = false;
745 state2[i] = false;
746 }
747 else
748 {
749 state1[i] = true;
750 state2[i] = true;
751 }
752 }
753
754 start = Sys_FloatTime();
755 while (count)
756 {
757 count = 0;
758 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
759 {
760 if (! state1[i])
761 {
762 if (NET_CanSendMessage (host_client->netconnection))
763 {
764 state1[i] = true;
765 NET_SendMessage(host_client->netconnection, data);
766 }
767 else
768 {
769 NET_GetMessage (host_client->netconnection);
770 }
771 count++;
772 continue;
773 }
774
775 if (! state2[i])
776 {
777 if (NET_CanSendMessage (host_client->netconnection))
778 {
779 state2[i] = true;
780 }
781 else
782 {
783 NET_GetMessage (host_client->netconnection);
784 }
785 count++;
786 continue;
787 }
788 }
789 if ((Sys_FloatTime() - start) > blocktime)
790 break;
791 }
792 return count;
793}
794
795
796//=============================================================================
797
798/*
799====================
800NET_Init
801====================
802*/
803
804void NET_Init (void)
805{
806 int i;
807 int controlSocket;
808 qsocket_t *s;
809
810 if (COM_CheckParm("-playback"))
811 {
812 net_numdrivers = 1;
813 net_drivers[0].Init = VCR_Init;
814 }
815
816 if (COM_CheckParm("-record"))
817 recording = true;
818
819 i = COM_CheckParm ("-port");
820 if (!i)
821 i = COM_CheckParm ("-udpport");
822 if (!i)
823 i = COM_CheckParm ("-ipxport");
824
825 if (i)
826 {
827 if (i < com_argc-1)
828 DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
829 else
830 Sys_Error ("NET_Init: you must specify a number after -port");
831 }
832 net_hostport = DEFAULTnet_hostport;
833
834 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
835 listening = true;
836 net_numsockets = svs.maxclientslimit;
837 if (cls.state != ca_dedicated)
838 net_numsockets++;
839
840 SetNetTime();
841
842 for (i = 0; i < net_numsockets; i++)
843 {
844 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
845 s->next = net_freeSockets;
846 net_freeSockets = s;
847 s->disconnected = true;
848 }
849
850 // allocate space for network message buffer
851 SZ_Alloc (&net_message, NET_MAXMESSAGE);
852
853 Cvar_RegisterVariable (&net_messagetimeout);
854 Cvar_RegisterVariable (&hostname);
855 Cvar_RegisterVariable (&config_com_port);
856 Cvar_RegisterVariable (&config_com_irq);
857 Cvar_RegisterVariable (&config_com_baud);
858 Cvar_RegisterVariable (&config_com_modem);
859 Cvar_RegisterVariable (&config_modem_dialtype);
860 Cvar_RegisterVariable (&config_modem_clear);
861 Cvar_RegisterVariable (&config_modem_init);
862 Cvar_RegisterVariable (&config_modem_hangup);
863#ifdef IDGODS
864 Cvar_RegisterVariable (&idgods);
865#endif
866
867 Cmd_AddCommand ("slist", NET_Slist_f);
868 Cmd_AddCommand ("listen", NET_Listen_f);
869 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
870 Cmd_AddCommand ("port", NET_Port_f);
871
872 // initialize all the drivers
873 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
874 {
875 controlSocket = net_drivers[net_driverlevel].Init();
876 if (controlSocket == -1)
877 continue;
878 net_drivers[net_driverlevel].initialized = true;
879 net_drivers[net_driverlevel].controlSock = controlSocket;
880 if (listening)
881 net_drivers[net_driverlevel].Listen (true);
882 }
883
884 if (*my_ipx_address)
885 Con_DPrintf("IPX address %s\n", my_ipx_address);
886 if (*my_tcpip_address)
887 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
888}
889
890/*
891====================
892NET_Shutdown
893====================
894*/
895
896void NET_Shutdown (void)
897{
898 qsocket_t *sock;
899
900 SetNetTime();
901
902 for (sock = net_activeSockets; sock; sock = sock->next)
903 NET_Close(sock);
904
905//
906// shutdown the drivers
907//
908 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
909 {
910 if (net_drivers[net_driverlevel].initialized == true)
911 {
912 net_drivers[net_driverlevel].Shutdown ();
913 net_drivers[net_driverlevel].initialized = false;
914 }
915 }
916
917 if (vcrFile != -1)
918 {
919 Con_Printf ("Closing vcrfile.\n");
920 Sys_FileClose(vcrFile);
921 }
922}
923
924
925static PollProcedure *pollProcedureList = NULL;
926
927void NET_Poll(void)
928{
929 PollProcedure *pp;
930 qboolean useModem;
931
932 if (!configRestored)
933 {
934 if (serialAvailable)
935 {
936 if (config_com_modem.value == 1.0)
937 useModem = true;
938 else
939 useModem = false;
940 SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
941 SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
942 }
943 configRestored = true;
944 }
945
946 SetNetTime();
947
948 for (pp = pollProcedureList; pp; pp = pp->next)
949 {
950 if (pp->nextTime > net_time)
951 break;
952 pollProcedureList = pp->next;
953 pp->procedure(pp->arg);
954 }
955}
956
957
958void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
959{
960 PollProcedure *pp, *prev;
961
962 proc->nextTime = Sys_FloatTime() + timeOffset;
963 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
964 {
965 if (pp->nextTime >= proc->nextTime)
966 break;
967 prev = pp;
968 }
969
970 if (prev == NULL)
971 {
972 proc->next = pollProcedureList;
973 pollProcedureList = proc;
974 return;
975 }
976
977 proc->next = pp;
978 prev->next = proc;
979}
980
981
982#ifdef IDGODS
983#define IDNET 0xc0f62800
984
985qboolean IsID(struct qsockaddr *addr)
986{
987 if (idgods.value == 0.0)
988 return false;
989
990 if (addr->sa_family != 2)
991 return false;
992
993 if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
994 return true;
995 return false;
996}
997#endif
diff --git a/apps/plugins/sdl/progs/quake/net_none.c b/apps/plugins/sdl/progs/quake/net_none.c
new file mode 100644
index 0000000000..c00c97505c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_none.c
@@ -0,0 +1,46 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include "quakedef.h"
21
22#include "net_loop.h"
23
24net_driver_t net_drivers[MAX_NET_DRIVERS] =
25{
26 {
27 "Loopback",
28 false,
29 Loop_Init,
30 Loop_Listen,
31 Loop_SearchForHosts,
32 Loop_Connect,
33 Loop_CheckNewConnections,
34 Loop_GetMessage,
35 Loop_SendMessage,
36 Loop_SendUnreliableMessage,
37 Loop_CanSendMessage,
38 Loop_CanSendUnreliableMessage,
39 Loop_Close,
40 Loop_Shutdown
41 }
42};
43int net_numdrivers = 1;
44
45net_landriver_t net_landrivers[MAX_NET_DRIVERS];
46int net_numlandrivers = 0;
diff --git a/apps/plugins/sdl/progs/quake/net_udp.c b/apps/plugins/sdl/progs/quake/net_udp.c
new file mode 100644
index 0000000000..c7e8256635
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_udp.c
@@ -0,0 +1,415 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_udp.c
21
22#include "quakedef.h"
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <netdb.h>
28#include <sys/param.h>
29#include <sys/ioctl.h>
30#include <errno.h>
31
32#ifdef __sun__
33#include <sys/filio.h>
34#endif
35
36#ifdef NeXT
37#include <libc.h>
38#endif
39
40extern int gethostname (char *, int);
41extern int close (int);
42
43extern cvar_t hostname;
44
45static int net_acceptsocket = -1; // socket for fielding new connections
46static int net_controlsocket;
47static int net_broadcastsocket = 0;
48static struct qsockaddr broadcastaddr;
49
50static unsigned long myAddr;
51
52#include "net_udp.h"
53
54//=============================================================================
55
56int UDP_Init (void)
57{
58 struct hostent *local;
59 char buff[MAXHOSTNAMELEN];
60 struct qsockaddr addr;
61 char *colon;
62
63 if (COM_CheckParm ("-noudp"))
64 return -1;
65
66 // determine my name & address
67 gethostname(buff, MAXHOSTNAMELEN);
68 local = gethostbyname(buff);
69 myAddr = *(int *)local->h_addr_list[0];
70
71 // if the quake hostname isn't set, set it to the machine name
72 if (Q_strcmp(hostname.string, "UNNAMED") == 0)
73 {
74 buff[15] = 0;
75 Cvar_Set ("hostname", buff);
76 }
77
78 if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
79 Sys_Error("UDP_Init: Unable to open control socket\n");
80
81 ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
82 ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
83 ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport);
84
85 UDP_GetSocketAddr (net_controlsocket, &addr);
86 Q_strcpy(my_tcpip_address, UDP_AddrToString (&addr));
87 colon = Q_strrchr (my_tcpip_address, ':');
88 if (colon)
89 *colon = 0;
90
91 Con_Printf("UDP Initialized\n");
92 tcpipAvailable = true;
93
94 return net_controlsocket;
95}
96
97//=============================================================================
98
99void UDP_Shutdown (void)
100{
101 UDP_Listen (false);
102 UDP_CloseSocket (net_controlsocket);
103}
104
105//=============================================================================
106
107void UDP_Listen (qboolean state)
108{
109 // enable listening
110 if (state)
111 {
112 if (net_acceptsocket != -1)
113 return;
114 if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)
115 Sys_Error ("UDP_Listen: Unable to open accept socket\n");
116 return;
117 }
118
119 // disable listening
120 if (net_acceptsocket == -1)
121 return;
122 UDP_CloseSocket (net_acceptsocket);
123 net_acceptsocket = -1;
124}
125
126//=============================================================================
127
128int UDP_OpenSocket (int port)
129{
130 int newsocket;
131 struct sockaddr_in address;
132 qboolean _true = true;
133
134 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
135 return -1;
136
137#if 0
138 if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1)
139 goto ErrorReturn;
140#endif
141 address.sin_family = AF_INET;
142 address.sin_addr.s_addr = INADDR_ANY;
143 address.sin_port = htons(port);
144 if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
145 goto ErrorReturn;
146
147 return newsocket;
148
149ErrorReturn:
150 close (newsocket);
151 return -1;
152}
153
154//=============================================================================
155
156int UDP_CloseSocket (int socket)
157{
158 if (socket == net_broadcastsocket)
159 net_broadcastsocket = 0;
160 return close (socket);
161}
162
163
164//=============================================================================
165/*
166============
167PartialIPAddress
168
169this lets you type only as much of the net address as required, using
170the local network components to fill in the rest
171============
172*/
173static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
174{
175 char buff[256];
176 char *b;
177 int addr;
178 int num;
179 int mask;
180 int run;
181 int port;
182
183 buff[0] = '.';
184 b = buff;
185 strcpy(buff+1, in);
186 if (buff[1] == '.')
187 b++;
188
189 addr = 0;
190 mask=-1;
191 while (*b == '.')
192 {
193 b++;
194 num = 0;
195 run = 0;
196 while (!( *b < '0' || *b > '9'))
197 {
198 num = num*10 + *b++ - '0';
199 if (++run > 3)
200 return -1;
201 }
202 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
203 return -1;
204 if (num < 0 || num > 255)
205 return -1;
206 mask<<=8;
207 addr = (addr<<8) + num;
208 }
209
210 if (*b++ == ':')
211 port = Q_atoi(b);
212 else
213 port = net_hostport;
214
215 hostaddr->sa_family = AF_INET;
216 ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
217 ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
218
219 return 0;
220}
221//=============================================================================
222
223int UDP_Connect (int socket, struct qsockaddr *addr)
224{
225 return 0;
226}
227
228//=============================================================================
229
230int UDP_CheckNewConnections (void)
231{
232 unsigned long available;
233
234 if (net_acceptsocket == -1)
235 return -1;
236
237 if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
238 Sys_Error ("UDP: ioctlsocket (FIONREAD) failed\n");
239 if (available)
240 return net_acceptsocket;
241 return -1;
242}
243
244//=============================================================================
245
246int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
247{
248 int addrlen = sizeof (struct qsockaddr);
249 int ret;
250
251 ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
252 if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
253 return 0;
254 return ret;
255}
256
257//=============================================================================
258
259int UDP_MakeSocketBroadcastCapable (int socket)
260{
261 int i = 1;
262
263 // make this socket broadcast capable
264 if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
265 return -1;
266 net_broadcastsocket = socket;
267
268 return 0;
269}
270
271//=============================================================================
272
273int UDP_Broadcast (int socket, byte *buf, int len)
274{
275 int ret;
276
277 if (socket != net_broadcastsocket)
278 {
279 if (net_broadcastsocket != 0)
280 Sys_Error("Attempted to use multiple broadcasts sockets\n");
281 ret = UDP_MakeSocketBroadcastCapable (socket);
282 if (ret == -1)
283 {
284 Con_Printf("Unable to make socket broadcast capable\n");
285 return ret;
286 }
287 }
288
289 return UDP_Write (socket, buf, len, &broadcastaddr);
290}
291
292//=============================================================================
293
294int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
295{
296 int ret;
297
298 ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
299 if (ret == -1 && errno == EWOULDBLOCK)
300 return 0;
301 return ret;
302}
303
304//=============================================================================
305
306char *UDP_AddrToString (struct qsockaddr *addr)
307{
308 static char buffer[22];
309 int haddr;
310
311 haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
312 sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
313 return buffer;
314}
315
316//=============================================================================
317
318int UDP_StringToAddr (char *string, struct qsockaddr *addr)
319{
320 int ha1, ha2, ha3, ha4, hp;
321 int ipaddr;
322
323 sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
324 ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
325
326 addr->sa_family = AF_INET;
327 ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
328 ((struct sockaddr_in *)addr)->sin_port = htons(hp);
329 return 0;
330}
331
332//=============================================================================
333
334int UDP_GetSocketAddr (int socket, struct qsockaddr *addr)
335{
336 int addrlen = sizeof(struct qsockaddr);
337 unsigned int a;
338
339 Q_memset(addr, 0, sizeof(struct qsockaddr));
340 getsockname(socket, (struct sockaddr *)addr, &addrlen);
341 a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
342 if (a == 0 || a == inet_addr("127.0.0.1"))
343 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
344
345 return 0;
346}
347
348//=============================================================================
349
350int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name)
351{
352 struct hostent *hostentry;
353
354 hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
355 if (hostentry)
356 {
357 Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
358 return 0;
359 }
360
361 Q_strcpy (name, UDP_AddrToString (addr));
362 return 0;
363}
364
365//=============================================================================
366
367int UDP_GetAddrFromName(char *name, struct qsockaddr *addr)
368{
369 struct hostent *hostentry;
370
371 if (name[0] >= '0' && name[0] <= '9')
372 return PartialIPAddress (name, addr);
373
374 hostentry = gethostbyname (name);
375 if (!hostentry)
376 return -1;
377
378 addr->sa_family = AF_INET;
379 ((struct sockaddr_in *)addr)->sin_port = htons(net_hostport);
380 ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
381
382 return 0;
383}
384
385//=============================================================================
386
387int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
388{
389 if (addr1->sa_family != addr2->sa_family)
390 return -1;
391
392 if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
393 return -1;
394
395 if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
396 return 1;
397
398 return 0;
399}
400
401//=============================================================================
402
403int UDP_GetSocketPort (struct qsockaddr *addr)
404{
405 return ntohs(((struct sockaddr_in *)addr)->sin_port);
406}
407
408
409int UDP_SetSocketPort (struct qsockaddr *addr, int port)
410{
411 ((struct sockaddr_in *)addr)->sin_port = htons(port);
412 return 0;
413}
414
415//=============================================================================
diff --git a/apps/plugins/sdl/progs/quake/net_udp.h b/apps/plugins/sdl/progs/quake/net_udp.h
new file mode 100644
index 0000000000..75303011cd
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_udp.h
@@ -0,0 +1,39 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_udp.h
21
22int UDP_Init (void);
23void UDP_Shutdown (void);
24void UDP_Listen (qboolean state);
25int UDP_OpenSocket (int port);
26int UDP_CloseSocket (int socket);
27int UDP_Connect (int socket, struct qsockaddr *addr);
28int UDP_CheckNewConnections (void);
29int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);
30int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);
31int UDP_Broadcast (int socket, byte *buf, int len);
32char *UDP_AddrToString (struct qsockaddr *addr);
33int UDP_StringToAddr (char *string, struct qsockaddr *addr);
34int UDP_GetSocketAddr (int socket, struct qsockaddr *addr);
35int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);
36int UDP_GetAddrFromName (char *name, struct qsockaddr *addr);
37int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);
38int UDP_GetSocketPort (struct qsockaddr *addr);
39int UDP_SetSocketPort (struct qsockaddr *addr, int port);
diff --git a/apps/plugins/sdl/progs/quake/net_vcr.c b/apps/plugins/sdl/progs/quake/net_vcr.c
new file mode 100644
index 0000000000..ba8f40dcc1
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_vcr.c
@@ -0,0 +1,167 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_vcr.c
21
22#include "quakedef.h"
23#include "net_vcr.h"
24
25extern int vcrFile;
26
27// This is the playback portion of the VCR. It reads the file produced
28// by the recorder and plays it back to the host. The recording contains
29// everything necessary (events, timestamps, and data) to duplicate the game
30// from the viewpoint of everything above the network layer.
31
32static struct
33{
34 double time;
35 int op;
36 long session;
37} next;
38
39int VCR_Init (void)
40{
41 net_drivers[0].Init = VCR_Init;
42
43 net_drivers[0].SearchForHosts = VCR_SearchForHosts;
44 net_drivers[0].Connect = VCR_Connect;
45 net_drivers[0].CheckNewConnections = VCR_CheckNewConnections;
46 net_drivers[0].QGetMessage = VCR_GetMessage;
47 net_drivers[0].QSendMessage = VCR_SendMessage;
48 net_drivers[0].CanSendMessage = VCR_CanSendMessage;
49 net_drivers[0].Close = VCR_Close;
50 net_drivers[0].Shutdown = VCR_Shutdown;
51
52 Sys_FileRead(vcrFile, &next, sizeof(next));
53 return 0;
54}
55
56void VCR_ReadNext (void)
57{
58 if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0)
59 {
60 next.op = 255;
61 Sys_Error ("=== END OF PLAYBACK===\n");
62 }
63 if (next.op < 1 || next.op > VCR_MAX_MESSAGE)
64 Sys_Error ("VCR_ReadNext: bad op");
65}
66
67
68void VCR_Listen (qboolean state)
69{
70}
71
72
73void VCR_Shutdown (void)
74{
75}
76
77
78int VCR_GetMessage (qsocket_t *sock)
79{
80 int ret;
81
82 if (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != *(long *)(&sock->driverdata))
83 Sys_Error ("VCR missmatch");
84
85 Sys_FileRead(vcrFile, &ret, sizeof(int));
86 if (ret != 1)
87 {
88 VCR_ReadNext ();
89 return ret;
90 }
91
92 Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int));
93 Sys_FileRead(vcrFile, net_message.data, net_message.cursize);
94
95 VCR_ReadNext ();
96
97 return 1;
98}
99
100
101int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data)
102{
103 int ret;
104
105 if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != *(long *)(&sock->driverdata))
106 Sys_Error ("VCR missmatch");
107
108 Sys_FileRead(vcrFile, &ret, sizeof(int));
109
110 VCR_ReadNext ();
111
112 return ret;
113}
114
115
116qboolean VCR_CanSendMessage (qsocket_t *sock)
117{
118 qboolean ret;
119
120 if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != *(long *)(&sock->driverdata))
121 Sys_Error ("VCR missmatch");
122
123 Sys_FileRead(vcrFile, &ret, sizeof(int));
124
125 VCR_ReadNext ();
126
127 return ret;
128}
129
130
131void VCR_Close (qsocket_t *sock)
132{
133}
134
135
136void VCR_SearchForHosts (qboolean xmit)
137{
138}
139
140
141qsocket_t *VCR_Connect (char *host)
142{
143 return NULL;
144}
145
146
147qsocket_t *VCR_CheckNewConnections (void)
148{
149 qsocket_t *sock;
150
151 if (host_time != next.time || next.op != VCR_OP_CONNECT)
152 Sys_Error ("VCR missmatch");
153
154 if (!next.session)
155 {
156 VCR_ReadNext ();
157 return NULL;
158 }
159
160 sock = NET_NewQSocket ();
161 *(long *)(&sock->driverdata) = next.session;
162
163 Sys_FileRead (vcrFile, sock->address, NET_NAMELEN);
164 VCR_ReadNext ();
165
166 return sock;
167}
diff --git a/apps/plugins/sdl/progs/quake/net_vcr.h b/apps/plugins/sdl/progs/quake/net_vcr.h
new file mode 100644
index 0000000000..95c2f34c30
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_vcr.h
@@ -0,0 +1,37 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// net_vcr.h
21
22#define VCR_OP_CONNECT 1
23#define VCR_OP_GETMESSAGE 2
24#define VCR_OP_SENDMESSAGE 3
25#define VCR_OP_CANSENDMESSAGE 4
26#define VCR_MAX_MESSAGE 4
27
28int VCR_Init (void);
29void VCR_Listen (qboolean state);
30void VCR_SearchForHosts (qboolean xmit);
31qsocket_t *VCR_Connect (char *host);
32qsocket_t *VCR_CheckNewConnections (void);
33int VCR_GetMessage (qsocket_t *sock);
34int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data);
35qboolean VCR_CanSendMessage (qsocket_t *sock);
36void VCR_Close (qsocket_t *sock);
37void VCR_Shutdown (void);
diff --git a/apps/plugins/sdl/progs/quake/net_wso.c b/apps/plugins/sdl/progs/quake/net_wso.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/net_wso.c
diff --git a/apps/plugins/sdl/progs/quake/nonintel.c b/apps/plugins/sdl/progs/quake/nonintel.c
new file mode 100644
index 0000000000..9e5903969c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/nonintel.c
@@ -0,0 +1,64 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// nonintel.c: code for non-Intel processors only
22//
23
24#include "quakedef.h"
25#include "r_local.h"
26#include "d_local.h"
27
28#if !id386
29
30/*
31================
32R_Surf8Patch
33================
34*/
35void R_Surf8Patch ()
36{
37 // we only patch code on Intel
38}
39
40
41/*
42================
43R_Surf16Patch
44================
45*/
46void R_Surf16Patch ()
47{
48 // we only patch code on Intel
49}
50
51
52/*
53================
54R_SurfacePatch
55================
56*/
57void R_SurfacePatch (void)
58{
59 // we only patch code on Intel
60}
61
62
63#endif // !id386
64
diff --git a/apps/plugins/sdl/progs/quake/pr_cmds.c b/apps/plugins/sdl/progs/quake/pr_cmds.c
new file mode 100644
index 0000000000..9036afa899
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/pr_cmds.c
@@ -0,0 +1,1936 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22
23#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
24
25/*
26===============================================================================
27
28 BUILT-IN FUNCTIONS
29
30===============================================================================
31*/
32
33char *PF_VarString (int first)
34{
35 int i;
36 static char out[256];
37
38 out[0] = 0;
39 for (i=first ; i<pr_argc ; i++)
40 {
41 strcat (out, G_STRING((OFS_PARM0+i*3)));
42 }
43 return out;
44}
45
46
47/*
48=================
49PF_errror
50
51This is a TERMINAL error, which will kill off the entire server.
52Dumps self.
53
54error(value)
55=================
56*/
57void PF_error (void)
58{
59 char *s;
60 edict_t *ed;
61
62 s = PF_VarString(0);
63 Con_Printf ("======SERVER ERROR in %s:\n%s\n"
64 ,pr_strings + pr_xfunction->s_name,s);
65 ed = PROG_TO_EDICT(pr_global_struct->self);
66 ED_Print (ed);
67
68 Host_Error ("Program error");
69}
70
71/*
72=================
73PF_objerror
74
75Dumps out self, then an error message. The program is aborted and self is
76removed, but the level can continue.
77
78objerror(value)
79=================
80*/
81void PF_objerror (void)
82{
83 char *s;
84 edict_t *ed;
85
86 s = PF_VarString(0);
87 Con_Printf ("======OBJECT ERROR in %s:\n%s\n"
88 ,pr_strings + pr_xfunction->s_name,s);
89 ed = PROG_TO_EDICT(pr_global_struct->self);
90 ED_Print (ed);
91 ED_Free (ed);
92
93 Host_Error ("Program error");
94}
95
96
97
98/*
99==============
100PF_makevectors
101
102Writes new values for v_forward, v_up, and v_right based on angles
103makevectors(vector)
104==============
105*/
106void PF_makevectors (void)
107{
108 AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);
109}
110
111/*
112=================
113PF_setorigin
114
115This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported.
116
117setorigin (entity, origin)
118=================
119*/
120void PF_setorigin (void)
121{
122
123 edict_t *e;
124 float *org;
125
126 e = G_EDICT(OFS_PARM0);
127 org = G_VECTOR(OFS_PARM1);
128 //printf("SetOrigin %f %f %f", org[0], org[1], org[2]);
129 VectorCopy (org, e->v.origin);
130 SV_LinkEdict (e, false);
131}
132
133
134void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate)
135{
136 float *angles;
137 vec3_t rmin, rmax;
138 float bounds[2][3];
139 float xvector[2], yvector[2];
140 float a;
141 vec3_t base, transformed;
142 int i, j, k, l;
143
144 for (i=0 ; i<3 ; i++)
145 if (min[i] > max[i])
146 PR_RunError ("backwards mins/maxs");
147
148 rotate = false; // FIXME: implement rotation properly again
149
150 if (!rotate)
151 {
152 VectorCopy (min, rmin);
153 VectorCopy (max, rmax);
154 }
155 else
156 {
157 // find min / max for rotations
158 angles = e->v.angles;
159
160 a = angles[1]/180 * M_PI;
161
162 xvector[0] = cos(a);
163 xvector[1] = sin(a);
164 yvector[0] = -sin(a);
165 yvector[1] = cos(a);
166
167 VectorCopy (min, bounds[0]);
168 VectorCopy (max, bounds[1]);
169
170 rmin[0] = rmin[1] = rmin[2] = 9999;
171 rmax[0] = rmax[1] = rmax[2] = -9999;
172
173 for (i=0 ; i<= 1 ; i++)
174 {
175 base[0] = bounds[i][0];
176 for (j=0 ; j<= 1 ; j++)
177 {
178 base[1] = bounds[j][1];
179 for (k=0 ; k<= 1 ; k++)
180 {
181 base[2] = bounds[k][2];
182
183 // transform the point
184 transformed[0] = xvector[0]*base[0] + yvector[0]*base[1];
185 transformed[1] = xvector[1]*base[0] + yvector[1]*base[1];
186 transformed[2] = base[2];
187
188 for (l=0 ; l<3 ; l++)
189 {
190 if (transformed[l] < rmin[l])
191 rmin[l] = transformed[l];
192 if (transformed[l] > rmax[l])
193 rmax[l] = transformed[l];
194 }
195 }
196 }
197 }
198 }
199
200// set derived values
201 VectorCopy (rmin, e->v.mins);
202 VectorCopy (rmax, e->v.maxs);
203 VectorSubtract (max, min, e->v.size);
204
205 SV_LinkEdict (e, false);
206}
207
208/*
209=================
210PF_setsize
211
212the size box is rotated by the current angle
213
214setsize (entity, minvector, maxvector)
215=================
216*/
217void PF_setsize (void)
218{
219 edict_t *e;
220 float *min, *max;
221
222 e = G_EDICT(OFS_PARM0);
223 min = G_VECTOR(OFS_PARM1);
224 max = G_VECTOR(OFS_PARM2);
225 SetMinMaxSize (e, min, max, false);
226}
227
228
229/*
230=================
231PF_setmodel
232
233setmodel(entity, model)
234=================
235*/
236void PF_setmodel (void)
237{
238 edict_t *e;
239 char *m, **check;
240 model_t *mod;
241 int i;
242
243 e = G_EDICT(OFS_PARM0);
244 m = G_STRING(OFS_PARM1);
245
246// check to see if model was properly precached
247 for (i=0, check = sv.model_precache ; *check ; i++, check++)
248 if (!strcmp(*check, m))
249 break;
250
251 if (!*check)
252 PR_RunError ("no precache: %s\n", m);
253
254
255 e->v.model = m - pr_strings;
256 e->v.modelindex = i; //SV_ModelIndex (m);
257
258 mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true);
259
260 if (mod)
261 SetMinMaxSize (e, mod->mins, mod->maxs, true);
262 else
263 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
264}
265
266/*
267=================
268PF_bprint
269
270broadcast print to everyone on server
271
272bprint(value)
273=================
274*/
275void PF_bprint (void)
276{
277 char *s;
278
279 s = PF_VarString(0);
280 SV_BroadcastPrintf ("%s", s);
281}
282
283/*
284=================
285PF_sprint
286
287single print to a specific client
288
289sprint(clientent, value)
290=================
291*/
292void PF_sprint (void)
293{
294 char *s;
295 client_t *client;
296 int entnum;
297
298 entnum = G_EDICTNUM(OFS_PARM0);
299 s = PF_VarString(1);
300
301 if (entnum < 1 || entnum > svs.maxclients)
302 {
303 Con_Printf ("tried to sprint to a non-client\n");
304 return;
305 }
306
307 client = &svs.clients[entnum-1];
308
309 MSG_WriteChar (&client->message,svc_print);
310 MSG_WriteString (&client->message, s );
311}
312
313
314/*
315=================
316PF_centerprint
317
318single print to a specific client
319
320centerprint(clientent, value)
321=================
322*/
323void PF_centerprint (void)
324{
325 char *s;
326 client_t *client;
327 int entnum;
328
329 entnum = G_EDICTNUM(OFS_PARM0);
330 s = PF_VarString(1);
331
332 if (entnum < 1 || entnum > svs.maxclients)
333 {
334 Con_Printf ("tried to sprint to a non-client\n");
335 return;
336 }
337
338 client = &svs.clients[entnum-1];
339
340 MSG_WriteChar (&client->message,svc_centerprint);
341 MSG_WriteString (&client->message, s );
342}
343
344
345/*
346=================
347PF_normalize
348
349vector normalize(vector)
350=================
351*/
352void PF_normalize (void)
353{
354 float *value1;
355 vec3_t newvalue;
356 float new;
357
358 value1 = G_VECTOR(OFS_PARM0);
359
360 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
361 new = sqrt(new);
362
363 if (new == 0)
364 newvalue[0] = newvalue[1] = newvalue[2] = 0;
365 else
366 {
367 new = 1/new;
368 newvalue[0] = value1[0] * new;
369 newvalue[1] = value1[1] * new;
370 newvalue[2] = value1[2] * new;
371 }
372
373 VectorCopy (newvalue, G_VECTOR(OFS_RETURN));
374}
375
376/*
377=================
378PF_vlen
379
380scalar vlen(vector)
381=================
382*/
383void PF_vlen (void)
384{
385 float *value1;
386 float new;
387
388 value1 = G_VECTOR(OFS_PARM0);
389
390 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
391 new = sqrt(new);
392
393 G_FLOAT(OFS_RETURN) = new;
394}
395
396/*
397=================
398PF_vectoyaw
399
400float vectoyaw(vector)
401=================
402*/
403void PF_vectoyaw (void)
404{
405 float *value1;
406 float yaw;
407
408 value1 = G_VECTOR(OFS_PARM0);
409
410 if (value1[1] == 0 && value1[0] == 0)
411 yaw = 0;
412 else
413 {
414 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
415 if (yaw < 0)
416 yaw += 360;
417 }
418
419 G_FLOAT(OFS_RETURN) = yaw;
420}
421
422
423/*
424=================
425PF_vectoangles
426
427vector vectoangles(vector)
428=================
429*/
430void PF_vectoangles (void)
431{
432 float *value1;
433 float forward;
434 float yaw, pitch;
435
436 value1 = G_VECTOR(OFS_PARM0);
437
438 if (value1[1] == 0 && value1[0] == 0)
439 {
440 yaw = 0;
441 if (value1[2] > 0)
442 pitch = 90;
443 else
444 pitch = 270;
445 }
446 else
447 {
448 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
449 if (yaw < 0)
450 yaw += 360;
451
452 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
453 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
454 if (pitch < 0)
455 pitch += 360;
456 }
457
458 G_FLOAT(OFS_RETURN+0) = pitch;
459 G_FLOAT(OFS_RETURN+1) = yaw;
460 G_FLOAT(OFS_RETURN+2) = 0;
461}
462
463/*
464=================
465PF_Random
466
467Returns a number from 0<= num < 1
468
469random()
470=================
471*/
472void PF_random (void)
473{
474 float num;
475
476 num = (rand ()&0x7fff) / ((float)0x7fff);
477
478 G_FLOAT(OFS_RETURN) = num;
479}
480
481/*
482=================
483PF_particle
484
485particle(origin, color, count)
486=================
487*/
488void PF_particle (void)
489{
490 float *org, *dir;
491 float color;
492 float count;
493
494 org = G_VECTOR(OFS_PARM0);
495 dir = G_VECTOR(OFS_PARM1);
496 color = G_FLOAT(OFS_PARM2);
497 count = G_FLOAT(OFS_PARM3);
498 SV_StartParticle (org, dir, color, count);
499}
500
501
502/*
503=================
504PF_ambientsound
505
506=================
507*/
508void PF_ambientsound (void)
509{
510 char **check;
511 char *samp;
512 float *pos;
513 float vol, attenuation;
514 int i, soundnum;
515
516 pos = G_VECTOR (OFS_PARM0);
517 samp = G_STRING(OFS_PARM1);
518 vol = G_FLOAT(OFS_PARM2);
519 attenuation = G_FLOAT(OFS_PARM3);
520
521// check to see if samp was properly precached
522 for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++)
523 if (!strcmp(*check,samp))
524 break;
525
526 if (!*check)
527 {
528 Con_Printf ("no precache: %s\n", samp);
529 return;
530 }
531
532// add an svc_spawnambient command to the level signon packet
533
534 MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
535 for (i=0 ; i<3 ; i++)
536 MSG_WriteCoord(&sv.signon, pos[i]);
537
538 MSG_WriteByte (&sv.signon, soundnum);
539
540 MSG_WriteByte (&sv.signon, vol*255);
541 MSG_WriteByte (&sv.signon, attenuation*64);
542
543}
544
545/*
546=================
547PF_sound
548
549Each entity can have eight independant sound sources, like voice,
550weapon, feet, etc.
551
552Channel 0 is an auto-allocate channel, the others override anything
553allready running on that entity/channel pair.
554
555An attenuation of 0 will play full volume everywhere in the level.
556Larger attenuations will drop off.
557
558=================
559*/
560void PF_sound (void)
561{
562 char *sample;
563 int channel;
564 edict_t *entity;
565 int volume;
566 float attenuation;
567
568 entity = G_EDICT(OFS_PARM0);
569 channel = G_FLOAT(OFS_PARM1);
570 sample = G_STRING(OFS_PARM2);
571 volume = G_FLOAT(OFS_PARM3) * 255;
572 attenuation = G_FLOAT(OFS_PARM4);
573
574 if (volume < 0 || volume > 255)
575 Sys_Error ("SV_StartSound: volume = %i", volume);
576
577 if (attenuation < 0 || attenuation > 4)
578 Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
579
580 if (channel < 0 || channel > 7)
581 Sys_Error ("SV_StartSound: channel = %i", channel);
582
583 SV_StartSound (entity, channel, sample, volume, attenuation);
584}
585
586/*
587=================
588PF_break
589
590break()
591=================
592*/
593void PF_break (void)
594{
595Con_Printf ("break statement\n");
596*(int *)-4 = 0; // dump to debugger
597// PR_RunError ("break statement");
598}
599
600/*
601=================
602PF_traceline
603
604Used for use tracing and shot targeting
605Traces are blocked by bbox and exact bsp entityes, and also slide box entities
606if the tryents flag is set.
607
608traceline (vector1, vector2, tryents)
609=================
610*/
611void PF_traceline (void)
612{
613 float *v1, *v2;
614 trace_t trace;
615 int nomonsters;
616 edict_t *ent;
617
618 v1 = G_VECTOR(OFS_PARM0);
619 v2 = G_VECTOR(OFS_PARM1);
620 nomonsters = G_FLOAT(OFS_PARM2);
621 ent = G_EDICT(OFS_PARM3);
622
623 trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent);
624
625 pr_global_struct->trace_allsolid = trace.allsolid;
626 pr_global_struct->trace_startsolid = trace.startsolid;
627 pr_global_struct->trace_fraction = trace.fraction;
628 pr_global_struct->trace_inwater = trace.inwater;
629 pr_global_struct->trace_inopen = trace.inopen;
630 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
631 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
632 pr_global_struct->trace_plane_dist = trace.plane.dist;
633 if (trace.ent)
634 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
635 else
636 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
637}
638
639
640#ifdef QUAKE2
641extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore);
642
643void PF_TraceToss (void)
644{
645 trace_t trace;
646 edict_t *ent;
647 edict_t *ignore;
648
649 ent = G_EDICT(OFS_PARM0);
650 ignore = G_EDICT(OFS_PARM1);
651
652 trace = SV_Trace_Toss (ent, ignore);
653
654 pr_global_struct->trace_allsolid = trace.allsolid;
655 pr_global_struct->trace_startsolid = trace.startsolid;
656 pr_global_struct->trace_fraction = trace.fraction;
657 pr_global_struct->trace_inwater = trace.inwater;
658 pr_global_struct->trace_inopen = trace.inopen;
659 VectorCopy (trace.endpos, pr_global_struct->trace_endpos);
660 VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);
661 pr_global_struct->trace_plane_dist = trace.plane.dist;
662 if (trace.ent)
663 pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);
664 else
665 pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);
666}
667#endif
668
669
670/*
671=================
672PF_checkpos
673
674Returns true if the given entity can move to the given position from it's
675current position by walking or rolling.
676FIXME: make work...
677scalar checkpos (entity, vector)
678=================
679*/
680void PF_checkpos (void)
681{
682}
683
684//============================================================================
685
686byte checkpvs[MAX_MAP_LEAFS/8];
687
688int PF_newcheckclient (int check)
689{
690 int i;
691 byte *pvs;
692 edict_t *ent;
693 mleaf_t *leaf;
694 vec3_t org;
695
696// cycle to the next one
697
698 if (check < 1)
699 check = 1;
700 if (check > svs.maxclients)
701 check = svs.maxclients;
702
703 if (check == svs.maxclients)
704 i = 1;
705 else
706 i = check + 1;
707
708 for ( ; ; i++)
709 {
710 if (i == svs.maxclients+1)
711 i = 1;
712
713 ent = EDICT_NUM(i);
714
715 if (i == check)
716 break; // didn't find anything else
717
718 if (ent->free)
719 continue;
720 if (ent->v.health <= 0)
721 continue;
722 if ((int)ent->v.flags & FL_NOTARGET)
723 continue;
724
725 // anything that is a client, or has a client as an enemy
726 break;
727 }
728
729// get the PVS for the entity
730 VectorAdd (ent->v.origin, ent->v.view_ofs, org);
731 leaf = Mod_PointInLeaf (org, sv.worldmodel);
732 pvs = Mod_LeafPVS (leaf, sv.worldmodel);
733 memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 );
734
735 return i;
736}
737
738/*
739=================
740PF_checkclient
741
742Returns a client (or object that has a client enemy) that would be a
743valid target.
744
745If there are more than one valid options, they are cycled each frame
746
747If (self.origin + self.viewofs) is not in the PVS of the current target,
748it is not returned at all.
749
750name checkclient ()
751=================
752*/
753#define MAX_CHECK 16
754int c_invis, c_notvis;
755void PF_checkclient (void)
756{
757 edict_t *ent, *self;
758 mleaf_t *leaf;
759 int l;
760 vec3_t view;
761
762// find a new check if on a new frame
763 if (sv.time - sv.lastchecktime >= 0.1)
764 {
765 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
766 sv.lastchecktime = sv.time;
767 }
768
769// return check if it might be visible
770 ent = EDICT_NUM(sv.lastcheck);
771 if (ent->free || ent->v.health <= 0)
772 {
773 RETURN_EDICT(sv.edicts);
774 return;
775 }
776
777// if current entity can't possibly see the check entity, return 0
778 self = PROG_TO_EDICT(pr_global_struct->self);
779 VectorAdd (self->v.origin, self->v.view_ofs, view);
780 leaf = Mod_PointInLeaf (view, sv.worldmodel);
781 l = (leaf - sv.worldmodel->leafs) - 1;
782 if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
783 {
784c_notvis++;
785 RETURN_EDICT(sv.edicts);
786 return;
787 }
788
789// might be able to see it
790c_invis++;
791 RETURN_EDICT(ent);
792}
793
794//============================================================================
795
796
797/*
798=================
799PF_stuffcmd
800
801Sends text over to the client's execution buffer
802
803stuffcmd (clientent, value)
804=================
805*/
806void PF_stuffcmd (void)
807{
808 int entnum;
809 char *str;
810 client_t *old;
811
812 entnum = G_EDICTNUM(OFS_PARM0);
813 if (entnum < 1 || entnum > svs.maxclients)
814 PR_RunError ("Parm 0 not a client");
815 str = G_STRING(OFS_PARM1);
816
817 old = host_client;
818 host_client = &svs.clients[entnum-1];
819 Host_ClientCommands ("%s", str);
820 host_client = old;
821}
822
823/*
824=================
825PF_localcmd
826
827Sends text over to the client's execution buffer
828
829localcmd (string)
830=================
831*/
832void PF_localcmd (void)
833{
834 char *str;
835
836 str = G_STRING(OFS_PARM0);
837 Cbuf_AddText (str);
838}
839
840/*
841=================
842PF_cvar
843
844float cvar (string)
845=================
846*/
847void PF_cvar (void)
848{
849 char *str;
850
851 str = G_STRING(OFS_PARM0);
852
853 G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
854}
855
856/*
857=================
858PF_cvar_set
859
860float cvar (string)
861=================
862*/
863void PF_cvar_set (void)
864{
865 char *var, *val;
866
867 var = G_STRING(OFS_PARM0);
868 val = G_STRING(OFS_PARM1);
869
870 Cvar_Set (var, val);
871}
872
873/*
874=================
875PF_findradius
876
877Returns a chain of entities that have origins within a spherical area
878
879findradius (origin, radius)
880=================
881*/
882void PF_findradius (void)
883{
884 edict_t *ent, *chain;
885 float rad;
886 float *org;
887 vec3_t eorg;
888 int i, j;
889
890 chain = (edict_t *)sv.edicts;
891
892 org = G_VECTOR(OFS_PARM0);
893 rad = G_FLOAT(OFS_PARM1);
894
895 ent = NEXT_EDICT(sv.edicts);
896 for (i=1 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
897 {
898 if (ent->free)
899 continue;
900 if (ent->v.solid == SOLID_NOT)
901 continue;
902 for (j=0 ; j<3 ; j++)
903 eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);
904 if (Length(eorg) > rad)
905 continue;
906
907 ent->v.chain = EDICT_TO_PROG(chain);
908 chain = ent;
909 }
910
911 RETURN_EDICT(chain);
912}
913
914
915/*
916=========
917PF_dprint
918=========
919*/
920void PF_dprint (void)
921{
922 Con_DPrintf ("%s",PF_VarString(0));
923}
924
925char pr_string_temp[128];
926
927void PF_ftos (void)
928{
929 float v;
930 v = G_FLOAT(OFS_PARM0);
931
932 if (v == (int)v)
933 sprintf (pr_string_temp, "%d",(int)v);
934 else
935 sprintf (pr_string_temp, "%5.1f",v);
936 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
937}
938
939void PF_fabs (void)
940{
941 float v;
942 v = G_FLOAT(OFS_PARM0);
943 G_FLOAT(OFS_RETURN) = fabs(v);
944}
945
946void PF_vtos (void)
947{
948 sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);
949 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
950}
951
952#ifdef QUAKE2
953void PF_etos (void)
954{
955 sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0));
956 G_INT(OFS_RETURN) = pr_string_temp - pr_strings;
957}
958#endif
959
960void PF_Spawn (void)
961{
962 edict_t *ed;
963 ed = ED_Alloc();
964 RETURN_EDICT(ed);
965}
966
967void PF_Remove (void)
968{
969 edict_t *ed;
970
971 ed = G_EDICT(OFS_PARM0);
972 ED_Free (ed);
973}
974
975
976// entity (entity start, .string field, string match) find = #5;
977void PF_Find (void)
978#ifdef QUAKE2
979{
980 int e;
981 int f;
982 char *s, *t;
983 edict_t *ed;
984 edict_t *first;
985 edict_t *second;
986 edict_t *last;
987
988 first = second = last = (edict_t *)sv.edicts;
989 e = G_EDICTNUM(OFS_PARM0);
990 f = G_INT(OFS_PARM1);
991 s = G_STRING(OFS_PARM2);
992 if (!s)
993 PR_RunError ("PF_Find: bad search string");
994
995 for (e++ ; e < sv.num_edicts ; e++)
996 {
997 ed = EDICT_NUM(e);
998 if (ed->free)
999 continue;
1000 t = E_STRING(ed,f);
1001 if (!t)
1002 continue;
1003 if (!strcmp(t,s))
1004 {
1005 if (first == (edict_t *)sv.edicts)
1006 first = ed;
1007 else if (second == (edict_t *)sv.edicts)
1008 second = ed;
1009 ed->v.chain = EDICT_TO_PROG(last);
1010 last = ed;
1011 }
1012 }
1013
1014 if (first != last)
1015 {
1016 if (last != second)
1017 first->v.chain = last->v.chain;
1018 else
1019 first->v.chain = EDICT_TO_PROG(last);
1020 last->v.chain = EDICT_TO_PROG((edict_t *)sv.edicts);
1021 if (second && second != last)
1022 second->v.chain = EDICT_TO_PROG(last);
1023 }
1024 RETURN_EDICT(first);
1025}
1026#else
1027{
1028 int e;
1029 int f;
1030 char *s, *t;
1031 edict_t *ed;
1032
1033 e = G_EDICTNUM(OFS_PARM0);
1034 f = G_INT(OFS_PARM1);
1035 s = G_STRING(OFS_PARM2);
1036 if (!s)
1037 PR_RunError ("PF_Find: bad search string");
1038
1039 for (e++ ; e < sv.num_edicts ; e++)
1040 {
1041 ed = EDICT_NUM(e);
1042 if (ed->free)
1043 continue;
1044 t = E_STRING(ed,f);
1045 if (!t)
1046 continue;
1047 if (!strcmp(t,s))
1048 {
1049 RETURN_EDICT(ed);
1050 return;
1051 }
1052 }
1053
1054 RETURN_EDICT(sv.edicts);
1055}
1056#endif
1057
1058void PR_CheckEmptyString (char *s)
1059{
1060 if (s[0] <= ' ')
1061 PR_RunError ("Bad string");
1062}
1063
1064void PF_precache_file (void)
1065{ // precache_file is only used to copy files with qcc, it does nothing
1066 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1067}
1068
1069void PF_precache_sound (void)
1070{
1071 char *s;
1072 int i;
1073
1074 if (sv.state != ss_loading)
1075 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1076
1077 s = G_STRING(OFS_PARM0);
1078 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1079 PR_CheckEmptyString (s);
1080
1081 for (i=0 ; i<MAX_SOUNDS ; i++)
1082 {
1083 if (!sv.sound_precache[i])
1084 {
1085 sv.sound_precache[i] = s;
1086 return;
1087 }
1088 if (!strcmp(sv.sound_precache[i], s))
1089 return;
1090 }
1091 PR_RunError ("PF_precache_sound: overflow");
1092}
1093
1094void PF_precache_model (void)
1095{
1096 char *s;
1097 int i;
1098
1099 if (sv.state != ss_loading)
1100 PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
1101
1102 s = G_STRING(OFS_PARM0);
1103 G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
1104 PR_CheckEmptyString (s);
1105
1106 for (i=0 ; i<MAX_MODELS ; i++)
1107 {
1108 if (!sv.model_precache[i])
1109 {
1110 sv.model_precache[i] = s;
1111 sv.models[i] = Mod_ForName (s, true);
1112 return;
1113 }
1114 if (!strcmp(sv.model_precache[i], s))
1115 return;
1116 }
1117 PR_RunError ("PF_precache_model: overflow");
1118}
1119
1120
1121void PF_coredump (void)
1122{
1123 ED_PrintEdicts ();
1124}
1125
1126void PF_traceon (void)
1127{
1128 pr_trace = true;
1129}
1130
1131void PF_traceoff (void)
1132{
1133 pr_trace = false;
1134}
1135
1136void PF_eprint (void)
1137{
1138 ED_PrintNum (G_EDICTNUM(OFS_PARM0));
1139}
1140
1141/*
1142===============
1143PF_walkmove
1144
1145float(float yaw, float dist) walkmove
1146===============
1147*/
1148void PF_walkmove (void)
1149{
1150 edict_t *ent;
1151 float yaw, dist;
1152 vec3_t move;
1153 dfunction_t *oldf;
1154 int oldself;
1155
1156 ent = PROG_TO_EDICT(pr_global_struct->self);
1157 yaw = G_FLOAT(OFS_PARM0);
1158 dist = G_FLOAT(OFS_PARM1);
1159
1160 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
1161 {
1162 G_FLOAT(OFS_RETURN) = 0;
1163 return;
1164 }
1165
1166 yaw = yaw*M_PI*2 / 360;
1167
1168 move[0] = cos(yaw)*dist;
1169 move[1] = sin(yaw)*dist;
1170 move[2] = 0;
1171
1172// save program state, because SV_movestep may call other progs
1173 oldf = pr_xfunction;
1174 oldself = pr_global_struct->self;
1175
1176 G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
1177
1178
1179// restore program state
1180 pr_xfunction = oldf;
1181 pr_global_struct->self = oldself;
1182}
1183
1184/*
1185===============
1186PF_droptofloor
1187
1188void() droptofloor
1189===============
1190*/
1191void PF_droptofloor (void)
1192{
1193 edict_t *ent;
1194 vec3_t end;
1195 trace_t trace;
1196
1197 ent = PROG_TO_EDICT(pr_global_struct->self);
1198
1199 VectorCopy (ent->v.origin, end);
1200 end[2] -= 256;
1201
1202 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
1203
1204 if (trace.fraction == 1 || trace.allsolid)
1205 G_FLOAT(OFS_RETURN) = 0;
1206 else
1207 {
1208 VectorCopy (trace.endpos, ent->v.origin);
1209 SV_LinkEdict (ent, false);
1210 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1211 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1212 G_FLOAT(OFS_RETURN) = 1;
1213 }
1214}
1215
1216/*
1217===============
1218PF_lightstyle
1219
1220void(float style, string value) lightstyle
1221===============
1222*/
1223void PF_lightstyle (void)
1224{
1225 int style;
1226 char *val;
1227 client_t *client;
1228 int j;
1229
1230 style = G_FLOAT(OFS_PARM0);
1231 val = G_STRING(OFS_PARM1);
1232
1233// change the string in sv
1234 sv.lightstyles[style] = val;
1235
1236// send message to all clients on this server
1237 if (sv.state != ss_active)
1238 return;
1239
1240 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
1241 if (client->active || client->spawned)
1242 {
1243 MSG_WriteChar (&client->message, svc_lightstyle);
1244 MSG_WriteChar (&client->message,style);
1245 MSG_WriteString (&client->message, val);
1246 }
1247}
1248
1249void PF_rint (void)
1250{
1251 float f;
1252 f = G_FLOAT(OFS_PARM0);
1253 if (f > 0)
1254 G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1255 else
1256 G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1257}
1258void PF_floor (void)
1259{
1260 G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));
1261}
1262void PF_ceil (void)
1263{
1264 G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));
1265}
1266
1267
1268/*
1269=============
1270PF_checkbottom
1271=============
1272*/
1273void PF_checkbottom (void)
1274{
1275 edict_t *ent;
1276
1277 ent = G_EDICT(OFS_PARM0);
1278
1279 G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent);
1280}
1281
1282/*
1283=============
1284PF_pointcontents
1285=============
1286*/
1287void PF_pointcontents (void)
1288{
1289 float *v;
1290
1291 v = G_VECTOR(OFS_PARM0);
1292
1293 G_FLOAT(OFS_RETURN) = SV_PointContents (v);
1294}
1295
1296/*
1297=============
1298PF_nextent
1299
1300entity nextent(entity)
1301=============
1302*/
1303void PF_nextent (void)
1304{
1305 int i;
1306 edict_t *ent;
1307
1308 i = G_EDICTNUM(OFS_PARM0);
1309 while (1)
1310 {
1311 i++;
1312 if (i == sv.num_edicts)
1313 {
1314 RETURN_EDICT(sv.edicts);
1315 return;
1316 }
1317 ent = EDICT_NUM(i);
1318 if (!ent->free)
1319 {
1320 RETURN_EDICT(ent);
1321 return;
1322 }
1323 }
1324}
1325
1326/*
1327=============
1328PF_aim
1329
1330Pick a vector for the player to shoot along
1331vector aim(entity, missilespeed)
1332=============
1333*/
1334cvar_t sv_aim = {"sv_aim", "0.93"};
1335void PF_aim (void)
1336{
1337 edict_t *ent, *check, *bestent;
1338 vec3_t start, dir, end, bestdir;
1339 int i, j;
1340 trace_t tr;
1341 float dist, bestdist;
1342 float speed;
1343
1344 ent = G_EDICT(OFS_PARM0);
1345 speed = G_FLOAT(OFS_PARM1);
1346
1347 VectorCopy (ent->v.origin, start);
1348 start[2] += 20;
1349
1350// try sending a trace straight
1351 VectorCopy (pr_global_struct->v_forward, dir);
1352 VectorMA (start, 2048, dir, end);
1353 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1354 if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM
1355 && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) )
1356 {
1357 VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));
1358 return;
1359 }
1360
1361
1362// try all possible entities
1363 VectorCopy (dir, bestdir);
1364 bestdist = sv_aim.value;
1365 bestent = NULL;
1366
1367 check = NEXT_EDICT(sv.edicts);
1368 for (i=1 ; i<sv.num_edicts ; i++, check = NEXT_EDICT(check) )
1369 {
1370 if (check->v.takedamage != DAMAGE_AIM)
1371 continue;
1372 if (check == ent)
1373 continue;
1374 if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)
1375 continue; // don't aim at teammate
1376 for (j=0 ; j<3 ; j++)
1377 end[j] = check->v.origin[j]
1378 + 0.5*(check->v.mins[j] + check->v.maxs[j]);
1379 VectorSubtract (end, start, dir);
1380 VectorNormalizeNoRet (dir);
1381 dist = DotProduct (dir, pr_global_struct->v_forward);
1382 if (dist < bestdist)
1383 continue; // to far to turn
1384 tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent);
1385 if (tr.ent == check)
1386 { // can shoot at this one
1387 bestdist = dist;
1388 bestent = check;
1389 }
1390 }
1391
1392 if (bestent)
1393 {
1394 VectorSubtract (bestent->v.origin, ent->v.origin, dir);
1395 dist = DotProduct (dir, pr_global_struct->v_forward);
1396 VectorScale (pr_global_struct->v_forward, dist, end);
1397 end[2] = dir[2];
1398 VectorNormalizeNoRet (end);
1399 VectorCopy (end, G_VECTOR(OFS_RETURN));
1400 }
1401 else
1402 {
1403 VectorCopy (bestdir, G_VECTOR(OFS_RETURN));
1404 }
1405}
1406
1407/*
1408==============
1409PF_changeyaw
1410
1411This was a major timewaster in progs, so it was converted to C
1412==============
1413*/
1414void PF_changeyaw (void)
1415{
1416 edict_t *ent;
1417 float ideal, current, move, speed;
1418
1419 ent = PROG_TO_EDICT(pr_global_struct->self);
1420 current = anglemod( ent->v.angles[1] );
1421 ideal = ent->v.ideal_yaw;
1422 speed = ent->v.yaw_speed;
1423
1424 if (current == ideal)
1425 return;
1426 move = ideal - current;
1427 if (ideal > current)
1428 {
1429 if (move >= 180)
1430 move = move - 360;
1431 }
1432 else
1433 {
1434 if (move <= -180)
1435 move = move + 360;
1436 }
1437 if (move > 0)
1438 {
1439 if (move > speed)
1440 move = speed;
1441 }
1442 else
1443 {
1444 if (move < -speed)
1445 move = -speed;
1446 }
1447
1448 ent->v.angles[1] = anglemod (current + move);
1449}
1450
1451#ifdef QUAKE2
1452/*
1453==============
1454PF_changepitch
1455==============
1456*/
1457void PF_changepitch (void)
1458{
1459 edict_t *ent;
1460 float ideal, current, move, speed;
1461
1462 ent = G_EDICT(OFS_PARM0);
1463 current = anglemod( ent->v.angles[0] );
1464 ideal = ent->v.idealpitch;
1465 speed = ent->v.pitch_speed;
1466
1467 if (current == ideal)
1468 return;
1469 move = ideal - current;
1470 if (ideal > current)
1471 {
1472 if (move >= 180)
1473 move = move - 360;
1474 }
1475 else
1476 {
1477 if (move <= -180)
1478 move = move + 360;
1479 }
1480 if (move > 0)
1481 {
1482 if (move > speed)
1483 move = speed;
1484 }
1485 else
1486 {
1487 if (move < -speed)
1488 move = -speed;
1489 }
1490
1491 ent->v.angles[0] = anglemod (current + move);
1492}
1493#endif
1494
1495/*
1496===============================================================================
1497
1498MESSAGE WRITING
1499
1500===============================================================================
1501*/
1502
1503#define MSG_BROADCAST 0 // unreliable to all
1504#define MSG_ONE 1 // reliable to one (msg_entity)
1505#define MSG_ALL 2 // reliable to all
1506#define MSG_INIT 3 // write to the init string
1507
1508sizebuf_t *WriteDest (void)
1509{
1510 int entnum;
1511 int dest;
1512 edict_t *ent;
1513
1514 dest = G_FLOAT(OFS_PARM0);
1515 switch (dest)
1516 {
1517 case MSG_BROADCAST:
1518 return &sv.datagram;
1519
1520 case MSG_ONE:
1521 ent = PROG_TO_EDICT(pr_global_struct->msg_entity);
1522 entnum = NUM_FOR_EDICT(ent);
1523 if (entnum < 1 || entnum > svs.maxclients)
1524 PR_RunError ("WriteDest: not a client");
1525 return &svs.clients[entnum-1].message;
1526
1527 case MSG_ALL:
1528 return &sv.reliable_datagram;
1529
1530 case MSG_INIT:
1531 return &sv.signon;
1532
1533 default:
1534 PR_RunError ("WriteDest: bad destination");
1535 break;
1536 }
1537
1538 return NULL;
1539}
1540
1541void PF_WriteByte (void)
1542{
1543 MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1));
1544}
1545
1546void PF_WriteChar (void)
1547{
1548 MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1));
1549}
1550
1551void PF_WriteShort (void)
1552{
1553 MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1));
1554}
1555
1556void PF_WriteLong (void)
1557{
1558 MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1));
1559}
1560
1561void PF_WriteAngle (void)
1562{
1563 MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
1564}
1565
1566void PF_WriteCoord (void)
1567{
1568 MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1));
1569}
1570
1571void PF_WriteString (void)
1572{
1573 MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1));
1574}
1575
1576
1577void PF_WriteEntity (void)
1578{
1579 MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1));
1580}
1581
1582//=============================================================================
1583
1584int SV_ModelIndex (char *name);
1585
1586void PF_makestatic (void)
1587{
1588 edict_t *ent;
1589 int i;
1590
1591 ent = G_EDICT(OFS_PARM0);
1592
1593 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1594
1595 MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));
1596
1597 MSG_WriteByte (&sv.signon, ent->v.frame);
1598 MSG_WriteByte (&sv.signon, ent->v.colormap);
1599 MSG_WriteByte (&sv.signon, ent->v.skin);
1600 for (i=0 ; i<3 ; i++)
1601 {
1602 MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
1603 MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
1604 }
1605
1606// throw the entity away now
1607 ED_Free (ent);
1608}
1609
1610//=============================================================================
1611
1612/*
1613==============
1614PF_setspawnparms
1615==============
1616*/
1617void PF_setspawnparms (void)
1618{
1619 edict_t *ent;
1620 int i;
1621 client_t *client;
1622
1623 ent = G_EDICT(OFS_PARM0);
1624 i = NUM_FOR_EDICT(ent);
1625 if (i < 1 || i > svs.maxclients)
1626 PR_RunError ("Entity is not a client");
1627
1628 // copy spawn parms out of the client_t
1629 client = svs.clients + (i-1);
1630
1631 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1632 (&pr_global_struct->parm1)[i] = client->spawn_parms[i];
1633}
1634
1635/*
1636==============
1637PF_changelevel
1638==============
1639*/
1640void PF_changelevel (void)
1641{
1642#ifdef QUAKE2
1643 char *s1, *s2;
1644
1645 if (svs.changelevel_issued)
1646 return;
1647 svs.changelevel_issued = true;
1648
1649 s1 = G_STRING(OFS_PARM0);
1650 s2 = G_STRING(OFS_PARM1);
1651
1652 if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE))
1653 Cbuf_AddText (va("changelevel %s %s\n",s1, s2));
1654 else
1655 Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2));
1656#else
1657 char *s;
1658
1659// make sure we don't issue two changelevels
1660 if (svs.changelevel_issued)
1661 return;
1662 svs.changelevel_issued = true;
1663
1664 s = G_STRING(OFS_PARM0);
1665 Cbuf_AddText (va("changelevel %s\n",s));
1666#endif
1667}
1668
1669
1670#ifdef QUAKE2
1671
1672#define CONTENT_WATER -3
1673#define CONTENT_SLIME -4
1674#define CONTENT_LAVA -5
1675
1676#define FL_IMMUNE_WATER 131072
1677#define FL_IMMUNE_SLIME 262144
1678#define FL_IMMUNE_LAVA 524288
1679
1680#define CHAN_VOICE 2
1681#define CHAN_BODY 4
1682
1683#define ATTN_NORM 1
1684
1685void PF_WaterMove (void)
1686{
1687 edict_t *self;
1688 int flags;
1689 int waterlevel;
1690 int watertype;
1691 float drownlevel;
1692 float damage = 0.0;
1693
1694 self = PROG_TO_EDICT(pr_global_struct->self);
1695
1696 if (self->v.movetype == MOVETYPE_NOCLIP)
1697 {
1698 self->v.air_finished = sv.time + 12;
1699 G_FLOAT(OFS_RETURN) = damage;
1700 return;
1701 }
1702
1703 if (self->v.health < 0)
1704 {
1705 G_FLOAT(OFS_RETURN) = damage;
1706 return;
1707 }
1708
1709 if (self->v.deadflag == DEAD_NO)
1710 drownlevel = 3;
1711 else
1712 drownlevel = 1;
1713
1714 flags = (int)self->v.flags;
1715 waterlevel = (int)self->v.waterlevel;
1716 watertype = (int)self->v.watertype;
1717
1718 if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE)))
1719 if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel))
1720 {
1721 if (self->v.air_finished < sv.time)
1722 if (self->v.pain_finished < sv.time)
1723 {
1724 self->v.dmg = self->v.dmg + 2;
1725 if (self->v.dmg > 15)
1726 self->v.dmg = 10;
1727// T_Damage (self, world, world, self.dmg, 0, FALSE);
1728 damage = self->v.dmg;
1729 self->v.pain_finished = sv.time + 1.0;
1730 }
1731 }
1732 else
1733 {
1734 if (self->v.air_finished < sv.time)
1735// sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
1736 SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM);
1737 else if (self->v.air_finished < sv.time + 9)
1738// sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
1739 SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM);
1740 self->v.air_finished = sv.time + 12.0;
1741 self->v.dmg = 2;
1742 }
1743
1744 if (!waterlevel)
1745 {
1746 if (flags & FL_INWATER)
1747 {
1748 // play leave water sound
1749// sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
1750 SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM);
1751 self->v.flags = (float)(flags &~FL_INWATER);
1752 }
1753 self->v.air_finished = sv.time + 12.0;
1754 G_FLOAT(OFS_RETURN) = damage;
1755 return;
1756 }
1757
1758 if (watertype == CONTENT_LAVA)
1759 { // do damage
1760 if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE)))
1761 if (self->v.dmgtime < sv.time)
1762 {
1763 if (self->v.radsuit_finished < sv.time)
1764 self->v.dmgtime = sv.time + 0.2;
1765 else
1766 self->v.dmgtime = sv.time + 1.0;
1767// T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);
1768 damage = (float)(10*waterlevel);
1769 }
1770 }
1771 else if (watertype == CONTENT_SLIME)
1772 { // do damage
1773 if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE)))
1774 if (self->v.dmgtime < sv.time && self->v.radsuit_finished < sv.time)
1775 {
1776 self->v.dmgtime = sv.time + 1.0;
1777// T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);
1778 damage = (float)(4*waterlevel);
1779 }
1780 }
1781
1782 if ( !(flags & FL_INWATER) )
1783 {
1784
1785// player enter water sound
1786 if (watertype == CONTENT_LAVA)
1787// sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
1788 SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM);
1789 if (watertype == CONTENT_WATER)
1790// sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
1791 SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM);
1792 if (watertype == CONTENT_SLIME)
1793// sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
1794 SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM);
1795
1796 self->v.flags = (float)(flags | FL_INWATER);
1797 self->v.dmgtime = 0;
1798 }
1799
1800 if (! (flags & FL_WATERJUMP) )
1801 {
1802// self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
1803 VectorMA (self->v.velocity, -0.8 * self->v.waterlevel * host_frametime, self->v.velocity, self->v.velocity);
1804 }
1805
1806 G_FLOAT(OFS_RETURN) = damage;
1807}
1808
1809
1810void PF_sin (void)
1811{
1812 G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0));
1813}
1814
1815void PF_cos (void)
1816{
1817 G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0));
1818}
1819
1820void PF_sqrt (void)
1821{
1822 G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));
1823}
1824#endif
1825
1826void PF_Fixme (void)
1827{
1828 PR_RunError ("unimplemented bulitin");
1829}
1830
1831
1832
1833builtin_t pr_builtin[] =
1834{
1835PF_Fixme,
1836PF_makevectors, // void(entity e) makevectors = #1;
1837PF_setorigin, // void(entity e, vector o) setorigin = #2;
1838PF_setmodel, // void(entity e, string m) setmodel = #3;
1839PF_setsize, // void(entity e, vector min, vector max) setsize = #4;
1840PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5;
1841PF_break, // void() break = #6;
1842PF_random, // float() random = #7;
1843PF_sound, // void(entity e, float chan, string samp) sound = #8;
1844PF_normalize, // vector(vector v) normalize = #9;
1845PF_error, // void(string e) error = #10;
1846PF_objerror, // void(string e) objerror = #11;
1847PF_vlen, // float(vector v) vlen = #12;
1848PF_vectoyaw, // float(vector v) vectoyaw = #13;
1849PF_Spawn, // entity() spawn = #14;
1850PF_Remove, // void(entity e) remove = #15;
1851PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16;
1852PF_checkclient, // entity() clientlist = #17;
1853PF_Find, // entity(entity start, .string fld, string match) find = #18;
1854PF_precache_sound, // void(string s) precache_sound = #19;
1855PF_precache_model, // void(string s) precache_model = #20;
1856PF_stuffcmd, // void(entity client, string s)stuffcmd = #21;
1857PF_findradius, // entity(vector org, float rad) findradius = #22;
1858PF_bprint, // void(string s) bprint = #23;
1859PF_sprint, // void(entity client, string s) sprint = #24;
1860PF_dprint, // void(string s) dprint = #25;
1861PF_ftos, // void(string s) ftos = #26;
1862PF_vtos, // void(string s) vtos = #27;
1863PF_coredump,
1864PF_traceon,
1865PF_traceoff,
1866PF_eprint, // void(entity e) debug print an entire entity
1867PF_walkmove, // float(float yaw, float dist) walkmove
1868PF_Fixme, // float(float yaw, float dist) walkmove
1869PF_droptofloor,
1870PF_lightstyle,
1871PF_rint,
1872PF_floor,
1873PF_ceil,
1874PF_Fixme,
1875PF_checkbottom,
1876PF_pointcontents,
1877PF_Fixme,
1878PF_fabs,
1879PF_aim,
1880PF_cvar,
1881PF_localcmd,
1882PF_nextent,
1883PF_particle,
1884PF_changeyaw,
1885PF_Fixme,
1886PF_vectoangles,
1887
1888PF_WriteByte,
1889PF_WriteChar,
1890PF_WriteShort,
1891PF_WriteLong,
1892PF_WriteCoord,
1893PF_WriteAngle,
1894PF_WriteString,
1895PF_WriteEntity,
1896
1897#ifdef QUAKE2
1898PF_sin,
1899PF_cos,
1900PF_sqrt,
1901PF_changepitch,
1902PF_TraceToss,
1903PF_etos,
1904PF_WaterMove,
1905#else
1906PF_Fixme,
1907PF_Fixme,
1908PF_Fixme,
1909PF_Fixme,
1910PF_Fixme,
1911PF_Fixme,
1912PF_Fixme,
1913#endif
1914
1915SV_MoveToGoal,
1916PF_precache_file,
1917PF_makestatic,
1918
1919PF_changelevel,
1920PF_Fixme,
1921
1922PF_cvar_set,
1923PF_centerprint,
1924
1925PF_ambientsound,
1926
1927PF_precache_model,
1928PF_precache_sound, // precache_sound2 is different only for qcc
1929PF_precache_file,
1930
1931PF_setspawnparms
1932};
1933
1934builtin_t *pr_builtins = pr_builtin;
1935int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]);
1936
diff --git a/apps/plugins/sdl/progs/quake/pr_comp.h b/apps/plugins/sdl/progs/quake/pr_comp.h
new file mode 100644
index 0000000000..483e8e6a82
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/pr_comp.h
@@ -0,0 +1,180 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// this file is shared by quake and qcc
22
23typedef int func_t;
24typedef int string_t;
25
26typedef int etype_t;
27enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer};
28
29#define OFS_NULL 0
30#define OFS_RETURN 1
31#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
32#define OFS_PARM1 7
33#define OFS_PARM2 10
34#define OFS_PARM3 13
35#define OFS_PARM4 16
36#define OFS_PARM5 19
37#define OFS_PARM6 22
38#define OFS_PARM7 25
39#define RESERVED_OFS 28
40
41
42enum {
43 OP_DONE,
44 OP_MUL_F,
45 OP_MUL_V,
46 OP_MUL_FV,
47 OP_MUL_VF,
48 OP_DIV_F,
49 OP_ADD_F,
50 OP_ADD_V,
51 OP_SUB_F,
52 OP_SUB_V,
53
54 OP_EQ_F,
55 OP_EQ_V,
56 OP_EQ_S,
57 OP_EQ_E,
58 OP_EQ_FNC,
59
60 OP_NE_F,
61 OP_NE_V,
62 OP_NE_S,
63 OP_NE_E,
64 OP_NE_FNC,
65
66 OP_LE,
67 OP_GE,
68 OP_LT,
69 OP_GT,
70
71 OP_LOAD_F,
72 OP_LOAD_V,
73 OP_LOAD_S,
74 OP_LOAD_ENT,
75 OP_LOAD_FLD,
76 OP_LOAD_FNC,
77
78 OP_ADDRESS,
79
80 OP_STORE_F,
81 OP_STORE_V,
82 OP_STORE_S,
83 OP_STORE_ENT,
84 OP_STORE_FLD,
85 OP_STORE_FNC,
86
87 OP_STOREP_F,
88 OP_STOREP_V,
89 OP_STOREP_S,
90 OP_STOREP_ENT,
91 OP_STOREP_FLD,
92 OP_STOREP_FNC,
93
94 OP_RETURN,
95 OP_NOT_F,
96 OP_NOT_V,
97 OP_NOT_S,
98 OP_NOT_ENT,
99 OP_NOT_FNC,
100 OP_IF,
101 OP_IFNOT,
102 OP_CALL0,
103 OP_CALL1,
104 OP_CALL2,
105 OP_CALL3,
106 OP_CALL4,
107 OP_CALL5,
108 OP_CALL6,
109 OP_CALL7,
110 OP_CALL8,
111 OP_STATE,
112 OP_GOTO,
113 OP_AND,
114 OP_OR,
115
116 OP_BITAND,
117 OP_BITOR
118};
119
120
121typedef struct statement_s
122{
123 unsigned short op;
124 short a,b,c;
125} dstatement_t;
126
127typedef struct
128{
129 unsigned short type; // if DEF_SAVEGLOBGAL bit is set
130 // the variable needs to be saved in savegames
131 unsigned short ofs;
132 int s_name;
133} ddef_t;
134#define DEF_SAVEGLOBAL (1<<15)
135
136#define MAX_PARMS 8
137
138typedef struct
139{
140 int first_statement; // negative numbers are builtins
141 int parm_start;
142 int locals; // total ints of parms + locals
143
144 int profile; // runtime
145
146 int s_name;
147 int s_file; // source file defined in
148
149 int numparms;
150 byte parm_size[MAX_PARMS];
151} dfunction_t;
152
153
154#define PROG_VERSION 6
155typedef struct
156{
157 int version;
158 int crc; // check of header file
159
160 int ofs_statements;
161 int numstatements; // statement 0 is an error
162
163 int ofs_globaldefs;
164 int numglobaldefs;
165
166 int ofs_fielddefs;
167 int numfielddefs;
168
169 int ofs_functions;
170 int numfunctions; // function 0 is an empty
171
172 int ofs_strings;
173 int numstrings; // first string is a null string
174
175 int ofs_globals;
176 int numglobals;
177
178 int entityfields;
179} dprograms_t;
180
diff --git a/apps/plugins/sdl/progs/quake/pr_edict.c b/apps/plugins/sdl/progs/quake/pr_edict.c
new file mode 100644
index 0000000000..2f0e8eccb3
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/pr_edict.c
@@ -0,0 +1,1113 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_edict.c -- entity dictionary
21
22#include "quakedef.h"
23
24dprograms_t *progs;
25dfunction_t *pr_functions;
26char *pr_strings;
27ddef_t *pr_fielddefs;
28ddef_t *pr_globaldefs;
29dstatement_t *pr_statements;
30globalvars_t *pr_global_struct;
31float *pr_globals; // same as pr_global_struct
32int pr_edict_size; // in bytes
33
34unsigned short pr_crc;
35
36int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
37
38ddef_t *ED_FieldAtOfs (int ofs);
39qboolean ED_ParseEpair (void *base, ddef_t *key, char *s);
40
41cvar_t nomonsters = {"nomonsters", "0"};
42cvar_t gamecfg = {"gamecfg", "0"};
43cvar_t scratch1 = {"scratch1", "0"};
44cvar_t scratch2 = {"scratch2", "0"};
45cvar_t scratch3 = {"scratch3", "0"};
46cvar_t scratch4 = {"scratch4", "0"};
47cvar_t savedgamecfg = {"savedgamecfg", "0", true};
48cvar_t saved1 = {"saved1", "0", true};
49cvar_t saved2 = {"saved2", "0", true};
50cvar_t saved3 = {"saved3", "0", true};
51cvar_t saved4 = {"saved4", "0", true};
52
53#define MAX_FIELD_LEN 64
54#define GEFV_CACHESIZE 2
55
56typedef struct {
57 ddef_t *pcache;
58 char field[MAX_FIELD_LEN];
59} gefv_cache;
60
61static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}};
62
63/*
64=================
65ED_ClearEdict
66
67Sets everything to NULL
68=================
69*/
70void ED_ClearEdict (edict_t *e)
71{
72 memset (&e->v, 0, progs->entityfields * 4);
73 e->free = false;
74}
75
76/*
77=================
78ED_Alloc
79
80Either finds a free edict, or allocates a new one.
81Try to avoid reusing an entity that was recently freed, because it
82can cause the client to think the entity morphed into something else
83instead of being removed and recreated, which can cause interpolated
84angles and bad trails.
85=================
86*/
87edict_t *ED_Alloc (void)
88{
89 int i;
90 edict_t *e;
91
92 for ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
93 {
94 e = EDICT_NUM(i);
95 // the first couple seconds of server time can involve a lot of
96 // freeing and allocating, so relax the replacement policy
97 if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
98 {
99 ED_ClearEdict (e);
100 return e;
101 }
102 }
103
104 if (i == MAX_EDICTS)
105 Sys_Error ("ED_Alloc: no free edicts");
106
107 sv.num_edicts++;
108 e = EDICT_NUM(i);
109 ED_ClearEdict (e);
110
111 return e;
112}
113
114/*
115=================
116ED_Free
117
118Marks the edict as free
119FIXME: walk all entities and NULL out references to this entity
120=================
121*/
122void ED_Free (edict_t *ed)
123{
124 SV_UnlinkEdict (ed); // unlink from world bsp
125
126 ed->free = true;
127 ed->v.model = 0;
128 ed->v.takedamage = 0;
129 ed->v.modelindex = 0;
130 ed->v.colormap = 0;
131 ed->v.skin = 0;
132 ed->v.frame = 0;
133 VectorCopy (vec3_origin, ed->v.origin);
134 VectorCopy (vec3_origin, ed->v.angles);
135 ed->v.nextthink = -1;
136 ed->v.solid = 0;
137
138 ed->freetime = sv.time;
139}
140
141//===========================================================================
142
143/*
144============
145ED_GlobalAtOfs
146============
147*/
148ddef_t *ED_GlobalAtOfs (int ofs)
149{
150 ddef_t *def;
151 int i;
152
153 for (i=0 ; i<progs->numglobaldefs ; i++)
154 {
155 def = &pr_globaldefs[i];
156 if (def->ofs == ofs)
157 return def;
158 }
159 return NULL;
160}
161
162/*
163============
164ED_FieldAtOfs
165============
166*/
167ddef_t *ED_FieldAtOfs (int ofs)
168{
169 ddef_t *def;
170 int i;
171
172 for (i=0 ; i<progs->numfielddefs ; i++)
173 {
174 def = &pr_fielddefs[i];
175 if (def->ofs == ofs)
176 return def;
177 }
178 return NULL;
179}
180
181/*
182============
183ED_FindField
184============
185*/
186ddef_t *ED_FindField (char *name)
187{
188 ddef_t *def;
189 int i;
190
191 for (i=0 ; i<progs->numfielddefs ; i++)
192 {
193 def = &pr_fielddefs[i];
194 if (!strcmp(pr_strings + def->s_name,name) )
195 return def;
196 }
197 return NULL;
198}
199
200
201/*
202============
203ED_FindGlobal
204============
205*/
206ddef_t *ED_FindGlobal (char *name)
207{
208 ddef_t *def;
209 int i;
210
211 for (i=0 ; i<progs->numglobaldefs ; i++)
212 {
213 def = &pr_globaldefs[i];
214 if (!strcmp(pr_strings + def->s_name,name) )
215 return def;
216 }
217 return NULL;
218}
219
220
221/*
222============
223ED_FindFunction
224============
225*/
226dfunction_t *ED_FindFunction (char *name)
227{
228 dfunction_t *func;
229 int i;
230
231 for (i=0 ; i<progs->numfunctions ; i++)
232 {
233 func = &pr_functions[i];
234 if (!strcmp(pr_strings + func->s_name,name) )
235 return func;
236 }
237 return NULL;
238}
239
240
241eval_t *GetEdictFieldValue(edict_t *ed, char *field)
242{
243 ddef_t *def = NULL;
244 int i;
245 static int rep = 0;
246
247 for (i=0 ; i<GEFV_CACHESIZE ; i++)
248 {
249 if (!strcmp(field, gefvCache[i].field))
250 {
251 def = gefvCache[i].pcache;
252 goto Done;
253 }
254 }
255
256 def = ED_FindField (field);
257
258 if (strlen(field) < MAX_FIELD_LEN)
259 {
260 gefvCache[rep].pcache = def;
261 strcpy (gefvCache[rep].field, field);
262 rep ^= 1;
263 }
264
265Done:
266 if (!def)
267 return NULL;
268
269 return (eval_t *)((char *)&ed->v + def->ofs*4);
270}
271
272
273/*
274============
275PR_ValueString
276
277Returns a string describing *data in a type specific manner
278=============
279*/
280char *PR_ValueString (etype_t type, eval_t *val)
281{
282 static char line[256];
283 ddef_t *def;
284 dfunction_t *f;
285
286 type &= ~DEF_SAVEGLOBAL;
287
288 switch (type)
289 {
290 case ev_string:
291 sprintf (line, "%s", pr_strings + val->string);
292 break;
293 case ev_entity:
294 sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );
295 break;
296 case ev_function:
297 f = pr_functions + val->function;
298 sprintf (line, "%s()", pr_strings + f->s_name);
299 break;
300 case ev_field:
301 def = ED_FieldAtOfs ( val->_int );
302 sprintf (line, ".%s", pr_strings + def->s_name);
303 break;
304 case ev_void:
305 sprintf (line, "void");
306 break;
307 case ev_float:
308 sprintf (line, "%5.1f", val->_float);
309 break;
310 case ev_vector:
311 sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]);
312 break;
313 case ev_pointer:
314 sprintf (line, "pointer");
315 break;
316 default:
317 sprintf (line, "bad type %i", type);
318 break;
319 }
320
321 return line;
322}
323
324/*
325============
326PR_UglyValueString
327
328Returns a string describing *data in a type specific manner
329Easier to parse than PR_ValueString
330=============
331*/
332char *PR_UglyValueString (etype_t type, eval_t *val)
333{
334 static char line[256];
335 ddef_t *def;
336 dfunction_t *f;
337
338 type &= ~DEF_SAVEGLOBAL;
339
340 switch (type)
341 {
342 case ev_string:
343 sprintf (line, "%s", pr_strings + val->string);
344 break;
345 case ev_entity:
346 sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));
347 break;
348 case ev_function:
349 f = pr_functions + val->function;
350 sprintf (line, "%s", pr_strings + f->s_name);
351 break;
352 case ev_field:
353 def = ED_FieldAtOfs ( val->_int );
354 sprintf (line, "%s", pr_strings + def->s_name);
355 break;
356 case ev_void:
357 sprintf (line, "void");
358 break;
359 case ev_float:
360 sprintf (line, "%f", val->_float);
361 break;
362 case ev_vector:
363 sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
364 break;
365 default:
366 sprintf (line, "bad type %i", type);
367 break;
368 }
369
370 return line;
371}
372
373/*
374============
375PR_GlobalString
376
377Returns a string with a description and the contents of a global,
378padded to 20 field width
379============
380*/
381char *PR_GlobalString (int ofs)
382{
383 char *s;
384 int i;
385 ddef_t *def;
386 void *val;
387 static char line[128];
388
389 val = (void *)&pr_globals[ofs];
390 def = ED_GlobalAtOfs(ofs);
391 if (!def)
392 sprintf (line,"%i(???)", ofs);
393 else
394 {
395 s = PR_ValueString (def->type, val);
396 sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s);
397 }
398
399 i = strlen(line);
400 for ( ; i<20 ; i++)
401 strcat (line," ");
402 strcat (line," ");
403
404 return line;
405}
406
407char *PR_GlobalStringNoContents (int ofs)
408{
409 int i;
410 ddef_t *def;
411 static char line[128];
412
413 def = ED_GlobalAtOfs(ofs);
414 if (!def)
415 sprintf (line,"%i(???)", ofs);
416 else
417 sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name);
418
419 i = strlen(line);
420 for ( ; i<20 ; i++)
421 strcat (line," ");
422 strcat (line," ");
423
424 return line;
425}
426
427
428/*
429=============
430ED_Print
431
432For debugging
433=============
434*/
435void ED_Print (edict_t *ed)
436{
437 int l;
438 ddef_t *d;
439 int *v;
440 int i, j;
441 char *name;
442 int type;
443
444 if (ed->free)
445 {
446 Con_Printf ("FREE\n");
447 return;
448 }
449
450 Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed));
451 for (i=1 ; i<progs->numfielddefs ; i++)
452 {
453 d = &pr_fielddefs[i];
454 name = pr_strings + d->s_name;
455 if (name[strlen(name)-2] == '_')
456 continue; // skip _x, _y, _z vars
457
458 v = (int *)((char *)&ed->v + d->ofs*4);
459
460 // if the value is still all 0, skip the field
461 type = d->type & ~DEF_SAVEGLOBAL;
462
463 for (j=0 ; j<type_size[type] ; j++)
464 if (v[j])
465 break;
466 if (j == type_size[type])
467 continue;
468
469 Con_Printf ("%s",name);
470 l = strlen (name);
471 while (l++ < 15)
472 Con_Printf (" ");
473
474 Con_Printf ("%s\n", PR_ValueString(d->type, (eval_t *)v));
475 }
476}
477
478/*
479=============
480ED_Write
481
482For savegames
483=============
484*/
485void ED_Write (FILE *f, edict_t *ed)
486{
487 ddef_t *d;
488 int *v;
489 int i, j;
490 char *name;
491 int type;
492
493 fprintf (f, "{\n");
494
495 if (ed->free)
496 {
497 fprintf (f, "}\n");
498 return;
499 }
500
501 for (i=1 ; i<progs->numfielddefs ; i++)
502 {
503 d = &pr_fielddefs[i];
504 name = pr_strings + d->s_name;
505 if (name[strlen(name)-2] == '_')
506 continue; // skip _x, _y, _z vars
507
508 v = (int *)((char *)&ed->v + d->ofs*4);
509
510 // if the value is still all 0, skip the field
511 type = d->type & ~DEF_SAVEGLOBAL;
512 for (j=0 ; j<type_size[type] ; j++)
513 if (v[j])
514 break;
515 if (j == type_size[type])
516 continue;
517
518 fprintf (f,"\"%s\" ",name);
519 fprintf (f,"\"%s\"\n", PR_UglyValueString(d->type, (eval_t *)v));
520 }
521
522 fprintf (f, "}\n");
523}
524
525void ED_PrintNum (int ent)
526{
527 ED_Print (EDICT_NUM(ent));
528}
529
530/*
531=============
532ED_PrintEdicts
533
534For debugging, prints all the entities in the current server
535=============
536*/
537void ED_PrintEdicts (void)
538{
539 int i;
540
541 Con_Printf ("%i entities\n", sv.num_edicts);
542 for (i=0 ; i<sv.num_edicts ; i++)
543 ED_PrintNum (i);
544}
545
546/*
547=============
548ED_PrintEdict_f
549
550For debugging, prints a single edicy
551=============
552*/
553void ED_PrintEdict_f (void)
554{
555 int i;
556
557 i = Q_atoi (Cmd_Argv(1));
558 if (i >= sv.num_edicts)
559 {
560 Con_Printf("Bad edict number\n");
561 return;
562 }
563 ED_PrintNum (i);
564}
565
566/*
567=============
568ED_Count
569
570For debugging
571=============
572*/
573void ED_Count (void)
574{
575 int i;
576 edict_t *ent;
577 int active, models, solid, step;
578
579 active = models = solid = step = 0;
580 for (i=0 ; i<sv.num_edicts ; i++)
581 {
582 ent = EDICT_NUM(i);
583 if (ent->free)
584 continue;
585 active++;
586 if (ent->v.solid)
587 solid++;
588 if (ent->v.model)
589 models++;
590 if (ent->v.movetype == MOVETYPE_STEP)
591 step++;
592 }
593
594 Con_Printf ("num_edicts:%3i\n", sv.num_edicts);
595 Con_Printf ("active :%3i\n", active);
596 Con_Printf ("view :%3i\n", models);
597 Con_Printf ("touch :%3i\n", solid);
598 Con_Printf ("step :%3i\n", step);
599
600}
601
602/*
603==============================================================================
604
605 ARCHIVING GLOBALS
606
607FIXME: need to tag constants, doesn't really work
608==============================================================================
609*/
610
611/*
612=============
613ED_WriteGlobals
614=============
615*/
616void ED_WriteGlobals (FILE *f)
617{
618 ddef_t *def;
619 int i;
620 char *name;
621 int type;
622
623 fprintf (f,"{\n");
624 for (i=0 ; i<progs->numglobaldefs ; i++)
625 {
626 def = &pr_globaldefs[i];
627 type = def->type;
628 if ( !(def->type & DEF_SAVEGLOBAL) )
629 continue;
630 type &= ~DEF_SAVEGLOBAL;
631
632 if (type != ev_string
633 && type != ev_float
634 && type != ev_entity)
635 continue;
636
637 name = pr_strings + def->s_name;
638 fprintf (f,"\"%s\" ", name);
639 fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs]));
640 }
641 fprintf (f,"}\n");
642}
643
644/*
645=============
646ED_ParseGlobals
647=============
648*/
649void ED_ParseGlobals (char *data)
650{
651 char keyname[64];
652 ddef_t *key;
653
654 while (1)
655 {
656 // parse key
657 data = COM_Parse (data);
658 if (com_token[0] == '}')
659 break;
660 if (!data)
661 Sys_Error ("ED_ParseEntity: EOF without closing brace");
662
663 strcpy (keyname, com_token);
664
665 // parse value
666 data = COM_Parse (data);
667 if (!data)
668 Sys_Error ("ED_ParseEntity: EOF without closing brace");
669
670 if (com_token[0] == '}')
671 Sys_Error ("ED_ParseEntity: closing brace without data");
672
673 key = ED_FindGlobal (keyname);
674 if (!key)
675 {
676 Con_Printf ("'%s' is not a global\n", keyname);
677 continue;
678 }
679
680 if (!ED_ParseEpair ((void *)pr_globals, key, com_token))
681 Host_Error ("ED_ParseGlobals: parse error");
682 }
683}
684
685//============================================================================
686
687
688/*
689=============
690ED_NewString
691=============
692*/
693char *ED_NewString (char *string)
694{
695 char *new, *new_p;
696 int i,l;
697
698 l = strlen(string) + 1;
699 new = Hunk_Alloc (l);
700 new_p = new;
701
702 for (i=0 ; i< l ; i++)
703 {
704 if (string[i] == '\\' && i < l-1)
705 {
706 i++;
707 if (string[i] == 'n')
708 *new_p++ = '\n';
709 else
710 *new_p++ = '\\';
711 }
712 else
713 *new_p++ = string[i];
714 }
715
716 return new;
717}
718
719
720/*
721=============
722ED_ParseEval
723
724Can parse either fields or globals
725returns false if error
726=============
727*/
728qboolean ED_ParseEpair (void *base, ddef_t *key, char *s)
729{
730 int i;
731 char string[128];
732 ddef_t *def;
733 char *v, *w;
734 void *d;
735 dfunction_t *func;
736
737 d = (void *)((int *)base + key->ofs);
738
739 switch (key->type & ~DEF_SAVEGLOBAL)
740 {
741 case ev_string:
742 *(string_t *)d = ED_NewString (s) - pr_strings;
743 break;
744
745 case ev_float:
746 *(float *)d = Q_atof (s);
747 break;
748
749 case ev_vector:
750 strcpy (string, s);
751 v = string;
752 w = string;
753 for (i=0 ; i<3 ; i++)
754 {
755 while (*v && *v != ' ')
756 v++;
757 *v = 0;
758 ((float *)d)[i] = Q_atof (w);
759 w = v = v+1;
760 }
761 break;
762
763 case ev_entity:
764 *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
765 break;
766
767 case ev_field:
768 def = ED_FindField (s);
769 if (!def)
770 {
771 Con_Printf ("Can't find field %s\n", s);
772 return false;
773 }
774 *(int *)d = G_INT(def->ofs);
775 break;
776
777 case ev_function:
778 func = ED_FindFunction (s);
779 if (!func)
780 {
781 Con_Printf ("Can't find function %s\n", s);
782 return false;
783 }
784 *(func_t *)d = func - pr_functions;
785 break;
786
787 default:
788 break;
789 }
790 return true;
791}
792
793/*
794====================
795ED_ParseEdict
796
797Parses an edict out of the given string, returning the new position
798ed should be a properly initialized empty edict.
799Used for initial level load and for savegames.
800====================
801*/
802char *ED_ParseEdict (char *data, edict_t *ent)
803{
804 ddef_t *key;
805 qboolean anglehack;
806 qboolean init;
807 char keyname[256];
808 int n;
809
810 init = false;
811
812// clear it
813 if (ent != sv.edicts) // hack
814 memset (&ent->v, 0, progs->entityfields * 4);
815
816// go through all the dictionary pairs
817 while (1)
818 {
819 // parse key
820 data = COM_Parse (data);
821 if (com_token[0] == '}')
822 break;
823 if (!data)
824 Sys_Error ("ED_ParseEntity: EOF without closing brace");
825
826// anglehack is to allow QuakeEd to write single scalar angles
827// and allow them to be turned into vectors. (FIXME...)
828if (!strcmp(com_token, "angle"))
829{
830 strcpy (com_token, "angles");
831 anglehack = true;
832}
833else
834 anglehack = false;
835
836// FIXME: change light to _light to get rid of this hack
837if (!strcmp(com_token, "light"))
838 strcpy (com_token, "light_lev"); // hack for single light def
839
840 strcpy (keyname, com_token);
841
842 // another hack to fix heynames with trailing spaces
843 n = strlen(keyname);
844 while (n && keyname[n-1] == ' ')
845 {
846 keyname[n-1] = 0;
847 n--;
848 }
849
850 // parse value
851 data = COM_Parse (data);
852 if (!data)
853 Sys_Error ("ED_ParseEntity: EOF without closing brace");
854
855 if (com_token[0] == '}')
856 Sys_Error ("ED_ParseEntity: closing brace without data");
857
858 init = true;
859
860// keynames with a leading underscore are used for utility comments,
861// and are immediately discarded by quake
862 if (keyname[0] == '_')
863 continue;
864
865 key = ED_FindField (keyname);
866 if (!key)
867 {
868 Con_Printf ("'%s' is not a field\n", keyname);
869 continue;
870 }
871
872if (anglehack)
873{
874char temp[32];
875strcpy (temp, com_token);
876sprintf (com_token, "0 %s 0", temp);
877}
878
879 if (!ED_ParseEpair ((void *)&ent->v, key, com_token))
880 Host_Error ("ED_ParseEdict: parse error");
881 }
882
883 if (!init)
884 ent->free = true;
885
886 return data;
887}
888
889
890/*
891================
892ED_LoadFromFile
893
894The entities are directly placed in the array, rather than allocated with
895ED_Alloc, because otherwise an error loading the map would have entity
896number references out of order.
897
898Creates a server's entity / program execution context by
899parsing textual entity definitions out of an ent file.
900
901Used for both fresh maps and savegame loads. A fresh map would also need
902to call ED_CallSpawnFunctions () to let the objects initialize themselves.
903================
904*/
905void ED_LoadFromFile (char *data)
906{
907 edict_t *ent;
908 int inhibit;
909 dfunction_t *func;
910
911 ent = NULL;
912 inhibit = 0;
913 pr_global_struct->time = sv.time;
914
915// parse ents
916 while (1)
917 {
918// parse the opening brace
919 data = COM_Parse (data);
920 if (!data)
921 break;
922 if (com_token[0] != '{')
923 Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token);
924
925 if (!ent)
926 ent = EDICT_NUM(0);
927 else
928 ent = ED_Alloc ();
929 data = ED_ParseEdict (data, ent);
930
931// remove things from different skill levels or deathmatch
932 if (deathmatch.value)
933 {
934 if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
935 {
936 ED_Free (ent);
937 inhibit++;
938 continue;
939 }
940 }
941 else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))
942 || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
943 || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )
944 {
945 ED_Free (ent);
946 inhibit++;
947 continue;
948 }
949
950//
951// immediately call spawn function
952//
953 if (!ent->v.classname)
954 {
955 Con_Printf ("No classname for:\n");
956 ED_Print (ent);
957 ED_Free (ent);
958 continue;
959 }
960
961 // look for the spawn function
962 func = ED_FindFunction ( pr_strings + ent->v.classname );
963
964 if (!func)
965 {
966 Con_Printf ("No spawn function for:\n");
967 ED_Print (ent);
968 ED_Free (ent);
969 continue;
970 }
971
972 pr_global_struct->self = EDICT_TO_PROG(ent);
973 PR_ExecuteProgram (func - pr_functions);
974 }
975
976 Con_DPrintf ("%i entities inhibited\n", inhibit);
977}
978
979
980/*
981===============
982PR_LoadProgs
983===============
984*/
985void PR_LoadProgs (void)
986{
987 int i;
988
989// flush the non-C variable lookup cache
990 for (i=0 ; i<GEFV_CACHESIZE ; i++)
991 gefvCache[i].field[0] = 0;
992
993 CRC_Init (&pr_crc);
994
995 //printf("loadprogs 1");
996
997 progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");
998 //printf("loadprogs 2");
999
1000 if (!progs)
1001 Sys_Error ("PR_LoadProgs: couldn't load progs.dat");
1002 Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
1003 //printf("loadprogs 3");
1004
1005 for (i=0 ; i<com_filesize ; i++)
1006 CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);
1007
1008 //printf("loadprogs 4");
1009// byte swap the header
1010 for (i=0 ; i<sizeof(*progs)/4 ; i++)
1011 ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );
1012
1013 if (progs->version != PROG_VERSION)
1014 Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
1015 if (progs->crc != PROGHEADER_CRC)
1016 Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date");
1017 //printf("loadprogs 5");
1018
1019 pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
1020 pr_strings = (char *)progs + progs->ofs_strings;
1021 pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
1022 pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
1023 pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
1024
1025 pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
1026 pr_globals = (float *)pr_global_struct;
1027
1028 pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
1029
1030// byte swap the lumps
1031 for (i=0 ; i<progs->numstatements ; i++)
1032 {
1033 pr_statements[i].op = LittleShort(pr_statements[i].op);
1034 pr_statements[i].a = LittleShort(pr_statements[i].a);
1035 pr_statements[i].b = LittleShort(pr_statements[i].b);
1036 pr_statements[i].c = LittleShort(pr_statements[i].c);
1037 }
1038
1039 for (i=0 ; i<progs->numfunctions; i++)
1040 {
1041 pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);
1042 pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);
1043 pr_functions[i].s_name = LittleLong (pr_functions[i].s_name);
1044 pr_functions[i].s_file = LittleLong (pr_functions[i].s_file);
1045 pr_functions[i].numparms = LittleLong (pr_functions[i].numparms);
1046 pr_functions[i].locals = LittleLong (pr_functions[i].locals);
1047 }
1048
1049 for (i=0 ; i<progs->numglobaldefs ; i++)
1050 {
1051 pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);
1052 pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);
1053 pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
1054 }
1055
1056 for (i=0 ; i<progs->numfielddefs ; i++)
1057 {
1058 pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
1059 if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
1060 Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
1061 pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
1062 pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
1063 }
1064
1065 for (i=0 ; i<progs->numglobals ; i++)
1066 ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
1067}
1068
1069
1070/*
1071===============
1072PR_Init
1073===============
1074*/
1075void PR_Init (void)
1076{
1077 Cmd_AddCommand ("edict", ED_PrintEdict_f);
1078 Cmd_AddCommand ("edicts", ED_PrintEdicts);
1079 Cmd_AddCommand ("edictcount", ED_Count);
1080 Cmd_AddCommand ("profile", PR_Profile_f);
1081 Cvar_RegisterVariable (&nomonsters);
1082 Cvar_RegisterVariable (&gamecfg);
1083 Cvar_RegisterVariable (&scratch1);
1084 Cvar_RegisterVariable (&scratch2);
1085 Cvar_RegisterVariable (&scratch3);
1086 Cvar_RegisterVariable (&scratch4);
1087 Cvar_RegisterVariable (&savedgamecfg);
1088 Cvar_RegisterVariable (&saved1);
1089 Cvar_RegisterVariable (&saved2);
1090 Cvar_RegisterVariable (&saved3);
1091 Cvar_RegisterVariable (&saved4);
1092}
1093
1094
1095
1096edict_t *EDICT_NUM(int n)
1097{
1098 if (n < 0 || n >= sv.max_edicts)
1099 Sys_Error ("EDICT_NUM: bad number %i", n);
1100 return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);
1101}
1102
1103int NUM_FOR_EDICT(edict_t *e)
1104{
1105 int b;
1106
1107 b = (byte *)e - (byte *)sv.edicts;
1108 b = b / pr_edict_size;
1109
1110 if (b < 0 || b >= sv.num_edicts)
1111 Sys_Error ("NUM_FOR_EDICT: bad pointer");
1112 return b;
1113}
diff --git a/apps/plugins/sdl/progs/quake/pr_exec.c b/apps/plugins/sdl/progs/quake/pr_exec.c
new file mode 100644
index 0000000000..4f2aa363e6
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/pr_exec.c
@@ -0,0 +1,668 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22
23
24/*
25
26*/
27
28typedef struct
29{
30 int s;
31 dfunction_t *f;
32} prstack_t;
33
34#define MAX_STACK_DEPTH 32
35prstack_t pr_stack[MAX_STACK_DEPTH];
36int pr_depth;
37
38#define LOCALSTACK_SIZE 2048
39int localstack[LOCALSTACK_SIZE];
40int localstack_used;
41
42
43qboolean pr_trace;
44dfunction_t *pr_xfunction;
45int pr_xstatement;
46
47
48int pr_argc;
49
50char *pr_opnames[] =
51{
52"DONE",
53
54"MUL_F",
55"MUL_V",
56"MUL_FV",
57"MUL_VF",
58
59"DIV",
60
61"ADD_F",
62"ADD_V",
63
64"SUB_F",
65"SUB_V",
66
67"EQ_F",
68"EQ_V",
69"EQ_S",
70"EQ_E",
71"EQ_FNC",
72
73"NE_F",
74"NE_V",
75"NE_S",
76"NE_E",
77"NE_FNC",
78
79"LE",
80"GE",
81"LT",
82"GT",
83
84"INDIRECT",
85"INDIRECT",
86"INDIRECT",
87"INDIRECT",
88"INDIRECT",
89"INDIRECT",
90
91"ADDRESS",
92
93"STORE_F",
94"STORE_V",
95"STORE_S",
96"STORE_ENT",
97"STORE_FLD",
98"STORE_FNC",
99
100"STOREP_F",
101"STOREP_V",
102"STOREP_S",
103"STOREP_ENT",
104"STOREP_FLD",
105"STOREP_FNC",
106
107"RETURN",
108
109"NOT_F",
110"NOT_V",
111"NOT_S",
112"NOT_ENT",
113"NOT_FNC",
114
115"IF",
116"IFNOT",
117
118"CALL0",
119"CALL1",
120"CALL2",
121"CALL3",
122"CALL4",
123"CALL5",
124"CALL6",
125"CALL7",
126"CALL8",
127
128"STATE",
129
130"GOTO",
131
132"AND",
133"OR",
134
135"BITAND",
136"BITOR"
137};
138
139char *PR_GlobalString (int ofs);
140char *PR_GlobalStringNoContents (int ofs);
141
142
143//=============================================================================
144
145/*
146=================
147PR_PrintStatement
148=================
149*/
150void PR_PrintStatement (dstatement_t *s)
151{
152 int i;
153
154 if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))
155 {
156 Con_Printf ("%s ", pr_opnames[s->op]);
157 i = strlen(pr_opnames[s->op]);
158 for ( ; i<10 ; i++)
159 Con_Printf (" ");
160 }
161
162 if (s->op == OP_IF || s->op == OP_IFNOT)
163 Con_Printf ("%sbranch %i",PR_GlobalString(s->a),s->b);
164 else if (s->op == OP_GOTO)
165 {
166 Con_Printf ("branch %i",s->a);
167 }
168 else if ( (unsigned)(s->op - OP_STORE_F) < 6)
169 {
170 Con_Printf ("%s",PR_GlobalString(s->a));
171 Con_Printf ("%s", PR_GlobalStringNoContents(s->b));
172 }
173 else
174 {
175 if (s->a)
176 Con_Printf ("%s",PR_GlobalString(s->a));
177 if (s->b)
178 Con_Printf ("%s",PR_GlobalString(s->b));
179 if (s->c)
180 Con_Printf ("%s", PR_GlobalStringNoContents(s->c));
181 }
182 Con_Printf ("\n");
183}
184
185/*
186============
187PR_StackTrace
188============
189*/
190void PR_StackTrace (void)
191{
192 dfunction_t *f;
193 int i;
194
195 if (pr_depth == 0)
196 {
197 Con_Printf ("<NO STACK>\n");
198 return;
199 }
200
201 pr_stack[pr_depth].f = pr_xfunction;
202 for (i=pr_depth ; i>=0 ; i--)
203 {
204 f = pr_stack[i].f;
205
206 if (!f)
207 {
208 Con_Printf ("<NO FUNCTION>\n");
209 }
210 else
211 Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name);
212 }
213}
214
215
216/*
217============
218PR_Profile_f
219
220============
221*/
222void PR_Profile_f (void)
223{
224 dfunction_t *f, *best;
225 int max;
226 int num;
227 int i;
228
229 num = 0;
230 do
231 {
232 max = 0;
233 best = NULL;
234 for (i=0 ; i<progs->numfunctions ; i++)
235 {
236 f = &pr_functions[i];
237 if (f->profile > max)
238 {
239 max = f->profile;
240 best = f;
241 }
242 }
243 if (best)
244 {
245 if (num < 10)
246 Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name);
247 num++;
248 best->profile = 0;
249 }
250 } while (best);
251}
252
253
254/*
255============
256PR_RunError
257
258Aborts the currently executing function
259============
260*/
261void PR_RunError (char *error, ...)
262{
263 va_list argptr;
264 char string[1024];
265
266 va_start (argptr,error);
267 vsprintf (string,error,argptr);
268 va_end (argptr);
269
270 PR_PrintStatement (pr_statements + pr_xstatement);
271 PR_StackTrace ();
272 Con_Printf ("%s\n", string);
273
274 pr_depth = 0; // dump the stack so host_error can shutdown functions
275
276 Host_Error ("Program error");
277}
278
279/*
280============================================================================
281PR_ExecuteProgram
282
283The interpretation main loop
284============================================================================
285*/
286
287/*
288====================
289PR_EnterFunction
290
291Returns the new program statement counter
292====================
293*/
294int PR_EnterFunction (dfunction_t *f)
295{
296 int i, j, c, o;
297
298 pr_stack[pr_depth].s = pr_xstatement;
299 pr_stack[pr_depth].f = pr_xfunction;
300 pr_depth++;
301 if (pr_depth >= MAX_STACK_DEPTH)
302 PR_RunError ("stack overflow");
303
304// save off any locals that the new function steps on
305 c = f->locals;
306 if (localstack_used + c > LOCALSTACK_SIZE)
307 PR_RunError ("PR_ExecuteProgram: locals stack overflow\n");
308
309 for (i=0 ; i < c ; i++)
310 localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];
311 localstack_used += c;
312
313// copy parameters
314 o = f->parm_start;
315 for (i=0 ; i<f->numparms ; i++)
316 {
317 for (j=0 ; j<f->parm_size[i] ; j++)
318 {
319 ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];
320 o++;
321 }
322 }
323
324 pr_xfunction = f;
325 return f->first_statement - 1; // offset the s++
326}
327
328/*
329====================
330PR_LeaveFunction
331====================
332*/
333int PR_LeaveFunction (void)
334{
335 int i, c;
336
337 if (pr_depth <= 0)
338 Sys_Error ("prog stack underflow");
339
340// restore locals from the stack
341 c = pr_xfunction->locals;
342 localstack_used -= c;
343 if (localstack_used < 0)
344 PR_RunError ("PR_ExecuteProgram: locals stack underflow\n");
345
346 for (i=0 ; i < c ; i++)
347 ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];
348
349// up stack
350 pr_depth--;
351 pr_xfunction = pr_stack[pr_depth].f;
352 return pr_stack[pr_depth].s;
353}
354
355
356/*
357====================
358PR_ExecuteProgram
359====================
360*/
361void PR_ExecuteProgram (func_t fnum)
362{
363 eval_t *a, *b, *c;
364 int s;
365 dstatement_t *st;
366 dfunction_t *f, *newf;
367 int runaway;
368 int i;
369 edict_t *ed;
370 int exitdepth;
371 eval_t *ptr;
372
373 if (!fnum || fnum >= progs->numfunctions)
374 {
375 if (pr_global_struct->self)
376 ED_Print (PROG_TO_EDICT(pr_global_struct->self));
377 Host_Error ("PR_ExecuteProgram: NULL function");
378 }
379
380 f = &pr_functions[fnum];
381
382 runaway = 100000;
383 pr_trace = false;
384
385// make a stack frame
386 exitdepth = pr_depth;
387
388 s = PR_EnterFunction (f);
389
390while (1)
391{
392 s++; // next statement
393
394 st = &pr_statements[s];
395 a = (eval_t *)&pr_globals[st->a];
396 b = (eval_t *)&pr_globals[st->b];
397 c = (eval_t *)&pr_globals[st->c];
398
399 if (!--runaway)
400 PR_RunError ("runaway loop error");
401
402 pr_xfunction->profile++;
403 pr_xstatement = s;
404
405 if (pr_trace)
406 PR_PrintStatement (st);
407
408 switch (st->op)
409 {
410 case OP_ADD_F:
411 c->_float = a->_float + b->_float;
412 break;
413 case OP_ADD_V:
414 c->vector[0] = a->vector[0] + b->vector[0];
415 c->vector[1] = a->vector[1] + b->vector[1];
416 c->vector[2] = a->vector[2] + b->vector[2];
417 break;
418
419 case OP_SUB_F:
420 c->_float = a->_float - b->_float;
421 break;
422 case OP_SUB_V:
423 c->vector[0] = a->vector[0] - b->vector[0];
424 c->vector[1] = a->vector[1] - b->vector[1];
425 c->vector[2] = a->vector[2] - b->vector[2];
426 break;
427
428 case OP_MUL_F:
429 c->_float = a->_float * b->_float;
430 break;
431 case OP_MUL_V:
432 c->_float = a->vector[0]*b->vector[0]
433 + a->vector[1]*b->vector[1]
434 + a->vector[2]*b->vector[2];
435 break;
436 case OP_MUL_FV:
437 c->vector[0] = a->_float * b->vector[0];
438 c->vector[1] = a->_float * b->vector[1];
439 c->vector[2] = a->_float * b->vector[2];
440 break;
441 case OP_MUL_VF:
442 c->vector[0] = b->_float * a->vector[0];
443 c->vector[1] = b->_float * a->vector[1];
444 c->vector[2] = b->_float * a->vector[2];
445 break;
446
447 case OP_DIV_F:
448 c->_float = a->_float / b->_float;
449 break;
450
451 case OP_BITAND:
452 c->_float = (int)a->_float & (int)b->_float;
453 break;
454
455 case OP_BITOR:
456 c->_float = (int)a->_float | (int)b->_float;
457 break;
458
459
460 case OP_GE:
461 c->_float = a->_float >= b->_float;
462 break;
463 case OP_LE:
464 c->_float = a->_float <= b->_float;
465 break;
466 case OP_GT:
467 c->_float = a->_float > b->_float;
468 break;
469 case OP_LT:
470 c->_float = a->_float < b->_float;
471 break;
472 case OP_AND:
473 c->_float = a->_float && b->_float;
474 break;
475 case OP_OR:
476 c->_float = a->_float || b->_float;
477 break;
478
479 case OP_NOT_F:
480 c->_float = !a->_float;
481 break;
482 case OP_NOT_V:
483 c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];
484 break;
485 case OP_NOT_S:
486 c->_float = !a->string || !pr_strings[a->string];
487 break;
488 case OP_NOT_FNC:
489 c->_float = !a->function;
490 break;
491 case OP_NOT_ENT:
492 c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);
493 break;
494
495 case OP_EQ_F:
496 c->_float = a->_float == b->_float;
497 break;
498 case OP_EQ_V:
499 c->_float = (a->vector[0] == b->vector[0]) &&
500 (a->vector[1] == b->vector[1]) &&
501 (a->vector[2] == b->vector[2]);
502 break;
503 case OP_EQ_S:
504 c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string);
505 break;
506 case OP_EQ_E:
507 c->_float = a->_int == b->_int;
508 break;
509 case OP_EQ_FNC:
510 c->_float = a->function == b->function;
511 break;
512
513
514 case OP_NE_F:
515 c->_float = a->_float != b->_float;
516 break;
517 case OP_NE_V:
518 c->_float = (a->vector[0] != b->vector[0]) ||
519 (a->vector[1] != b->vector[1]) ||
520 (a->vector[2] != b->vector[2]);
521 break;
522 case OP_NE_S:
523 c->_float = strcmp(pr_strings+a->string,pr_strings+b->string);
524 break;
525 case OP_NE_E:
526 c->_float = a->_int != b->_int;
527 break;
528 case OP_NE_FNC:
529 c->_float = a->function != b->function;
530 break;
531
532//==================
533 case OP_STORE_F:
534 case OP_STORE_ENT:
535 case OP_STORE_FLD: // integers
536 case OP_STORE_S:
537 case OP_STORE_FNC: // pointers
538 b->_int = a->_int;
539 break;
540 case OP_STORE_V:
541 b->vector[0] = a->vector[0];
542 b->vector[1] = a->vector[1];
543 b->vector[2] = a->vector[2];
544 break;
545
546 case OP_STOREP_F:
547 case OP_STOREP_ENT:
548 case OP_STOREP_FLD: // integers
549 case OP_STOREP_S:
550 case OP_STOREP_FNC: // pointers
551 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
552 ptr->_int = a->_int;
553 break;
554 case OP_STOREP_V:
555 ptr = (eval_t *)((byte *)sv.edicts + b->_int);
556 ptr->vector[0] = a->vector[0];
557 ptr->vector[1] = a->vector[1];
558 ptr->vector[2] = a->vector[2];
559 break;
560
561 case OP_ADDRESS:
562 ed = PROG_TO_EDICT(a->edict);
563#ifdef PARANOID
564 NUM_FOR_EDICT(ed); // make sure it's in range
565#endif
566 if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
567 PR_RunError ("assignment to world entity");
568 c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts;
569 break;
570
571 case OP_LOAD_F:
572 case OP_LOAD_FLD:
573 case OP_LOAD_ENT:
574 case OP_LOAD_S:
575 case OP_LOAD_FNC:
576 ed = PROG_TO_EDICT(a->edict);
577#ifdef PARANOID
578 NUM_FOR_EDICT(ed); // make sure it's in range
579#endif
580 a = (eval_t *)((int *)&ed->v + b->_int);
581 c->_int = a->_int;
582 break;
583
584 case OP_LOAD_V:
585 ed = PROG_TO_EDICT(a->edict);
586#ifdef PARANOID
587 NUM_FOR_EDICT(ed); // make sure it's in range
588#endif
589 a = (eval_t *)((int *)&ed->v + b->_int);
590 c->vector[0] = a->vector[0];
591 c->vector[1] = a->vector[1];
592 c->vector[2] = a->vector[2];
593 break;
594
595//==================
596
597 case OP_IFNOT:
598 if (!a->_int)
599 s += st->b - 1; // offset the s++
600 break;
601
602 case OP_IF:
603 if (a->_int)
604 s += st->b - 1; // offset the s++
605 break;
606
607 case OP_GOTO:
608 s += st->a - 1; // offset the s++
609 break;
610
611 case OP_CALL0:
612 case OP_CALL1:
613 case OP_CALL2:
614 case OP_CALL3:
615 case OP_CALL4:
616 case OP_CALL5:
617 case OP_CALL6:
618 case OP_CALL7:
619 case OP_CALL8:
620 pr_argc = st->op - OP_CALL0;
621 if (!a->function)
622 PR_RunError ("NULL function");
623
624 newf = &pr_functions[a->function];
625
626 if (newf->first_statement < 0)
627 { // negative statements are built in functions
628 i = -newf->first_statement;
629 if (i >= pr_numbuiltins)
630 PR_RunError ("Bad builtin call number");
631 pr_builtins[i] ();
632 break;
633 }
634
635 s = PR_EnterFunction (newf);
636 break;
637
638 case OP_DONE:
639 case OP_RETURN:
640 pr_globals[OFS_RETURN] = pr_globals[st->a];
641 pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
642 pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
643
644 s = PR_LeaveFunction ();
645 if (pr_depth == exitdepth)
646 return; // all done
647 break;
648
649 case OP_STATE:
650 ed = PROG_TO_EDICT(pr_global_struct->self);
651#ifdef FPS_20
652 ed->v.nextthink = pr_global_struct->time + 0.05;
653#else
654 ed->v.nextthink = pr_global_struct->time + 0.1;
655#endif
656 if (a->_float != ed->v.frame)
657 {
658 ed->v.frame = a->_float;
659 }
660 ed->v.think = b->function;
661 break;
662
663 default:
664 PR_RunError ("Bad opcode %i", st->op);
665 }
666}
667
668}
diff --git a/apps/plugins/sdl/progs/quake/progdefs.h b/apps/plugins/sdl/progs/quake/progdefs.h
new file mode 100644
index 0000000000..db86de156f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/progdefs.h
@@ -0,0 +1,24 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#ifdef QUAKE2
21#include "progdefs.q2"
22#else
23#include "progdefs.q1"
24#endif
diff --git a/apps/plugins/sdl/progs/quake/progdefs.q1 b/apps/plugins/sdl/progs/quake/progdefs.q1
new file mode 100644
index 0000000000..eb15c45c65
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/progdefs.q1
@@ -0,0 +1,143 @@
1
2/* file generated by qcc, do not modify */
3
4typedef struct
5{ int pad[28];
6 int self;
7 int other;
8 int world;
9 float time;
10 float frametime;
11 float force_retouch;
12 string_t mapname;
13 float deathmatch;
14 float coop;
15 float teamplay;
16 float serverflags;
17 float total_secrets;
18 float total_monsters;
19 float found_secrets;
20 float killed_monsters;
21 float parm1;
22 float parm2;
23 float parm3;
24 float parm4;
25 float parm5;
26 float parm6;
27 float parm7;
28 float parm8;
29 float parm9;
30 float parm10;
31 float parm11;
32 float parm12;
33 float parm13;
34 float parm14;
35 float parm15;
36 float parm16;
37 vec3_t v_forward;
38 vec3_t v_up;
39 vec3_t v_right;
40 float trace_allsolid;
41 float trace_startsolid;
42 float trace_fraction;
43 vec3_t trace_endpos;
44 vec3_t trace_plane_normal;
45 float trace_plane_dist;
46 int trace_ent;
47 float trace_inopen;
48 float trace_inwater;
49 int msg_entity;
50 func_t main;
51 func_t StartFrame;
52 func_t PlayerPreThink;
53 func_t PlayerPostThink;
54 func_t ClientKill;
55 func_t ClientConnect;
56 func_t PutClientInServer;
57 func_t ClientDisconnect;
58 func_t SetNewParms;
59 func_t SetChangeParms;
60} globalvars_t;
61
62typedef struct
63{
64 float modelindex;
65 vec3_t absmin;
66 vec3_t absmax;
67 float ltime;
68 float movetype;
69 float solid;
70 vec3_t origin;
71 vec3_t oldorigin;
72 vec3_t velocity;
73 vec3_t angles;
74 vec3_t avelocity;
75 vec3_t punchangle;
76 string_t classname;
77 string_t model;
78 float frame;
79 float skin;
80 float effects;
81 vec3_t mins;
82 vec3_t maxs;
83 vec3_t size;
84 func_t touch;
85 func_t use;
86 func_t think;
87 func_t blocked;
88 float nextthink;
89 int groundentity;
90 float health;
91 float frags;
92 float weapon;
93 string_t weaponmodel;
94 float weaponframe;
95 float currentammo;
96 float ammo_shells;
97 float ammo_nails;
98 float ammo_rockets;
99 float ammo_cells;
100 float items;
101 float takedamage;
102 int chain;
103 float deadflag;
104 vec3_t view_ofs;
105 float button0;
106 float button1;
107 float button2;
108 float impulse;
109 float fixangle;
110 vec3_t v_angle;
111 float idealpitch;
112 string_t netname;
113 int enemy;
114 float flags;
115 float colormap;
116 float team;
117 float max_health;
118 float teleport_time;
119 float armortype;
120 float armorvalue;
121 float waterlevel;
122 float watertype;
123 float ideal_yaw;
124 float yaw_speed;
125 int aiment;
126 int goalentity;
127 float spawnflags;
128 string_t target;
129 string_t targetname;
130 float dmg_take;
131 float dmg_save;
132 int dmg_inflictor;
133 int owner;
134 vec3_t movedir;
135 string_t message;
136 float sounds;
137 string_t noise;
138 string_t noise1;
139 string_t noise2;
140 string_t noise3;
141} entvars_t;
142
143#define PROGHEADER_CRC 5927
diff --git a/apps/plugins/sdl/progs/quake/progdefs.q2 b/apps/plugins/sdl/progs/quake/progdefs.q2
new file mode 100644
index 0000000000..dc7f3be9bb
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/progdefs.q2
@@ -0,0 +1,158 @@
1
2/* file generated by qcc, do not modify */
3
4typedef struct
5{ int pad[28];
6 int self;
7 int other;
8 int world;
9 float time;
10 float frametime;
11 float force_retouch;
12 string_t mapname;
13 string_t startspot;
14 float deathmatch;
15 float coop;
16 float teamplay;
17 float serverflags;
18 float total_secrets;
19 float total_monsters;
20 float found_secrets;
21 float killed_monsters;
22 float parm1;
23 float parm2;
24 float parm3;
25 float parm4;
26 float parm5;
27 float parm6;
28 float parm7;
29 float parm8;
30 float parm9;
31 float parm10;
32 float parm11;
33 float parm12;
34 float parm13;
35 float parm14;
36 float parm15;
37 float parm16;
38 vec3_t v_forward;
39 vec3_t v_up;
40 vec3_t v_right;
41 float trace_allsolid;
42 float trace_startsolid;
43 float trace_fraction;
44 vec3_t trace_endpos;
45 vec3_t trace_plane_normal;
46 float trace_plane_dist;
47 int trace_ent;
48 float trace_inopen;
49 float trace_inwater;
50 int msg_entity;
51 string_t null;
52 func_t main;
53 func_t StartFrame;
54 func_t PlayerPreThink;
55 func_t PlayerPostThink;
56 func_t ClientKill;
57 func_t ClientConnect;
58 func_t PutClientInServer;
59 func_t ClientDisconnect;
60 func_t SetNewParms;
61 func_t SetChangeParms;
62} globalvars_t;
63
64typedef struct
65{
66 float modelindex;
67 vec3_t absmin;
68 vec3_t absmax;
69 float ltime;
70 float movetype;
71 float solid;
72 vec3_t origin;
73 vec3_t oldorigin;
74 vec3_t velocity;
75 vec3_t angles;
76 vec3_t avelocity;
77 vec3_t basevelocity;
78 vec3_t punchangle;
79 string_t classname;
80 string_t model;
81 float frame;
82 float skin;
83 float effects;
84 float drawPercent;
85 float gravity;
86 float mass;
87 float light_level;
88 vec3_t mins;
89 vec3_t maxs;
90 vec3_t size;
91 func_t touch;
92 func_t use;
93 func_t think;
94 func_t blocked;
95 float nextthink;
96 int groundentity;
97 float health;
98 float frags;
99 float weapon;
100 string_t weaponmodel;
101 float weaponframe;
102 float currentammo;
103 float ammo_shells;
104 float ammo_nails;
105 float ammo_rockets;
106 float ammo_cells;
107 float items;
108 float items2;
109 float takedamage;
110 int chain;
111 float deadflag;
112 vec3_t view_ofs;
113 float button0;
114 float button1;
115 float button2;
116 float impulse;
117 float fixangle;
118 vec3_t v_angle;
119 float idealpitch;
120 float pitch_speed;
121 string_t netname;
122 int enemy;
123 float flags;
124 float colormap;
125 float team;
126 float max_health;
127 float teleport_time;
128 float armortype;
129 float armorvalue;
130 float waterlevel;
131 float watertype;
132 float ideal_yaw;
133 float yaw_speed;
134 int aiment;
135 int goalentity;
136 float spawnflags;
137 string_t target;
138 string_t targetname;
139 float dmg_take;
140 float dmg_save;
141 int dmg_inflictor;
142 int owner;
143 vec3_t movedir;
144 string_t message;
145 float sounds;
146 string_t noise;
147 string_t noise1;
148 string_t noise2;
149 string_t noise3;
150 float dmg;
151 float dmgtime;
152 float air_finished;
153 float pain_finished;
154 float radsuit_finished;
155 float speed;
156} entvars_t;
157
158#define PROGHEADER_CRC 31586
diff --git a/apps/plugins/sdl/progs/quake/progs.h b/apps/plugins/sdl/progs/quake/progs.h
new file mode 100644
index 0000000000..6d3aa8acaa
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/progs.h
@@ -0,0 +1,134 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "pr_comp.h" // defs shared with qcc
22#include "progdefs.h" // generated by program cdefs
23
24typedef union eval_s
25{
26 string_t string;
27 float _float;
28 float vector[3];
29 func_t function;
30 int _int;
31 int edict;
32} eval_t;
33
34#define MAX_ENT_LEAFS 16
35typedef struct edict_s
36{
37 qboolean free;
38 link_t area; // linked to a division node or leaf
39
40 int num_leafs;
41 short leafnums[MAX_ENT_LEAFS];
42
43 entity_state_t baseline;
44
45 float freetime; // sv.time when the object was freed
46 entvars_t v; // C exported fields from progs
47// other fields from progs come immediately after
48} edict_t;
49#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
50
51//============================================================================
52
53extern dprograms_t *progs;
54extern dfunction_t *pr_functions;
55extern char *pr_strings;
56extern ddef_t *pr_globaldefs;
57extern ddef_t *pr_fielddefs;
58extern dstatement_t *pr_statements;
59extern globalvars_t *pr_global_struct;
60extern float *pr_globals; // same as pr_global_struct
61
62extern int pr_edict_size; // in bytes
63
64//============================================================================
65
66void PR_Init (void);
67
68void PR_ExecuteProgram (func_t fnum);
69void PR_LoadProgs (void);
70
71void PR_Profile_f (void);
72
73edict_t *ED_Alloc (void);
74void ED_Free (edict_t *ed);
75
76char *ED_NewString (char *string);
77// returns a copy of the string allocated from the server's string heap
78
79void ED_Print (edict_t *ed);
80void ED_Write (FILE *f, edict_t *ed);
81char *ED_ParseEdict (char *data, edict_t *ent);
82
83void ED_WriteGlobals (FILE *f);
84void ED_ParseGlobals (char *data);
85
86void ED_LoadFromFile (char *data);
87
88//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))
89//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)
90
91edict_t *EDICT_NUM(int n);
92int NUM_FOR_EDICT(edict_t *e);
93
94#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))
95
96#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)
97#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))
98
99//============================================================================
100
101#define G_FLOAT(o) (pr_globals[o])
102#define G_INT(o) (*(int *)&pr_globals[o])
103#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
104#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
105#define G_VECTOR(o) (&pr_globals[o])
106#define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o])
107#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
108
109#define E_FLOAT(e,o) (((float*)&e->v)[o])
110#define E_INT(e,o) (*(int *)&((float*)&e->v)[o])
111#define E_VECTOR(e,o) (&((float*)&e->v)[o])
112#define E_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o])
113
114extern int type_size[8];
115
116typedef void (*builtin_t) (void);
117extern builtin_t *pr_builtins;
118extern int pr_numbuiltins;
119
120extern int pr_argc;
121
122extern qboolean pr_trace;
123extern dfunction_t *pr_xfunction;
124extern int pr_xstatement;
125
126extern unsigned short pr_crc;
127
128void PR_RunError (char *error, ...);
129
130void ED_PrintEdicts (void);
131void ED_PrintNum (int ent);
132
133eval_t *GetEdictFieldValue(edict_t *ed, char *field);
134
diff --git a/apps/plugins/sdl/progs/quake/protocol.h b/apps/plugins/sdl/progs/quake/protocol.h
new file mode 100644
index 0000000000..01780f89da
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/protocol.h
@@ -0,0 +1,167 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// protocol.h -- communications protocols
21
22#define PROTOCOL_VERSION 15
23
24// if the high bit of the servercmd is set, the low bits are fast update flags:
25#define U_MOREBITS (1<<0)
26#define U_ORIGIN1 (1<<1)
27#define U_ORIGIN2 (1<<2)
28#define U_ORIGIN3 (1<<3)
29#define U_ANGLE2 (1<<4)
30#define U_NOLERP (1<<5) // don't interpolate movement
31#define U_FRAME (1<<6)
32#define U_SIGNAL (1<<7) // just differentiates from other updates
33
34// svc_update can pass all of the fast update bits, plus more
35#define U_ANGLE1 (1<<8)
36#define U_ANGLE3 (1<<9)
37#define U_MODEL (1<<10)
38#define U_COLORMAP (1<<11)
39#define U_SKIN (1<<12)
40#define U_EFFECTS (1<<13)
41#define U_LONGENTITY (1<<14)
42
43
44#define SU_VIEWHEIGHT (1<<0)
45#define SU_IDEALPITCH (1<<1)
46#define SU_PUNCH1 (1<<2)
47#define SU_PUNCH2 (1<<3)
48#define SU_PUNCH3 (1<<4)
49#define SU_VELOCITY1 (1<<5)
50#define SU_VELOCITY2 (1<<6)
51#define SU_VELOCITY3 (1<<7)
52//define SU_AIMENT (1<<8) AVAILABLE BIT
53#define SU_ITEMS (1<<9)
54#define SU_ONGROUND (1<<10) // no data follows, the bit is it
55#define SU_INWATER (1<<11) // no data follows, the bit is it
56#define SU_WEAPONFRAME (1<<12)
57#define SU_ARMOR (1<<13)
58#define SU_WEAPON (1<<14)
59
60// a sound with no channel is a local only sound
61#define SND_VOLUME (1<<0) // a byte
62#define SND_ATTENUATION (1<<1) // a byte
63#define SND_LOOPING (1<<2) // a long
64
65
66// defaults for clientinfo messages
67#define DEFAULT_VIEWHEIGHT 22
68
69
70// game types sent by serverinfo
71// these determine which intermission screen plays
72#define GAME_COOP 0
73#define GAME_DEATHMATCH 1
74
75//==================
76// note that there are some defs.qc that mirror to these numbers
77// also related to svc_strings[] in cl_parse
78//==================
79
80//
81// server to client
82//
83#define svc_bad 0
84#define svc_nop 1
85#define svc_disconnect 2
86#define svc_updatestat 3 // [byte] [long]
87#define svc_version 4 // [long] server version
88#define svc_setview 5 // [short] entity number
89#define svc_sound 6 // <see code>
90#define svc_time 7 // [float] server time
91#define svc_print 8 // [string] null terminated string
92#define svc_stufftext 9 // [string] stuffed into client's console buffer
93 // the string should be \n terminated
94#define svc_setangle 10 // [angle3] set the view angle to this absolute value
95
96#define svc_serverinfo 11 // [long] version
97 // [string] signon string
98 // [string]..[0]model cache
99 // [string]...[0]sounds cache
100#define svc_lightstyle 12 // [byte] [string]
101#define svc_updatename 13 // [byte] [string]
102#define svc_updatefrags 14 // [byte] [short]
103#define svc_clientdata 15 // <shortbits + data>
104#define svc_stopsound 16 // <see code>
105#define svc_updatecolors 17 // [byte] [byte]
106#define svc_particle 18 // [vec3] <variable>
107#define svc_damage 19
108
109#define svc_spawnstatic 20
110// svc_spawnbinary 21
111#define svc_spawnbaseline 22
112
113#define svc_temp_entity 23
114
115#define svc_setpause 24 // [byte] on / off
116#define svc_signonnum 25 // [byte] used for the signon sequence
117
118#define svc_centerprint 26 // [string] to put in center of the screen
119
120#define svc_killedmonster 27
121#define svc_foundsecret 28
122
123#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten
124
125#define svc_intermission 30 // [string] music
126#define svc_finale 31 // [string] music [string] text
127
128#define svc_cdtrack 32 // [byte] track [byte] looptrack
129#define svc_sellscreen 33
130
131#define svc_cutscene 34
132
133//
134// client to server
135//
136#define clc_bad 0
137#define clc_nop 1
138#define clc_disconnect 2
139#define clc_move 3 // [usercmd_t]
140#define clc_stringcmd 4 // [string] message
141
142
143//
144// temp entity events
145//
146#define TE_SPIKE 0
147#define TE_SUPERSPIKE 1
148#define TE_GUNSHOT 2
149#define TE_EXPLOSION 3
150#define TE_TAREXPLOSION 4
151#define TE_LIGHTNING1 5
152#define TE_LIGHTNING2 6
153#define TE_WIZSPIKE 7
154#define TE_KNIGHTSPIKE 8
155#define TE_LIGHTNING3 9
156#define TE_LAVASPLASH 10
157#define TE_TELEPORT 11
158#define TE_EXPLOSION2 12
159
160// PGM 01/21/97
161#define TE_BEAM 13
162// PGM 01/21/97
163
164#ifdef QUAKE2
165#define TE_IMPLOSION 14
166#define TE_RAILTRAIL 15
167#endif
diff --git a/apps/plugins/sdl/progs/quake/quakeasm.h b/apps/plugins/sdl/progs/quake/quakeasm.h
new file mode 100644
index 0000000000..303853944e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/quakeasm.h
@@ -0,0 +1,280 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// quakeasm.h: general asm header file
22//
23
24//#define GLQUAKE 1
25
26#if defined(_WIN32) && !defined(WINDED)
27
28#if defined(_M_IX86)
29#define __i386__ 1
30#endif
31
32#endif
33
34#if defined(__i386__) && defined(USE_ASM)
35#define id386 1
36#else
37#define id386 0
38#endif
39
40// !!! must be kept the same as in d_iface.h !!!
41#define TRANSPARENT_COLOR 255
42
43#ifndef NeXT
44#ifndef GLQUAKE
45 .extern C(d_zistepu)
46 .extern C(d_pzbuffer)
47 .extern C(d_zistepv)
48 .extern C(d_zrowbytes)
49 .extern C(d_ziorigin)
50 .extern C(r_turb_s)
51 .extern C(r_turb_t)
52 .extern C(r_turb_pdest)
53 .extern C(r_turb_spancount)
54 .extern C(r_turb_turb)
55 .extern C(r_turb_pbase)
56 .extern C(r_turb_sstep)
57 .extern C(r_turb_tstep)
58 .extern C(r_bmodelactive)
59 .extern C(d_sdivzstepu)
60 .extern C(d_tdivzstepu)
61 .extern C(d_sdivzstepv)
62 .extern C(d_tdivzstepv)
63 .extern C(d_sdivzorigin)
64 .extern C(d_tdivzorigin)
65 .extern C(sadjust)
66 .extern C(tadjust)
67 .extern C(bbextents)
68 .extern C(bbextentt)
69 .extern C(cacheblock)
70 .extern C(d_viewbuffer)
71 .extern C(cachewidth)
72 .extern C(d_pzbuffer)
73 .extern C(d_zrowbytes)
74 .extern C(d_zwidth)
75 .extern C(d_scantable)
76 .extern C(r_lightptr)
77 .extern C(r_numvblocks)
78 .extern C(prowdestbase)
79 .extern C(pbasesource)
80 .extern C(r_lightwidth)
81 .extern C(lightright)
82 .extern C(lightrightstep)
83 .extern C(lightdeltastep)
84 .extern C(lightdelta)
85 .extern C(lightright)
86 .extern C(lightdelta)
87 .extern C(sourcetstep)
88 .extern C(surfrowbytes)
89 .extern C(lightrightstep)
90 .extern C(lightdeltastep)
91 .extern C(r_sourcemax)
92 .extern C(r_stepback)
93 .extern C(colormap)
94 .extern C(blocksize)
95 .extern C(sourcesstep)
96 .extern C(lightleft)
97 .extern C(blockdivshift)
98 .extern C(blockdivmask)
99 .extern C(lightleftstep)
100 .extern C(r_origin)
101 .extern C(r_ppn)
102 .extern C(r_pup)
103 .extern C(r_pright)
104 .extern C(ycenter)
105 .extern C(xcenter)
106 .extern C(d_vrectbottom_particle)
107 .extern C(d_vrectright_particle)
108 .extern C(d_vrecty)
109 .extern C(d_vrectx)
110 .extern C(d_pix_shift)
111 .extern C(d_pix_min)
112 .extern C(d_pix_max)
113 .extern C(d_y_aspect_shift)
114 .extern C(screenwidth)
115 .extern C(r_leftclipped)
116 .extern C(r_leftenter)
117 .extern C(r_rightclipped)
118 .extern C(r_rightenter)
119 .extern C(modelorg)
120 .extern C(xscale)
121 .extern C(r_refdef)
122 .extern C(yscale)
123 .extern C(r_leftexit)
124 .extern C(r_rightexit)
125 .extern C(r_lastvertvalid)
126 .extern C(cacheoffset)
127 .extern C(newedges)
128 .extern C(removeedges)
129 .extern C(r_pedge)
130 .extern C(r_framecount)
131 .extern C(r_u1)
132 .extern C(r_emitted)
133 .extern C(edge_p)
134 .extern C(surface_p)
135 .extern C(surfaces)
136 .extern C(r_lzi1)
137 .extern C(r_v1)
138 .extern C(r_ceilv1)
139 .extern C(r_nearzi)
140 .extern C(r_nearzionly)
141 .extern C(edge_aftertail)
142 .extern C(edge_tail)
143 .extern C(current_iv)
144 .extern C(edge_head_u_shift20)
145 .extern C(span_p)
146 .extern C(edge_head)
147 .extern C(fv)
148 .extern C(edge_tail_u_shift20)
149 .extern C(r_apverts)
150 .extern C(r_anumverts)
151 .extern C(aliastransform)
152 .extern C(r_avertexnormals)
153 .extern C(r_plightvec)
154 .extern C(r_ambientlight)
155 .extern C(r_shadelight)
156 .extern C(aliasxcenter)
157 .extern C(aliasycenter)
158 .extern C(a_sstepxfrac)
159 .extern C(r_affinetridesc)
160 .extern C(acolormap)
161 .extern C(d_pcolormap)
162 .extern C(r_affinetridesc)
163 .extern C(d_sfrac)
164 .extern C(d_ptex)
165 .extern C(d_pedgespanpackage)
166 .extern C(d_tfrac)
167 .extern C(d_light)
168 .extern C(d_zi)
169 .extern C(d_pdest)
170 .extern C(d_pz)
171 .extern C(d_aspancount)
172 .extern C(erroradjustup)
173 .extern C(errorterm)
174 .extern C(d_xdenom)
175 .extern C(r_p0)
176 .extern C(r_p1)
177 .extern C(r_p2)
178 .extern C(a_tstepxfrac)
179 .extern C(r_sstepx)
180 .extern C(r_tstepx)
181 .extern C(a_ststepxwhole)
182 .extern C(zspantable)
183 .extern C(skintable)
184 .extern C(r_zistepx)
185 .extern C(erroradjustdown)
186 .extern C(d_countextrastep)
187 .extern C(ubasestep)
188 .extern C(a_ststepxwhole)
189 .extern C(a_tstepxfrac)
190 .extern C(r_lstepx)
191 .extern C(a_spans)
192 .extern C(erroradjustdown)
193 .extern C(d_pdestextrastep)
194 .extern C(d_pzextrastep)
195 .extern C(d_sfracextrastep)
196 .extern C(d_ptexextrastep)
197 .extern C(d_countextrastep)
198 .extern C(d_tfracextrastep)
199 .extern C(d_lightextrastep)
200 .extern C(d_ziextrastep)
201 .extern C(d_pdestbasestep)
202 .extern C(d_pzbasestep)
203 .extern C(d_sfracbasestep)
204 .extern C(d_ptexbasestep)
205 .extern C(ubasestep)
206 .extern C(d_tfracbasestep)
207 .extern C(d_lightbasestep)
208 .extern C(d_zibasestep)
209 .extern C(zspantable)
210 .extern C(r_lstepy)
211 .extern C(r_sstepy)
212 .extern C(r_tstepy)
213 .extern C(r_zistepy)
214 .extern C(D_PolysetSetEdgeTable)
215 .extern C(D_RasterizeAliasPolySmooth)
216
217 .extern float_point5
218 .extern Float2ToThe31nd
219 .extern izistep
220 .extern izi
221 .extern FloatMinus2ToThe31nd
222 .extern float_1
223 .extern float_particle_z_clip
224 .extern float_minus_1
225 .extern float_0
226 .extern fp_16
227 .extern fp_64k
228 .extern fp_1m
229 .extern fp_1m_minus_1
230 .extern fp_8
231 .extern entryvec_table
232 .extern advancetable
233 .extern sstep
234 .extern tstep
235 .extern pspantemp
236 .extern counttemp
237 .extern jumptemp
238 .extern reciprocal_table
239 .extern DP_Count
240 .extern DP_u
241 .extern DP_v
242 .extern DP_32768
243 .extern DP_Color
244 .extern DP_Pix
245 .extern DP_EntryTable
246 .extern pbase
247 .extern s
248 .extern t
249 .extern sfracf
250 .extern tfracf
251 .extern snext
252 .extern tnext
253 .extern spancountminus1
254 .extern zi16stepu
255 .extern sdivz16stepu
256 .extern tdivz16stepu
257 .extern zi8stepu
258 .extern sdivz8stepu
259 .extern tdivz8stepu
260 .extern reciprocal_table_16
261 .extern entryvec_table_16
262 .extern ceil_cw
263 .extern single_cw
264 .extern fp_64kx64k
265 .extern pz
266 .extern spr8entryvec_table
267#endif
268
269 .extern C(snd_scaletable)
270 .extern C(paintbuffer)
271 .extern C(snd_linear_count)
272 .extern C(snd_p)
273 .extern C(snd_vol)
274 .extern C(snd_out)
275 .extern C(vright)
276 .extern C(vup)
277 .extern C(vpn)
278 .extern C(BOPS_Error)
279
280#endif
diff --git a/apps/plugins/sdl/progs/quake/quakedef.h b/apps/plugins/sdl/progs/quake/quakedef.h
new file mode 100644
index 0000000000..e676b7c9e7
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/quakedef.h
@@ -0,0 +1,333 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// quakedef.h -- primary header for client
21
22//#define GLTEST // experimental stuff
23
24#include "SDL.h"
25#include <stdarg.h>
26#include <setjmp.h>
27
28#define QUAKE_GAME // as opposed to utilities
29
30#undef VERSION
31#define VERSION 1.09
32#define GLQUAKE_VERSION 1.00
33#define D3DQUAKE_VERSION 0.01
34#define WINQUAKE_VERSION 0.996
35#define LINUX_VERSION 1.30
36#define X11_VERSION 1.10
37
38//define PARANOID // speed sapping error checking
39
40#ifdef QUAKE2
41#define GAMENAME "id1" // directory to look in by default
42#else
43#define GAMENAME "id1"
44#endif
45
46#if defined(_WIN32) && !defined(WINDED)
47
48#if defined(_M_IX86)
49#define __i386__ 1
50#endif
51
52void VID_LockBuffer (void);
53void VID_UnlockBuffer (void);
54
55#else
56
57#define VID_LockBuffer()
58#define VID_UnlockBuffer()
59
60#endif
61
62#if defined(__i386__) && defined(USE_ASM)
63#define id386 1
64#else
65#define id386 0
66#endif
67
68#if id386
69#define UNALIGNED_OK 1 // set to 0 if unaligned accesses are not supported
70#else
71#define UNALIGNED_OK 0
72#endif
73
74// !!! if this is changed, it must be changed in d_ifacea.h too !!!
75#define CACHE_SIZE 32 // used to align key data structures
76
77#define UNUSED(x) (x = x) // for pesky compiler / lint warnings
78
79#define MINIMUM_MEMORY 0x550000
80#define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000)
81
82#define MAX_NUM_ARGVS 50
83
84// up / down
85#define PITCH 0
86
87// left / right
88#define YAW 1
89
90// fall over
91#define ROLL 2
92
93
94#define MAX_QPATH 64 // max length of a quake game pathname
95#define MAX_OSPATH 128 // max length of a filesystem pathname
96
97#define ON_EPSILON 0.1 // point on plane side epsilon
98
99#define MAX_MSGLEN 8000 // max length of a reliable message
100#define MAX_DATAGRAM 1024 // max length of unreliable message
101
102//
103// per-level limits
104//
105#define MAX_EDICTS 600 // FIXME: ouch! ouch! ouch!
106#define MAX_LIGHTSTYLES 64
107#define MAX_MODELS 256 // these are sent over the net as bytes
108#define MAX_SOUNDS 256 // so they cannot be blindly increased
109
110#define SAVEGAME_COMMENT_LENGTH 39
111
112#define MAX_STYLESTRING 64
113
114//
115// stats are integers communicated to the client by the server
116//
117#define MAX_CL_STATS 32
118#define STAT_HEALTH 0
119#define STAT_FRAGS 1
120#define STAT_WEAPON 2
121#define STAT_AMMO 3
122#define STAT_ARMOR 4
123#define STAT_WEAPONFRAME 5
124#define STAT_SHELLS 6
125#define STAT_NAILS 7
126#define STAT_ROCKETS 8
127#define STAT_CELLS 9
128#define STAT_ACTIVEWEAPON 10
129#define STAT_TOTALSECRETS 11
130#define STAT_TOTALMONSTERS 12
131#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret
132#define STAT_MONSTERS 14 // bumped by svc_killedmonster
133
134// stock defines
135
136#define IT_SHOTGUN 1
137#define IT_SUPER_SHOTGUN 2
138#define IT_NAILGUN 4
139#define IT_SUPER_NAILGUN 8
140#define IT_GRENADE_LAUNCHER 16
141#define IT_ROCKET_LAUNCHER 32
142#define IT_LIGHTNING 64
143#define IT_SUPER_LIGHTNING 128
144#define IT_SHELLS 256
145#define IT_NAILS 512
146#define IT_ROCKETS 1024
147#define IT_CELLS 2048
148#define IT_AXE 4096
149#define IT_ARMOR1 8192
150#define IT_ARMOR2 16384
151#define IT_ARMOR3 32768
152#define IT_SUPERHEALTH 65536
153#define IT_KEY1 131072
154#define IT_KEY2 262144
155#define IT_INVISIBILITY 524288
156#define IT_INVULNERABILITY 1048576
157#define IT_SUIT 2097152
158#define IT_QUAD 4194304
159#define IT_SIGIL1 (1<<28)
160#define IT_SIGIL2 (1<<29)
161#define IT_SIGIL3 (1<<30)
162#define IT_SIGIL4 (1<<31)
163
164//===========================================
165//rogue changed and added defines
166
167#define RIT_SHELLS 128
168#define RIT_NAILS 256
169#define RIT_ROCKETS 512
170#define RIT_CELLS 1024
171#define RIT_AXE 2048
172#define RIT_LAVA_NAILGUN 4096
173#define RIT_LAVA_SUPER_NAILGUN 8192
174#define RIT_MULTI_GRENADE 16384
175#define RIT_MULTI_ROCKET 32768
176#define RIT_PLASMA_GUN 65536
177#define RIT_ARMOR1 8388608
178#define RIT_ARMOR2 16777216
179#define RIT_ARMOR3 33554432
180#define RIT_LAVA_NAILS 67108864
181#define RIT_PLASMA_AMMO 134217728
182#define RIT_MULTI_ROCKETS 268435456
183#define RIT_SHIELD 536870912
184#define RIT_ANTIGRAV 1073741824
185#define RIT_SUPERHEALTH 2147483648
186
187//MED 01/04/97 added hipnotic defines
188//===========================================
189//hipnotic added defines
190#define HIT_PROXIMITY_GUN_BIT 16
191#define HIT_MJOLNIR_BIT 7
192#define HIT_LASER_CANNON_BIT 23
193#define HIT_PROXIMITY_GUN (1<<HIT_PROXIMITY_GUN_BIT)
194#define HIT_MJOLNIR (1<<HIT_MJOLNIR_BIT)
195#define HIT_LASER_CANNON (1<<HIT_LASER_CANNON_BIT)
196#define HIT_WETSUIT (1<<(23+2))
197#define HIT_EMPATHY_SHIELDS (1<<(23+3))
198
199//===========================================
200
201#define MAX_SCOREBOARD 16
202#define MAX_SCOREBOARDNAME 32
203
204#define SOUND_CHANNELS 8
205
206// This makes anyone on id's net privileged
207// Use for multiplayer testing only - VERY dangerous!!!
208// #define IDGODS
209
210#include "common.h"
211#include "bspfile.h"
212#include "vid.h"
213#include "sys.h"
214#include "zone.h"
215#include "mathlib.h"
216
217typedef struct
218{
219 vec3_t origin;
220 vec3_t angles;
221 int modelindex;
222 int frame;
223 int colormap;
224 int skin;
225 int effects;
226} entity_state_t;
227
228
229#include "wad.h"
230#include "draw.h"
231#include "cvar.h"
232#include "screen.h"
233#include "net.h"
234#include "protocol.h"
235#include "cmd.h"
236#include "sbar.h"
237#include "quakesound.h"
238#include "render.h"
239#include "client.h"
240#include "progs.h"
241#include "server.h"
242
243#ifdef GLQUAKE
244#include "gl_model.h"
245#else
246#include "model.h"
247#include "d_iface.h"
248#endif
249
250#include "input.h"
251#include "world.h"
252#include "keys.h"
253#include "console.h"
254#include "view.h"
255#include "menu.h"
256#include "crc.h"
257#include "cdaudio.h"
258
259#ifdef GLQUAKE
260#include "glquake.h"
261#endif
262
263//=============================================================================
264
265// the host system specifies the base of the directory tree, the
266// command line parms passed to the program, and the amount of memory
267// available for the program to use
268
269typedef struct
270{
271 char *basedir;
272 char *cachedir; // for development over ISDN lines
273 int argc;
274 char **argv;
275 void *membase;
276 int memsize;
277} quakeparms_t;
278
279
280//=============================================================================
281
282
283
284extern qboolean noclip_anglehack;
285
286
287//
288// host
289//
290extern quakeparms_t host_parms;
291
292extern cvar_t sys_ticrate;
293extern cvar_t sys_nostdout;
294extern cvar_t developer;
295
296extern qboolean host_initialized; // true if into command execution
297extern double host_frametime;
298extern byte *host_basepal;
299extern byte *host_colormap;
300extern int host_framecount; // incremented every frame, never reset
301extern double realtime; // not bounded in any way, changed at
302 // start of every frame, never reset
303
304void Host_ClearMemory (void);
305void Host_ServerFrame (void);
306void Host_InitCommands (void);
307void Host_Init (quakeparms_t *parms);
308void Host_Shutdown(void);
309void Host_Error (char *error, ...);
310void Host_EndGame (char *message, ...);
311void Host_Frame (float time);
312void Host_Quit_f (void);
313void Host_ClientCommands (char *fmt, ...);
314void Host_ShutdownServer (qboolean crash);
315
316extern qboolean msg_suppress_1; // suppresses resolution and cache size console output
317 // an fullscreen DIB focus gain/loss
318extern int current_skill; // skill level for currently loaded level (in case
319 // the user changes the cvar while the level is
320 // running, this reflects the level actually in use)
321
322extern qboolean isDedicated;
323
324extern int minimum_memory;
325
326//
327// chase
328//
329extern cvar_t chase_active;
330
331void Chase_Init (void);
332void Chase_Reset (void);
333void Chase_Update (void);
diff --git a/apps/plugins/sdl/progs/quake/quakesound.h b/apps/plugins/sdl/progs/quake/quakesound.h
new file mode 100644
index 0000000000..1ba08d3f6e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/quakesound.h
@@ -0,0 +1,177 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sound.h -- client sound i/o functions
21
22#ifndef __SOUND__
23#define __SOUND__
24
25#define DEFAULT_SOUND_PACKET_VOLUME 255
26#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
27
28// !!! if this is changed, it much be changed in asm_i386.h too !!!
29typedef struct
30{
31 int left;
32 int right;
33} portable_samplepair_t;
34
35typedef struct sfx_s
36{
37 char name[MAX_QPATH];
38 cache_user_t cache;
39} sfx_t;
40
41// !!! if this is changed, it much be changed in asm_i386.h too !!!
42typedef struct
43{
44 int length;
45 int loopstart;
46 int speed;
47 int width;
48 int stereo;
49 byte data[1]; // variable sized
50} sfxcache_t;
51
52typedef struct
53{
54 qboolean gamealive;
55 qboolean soundalive;
56 qboolean splitbuffer;
57 int channels;
58 int samples; // mono samples in buffer
59 int submission_chunk; // don't mix less than this #
60 int samplepos; // in mono samples
61 int samplebits;
62 int speed;
63 unsigned char *buffer;
64} dma_t;
65
66// !!! if this is changed, it much be changed in asm_i386.h too !!!
67typedef struct
68{
69 sfx_t *sfx; // sfx number
70 int leftvol; // 0-255 volume
71 int rightvol; // 0-255 volume
72 int end; // end time in global paintsamples
73 int pos; // sample position in sfx
74 int looping; // where to loop, -1 = no looping
75 int entnum; // to allow overriding a specific sound
76 int entchannel; //
77 vec3_t origin; // origin of sound effect
78 vec_t dist_mult; // distance multiplier (attenuation/clipK)
79 int master_vol; // 0-255 master volume
80} channel_t;
81
82typedef struct
83{
84 int rate;
85 int width;
86 int channels;
87 int loopstart;
88 int samples;
89 int dataofs; // chunk starts this many bytes from file start
90} wavinfo_t;
91
92void S_Init (void);
93void S_Startup (void);
94void S_Shutdown (void);
95void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation);
96void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
97void S_StopSound (int entnum, int entchannel);
98void S_StopAllSounds(qboolean clear);
99void S_ClearBuffer (void);
100void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);
101void S_ExtraUpdate (void);
102
103sfx_t *S_PrecacheSound (char *sample);
104void S_TouchSound (char *sample);
105void S_ClearPrecache (void);
106void S_BeginPrecaching (void);
107void S_EndPrecaching (void);
108void S_PaintChannels(int endtime);
109void S_InitPaintChannels (void);
110
111// picks a channel based on priorities, empty slots, number of channels
112channel_t *SND_PickChannel(int entnum, int entchannel);
113
114// spatializes a channel
115void SND_Spatialize(channel_t *ch);
116
117// initializes cycling through a DMA buffer and returns information on it
118qboolean SNDDMA_Init(void);
119
120// gets the current DMA position
121int SNDDMA_GetDMAPos(void);
122
123// shutdown the DMA xfer.
124void SNDDMA_Shutdown(void);
125
126// ====================================================================
127// User-setable variables
128// ====================================================================
129
130#define MAX_CHANNELS 128
131#define MAX_DYNAMIC_CHANNELS 8
132
133
134extern channel_t channels[MAX_CHANNELS];
135// 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds
136// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
137// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
138
139extern int total_channels;
140
141//
142// Fake dma is a synchronous faking of the DMA progress used for
143// isolating performance in the renderer. The fakedma_updates is
144// number of times S_Update() is called per second.
145//
146
147extern qboolean fakedma;
148extern int fakedma_updates;
149extern int paintedtime;
150extern vec3_t listener_origin;
151extern vec3_t listener_forward;
152extern vec3_t listener_right;
153extern vec3_t listener_up;
154extern volatile dma_t *shm;
155extern volatile dma_t sn;
156extern vec_t sound_nominal_clip_dist;
157
158extern cvar_t loadas8bit;
159extern cvar_t bgmvolume;
160extern cvar_t volume;
161
162extern qboolean snd_initialized;
163
164extern int snd_blocked;
165
166void S_LocalSound (char *s);
167sfxcache_t *S_LoadSound (sfx_t *s);
168
169wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);
170
171void SND_InitScaletable (void);
172void SNDDMA_Submit(void);
173
174void S_AmbientOff (void);
175void S_AmbientOn (void);
176
177#endif
diff --git a/apps/plugins/sdl/progs/quake/r_aclip.c b/apps/plugins/sdl/progs/quake/r_aclip.c
new file mode 100644
index 0000000000..61fef0cd6f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_aclip.c
@@ -0,0 +1,350 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_aclip.c: clip routines for drawing Alias models directly to the screen
21
22#include "quakedef.h"
23#include "r_local.h"
24#include "d_local.h"
25
26static finalvert_t fv[2][8];
27static auxvert_t av[8];
28
29void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
30void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1,
31 finalvert_t *out);
32void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
33 finalvert_t *out);
34void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1,
35 finalvert_t *out);
36void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
37 finalvert_t *out);
38
39
40/*
41================
42R_Alias_clip_z
43
44pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex
45================
46*/
47void R_Alias_clip_z (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
48{
49 float scale;
50 auxvert_t *pav0, *pav1, avout;
51
52 pav0 = &av[pfv0 - &fv[0][0]];
53 pav1 = &av[pfv1 - &fv[0][0]];
54
55 if (pfv0->v[1] >= pfv1->v[1])
56 {
57 scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) /
58 (pav1->fv[2] - pav0->fv[2]);
59
60 avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale;
61 avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale;
62 avout.fv[2] = ALIAS_Z_CLIP_PLANE;
63
64 out->v[2] = pfv0->v[2] + (pfv1->v[2] - pfv0->v[2]) * scale;
65 out->v[3] = pfv0->v[3] + (pfv1->v[3] - pfv0->v[3]) * scale;
66 out->v[4] = pfv0->v[4] + (pfv1->v[4] - pfv0->v[4]) * scale;
67 }
68 else
69 {
70 scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) /
71 (pav0->fv[2] - pav1->fv[2]);
72
73 avout.fv[0] = pav1->fv[0] + (pav0->fv[0] - pav1->fv[0]) * scale;
74 avout.fv[1] = pav1->fv[1] + (pav0->fv[1] - pav1->fv[1]) * scale;
75 avout.fv[2] = ALIAS_Z_CLIP_PLANE;
76
77 out->v[2] = pfv1->v[2] + (pfv0->v[2] - pfv1->v[2]) * scale;
78 out->v[3] = pfv1->v[3] + (pfv0->v[3] - pfv1->v[3]) * scale;
79 out->v[4] = pfv1->v[4] + (pfv0->v[4] - pfv1->v[4]) * scale;
80 }
81
82 R_AliasProjectFinalVert (out, &avout);
83
84 if (out->v[0] < r_refdef.aliasvrect.x)
85 out->flags |= ALIAS_LEFT_CLIP;
86 if (out->v[1] < r_refdef.aliasvrect.y)
87 out->flags |= ALIAS_TOP_CLIP;
88 if (out->v[0] > r_refdef.aliasvrectright)
89 out->flags |= ALIAS_RIGHT_CLIP;
90 if (out->v[1] > r_refdef.aliasvrectbottom)
91 out->flags |= ALIAS_BOTTOM_CLIP;
92}
93
94
95#if !id386
96
97void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
98{
99 float scale;
100 int i;
101
102 if (pfv0->v[1] >= pfv1->v[1])
103 {
104 scale = (float)(r_refdef.aliasvrect.x - pfv0->v[0]) /
105 (pfv1->v[0] - pfv0->v[0]);
106 for (i=0 ; i<6 ; i++)
107 out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
108 }
109 else
110 {
111 scale = (float)(r_refdef.aliasvrect.x - pfv1->v[0]) /
112 (pfv0->v[0] - pfv1->v[0]);
113 for (i=0 ; i<6 ; i++)
114 out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
115 }
116}
117
118
119void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1,
120 finalvert_t *out)
121{
122 float scale;
123 int i;
124
125 if (pfv0->v[1] >= pfv1->v[1])
126 {
127 scale = (float)(r_refdef.aliasvrectright - pfv0->v[0]) /
128 (pfv1->v[0] - pfv0->v[0]);
129 for (i=0 ; i<6 ; i++)
130 out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
131 }
132 else
133 {
134 scale = (float)(r_refdef.aliasvrectright - pfv1->v[0]) /
135 (pfv0->v[0] - pfv1->v[0]);
136 for (i=0 ; i<6 ; i++)
137 out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
138 }
139}
140
141
142void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out)
143{
144 float scale;
145 int i;
146
147 if (pfv0->v[1] >= pfv1->v[1])
148 {
149 scale = (float)(r_refdef.aliasvrect.y - pfv0->v[1]) /
150 (pfv1->v[1] - pfv0->v[1]);
151 for (i=0 ; i<6 ; i++)
152 out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
153 }
154 else
155 {
156 scale = (float)(r_refdef.aliasvrect.y - pfv1->v[1]) /
157 (pfv0->v[1] - pfv1->v[1]);
158 for (i=0 ; i<6 ; i++)
159 out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
160 }
161}
162
163
164void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1,
165 finalvert_t *out)
166{
167 float scale;
168 int i;
169
170 if (pfv0->v[1] >= pfv1->v[1])
171 {
172 scale = (float)(r_refdef.aliasvrectbottom - pfv0->v[1]) /
173 (pfv1->v[1] - pfv0->v[1]);
174
175 for (i=0 ; i<6 ; i++)
176 out->v[i] = pfv0->v[i] + (pfv1->v[i] - pfv0->v[i])*scale + 0.5;
177 }
178 else
179 {
180 scale = (float)(r_refdef.aliasvrectbottom - pfv1->v[1]) /
181 (pfv0->v[1] - pfv1->v[1]);
182
183 for (i=0 ; i<6 ; i++)
184 out->v[i] = pfv1->v[i] + (pfv0->v[i] - pfv1->v[i])*scale + 0.5;
185 }
186}
187
188#endif
189
190
191int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count,
192 void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) )
193{
194 int i,j,k;
195 int flags, oldflags;
196
197 j = count-1;
198 k = 0;
199 for (i=0 ; i<count ; j = i, i++)
200 {
201 oldflags = in[j].flags & flag;
202 flags = in[i].flags & flag;
203
204 if (flags && oldflags)
205 continue;
206 if (oldflags ^ flags)
207 {
208 clip (&in[j], &in[i], &out[k]);
209 out[k].flags = 0;
210 if (out[k].v[0] < r_refdef.aliasvrect.x)
211 out[k].flags |= ALIAS_LEFT_CLIP;
212 if (out[k].v[1] < r_refdef.aliasvrect.y)
213 out[k].flags |= ALIAS_TOP_CLIP;
214 if (out[k].v[0] > r_refdef.aliasvrectright)
215 out[k].flags |= ALIAS_RIGHT_CLIP;
216 if (out[k].v[1] > r_refdef.aliasvrectbottom)
217 out[k].flags |= ALIAS_BOTTOM_CLIP;
218 k++;
219 }
220 if (!flags)
221 {
222 out[k] = in[i];
223 k++;
224 }
225 }
226
227 return k;
228}
229
230
231/*
232================
233R_AliasClipTriangle
234================
235*/
236void R_AliasClipTriangle (mtriangle_t *ptri)
237{
238 int i, k, pingpong;
239 mtriangle_t mtri;
240 unsigned clipflags;
241
242// copy vertexes and fix seam texture coordinates
243 if (ptri->facesfront)
244 {
245 fv[0][0] = pfinalverts[ptri->vertindex[0]];
246 fv[0][1] = pfinalverts[ptri->vertindex[1]];
247 fv[0][2] = pfinalverts[ptri->vertindex[2]];
248 }
249 else
250 {
251 for (i=0 ; i<3 ; i++)
252 {
253 fv[0][i] = pfinalverts[ptri->vertindex[i]];
254
255 if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM) )
256 fv[0][i].v[2] += r_affinetridesc.seamfixupX16;
257 }
258 }
259
260// clip
261 clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags;
262
263 if (clipflags & ALIAS_Z_CLIP)
264 {
265 for (i=0 ; i<3 ; i++)
266 av[i] = pauxverts[ptri->vertindex[i]];
267
268 k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z);
269 if (k == 0)
270 return;
271
272 pingpong = 1;
273 clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags;
274 }
275 else
276 {
277 pingpong = 0;
278 k = 3;
279 }
280
281 if (clipflags & ALIAS_LEFT_CLIP)
282 {
283 k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
284 ALIAS_LEFT_CLIP, k, R_Alias_clip_left);
285 if (k == 0)
286 return;
287
288 pingpong ^= 1;
289 }
290
291 if (clipflags & ALIAS_RIGHT_CLIP)
292 {
293 k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
294 ALIAS_RIGHT_CLIP, k, R_Alias_clip_right);
295 if (k == 0)
296 return;
297
298 pingpong ^= 1;
299 }
300
301 if (clipflags & ALIAS_BOTTOM_CLIP)
302 {
303 k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
304 ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom);
305 if (k == 0)
306 return;
307
308 pingpong ^= 1;
309 }
310
311 if (clipflags & ALIAS_TOP_CLIP)
312 {
313 k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1],
314 ALIAS_TOP_CLIP, k, R_Alias_clip_top);
315 if (k == 0)
316 return;
317
318 pingpong ^= 1;
319 }
320
321 for (i=0 ; i<k ; i++)
322 {
323 if (fv[pingpong][i].v[0] < r_refdef.aliasvrect.x)
324 fv[pingpong][i].v[0] = r_refdef.aliasvrect.x;
325 else if (fv[pingpong][i].v[0] > r_refdef.aliasvrectright)
326 fv[pingpong][i].v[0] = r_refdef.aliasvrectright;
327
328 if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y)
329 fv[pingpong][i].v[1] = r_refdef.aliasvrect.y;
330 else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom)
331 fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom;
332
333 fv[pingpong][i].flags = 0;
334 }
335
336// draw triangles
337 mtri.facesfront = ptri->facesfront;
338 r_affinetridesc.ptriangles = &mtri;
339 r_affinetridesc.pfinalverts = fv[pingpong];
340
341// FIXME: do all at once as trifan?
342 mtri.vertindex[0] = 0;
343 for (i=1 ; i<k-1 ; i++)
344 {
345 mtri.vertindex[1] = i;
346 mtri.vertindex[2] = i+1;
347 D_PolysetDraw ();
348 }
349}
350
diff --git a/apps/plugins/sdl/progs/quake/r_alias.c b/apps/plugins/sdl/progs/quake/r_alias.c
new file mode 100644
index 0000000000..86074199bc
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_alias.c
@@ -0,0 +1,753 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_alias.c: routines for setting up to draw alias models
21
22#include "quakedef.h"
23#include "r_local.h"
24#include "d_local.h" // FIXME: shouldn't be needed (is needed for patch
25 // right now, but that should move)
26
27#define LIGHT_MIN 5 // lowest light value we'll allow, to avoid the
28 // need for inner-loop light clamping
29
30mtriangle_t *ptriangles;
31affinetridesc_t r_affinetridesc;
32
33void * acolormap; // FIXME: should go away
34
35trivertx_t *r_apverts;
36
37// TODO: these probably will go away with optimized rasterization
38mdl_t *pmdl;
39vec3_t r_plightvec;
40int r_ambientlight;
41float r_shadelight;
42aliashdr_t *paliashdr;
43finalvert_t *pfinalverts;
44auxvert_t *pauxverts;
45static float ziscale;
46static model_t *pmodel;
47
48static vec3_t alias_forward, alias_right, alias_up;
49
50static maliasskindesc_t *pskindesc;
51
52int r_amodels_drawn;
53int a_skinwidth;
54int r_anumverts;
55
56float aliastransform[3][4];
57
58typedef struct {
59 int index0;
60 int index1;
61} aedge_t;
62
63static aedge_t aedges[12] = {
64{0, 1}, {1, 2}, {2, 3}, {3, 0},
65{4, 5}, {5, 6}, {6, 7}, {7, 4},
66{0, 5}, {1, 4}, {2, 7}, {3, 6}
67};
68
69#define NUMVERTEXNORMALS 162
70
71float r_avertexnormals[NUMVERTEXNORMALS][3] = {
72#include "anorms.h"
73};
74
75void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv,
76 stvert_t *pstverts);
77void R_AliasSetUpTransform (int trivial_accept);
78void R_AliasTransformVector (vec3_t in, vec3_t out);
79void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
80 trivertx_t *pverts, stvert_t *pstverts);
81void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av);
82
83
84/*
85================
86R_AliasCheckBBox
87================
88*/
89qboolean R_AliasCheckBBox (void)
90{
91 int i, flags, frame, numv;
92 aliashdr_t *pahdr;
93 float zi, basepts[8][3], v0, v1, frac;
94 finalvert_t *pv0, *pv1, viewpts[16];
95 auxvert_t *pa0, *pa1, viewaux[16];
96 maliasframedesc_t *pframedesc;
97 qboolean zclipped, zfullyclipped;
98 unsigned anyclip, allclip;
99 int minz;
100
101// expand, rotate, and translate points into worldspace
102
103 currententity->trivial_accept = 0;
104 pmodel = currententity->model;
105 pahdr = Mod_Extradata (pmodel);
106 pmdl = (mdl_t *)((byte *)pahdr + pahdr->model);
107
108 R_AliasSetUpTransform (0);
109
110// construct the base bounding box for this frame
111 frame = currententity->frame;
112// TODO: don't repeat this check when drawing?
113 if ((frame >= pmdl->numframes) || (frame < 0))
114 {
115 Con_DPrintf ("No such frame %d %s\n", frame,
116 pmodel->name);
117 frame = 0;
118 }
119
120 pframedesc = &pahdr->frames[frame];
121
122// x worldspace coordinates
123 basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] =
124 (float)pframedesc->bboxmin.v[0];
125 basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] =
126 (float)pframedesc->bboxmax.v[0];
127
128// y worldspace coordinates
129 basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] =
130 (float)pframedesc->bboxmin.v[1];
131 basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] =
132 (float)pframedesc->bboxmax.v[1];
133
134// z worldspace coordinates
135 basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] =
136 (float)pframedesc->bboxmin.v[2];
137 basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] =
138 (float)pframedesc->bboxmax.v[2];
139
140 zclipped = false;
141 zfullyclipped = true;
142
143 minz = 9999;
144 for (i=0; i<8 ; i++)
145 {
146 R_AliasTransformVector (&basepts[i][0], &viewaux[i].fv[0]);
147
148 if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE)
149 {
150 // we must clip points that are closer than the near clip plane
151 viewpts[i].flags = ALIAS_Z_CLIP;
152 zclipped = true;
153 }
154 else
155 {
156 if (viewaux[i].fv[2] < minz)
157 minz = viewaux[i].fv[2];
158 viewpts[i].flags = 0;
159 zfullyclipped = false;
160 }
161 }
162
163
164 if (zfullyclipped)
165 {
166 return false; // everything was near-z-clipped
167 }
168
169 numv = 8;
170
171 if (zclipped)
172 {
173 // organize points by edges, use edges to get new points (possible trivial
174 // reject)
175 for (i=0 ; i<12 ; i++)
176 {
177 // edge endpoints
178 pv0 = &viewpts[aedges[i].index0];
179 pv1 = &viewpts[aedges[i].index1];
180 pa0 = &viewaux[aedges[i].index0];
181 pa1 = &viewaux[aedges[i].index1];
182
183 // if one end is clipped and the other isn't, make a new point
184 if (pv0->flags ^ pv1->flags)
185 {
186 frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) /
187 (pa1->fv[2] - pa0->fv[2]);
188 viewaux[numv].fv[0] = pa0->fv[0] +
189 (pa1->fv[0] - pa0->fv[0]) * frac;
190 viewaux[numv].fv[1] = pa0->fv[1] +
191 (pa1->fv[1] - pa0->fv[1]) * frac;
192 viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE;
193 viewpts[numv].flags = 0;
194 numv++;
195 }
196 }
197 }
198
199// project the vertices that remain after clipping
200 anyclip = 0;
201 allclip = ALIAS_XY_CLIP_MASK;
202
203// TODO: probably should do this loop in ASM, especially if we use floats
204 for (i=0 ; i<numv ; i++)
205 {
206 // we don't need to bother with vertices that were z-clipped
207 if (viewpts[i].flags & ALIAS_Z_CLIP)
208 continue;
209
210 zi = 1.0 / viewaux[i].fv[2];
211
212 // FIXME: do with chop mode in ASM, or convert to float
213 v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter;
214 v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter;
215
216 flags = 0;
217
218 if (v0 < r_refdef.fvrectx)
219 flags |= ALIAS_LEFT_CLIP;
220 if (v1 < r_refdef.fvrecty)
221 flags |= ALIAS_TOP_CLIP;
222 if (v0 > r_refdef.fvrectright)
223 flags |= ALIAS_RIGHT_CLIP;
224 if (v1 > r_refdef.fvrectbottom)
225 flags |= ALIAS_BOTTOM_CLIP;
226
227 anyclip |= flags;
228 allclip &= flags;
229 }
230
231 if (allclip)
232 return false; // trivial reject off one side
233
234 currententity->trivial_accept = !anyclip & !zclipped;
235
236 if (currententity->trivial_accept)
237 {
238 if (minz > (r_aliastransition + (pmdl->size * r_resfudge)))
239 {
240 currententity->trivial_accept |= 2;
241 }
242 }
243
244 return true;
245}
246
247
248/*
249================
250R_AliasTransformVector
251================
252*/
253void R_AliasTransformVector (vec3_t in, vec3_t out)
254{
255 out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3];
256 out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3];
257 out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3];
258}
259
260
261/*
262================
263R_AliasPreparePoints
264
265General clipped case
266================
267*/
268void R_AliasPreparePoints (void)
269{
270 int i;
271 stvert_t *pstverts;
272 finalvert_t *fv;
273 auxvert_t *av;
274 mtriangle_t *ptri;
275 finalvert_t *pfv[3];
276
277 pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
278 r_anumverts = pmdl->numverts;
279 fv = pfinalverts;
280 av = pauxverts;
281
282 for (i=0 ; i<r_anumverts ; i++, fv++, av++, r_apverts++, pstverts++)
283 {
284 R_AliasTransformFinalVert (fv, av, r_apverts, pstverts);
285 if (av->fv[2] < ALIAS_Z_CLIP_PLANE)
286 fv->flags |= ALIAS_Z_CLIP;
287 else
288 {
289 R_AliasProjectFinalVert (fv, av);
290
291 if (fv->v[0] < r_refdef.aliasvrect.x)
292 fv->flags |= ALIAS_LEFT_CLIP;
293 if (fv->v[1] < r_refdef.aliasvrect.y)
294 fv->flags |= ALIAS_TOP_CLIP;
295 if (fv->v[0] > r_refdef.aliasvrectright)
296 fv->flags |= ALIAS_RIGHT_CLIP;
297 if (fv->v[1] > r_refdef.aliasvrectbottom)
298 fv->flags |= ALIAS_BOTTOM_CLIP;
299 }
300 }
301
302//
303// clip and draw all triangles
304//
305 r_affinetridesc.numtriangles = 1;
306
307 ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
308 for (i=0 ; i<pmdl->numtris ; i++, ptri++)
309 {
310 pfv[0] = &pfinalverts[ptri->vertindex[0]];
311 pfv[1] = &pfinalverts[ptri->vertindex[1]];
312 pfv[2] = &pfinalverts[ptri->vertindex[2]];
313
314 if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) )
315 continue; // completely clipped
316
317 if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) &
318 (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) )
319 { // totally unclipped
320 r_affinetridesc.pfinalverts = pfinalverts;
321 r_affinetridesc.ptriangles = ptri;
322 D_PolysetDraw ();
323 }
324 else
325 { // partially clipped
326 R_AliasClipTriangle (ptri);
327 }
328 }
329}
330
331
332/*
333================
334R_AliasSetUpTransform
335================
336*/
337void R_AliasSetUpTransform (int trivial_accept)
338{
339 int i;
340 float rotationmatrix[3][4], t2matrix[3][4];
341 static float tmatrix[3][4];
342 static float viewmatrix[3][4];
343 vec3_t angles;
344
345// TODO: should really be stored with the entity instead of being reconstructed
346// TODO: should use a look-up table
347// TODO: could cache lazily, stored in the entity
348
349 angles[ROLL] = currententity->angles[ROLL];
350 angles[PITCH] = -currententity->angles[PITCH];
351 angles[YAW] = currententity->angles[YAW];
352 AngleVectors (angles, alias_forward, alias_right, alias_up);
353
354 tmatrix[0][0] = pmdl->scale[0];
355 tmatrix[1][1] = pmdl->scale[1];
356 tmatrix[2][2] = pmdl->scale[2];
357
358 tmatrix[0][3] = pmdl->scale_origin[0];
359 tmatrix[1][3] = pmdl->scale_origin[1];
360 tmatrix[2][3] = pmdl->scale_origin[2];
361
362// TODO: can do this with simple matrix rearrangement
363
364 for (i=0 ; i<3 ; i++)
365 {
366 t2matrix[i][0] = alias_forward[i];
367 t2matrix[i][1] = -alias_right[i];
368 t2matrix[i][2] = alias_up[i];
369 }
370
371 t2matrix[0][3] = -modelorg[0];
372 t2matrix[1][3] = -modelorg[1];
373 t2matrix[2][3] = -modelorg[2];
374
375// FIXME: can do more efficiently than full concatenation
376 R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix);
377
378// TODO: should be global, set when vright, etc., set
379 VectorCopy (vright, viewmatrix[0]);
380 VectorCopy (vup, viewmatrix[1]);
381 VectorInverse (viewmatrix[1]);
382 VectorCopy (vpn, viewmatrix[2]);
383
384// viewmatrix[0][3] = 0;
385// viewmatrix[1][3] = 0;
386// viewmatrix[2][3] = 0;
387
388 R_ConcatTransforms (viewmatrix, rotationmatrix, aliastransform);
389
390// do the scaling up of x and y to screen coordinates as part of the transform
391// for the unclipped case (it would mess up clipping in the clipped case).
392// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y
393// correspondingly so the projected x and y come out right
394// FIXME: make this work for clipped case too?
395 if (trivial_accept)
396 {
397 for (i=0 ; i<4 ; i++)
398 {
399 aliastransform[0][i] *= aliasxscale *
400 (1.0 / ((float)0x8000 * 0x10000));
401 aliastransform[1][i] *= aliasyscale *
402 (1.0 / ((float)0x8000 * 0x10000));
403 aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000);
404
405 }
406 }
407}
408
409
410/*
411================
412R_AliasTransformFinalVert
413================
414*/
415void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av,
416 trivertx_t *pverts, stvert_t *pstverts)
417{
418 int temp;
419 float lightcos, *plightnormal;
420
421 av->fv[0] = DotProduct(pverts->v, aliastransform[0]) +
422 aliastransform[0][3];
423 av->fv[1] = DotProduct(pverts->v, aliastransform[1]) +
424 aliastransform[1][3];
425 av->fv[2] = DotProduct(pverts->v, aliastransform[2]) +
426 aliastransform[2][3];
427
428 fv->v[2] = pstverts->s;
429 fv->v[3] = pstverts->t;
430
431 fv->flags = pstverts->onseam;
432
433// lighting
434 plightnormal = r_avertexnormals[pverts->lightnormalindex];
435 lightcos = DotProduct (plightnormal, r_plightvec);
436 temp = r_ambientlight;
437
438 if (lightcos < 0)
439 {
440 temp += (int)(r_shadelight * lightcos);
441
442 // clamp; because we limited the minimum ambient and shading light, we
443 // don't have to clamp low light, just bright
444 if (temp < 0)
445 temp = 0;
446 }
447
448 fv->v[4] = temp;
449}
450
451
452#if !id386
453
454/*
455================
456R_AliasTransformAndProjectFinalVerts
457================
458*/
459void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv, stvert_t *pstverts)
460{
461 int i, temp;
462 float lightcos, *plightnormal, zi;
463 trivertx_t *pverts;
464
465 pverts = r_apverts;
466
467 for (i=0 ; i<r_anumverts ; i++, fv++, pverts++, pstverts++)
468 {
469 // transform and project
470 zi = 1.0 / (DotProduct(pverts->v, aliastransform[2]) +
471 aliastransform[2][3]);
472
473 // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is
474 // scaled up by 1/2**31, and the scaling cancels out for x and y in the
475 // projection
476 fv->v[5] = zi;
477
478 fv->v[0] = ((DotProduct(pverts->v, aliastransform[0]) +
479 aliastransform[0][3]) * zi) + aliasxcenter;
480 fv->v[1] = ((DotProduct(pverts->v, aliastransform[1]) +
481 aliastransform[1][3]) * zi) + aliasycenter;
482
483 fv->v[2] = pstverts->s;
484 fv->v[3] = pstverts->t;
485 fv->flags = pstverts->onseam;
486
487 // lighting
488 plightnormal = r_avertexnormals[pverts->lightnormalindex];
489 lightcos = DotProduct (plightnormal, r_plightvec);
490 temp = r_ambientlight;
491
492 if (lightcos < 0)
493 {
494 temp += (int)(r_shadelight * lightcos);
495
496 // clamp; because we limited the minimum ambient and shading light, we
497 // don't have to clamp low light, just bright
498 if (temp < 0)
499 temp = 0;
500 }
501
502 fv->v[4] = temp;
503 }
504}
505
506#endif
507
508
509/*
510================
511R_AliasProjectFinalVert
512================
513*/
514void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av)
515{
516 float zi;
517
518// project points
519 zi = 1.0 / av->fv[2];
520
521 fv->v[5] = zi * ziscale;
522
523 fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter;
524 fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter;
525}
526
527
528/*
529================
530R_AliasPrepareUnclippedPoints
531================
532*/
533void R_AliasPrepareUnclippedPoints (void)
534{
535 stvert_t *pstverts;
536 finalvert_t *fv;
537
538 pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts);
539 r_anumverts = pmdl->numverts;
540// FIXME: just use pfinalverts directly?
541 fv = pfinalverts;
542
543 R_AliasTransformAndProjectFinalVerts (fv, pstverts);
544
545 if (r_affinetridesc.drawtype)
546 D_PolysetDrawFinalVerts (fv, r_anumverts);
547
548 r_affinetridesc.pfinalverts = pfinalverts;
549 r_affinetridesc.ptriangles = (mtriangle_t *)
550 ((byte *)paliashdr + paliashdr->triangles);
551 r_affinetridesc.numtriangles = pmdl->numtris;
552
553 D_PolysetDraw ();
554}
555
556/*
557===============
558R_AliasSetupSkin
559===============
560*/
561void R_AliasSetupSkin (void)
562{
563 int skinnum;
564 int i, numskins;
565 maliasskingroup_t *paliasskingroup;
566 float *pskinintervals, fullskininterval;
567 float skintargettime, skintime;
568
569 skinnum = currententity->skinnum;
570 if ((skinnum >= pmdl->numskins) || (skinnum < 0))
571 {
572 Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum);
573 skinnum = 0;
574 }
575
576 pskindesc = ((maliasskindesc_t *)
577 ((byte *)paliashdr + paliashdr->skindesc)) + skinnum;
578 a_skinwidth = pmdl->skinwidth;
579
580 if (pskindesc->type == ALIAS_SKIN_GROUP)
581 {
582 paliasskingroup = (maliasskingroup_t *)((byte *)paliashdr +
583 pskindesc->skin);
584 pskinintervals = (float *)
585 ((byte *)paliashdr + paliasskingroup->intervals);
586 numskins = paliasskingroup->numskins;
587 fullskininterval = pskinintervals[numskins-1];
588
589 skintime = cl.time + currententity->syncbase;
590
591 // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval
592 // values are positive, so we don't have to worry about division by 0
593 skintargettime = skintime -
594 ((int)(skintime / fullskininterval)) * fullskininterval;
595
596 for (i=0 ; i<(numskins-1) ; i++)
597 {
598 if (pskinintervals[i] > skintargettime)
599 break;
600 }
601
602 pskindesc = &paliasskingroup->skindescs[i];
603 }
604
605 r_affinetridesc.pskindesc = pskindesc;
606 r_affinetridesc.pskin = (void *)((byte *)paliashdr + pskindesc->skin);
607 r_affinetridesc.skinwidth = a_skinwidth;
608 r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16;
609 r_affinetridesc.skinheight = pmdl->skinheight;
610}
611
612/*
613================
614R_AliasSetupLighting
615================
616*/
617void R_AliasSetupLighting (alight_t *plighting)
618{
619
620// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have
621// to clamp off the bottom
622 r_ambientlight = plighting->ambientlight;
623
624 if (r_ambientlight < LIGHT_MIN)
625 r_ambientlight = LIGHT_MIN;
626
627 r_ambientlight = (255 - r_ambientlight) << VID_CBITS;
628
629 if (r_ambientlight < LIGHT_MIN)
630 r_ambientlight = LIGHT_MIN;
631
632 r_shadelight = plighting->shadelight;
633
634 if (r_shadelight < 0)
635 r_shadelight = 0;
636
637 r_shadelight *= VID_GRADES;
638
639// rotate the lighting vector into the model's frame of reference
640 r_plightvec[0] = DotProduct (plighting->plightvec, alias_forward);
641 r_plightvec[1] = -DotProduct (plighting->plightvec, alias_right);
642 r_plightvec[2] = DotProduct (plighting->plightvec, alias_up);
643}
644
645/*
646=================
647R_AliasSetupFrame
648
649set r_apverts
650=================
651*/
652void R_AliasSetupFrame (void)
653{
654 int frame;
655 int i, numframes;
656 maliasgroup_t *paliasgroup;
657 float *pintervals, fullinterval, targettime, time;
658
659 frame = currententity->frame;
660 if ((frame >= pmdl->numframes) || (frame < 0))
661 {
662 Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
663 frame = 0;
664 }
665
666 if (paliashdr->frames[frame].type == ALIAS_SINGLE)
667 {
668 r_apverts = (trivertx_t *)
669 ((byte *)paliashdr + paliashdr->frames[frame].frame);
670 return;
671 }
672
673 paliasgroup = (maliasgroup_t *)
674 ((byte *)paliashdr + paliashdr->frames[frame].frame);
675 pintervals = (float *)((byte *)paliashdr + paliasgroup->intervals);
676 numframes = paliasgroup->numframes;
677 fullinterval = pintervals[numframes-1];
678
679 time = cl.time + currententity->syncbase;
680
681//
682// when loading in Mod_LoadAliasGroup, we guaranteed all interval values
683// are positive, so we don't have to worry about division by 0
684//
685 targettime = time - ((int)(time / fullinterval)) * fullinterval;
686
687 for (i=0 ; i<(numframes-1) ; i++)
688 {
689 if (pintervals[i] > targettime)
690 break;
691 }
692
693 r_apverts = (trivertx_t *)
694 ((byte *)paliashdr + paliasgroup->frames[i].frame);
695}
696
697
698/*
699================
700R_AliasDrawModel
701================
702*/
703void R_AliasDrawModel (alight_t *plighting)
704{
705 finalvert_t finalverts[MAXALIASVERTS +
706 ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1];
707 auxvert_t auxverts[MAXALIASVERTS];
708
709 r_amodels_drawn++;
710
711// cache align
712 pfinalverts = (finalvert_t *)
713 (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
714 pauxverts = &auxverts[0];
715
716 paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
717 pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model);
718
719 R_AliasSetupSkin ();
720 R_AliasSetUpTransform (currententity->trivial_accept);
721 R_AliasSetupLighting (plighting);
722 R_AliasSetupFrame ();
723
724 if (!currententity->colormap)
725 Sys_Error ("R_AliasDrawModel: !currententity->colormap");
726
727 r_affinetridesc.drawtype = (currententity->trivial_accept == 3) &&
728 r_recursiveaffinetriangles;
729
730 if (r_affinetridesc.drawtype)
731 {
732 D_PolysetUpdateTables (); // FIXME: precalc...
733 }
734 else
735 {
736#if id386
737 D_Aff8Patch (currententity->colormap);
738#endif
739 }
740
741 acolormap = currententity->colormap;
742
743 if (currententity != &cl.viewent)
744 ziscale = (float)0x8000 * (float)0x10000;
745 else
746 ziscale = (float)0x8000 * (float)0x10000 * 3.0;
747
748 if (currententity->trivial_accept)
749 R_AliasPrepareUnclippedPoints ();
750 else
751 R_AliasPreparePoints ();
752}
753
diff --git a/apps/plugins/sdl/progs/quake/r_bsp.c b/apps/plugins/sdl/progs/quake/r_bsp.c
new file mode 100644
index 0000000000..f8c38cf601
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_bsp.c
@@ -0,0 +1,675 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_bsp.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25//
26// current entity info
27//
28qboolean insubmodel;
29entity_t *currententity;
30vec3_t modelorg, base_modelorg;
31 // modelorg is the viewpoint reletive to
32 // the currently rendering entity
33vec3_t r_entorigin; // the currently rendering entity in world
34 // coordinates
35
36float entity_rotation[3][3];
37
38vec3_t r_worldmodelorg;
39
40int r_currentbkey;
41
42typedef int solidstate_t;
43enum {touchessolid, drawnode, nodrawnode};
44
45#define MAX_BMODEL_VERTS 500 // 6K
46#define MAX_BMODEL_EDGES 1000 // 12K
47
48static mvertex_t *pbverts;
49static bedge_t *pbedges;
50static int numbverts, numbedges;
51
52static mvertex_t *pfrontenter, *pfrontexit;
53
54static qboolean makeclippededge;
55
56
57//===========================================================================
58
59/*
60================
61R_EntityRotate
62================
63*/
64void R_EntityRotate (vec3_t vec)
65{
66 vec3_t tvec;
67
68 VectorCopy (vec, tvec);
69 vec[0] = DotProduct (entity_rotation[0], tvec);
70 vec[1] = DotProduct (entity_rotation[1], tvec);
71 vec[2] = DotProduct (entity_rotation[2], tvec);
72}
73
74
75/*
76================
77R_RotateBmodel
78================
79*/
80void R_RotateBmodel (void)
81{
82 float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3];
83
84// TODO: should use a look-up table
85// TODO: should really be stored with the entity instead of being reconstructed
86// TODO: could cache lazily, stored in the entity
87// TODO: share work with R_SetUpAliasTransform
88
89// yaw
90 angle = currententity->angles[YAW];
91 angle = angle * M_PI*2 / 360;
92 s = sin(angle);
93 c = cos(angle);
94
95 temp1[0][0] = c;
96 temp1[0][1] = s;
97 temp1[0][2] = 0;
98 temp1[1][0] = -s;
99 temp1[1][1] = c;
100 temp1[1][2] = 0;
101 temp1[2][0] = 0;
102 temp1[2][1] = 0;
103 temp1[2][2] = 1;
104
105
106// pitch
107 angle = currententity->angles[PITCH];
108 angle = angle * M_PI*2 / 360;
109 s = sin(angle);
110 c = cos(angle);
111
112 temp2[0][0] = c;
113 temp2[0][1] = 0;
114 temp2[0][2] = -s;
115 temp2[1][0] = 0;
116 temp2[1][1] = 1;
117 temp2[1][2] = 0;
118 temp2[2][0] = s;
119 temp2[2][1] = 0;
120 temp2[2][2] = c;
121
122 R_ConcatRotations (temp2, temp1, temp3);
123
124// roll
125 angle = currententity->angles[ROLL];
126 angle = angle * M_PI*2 / 360;
127 s = sin(angle);
128 c = cos(angle);
129
130 temp1[0][0] = 1;
131 temp1[0][1] = 0;
132 temp1[0][2] = 0;
133 temp1[1][0] = 0;
134 temp1[1][1] = c;
135 temp1[1][2] = s;
136 temp1[2][0] = 0;
137 temp1[2][1] = -s;
138 temp1[2][2] = c;
139
140 R_ConcatRotations (temp1, temp3, entity_rotation);
141
142//
143// rotate modelorg and the transformation matrix
144//
145 R_EntityRotate (modelorg);
146 R_EntityRotate (vpn);
147 R_EntityRotate (vright);
148 R_EntityRotate (vup);
149
150 R_TransformFrustum ();
151}
152
153
154/*
155================
156R_RecursiveClipBPoly
157================
158*/
159void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf)
160{
161 bedge_t *psideedges[2], *pnextedge, *ptedge;
162 int i, side, lastside;
163 float dist, frac, lastdist;
164 mplane_t *splitplane, tplane;
165 mvertex_t *pvert, *plastvert, *ptvert;
166 mnode_t *pn;
167
168 psideedges[0] = psideedges[1] = NULL;
169
170 makeclippededge = false;
171
172// transform the BSP plane into model space
173// FIXME: cache these?
174 splitplane = pnode->plane;
175 tplane.dist = splitplane->dist -
176 DotProduct(r_entorigin, splitplane->normal);
177 tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal);
178 tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal);
179 tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal);
180
181// clip edges to BSP plane
182 for ( ; pedges ; pedges = pnextedge)
183 {
184 pnextedge = pedges->pnext;
185
186 // set the status for the last point as the previous point
187 // FIXME: cache this stuff somehow?
188 plastvert = pedges->v[0];
189 lastdist = DotProduct (plastvert->position, tplane.normal) -
190 tplane.dist;
191
192 if (lastdist > 0)
193 lastside = 0;
194 else
195 lastside = 1;
196
197 pvert = pedges->v[1];
198
199 dist = DotProduct (pvert->position, tplane.normal) - tplane.dist;
200
201 if (dist > 0)
202 side = 0;
203 else
204 side = 1;
205
206 if (side != lastside)
207 {
208 // clipped
209 if (numbverts >= MAX_BMODEL_VERTS)
210 return;
211
212 // generate the clipped vertex
213 frac = lastdist / (lastdist - dist);
214 ptvert = &pbverts[numbverts++];
215 ptvert->position[0] = plastvert->position[0] +
216 frac * (pvert->position[0] -
217 plastvert->position[0]);
218 ptvert->position[1] = plastvert->position[1] +
219 frac * (pvert->position[1] -
220 plastvert->position[1]);
221 ptvert->position[2] = plastvert->position[2] +
222 frac * (pvert->position[2] -
223 plastvert->position[2]);
224
225 // split into two edges, one on each side, and remember entering
226 // and exiting points
227 // FIXME: share the clip edge by having a winding direction flag?
228 if (numbedges >= (MAX_BMODEL_EDGES - 1))
229 {
230 Con_Printf ("Out of edges for bmodel\n");
231 return;
232 }
233
234 ptedge = &pbedges[numbedges];
235 ptedge->pnext = psideedges[lastside];
236 psideedges[lastside] = ptedge;
237 ptedge->v[0] = plastvert;
238 ptedge->v[1] = ptvert;
239
240 ptedge = &pbedges[numbedges + 1];
241 ptedge->pnext = psideedges[side];
242 psideedges[side] = ptedge;
243 ptedge->v[0] = ptvert;
244 ptedge->v[1] = pvert;
245
246 numbedges += 2;
247
248 if (side == 0)
249 {
250 // entering for front, exiting for back
251 pfrontenter = ptvert;
252 makeclippededge = true;
253 }
254 else
255 {
256 pfrontexit = ptvert;
257 makeclippededge = true;
258 }
259 }
260 else
261 {
262 // add the edge to the appropriate side
263 pedges->pnext = psideedges[side];
264 psideedges[side] = pedges;
265 }
266 }
267
268// if anything was clipped, reconstitute and add the edges along the clip
269// plane to both sides (but in opposite directions)
270 if (makeclippededge)
271 {
272 if (numbedges >= (MAX_BMODEL_EDGES - 2))
273 {
274 Con_Printf ("Out of edges for bmodel\n");
275 return;
276 }
277
278 ptedge = &pbedges[numbedges];
279 ptedge->pnext = psideedges[0];
280 psideedges[0] = ptedge;
281 ptedge->v[0] = pfrontexit;
282 ptedge->v[1] = pfrontenter;
283
284 ptedge = &pbedges[numbedges + 1];
285 ptedge->pnext = psideedges[1];
286 psideedges[1] = ptedge;
287 ptedge->v[0] = pfrontenter;
288 ptedge->v[1] = pfrontexit;
289
290 numbedges += 2;
291 }
292
293// draw or recurse further
294 for (i=0 ; i<2 ; i++)
295 {
296 if (psideedges[i])
297 {
298 // draw if we've reached a non-solid leaf, done if all that's left is a
299 // solid leaf, and continue down the tree if it's not a leaf
300 pn = pnode->children[i];
301
302 // we're done with this branch if the node or leaf isn't in the PVS
303 if (pn->visframe == r_visframecount)
304 {
305 if (pn->contents < 0)
306 {
307 if (pn->contents != CONTENTS_SOLID)
308 {
309 r_currentbkey = ((mleaf_t *)pn)->key;
310 R_RenderBmodelFace (psideedges[i], psurf);
311 }
312 }
313 else
314 {
315 R_RecursiveClipBPoly (psideedges[i], pnode->children[i],
316 psurf);
317 }
318 }
319 }
320 }
321}
322
323
324/*
325================
326R_DrawSolidClippedSubmodelPolygons
327================
328*/
329void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel)
330{
331 int i, j, lindex;
332 vec_t dot;
333 msurface_t *psurf;
334 int numsurfaces;
335 mplane_t *pplane;
336 mvertex_t bverts[MAX_BMODEL_VERTS];
337 bedge_t bedges[MAX_BMODEL_EDGES], *pbedge;
338 medge_t *pedge, *pedges;
339
340// FIXME: use bounding-box-based frustum clipping info?
341
342 psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
343 numsurfaces = pmodel->nummodelsurfaces;
344 pedges = pmodel->edges;
345
346 for (i=0 ; i<numsurfaces ; i++, psurf++)
347 {
348 // find which side of the node we are on
349 pplane = psurf->plane;
350
351 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
352
353 // draw the polygon
354 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
355 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
356 {
357 // FIXME: use bounding-box-based frustum clipping info?
358
359 // copy the edges to bedges, flipping if necessary so always
360 // clockwise winding
361 // FIXME: if edges and vertices get caches, these assignments must move
362 // outside the loop, and overflow checking must be done here
363 pbverts = bverts;
364 pbedges = bedges;
365 numbverts = numbedges = 0;
366
367 if (psurf->numedges > 0)
368 {
369 pbedge = &bedges[numbedges];
370 numbedges += psurf->numedges;
371
372 for (j=0 ; j<psurf->numedges ; j++)
373 {
374 lindex = pmodel->surfedges[psurf->firstedge+j];
375
376 if (lindex > 0)
377 {
378 pedge = &pedges[lindex];
379 pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]];
380 pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]];
381 }
382 else
383 {
384 lindex = -lindex;
385 pedge = &pedges[lindex];
386 pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]];
387 pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]];
388 }
389
390 pbedge[j].pnext = &pbedge[j+1];
391 }
392
393 pbedge[j-1].pnext = NULL; // mark end of edges
394
395 R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf);
396 }
397 else
398 {
399 Sys_Error ("no edges in bmodel");
400 }
401 }
402 }
403}
404
405
406/*
407================
408R_DrawSubmodelPolygons
409================
410*/
411void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags)
412{
413 int i;
414 vec_t dot;
415 msurface_t *psurf;
416 int numsurfaces;
417 mplane_t *pplane;
418
419// FIXME: use bounding-box-based frustum clipping info?
420
421 psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
422 numsurfaces = pmodel->nummodelsurfaces;
423
424 for (i=0 ; i<numsurfaces ; i++, psurf++)
425 {
426 // find which side of the node we are on
427 pplane = psurf->plane;
428
429 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
430
431 // draw the polygon
432 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
433 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
434 {
435 r_currentkey = ((mleaf_t *)currententity->topnode)->key;
436
437 // FIXME: use bounding-box-based frustum clipping info?
438 R_RenderFace (psurf, clipflags);
439 }
440 }
441}
442
443
444/*
445================
446R_RecursiveWorldNode
447================
448*/
449void R_RecursiveWorldNode (mnode_t *node, int clipflags)
450{
451 int i, c, side, *pindex;
452 vec3_t acceptpt, rejectpt;
453 mplane_t *plane;
454 msurface_t *surf, **mark;
455 mleaf_t *pleaf;
456 double d, dot;
457
458 if (node->contents == CONTENTS_SOLID)
459 return; // solid
460
461 if (node->visframe != r_visframecount)
462 return;
463
464// cull the clipping planes if not trivial accept
465// FIXME: the compiler is doing a lousy job of optimizing here; it could be
466// twice as fast in ASM
467 if (clipflags)
468 {
469 for (i=0 ; i<4 ; i++)
470 {
471 if (! (clipflags & (1<<i)) )
472 continue; // don't need to clip against it
473
474 // generate accept and reject points
475 // FIXME: do with fast look-ups or integer tests based on the sign bit
476 // of the floating point values
477
478 pindex = pfrustum_indexes[i];
479
480 rejectpt[0] = (float)node->minmaxs[pindex[0]];
481 rejectpt[1] = (float)node->minmaxs[pindex[1]];
482 rejectpt[2] = (float)node->minmaxs[pindex[2]];
483
484 d = DotProduct (rejectpt, view_clipplanes[i].normal);
485 d -= view_clipplanes[i].dist;
486
487 if (d <= 0)
488 return;
489
490 acceptpt[0] = (float)node->minmaxs[pindex[3+0]];
491 acceptpt[1] = (float)node->minmaxs[pindex[3+1]];
492 acceptpt[2] = (float)node->minmaxs[pindex[3+2]];
493
494 d = DotProduct (acceptpt, view_clipplanes[i].normal);
495 d -= view_clipplanes[i].dist;
496
497 if (d >= 0)
498 clipflags &= ~(1<<i); // node is entirely on screen
499 }
500 }
501
502// if a leaf node, draw stuff
503 if (node->contents < 0)
504 {
505 pleaf = (mleaf_t *)node;
506
507 mark = pleaf->firstmarksurface;
508 c = pleaf->nummarksurfaces;
509
510 if (c)
511 {
512 do
513 {
514 (*mark)->visframe = r_framecount;
515 mark++;
516 } while (--c);
517 }
518
519 // deal with model fragments in this leaf
520 if (pleaf->efrags)
521 {
522 R_StoreEfrags (&pleaf->efrags);
523 }
524
525 pleaf->key = r_currentkey;
526 r_currentkey++; // all bmodels in a leaf share the same key
527 }
528 else
529 {
530 // node is just a decision point, so go down the apropriate sides
531
532 // find which side of the node we are on
533 plane = node->plane;
534
535 switch (plane->type)
536 {
537 case PLANE_X:
538 dot = modelorg[0] - plane->dist;
539 break;
540 case PLANE_Y:
541 dot = modelorg[1] - plane->dist;
542 break;
543 case PLANE_Z:
544 dot = modelorg[2] - plane->dist;
545 break;
546 default:
547 dot = DotProduct (modelorg, plane->normal) - plane->dist;
548 break;
549 }
550
551 if (dot >= 0)
552 side = 0;
553 else
554 side = 1;
555
556 // recurse down the children, front side first
557 R_RecursiveWorldNode (node->children[side], clipflags);
558
559 // draw stuff
560 c = node->numsurfaces;
561
562 if (c)
563 {
564 surf = cl.worldmodel->surfaces + node->firstsurface;
565
566 if (dot < -BACKFACE_EPSILON)
567 {
568 do
569 {
570 if ((surf->flags & SURF_PLANEBACK) &&
571 (surf->visframe == r_framecount))
572 {
573 if (r_drawpolys)
574 {
575 if (r_worldpolysbacktofront)
576 {
577 if (numbtofpolys < MAX_BTOFPOLYS)
578 {
579 pbtofpolys[numbtofpolys].clipflags =
580 clipflags;
581 pbtofpolys[numbtofpolys].psurf = surf;
582 numbtofpolys++;
583 }
584 }
585 else
586 {
587 R_RenderPoly (surf, clipflags);
588 }
589 }
590 else
591 {
592 R_RenderFace (surf, clipflags);
593 }
594 }
595
596 surf++;
597 } while (--c);
598 }
599 else if (dot > BACKFACE_EPSILON)
600 {
601 do
602 {
603 if (!(surf->flags & SURF_PLANEBACK) &&
604 (surf->visframe == r_framecount))
605 {
606 if (r_drawpolys)
607 {
608 if (r_worldpolysbacktofront)
609 {
610 if (numbtofpolys < MAX_BTOFPOLYS)
611 {
612 pbtofpolys[numbtofpolys].clipflags =
613 clipflags;
614 pbtofpolys[numbtofpolys].psurf = surf;
615 numbtofpolys++;
616 }
617 }
618 else
619 {
620 R_RenderPoly (surf, clipflags);
621 }
622 }
623 else
624 {
625 R_RenderFace (surf, clipflags);
626 }
627 }
628
629 surf++;
630 } while (--c);
631 }
632
633 // all surfaces on the same node share the same sequence number
634 r_currentkey++;
635 }
636
637 // recurse down the back side
638 R_RecursiveWorldNode (node->children[!side], clipflags);
639 }
640}
641
642
643
644/*
645================
646R_RenderWorld
647================
648*/
649void R_RenderWorld (void)
650{
651 int i;
652 model_t *clmodel;
653 btofpoly_t btofpolys[MAX_BTOFPOLYS];
654
655 pbtofpolys = btofpolys;
656
657 currententity = &cl_entities[0];
658 VectorCopy (r_origin, modelorg);
659 clmodel = currententity->model;
660 r_pcurrentvertbase = clmodel->vertexes;
661
662 R_RecursiveWorldNode (clmodel->nodes, 15);
663
664// if the driver wants the polygons back to front, play the visible ones back
665// in that order
666 if (r_worldpolysbacktofront)
667 {
668 for (i=numbtofpolys-1 ; i>=0 ; i--)
669 {
670 R_RenderPoly (btofpolys[i].psurf, btofpolys[i].clipflags);
671 }
672 }
673}
674
675
diff --git a/apps/plugins/sdl/progs/quake/r_draw.c b/apps/plugins/sdl/progs/quake/r_draw.c
new file mode 100644
index 0000000000..8789cc015a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_draw.c
@@ -0,0 +1,908 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// r_draw.c
22
23#include "quakedef.h"
24#include "r_local.h"
25#include "d_local.h" // FIXME: shouldn't need to include this
26
27#define MAXLEFTCLIPEDGES 100
28
29// !!! if these are changed, they must be changed in asm_draw.h too !!!
30#define FULLY_CLIPPED_CACHED 0x80000000
31#define FRAMECOUNT_MASK 0x7FFFFFFF
32
33unsigned int cacheoffset;
34
35int c_faceclip; // number of faces clipped
36
37zpointdesc_t r_zpointdesc;
38
39polydesc_t r_polydesc;
40
41
42
43clipplane_t *entity_clipplanes;
44clipplane_t view_clipplanes[4];
45clipplane_t world_clipplanes[16];
46
47medge_t *r_pedge;
48
49qboolean r_leftclipped, r_rightclipped;
50static qboolean makeleftedge, makerightedge;
51qboolean r_nearzionly;
52
53int sintable[SIN_BUFFER_SIZE];
54int intsintable[SIN_BUFFER_SIZE];
55
56mvertex_t r_leftenter, r_leftexit;
57mvertex_t r_rightenter, r_rightexit;
58
59typedef struct
60{
61 float u,v;
62 int ceilv;
63} evert_t;
64
65int r_emitted;
66float r_nearzi;
67float r_u1, r_v1, r_lzi1;
68int r_ceilv1;
69
70qboolean r_lastvertvalid;
71
72
73#if !id386
74
75/*
76================
77R_EmitEdge
78================
79*/
80void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
81{
82 edge_t *edge, *pcheck;
83 int u_check;
84 float u, u_step;
85 vec3_t local, transformed;
86 float *world;
87 int v, v2, ceilv0;
88 float scale, lzi0, u0, v0;
89 int side;
90
91 if (r_lastvertvalid)
92 {
93 u0 = r_u1;
94 v0 = r_v1;
95 lzi0 = r_lzi1;
96 ceilv0 = r_ceilv1;
97 }
98 else
99 {
100 world = &pv0->position[0];
101
102 // transform and project
103 VectorSubtract (world, modelorg, local);
104 TransformVector (local, transformed);
105
106 if (transformed[2] < NEAR_CLIP)
107 transformed[2] = NEAR_CLIP;
108
109 lzi0 = 1.0 / transformed[2];
110
111 // FIXME: build x/yscale into transform?
112 scale = xscale * lzi0;
113 u0 = (xcenter + scale*transformed[0]);
114 if (u0 < r_refdef.fvrectx_adj)
115 u0 = r_refdef.fvrectx_adj;
116 if (u0 > r_refdef.fvrectright_adj)
117 u0 = r_refdef.fvrectright_adj;
118
119 scale = yscale * lzi0;
120 v0 = (ycenter - scale*transformed[1]);
121 if (v0 < r_refdef.fvrecty_adj)
122 v0 = r_refdef.fvrecty_adj;
123 if (v0 > r_refdef.fvrectbottom_adj)
124 v0 = r_refdef.fvrectbottom_adj;
125
126 ceilv0 = (int) ceil(v0);
127 }
128
129 world = &pv1->position[0];
130
131// transform and project
132 VectorSubtract (world, modelorg, local);
133 TransformVector (local, transformed);
134
135 if (transformed[2] < NEAR_CLIP)
136 transformed[2] = NEAR_CLIP;
137
138 r_lzi1 = 1.0 / transformed[2];
139
140 scale = xscale * r_lzi1;
141 r_u1 = (xcenter + scale*transformed[0]);
142 if (r_u1 < r_refdef.fvrectx_adj)
143 r_u1 = r_refdef.fvrectx_adj;
144 if (r_u1 > r_refdef.fvrectright_adj)
145 r_u1 = r_refdef.fvrectright_adj;
146
147 scale = yscale * r_lzi1;
148 r_v1 = (ycenter - scale*transformed[1]);
149 if (r_v1 < r_refdef.fvrecty_adj)
150 r_v1 = r_refdef.fvrecty_adj;
151 if (r_v1 > r_refdef.fvrectbottom_adj)
152 r_v1 = r_refdef.fvrectbottom_adj;
153
154 if (r_lzi1 > lzi0)
155 lzi0 = r_lzi1;
156
157 if (lzi0 > r_nearzi) // for mipmap finding
158 r_nearzi = lzi0;
159
160// for right edges, all we want is the effect on 1/z
161 if (r_nearzionly)
162 return;
163
164 r_emitted = 1;
165
166 r_ceilv1 = (int) ceil(r_v1);
167
168
169// create the edge
170 if (ceilv0 == r_ceilv1)
171 {
172 // we cache unclipped horizontal edges as fully clipped
173 if (cacheoffset != 0x7FFFFFFF)
174 {
175 cacheoffset = FULLY_CLIPPED_CACHED |
176 (r_framecount & FRAMECOUNT_MASK);
177 }
178
179 return; // horizontal edge
180 }
181
182 side = ceilv0 > r_ceilv1;
183
184 edge = edge_p++;
185
186 edge->owner = r_pedge;
187
188 edge->nearzi = lzi0;
189
190 if (side == 0)
191 {
192 // trailing edge (go from p1 to p2)
193 v = ceilv0;
194 v2 = r_ceilv1 - 1;
195
196 edge->surfs[0] = surface_p - surfaces;
197 edge->surfs[1] = 0;
198
199 u_step = ((r_u1 - u0) / (r_v1 - v0));
200 u = u0 + ((float)v - v0) * u_step;
201 }
202 else
203 {
204 // leading edge (go from p2 to p1)
205 v2 = ceilv0 - 1;
206 v = r_ceilv1;
207
208 edge->surfs[0] = 0;
209 edge->surfs[1] = surface_p - surfaces;
210
211 u_step = ((u0 - r_u1) / (v0 - r_v1));
212 u = r_u1 + ((float)v - r_v1) * u_step;
213 }
214
215 edge->u_step = u_step*0x100000;
216 edge->u = u*0x100000 + 0xFFFFF;
217
218// we need to do this to avoid stepping off the edges if a very nearly
219// horizontal edge is less than epsilon above a scan, and numeric error causes
220// it to incorrectly extend to the scan, and the extension of the line goes off
221// the edge of the screen
222// FIXME: is this actually needed?
223 if (edge->u < r_refdef.vrect_x_adj_shift20)
224 edge->u = r_refdef.vrect_x_adj_shift20;
225 if (edge->u > r_refdef.vrectright_adj_shift20)
226 edge->u = r_refdef.vrectright_adj_shift20;
227
228//
229// sort the edge in normally
230//
231 u_check = edge->u;
232 if (edge->surfs[0])
233 u_check++; // sort trailers after leaders
234
235 if (!newedges[v] || newedges[v]->u >= u_check)
236 {
237 edge->next = newedges[v];
238 newedges[v] = edge;
239 }
240 else
241 {
242 pcheck = newedges[v];
243 while (pcheck->next && pcheck->next->u < u_check)
244 pcheck = pcheck->next;
245 edge->next = pcheck->next;
246 pcheck->next = edge;
247 }
248
249 edge->nextremove = removeedges[v2];
250 removeedges[v2] = edge;
251}
252
253
254/*
255================
256R_ClipEdge
257================
258*/
259static inline void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
260{
261 float d0, d1, f;
262 mvertex_t clipvert;
263
264 if (clip)
265 {
266 do
267 {
268 d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
269 d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
270
271 if (d0 >= 0)
272 {
273 // point 0 is unclipped
274 if (d1 >= 0)
275 {
276 // both points are unclipped
277 continue;
278 }
279
280 // only point 1 is clipped
281
282 // we don't cache clipped edges
283 cacheoffset = 0x7FFFFFFF;
284
285 f = d0 / (d0 - d1);
286 clipvert.position[0] = pv0->position[0] +
287 f * (pv1->position[0] - pv0->position[0]);
288 clipvert.position[1] = pv0->position[1] +
289 f * (pv1->position[1] - pv0->position[1]);
290 clipvert.position[2] = pv0->position[2] +
291 f * (pv1->position[2] - pv0->position[2]);
292
293 if (clip->leftedge)
294 {
295 r_leftclipped = true;
296 r_leftexit = clipvert;
297 }
298 else if (clip->rightedge)
299 {
300 r_rightclipped = true;
301 r_rightexit = clipvert;
302 }
303
304 R_ClipEdge (pv0, &clipvert, clip->next);
305 return;
306 }
307 else
308 {
309 // point 0 is clipped
310 if (d1 < 0)
311 {
312 // both points are clipped
313 // we do cache fully clipped edges
314 if (!r_leftclipped)
315 cacheoffset = FULLY_CLIPPED_CACHED |
316 (r_framecount & FRAMECOUNT_MASK);
317 return;
318 }
319
320 // only point 0 is clipped
321 r_lastvertvalid = false;
322
323 // we don't cache partially clipped edges
324 cacheoffset = 0x7FFFFFFF;
325
326 f = d0 / (d0 - d1);
327 clipvert.position[0] = pv0->position[0] +
328 f * (pv1->position[0] - pv0->position[0]);
329 clipvert.position[1] = pv0->position[1] +
330 f * (pv1->position[1] - pv0->position[1]);
331 clipvert.position[2] = pv0->position[2] +
332 f * (pv1->position[2] - pv0->position[2]);
333
334 if (clip->leftedge)
335 {
336 r_leftclipped = true;
337 r_leftenter = clipvert;
338 }
339 else if (clip->rightedge)
340 {
341 r_rightclipped = true;
342 r_rightenter = clipvert;
343 }
344
345 R_ClipEdge (&clipvert, pv1, clip->next);
346 return;
347 }
348 } while ((clip = clip->next) != NULL);
349 }
350
351// add the edge
352 R_EmitEdge (pv0, pv1);
353}
354
355#endif // !id386
356
357
358/*
359================
360R_EmitCachedEdge
361================
362*/
363void R_EmitCachedEdge (void)
364{
365 edge_t *pedge_t;
366
367 pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
368
369 if (!pedge_t->surfs[0])
370 pedge_t->surfs[0] = surface_p - surfaces;
371 else
372 pedge_t->surfs[1] = surface_p - surfaces;
373
374 if (pedge_t->nearzi > r_nearzi) // for mipmap finding
375 r_nearzi = pedge_t->nearzi;
376
377 r_emitted = 1;
378}
379
380
381/*
382================
383R_RenderFace
384================
385*/
386void R_RenderFace (msurface_t *fa, int clipflags)
387{
388 int i, lindex;
389 unsigned mask;
390 mplane_t *pplane;
391 float distinv;
392 vec3_t p_normal;
393 medge_t *pedges, tedge;
394 clipplane_t *pclip;
395
396// skip out if no more surfs
397 if ((surface_p) >= surf_max)
398 {
399 r_outofsurfaces++;
400 return;
401 }
402
403// ditto if not enough edges left, or switch to auxedges if possible
404 if ((edge_p + fa->numedges + 4) >= edge_max)
405 {
406 r_outofedges += fa->numedges;
407 return;
408 }
409
410 c_faceclip++;
411
412// set up clip planes
413 pclip = NULL;
414
415 for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
416 {
417 if (clipflags & mask)
418 {
419 view_clipplanes[i].next = pclip;
420 pclip = &view_clipplanes[i];
421 }
422 }
423
424// push the edges through
425 r_emitted = 0;
426 r_nearzi = 0;
427 r_nearzionly = false;
428 makeleftedge = makerightedge = false;
429 pedges = currententity->model->edges;
430 r_lastvertvalid = false;
431
432 for (i=0 ; i<fa->numedges ; i++)
433 {
434 lindex = currententity->model->surfedges[fa->firstedge + i];
435
436 if (lindex > 0)
437 {
438 r_pedge = &pedges[lindex];
439
440 // if the edge is cached, we can just reuse the edge
441 if (!insubmodel)
442 {
443 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
444 {
445 if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
446 r_framecount)
447 {
448 r_lastvertvalid = false;
449 continue;
450 }
451 }
452 else
453 {
454 if ((((unsigned long)edge_p - (unsigned long)r_edges) >
455 r_pedge->cachededgeoffset) &&
456 (((edge_t *)((unsigned long)r_edges +
457 r_pedge->cachededgeoffset))->owner == r_pedge))
458 {
459 R_EmitCachedEdge ();
460 r_lastvertvalid = false;
461 continue;
462 }
463 }
464 }
465
466 // assume it's cacheable
467 cacheoffset = (byte *)edge_p - (byte *)r_edges;
468 r_leftclipped = r_rightclipped = false;
469 R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
470 &r_pcurrentvertbase[r_pedge->v[1]],
471 pclip);
472 r_pedge->cachededgeoffset = cacheoffset;
473
474 if (r_leftclipped)
475 makeleftedge = true;
476 if (r_rightclipped)
477 makerightedge = true;
478 r_lastvertvalid = true;
479 }
480 else
481 {
482 lindex = -lindex;
483 r_pedge = &pedges[lindex];
484 // if the edge is cached, we can just reuse the edge
485 if (!insubmodel)
486 {
487 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
488 {
489 if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
490 r_framecount)
491 {
492 r_lastvertvalid = false;
493 continue;
494 }
495 }
496 else
497 {
498 // it's cached if the cached edge is valid and is owned
499 // by this medge_t
500 if ((((unsigned long)edge_p - (unsigned long)r_edges) >
501 r_pedge->cachededgeoffset) &&
502 (((edge_t *)((unsigned long)r_edges +
503 r_pedge->cachededgeoffset))->owner == r_pedge))
504 {
505 R_EmitCachedEdge ();
506 r_lastvertvalid = false;
507 continue;
508 }
509 }
510 }
511
512 // assume it's cacheable
513 cacheoffset = (byte *)edge_p - (byte *)r_edges;
514 r_leftclipped = r_rightclipped = false;
515 R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
516 &r_pcurrentvertbase[r_pedge->v[0]],
517 pclip);
518 r_pedge->cachededgeoffset = cacheoffset;
519
520 if (r_leftclipped)
521 makeleftedge = true;
522 if (r_rightclipped)
523 makerightedge = true;
524 r_lastvertvalid = true;
525 }
526 }
527
528// if there was a clip off the left edge, add that edge too
529// FIXME: faster to do in screen space?
530// FIXME: share clipped edges?
531 if (makeleftedge)
532 {
533 r_pedge = &tedge;
534 r_lastvertvalid = false;
535 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
536 }
537
538// if there was a clip off the right edge, get the right r_nearzi
539 if (makerightedge)
540 {
541 r_pedge = &tedge;
542 r_lastvertvalid = false;
543 r_nearzionly = true;
544 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
545 }
546
547// if no edges made it out, return without posting the surface
548 if (!r_emitted)
549 return;
550
551 r_polycount++;
552
553 surface_p->data = (void *)fa;
554 surface_p->nearzi = r_nearzi;
555 surface_p->flags = fa->flags;
556 surface_p->insubmodel = insubmodel;
557 surface_p->spanstate = 0;
558 surface_p->entity = currententity;
559 surface_p->key = r_currentkey++;
560 surface_p->spans = NULL;
561
562 pplane = fa->plane;
563// FIXME: cache this?
564 TransformVector (pplane->normal, p_normal);
565// FIXME: cache this?
566 distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
567
568 surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
569 surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
570 surface_p->d_ziorigin = p_normal[2] * distinv -
571 xcenter * surface_p->d_zistepu -
572 ycenter * surface_p->d_zistepv;
573
574//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg);
575 surface_p++;
576}
577
578
579/*
580================
581R_RenderBmodelFace
582================
583*/
584void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
585{
586 int i;
587 unsigned mask;
588 mplane_t *pplane;
589 float distinv;
590 vec3_t p_normal;
591 medge_t tedge;
592 clipplane_t *pclip;
593
594// skip out if no more surfs
595 if (surface_p >= surf_max)
596 {
597 r_outofsurfaces++;
598 return;
599 }
600
601// ditto if not enough edges left, or switch to auxedges if possible
602 if ((edge_p + psurf->numedges + 4) >= edge_max)
603 {
604 r_outofedges += psurf->numedges;
605 return;
606 }
607
608 c_faceclip++;
609
610// this is a dummy to give the caching mechanism someplace to write to
611 r_pedge = &tedge;
612
613// set up clip planes
614 pclip = NULL;
615
616 for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
617 {
618 if (r_clipflags & mask)
619 {
620 view_clipplanes[i].next = pclip;
621 pclip = &view_clipplanes[i];
622 }
623 }
624
625// push the edges through
626 r_emitted = 0;
627 r_nearzi = 0;
628 r_nearzionly = false;
629 makeleftedge = makerightedge = false;
630// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
631// can be used?
632 r_lastvertvalid = false;
633
634 for ( ; pedges ; pedges = pedges->pnext)
635 {
636 r_leftclipped = r_rightclipped = false;
637 R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
638
639 if (r_leftclipped)
640 makeleftedge = true;
641 if (r_rightclipped)
642 makerightedge = true;
643 }
644
645// if there was a clip off the left edge, add that edge too
646// FIXME: faster to do in screen space?
647// FIXME: share clipped edges?
648 if (makeleftedge)
649 {
650 r_pedge = &tedge;
651 R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
652 }
653
654// if there was a clip off the right edge, get the right r_nearzi
655 if (makerightedge)
656 {
657 r_pedge = &tedge;
658 r_nearzionly = true;
659 R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
660 }
661
662// if no edges made it out, return without posting the surface
663 if (!r_emitted)
664 return;
665
666 r_polycount++;
667
668 surface_p->data = (void *)psurf;
669 surface_p->nearzi = r_nearzi;
670 surface_p->flags = psurf->flags;
671 surface_p->insubmodel = true;
672 surface_p->spanstate = 0;
673 surface_p->entity = currententity;
674 surface_p->key = r_currentbkey;
675 surface_p->spans = NULL;
676
677 pplane = psurf->plane;
678// FIXME: cache this?
679 TransformVector (pplane->normal, p_normal);
680// FIXME: cache this?
681 distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
682
683 surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
684 surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
685 surface_p->d_ziorigin = p_normal[2] * distinv -
686 xcenter * surface_p->d_zistepu -
687 ycenter * surface_p->d_zistepv;
688
689//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg);
690 surface_p++;
691}
692
693
694/*
695================
696R_RenderPoly
697================
698*/
699void R_RenderPoly (msurface_t *fa, int clipflags)
700{
701 int i, lindex, lnumverts, s_axis, t_axis;
702 float dist, lastdist, lzi, scale, u, v, frac;
703 unsigned mask;
704 vec3_t local, transformed;
705 clipplane_t *pclip;
706 medge_t *pedges;
707 mplane_t *pplane;
708 mvertex_t verts[2][100]; //FIXME: do real number
709 polyvert_t pverts[100]; //FIXME: do real number, safely
710 int vertpage, newverts, newpage, lastvert;
711 qboolean visible;
712
713// FIXME: clean this up and make it faster
714// FIXME: guard against running out of vertices
715
716 s_axis = t_axis = 0; // keep compiler happy
717
718// set up clip planes
719 pclip = NULL;
720
721 for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
722 {
723 if (clipflags & mask)
724 {
725 view_clipplanes[i].next = pclip;
726 pclip = &view_clipplanes[i];
727 }
728 }
729
730// reconstruct the polygon
731// FIXME: these should be precalculated and loaded off disk
732 pedges = currententity->model->edges;
733 lnumverts = fa->numedges;
734 vertpage = 0;
735
736 for (i=0 ; i<lnumverts ; i++)
737 {
738 lindex = currententity->model->surfedges[fa->firstedge + i];
739
740 if (lindex > 0)
741 {
742 r_pedge = &pedges[lindex];
743 verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]];
744 }
745 else
746 {
747 r_pedge = &pedges[-lindex];
748 verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]];
749 }
750 }
751
752// clip the polygon, done if not visible
753 while (pclip)
754 {
755 lastvert = lnumverts - 1;
756 lastdist = DotProduct (verts[vertpage][lastvert].position,
757 pclip->normal) - pclip->dist;
758
759 visible = false;
760 newverts = 0;
761 newpage = vertpage ^ 1;
762
763 for (i=0 ; i<lnumverts ; i++)
764 {
765 dist = DotProduct (verts[vertpage][i].position, pclip->normal) -
766 pclip->dist;
767
768 if ((lastdist > 0) != (dist > 0))
769 {
770 frac = dist / (dist - lastdist);
771 verts[newpage][newverts].position[0] =
772 verts[vertpage][i].position[0] +
773 ((verts[vertpage][lastvert].position[0] -
774 verts[vertpage][i].position[0]) * frac);
775 verts[newpage][newverts].position[1] =
776 verts[vertpage][i].position[1] +
777 ((verts[vertpage][lastvert].position[1] -
778 verts[vertpage][i].position[1]) * frac);
779 verts[newpage][newverts].position[2] =
780 verts[vertpage][i].position[2] +
781 ((verts[vertpage][lastvert].position[2] -
782 verts[vertpage][i].position[2]) * frac);
783 newverts++;
784 }
785
786 if (dist >= 0)
787 {
788 verts[newpage][newverts] = verts[vertpage][i];
789 newverts++;
790 visible = true;
791 }
792
793 lastvert = i;
794 lastdist = dist;
795 }
796
797 if (!visible || (newverts < 3))
798 return;
799
800 lnumverts = newverts;
801 vertpage ^= 1;
802 pclip = pclip->next;
803 }
804
805// transform and project, remembering the z values at the vertices and
806// r_nearzi, and extract the s and t coordinates at the vertices
807 pplane = fa->plane;
808 switch (pplane->type)
809 {
810 case PLANE_X:
811 case PLANE_ANYX:
812 s_axis = 1;
813 t_axis = 2;
814 break;
815 case PLANE_Y:
816 case PLANE_ANYY:
817 s_axis = 0;
818 t_axis = 2;
819 break;
820 case PLANE_Z:
821 case PLANE_ANYZ:
822 s_axis = 0;
823 t_axis = 1;
824 break;
825 }
826
827 r_nearzi = 0;
828
829 for (i=0 ; i<lnumverts ; i++)
830 {
831 // transform and project
832 VectorSubtract (verts[vertpage][i].position, modelorg, local);
833 TransformVector (local, transformed);
834
835 if (transformed[2] < NEAR_CLIP)
836 transformed[2] = NEAR_CLIP;
837
838 lzi = 1.0 / transformed[2];
839
840 if (lzi > r_nearzi) // for mipmap finding
841 r_nearzi = lzi;
842
843 // FIXME: build x/yscale into transform?
844 scale = xscale * lzi;
845 u = (xcenter + scale*transformed[0]);
846 if (u < r_refdef.fvrectx_adj)
847 u = r_refdef.fvrectx_adj;
848 if (u > r_refdef.fvrectright_adj)
849 u = r_refdef.fvrectright_adj;
850
851 scale = yscale * lzi;
852 v = (ycenter - scale*transformed[1]);
853 if (v < r_refdef.fvrecty_adj)
854 v = r_refdef.fvrecty_adj;
855 if (v > r_refdef.fvrectbottom_adj)
856 v = r_refdef.fvrectbottom_adj;
857
858 pverts[i].u = u;
859 pverts[i].v = v;
860 pverts[i].zi = lzi;
861 pverts[i].s = verts[vertpage][i].position[s_axis];
862 pverts[i].t = verts[vertpage][i].position[t_axis];
863 }
864
865// build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z
866// for each vertex
867 r_polydesc.numverts = lnumverts;
868 r_polydesc.nearzi = r_nearzi;
869 r_polydesc.pcurrentface = fa;
870 r_polydesc.pverts = pverts;
871
872// draw the polygon
873 D_DrawPoly ();
874}
875
876
877/*
878================
879R_ZDrawSubmodelPolys
880================
881*/
882void R_ZDrawSubmodelPolys (model_t *pmodel)
883{
884 int i, numsurfaces;
885 msurface_t *psurf;
886 float dot;
887 mplane_t *pplane;
888
889 psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
890 numsurfaces = pmodel->nummodelsurfaces;
891
892 for (i=0 ; i<numsurfaces ; i++, psurf++)
893 {
894 // find which side of the node we are on
895 pplane = psurf->plane;
896
897 dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
898
899 // draw the polygon
900 if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
901 (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
902 {
903 // FIXME: use bounding-box-based frustum clipping info?
904 R_RenderPoly (psurf, 15);
905 }
906 }
907}
908
diff --git a/apps/plugins/sdl/progs/quake/r_edge.c b/apps/plugins/sdl/progs/quake/r_edge.c
new file mode 100644
index 0000000000..1fff765a3a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_edge.c
@@ -0,0 +1,775 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_edge.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25#if 0
26// FIXME
27the complex cases add new polys on most lines, so dont optimize for keeping them the same
28have multiple free span lists to try to get better coherence?
29low depth complexity -- 1 to 3 or so
30
31this breaks spans at every edge, even hidden ones (bad)
32
33have a sentinal at both ends?
34#endif
35
36
37edge_t *auxedges;
38edge_t *r_edges, *edge_p, *edge_max;
39
40surf_t *surfaces, *surface_p, *surf_max;
41
42// surfaces are generated in back to front order by the bsp, so if a surf
43// pointer is greater than another one, it should be drawn in front
44// surfaces[1] is the background, and is used as the active surface stack
45
46edge_t *newedges[MAXHEIGHT];
47edge_t *removeedges[MAXHEIGHT];
48
49espan_t *span_p, *max_span_p;
50
51int r_currentkey;
52
53extern int screenwidth;
54
55int current_iv;
56
57int edge_head_u_shift20, edge_tail_u_shift20;
58
59static void (*pdrawfunc)(void);
60
61edge_t edge_head;
62edge_t edge_tail;
63edge_t edge_aftertail;
64edge_t edge_sentinel;
65
66float fv;
67
68void R_GenerateSpans (void);
69void R_GenerateSpansBackward (void);
70
71// made static
72//void R_LeadingEdge (edge_t *edge);
73//void R_LeadingEdgeBackwards (edge_t *edge);
74//void R_TrailingEdge (surf_t *surf, edge_t *edge);
75
76
77//=============================================================================
78
79
80/*
81==============
82R_DrawCulledPolys
83==============
84*/
85static inline void R_DrawCulledPolys (void)
86{
87 surf_t *s;
88 msurface_t *pface;
89
90 currententity = &cl_entities[0];
91
92 if (r_worldpolysbacktofront)
93 {
94 for (s=surface_p-1 ; s>&surfaces[1] ; s--)
95 {
96 if (!s->spans)
97 continue;
98
99 if (!(s->flags & SURF_DRAWBACKGROUND))
100 {
101 pface = (msurface_t *)s->data;
102 R_RenderPoly (pface, 15);
103 }
104 }
105 }
106 else
107 {
108 for (s = &surfaces[1] ; s<surface_p ; s++)
109 {
110 if (!s->spans)
111 continue;
112
113 if (!(s->flags & SURF_DRAWBACKGROUND))
114 {
115 pface = (msurface_t *)s->data;
116 R_RenderPoly (pface, 15);
117 }
118 }
119 }
120}
121
122
123/*
124==============
125R_BeginEdgeFrame
126==============
127*/
128void R_BeginEdgeFrame (void)
129{
130 int v;
131
132 edge_p = r_edges;
133 edge_max = &r_edges[r_numallocatededges];
134
135 surface_p = &surfaces[2]; // background is surface 1,
136 // surface 0 is a dummy
137 surfaces[1].spans = NULL; // no background spans yet
138 surfaces[1].flags = SURF_DRAWBACKGROUND;
139
140// put the background behind everything in the world
141 if (r_draworder.value)
142 {
143 pdrawfunc = R_GenerateSpansBackward;
144 surfaces[1].key = 0;
145 r_currentkey = 1;
146 }
147 else
148 {
149 pdrawfunc = R_GenerateSpans;
150 surfaces[1].key = 0x7FFFFFFF;
151 r_currentkey = 0;
152 }
153
154// FIXME: set with memset
155 for (v=r_refdef.vrect.y ; v<r_refdef.vrectbottom ; v++)
156 {
157 newedges[v] = removeedges[v] = NULL;
158 }
159}
160
161
162#if !id386
163
164/*
165==============
166R_InsertNewEdges
167
168Adds the edges in the linked list edgestoadd, adding them to the edges in the
169linked list edgelist. edgestoadd is assumed to be sorted on u, and non-empty (this is actually newedges[v]). edgelist is assumed to be sorted on u, with a
170sentinel at the end (actually, this is the active edge table starting at
171edge_head.next).
172==============
173*/
174void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist)
175{
176 edge_t *next_edge;
177
178 do
179 {
180 next_edge = edgestoadd->next;
181edgesearch:
182 if (edgelist->u >= edgestoadd->u)
183 goto addedge;
184 edgelist=edgelist->next;
185 if (edgelist->u >= edgestoadd->u)
186 goto addedge;
187 edgelist=edgelist->next;
188 if (edgelist->u >= edgestoadd->u)
189 goto addedge;
190 edgelist=edgelist->next;
191 if (edgelist->u >= edgestoadd->u)
192 goto addedge;
193 edgelist=edgelist->next;
194 goto edgesearch;
195
196 // insert edgestoadd before edgelist
197addedge:
198 edgestoadd->next = edgelist;
199 edgestoadd->prev = edgelist->prev;
200 edgelist->prev->next = edgestoadd;
201 edgelist->prev = edgestoadd;
202 } while ((edgestoadd = next_edge) != NULL);
203}
204
205#endif // !id386
206
207
208#if !id386
209
210/*
211==============
212R_RemoveEdges
213==============
214*/
215void R_RemoveEdges (edge_t *pedge)
216{
217
218 do
219 {
220 pedge->next->prev = pedge->prev;
221 pedge->prev->next = pedge->next;
222 } while ((pedge = pedge->nextremove) != NULL);
223}
224
225#endif // !id386
226
227
228#if !id386
229
230/*
231==============
232R_StepActiveU
233==============
234*/
235void R_StepActiveU (edge_t *pedge)
236{
237 edge_t *pnext_edge, *pwedge;
238
239 while (1)
240 {
241nextedge:
242 pedge->u += pedge->u_step;
243 if (pedge->u < pedge->prev->u)
244 goto pushback;
245 pedge = pedge->next;
246
247 pedge->u += pedge->u_step;
248 if (pedge->u < pedge->prev->u)
249 goto pushback;
250 pedge = pedge->next;
251
252 pedge->u += pedge->u_step;
253 if (pedge->u < pedge->prev->u)
254 goto pushback;
255 pedge = pedge->next;
256
257 pedge->u += pedge->u_step;
258 if (pedge->u < pedge->prev->u)
259 goto pushback;
260 pedge = pedge->next;
261
262 goto nextedge;
263
264pushback:
265 if (pedge == &edge_aftertail)
266 return;
267
268 // push it back to keep it sorted
269 pnext_edge = pedge->next;
270
271 // pull the edge out of the edge list
272 pedge->next->prev = pedge->prev;
273 pedge->prev->next = pedge->next;
274
275 // find out where the edge goes in the edge list
276 pwedge = pedge->prev->prev;
277
278 while (pwedge->u > pedge->u)
279 {
280 pwedge = pwedge->prev;
281 }
282
283 // put the edge back into the edge list
284 pedge->next = pwedge->next;
285 pedge->prev = pwedge;
286 pedge->next->prev = pedge;
287 pwedge->next = pedge;
288
289 pedge = pnext_edge;
290 if (pedge == &edge_tail)
291 return;
292 }
293}
294
295#endif // !id386
296
297
298/*
299==============
300R_CleanupSpan
301==============
302*/
303void R_CleanupSpan ()
304{
305 surf_t *surf;
306 int iu;
307 espan_t *span;
308
309// now that we've reached the right edge of the screen, we're done with any
310// unfinished surfaces, so emit a span for whatever's on top
311 surf = surfaces[1].next;
312 iu = edge_tail_u_shift20;
313 if (iu > surf->last_u)
314 {
315 span = span_p++;
316 span->u = surf->last_u;
317 span->count = iu - span->u;
318 span->v = current_iv;
319 span->pnext = surf->spans;
320 surf->spans = span;
321 }
322
323// reset spanstate for all surfaces in the surface stack
324 do
325 {
326 surf->spanstate = 0;
327 surf = surf->next;
328 } while (surf != &surfaces[1]);
329}
330
331
332/*
333==============
334R_LeadingEdgeBackwards
335==============
336*/
337static inline void R_LeadingEdgeBackwards (edge_t *edge)
338{
339 espan_t *span;
340 surf_t *surf, *surf2;
341 int iu;
342
343// it's adding a new surface in, so find the correct place
344 surf = &surfaces[edge->surfs[1]];
345
346// don't start a span if this is an inverted span, with the end
347// edge preceding the start edge (that is, we've already seen the
348// end edge)
349 if (++surf->spanstate == 1)
350 {
351 surf2 = surfaces[1].next;
352
353 if (surf->key > surf2->key)
354 goto newtop;
355
356 // if it's two surfaces on the same plane, the one that's already
357 // active is in front, so keep going unless it's a bmodel
358 if (surf->insubmodel && (surf->key == surf2->key))
359 {
360 // must be two bmodels in the same leaf; don't care, because they'll
361 // never be farthest anyway
362 goto newtop;
363 }
364
365continue_search:
366
367 do
368 {
369 surf2 = surf2->next;
370 } while (surf->key < surf2->key);
371
372 if (surf->key == surf2->key)
373 {
374 // if it's two surfaces on the same plane, the one that's already
375 // active is in front, so keep going unless it's a bmodel
376 if (!surf->insubmodel)
377 goto continue_search;
378
379 // must be two bmodels in the same leaf; don't care which is really
380 // in front, because they'll never be farthest anyway
381 }
382
383 goto gotposition;
384
385newtop:
386 // emit a span (obscures current top)
387 iu = edge->u >> 20;
388
389 if (iu > surf2->last_u)
390 {
391 span = span_p++;
392 span->u = surf2->last_u;
393 span->count = iu - span->u;
394 span->v = current_iv;
395 span->pnext = surf2->spans;
396 surf2->spans = span;
397 }
398
399 // set last_u on the new span
400 surf->last_u = iu;
401
402gotposition:
403 // insert before surf2
404 surf->next = surf2;
405 surf->prev = surf2->prev;
406 surf2->prev->next = surf;
407 surf2->prev = surf;
408 }
409}
410
411
412/*
413==============
414R_TrailingEdge
415==============
416*/
417static inline void R_TrailingEdge (surf_t *surf, edge_t *edge)
418{
419 espan_t *span;
420 int iu;
421
422// don't generate a span if this is an inverted span, with the end
423// edge preceding the start edge (that is, we haven't seen the
424// start edge yet)
425 if (--surf->spanstate == 0)
426 {
427 if (surf->insubmodel)
428 r_bmodelactive--;
429
430 if (surf == surfaces[1].next)
431 {
432 // emit a span (current top going away)
433 iu = edge->u >> 20;
434 if (iu > surf->last_u)
435 {
436 span = span_p++;
437 span->u = surf->last_u;
438 span->count = iu - span->u;
439 span->v = current_iv;
440 span->pnext = surf->spans;
441 surf->spans = span;
442 }
443
444 // set last_u on the surface below
445 surf->next->last_u = iu;
446 }
447
448 surf->prev->next = surf->next;
449 surf->next->prev = surf->prev;
450 }
451}
452
453
454#if !id386
455
456/*
457==============
458R_LeadingEdge
459==============
460*/
461static inline void R_LeadingEdge (edge_t *edge)
462{
463 espan_t *span;
464 surf_t *surf, *surf2;
465 int iu;
466 double fu, newzi, testzi, newzitop, newzibottom;
467
468 if (edge->surfs[1])
469 {
470 // it's adding a new surface in, so find the correct place
471 surf = &surfaces[edge->surfs[1]];
472
473 // don't start a span if this is an inverted span, with the end
474 // edge preceding the start edge (that is, we've already seen the
475 // end edge)
476 if (++surf->spanstate == 1)
477 {
478 if (surf->insubmodel)
479 r_bmodelactive++;
480
481 surf2 = surfaces[1].next;
482
483 if (surf->key < surf2->key)
484 goto newtop;
485
486 // if it's two surfaces on the same plane, the one that's already
487 // active is in front, so keep going unless it's a bmodel
488 if (surf->insubmodel && (surf->key == surf2->key))
489 {
490 // must be two bmodels in the same leaf; sort on 1/z
491 fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
492 newzi = surf->d_ziorigin + fv*surf->d_zistepv +
493 fu*surf->d_zistepu;
494 newzibottom = newzi * 0.99;
495
496 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
497 fu*surf2->d_zistepu;
498
499 if (newzibottom >= testzi)
500 {
501 goto newtop;
502 }
503
504 newzitop = newzi * 1.01;
505 if (newzitop >= testzi)
506 {
507 if (surf->d_zistepu >= surf2->d_zistepu)
508 {
509 goto newtop;
510 }
511 }
512 }
513
514continue_search:
515
516 do
517 {
518 surf2 = surf2->next;
519 } while (surf->key > surf2->key);
520
521 if (surf->key == surf2->key)
522 {
523 // if it's two surfaces on the same plane, the one that's already
524 // active is in front, so keep going unless it's a bmodel
525 if (!surf->insubmodel)
526 goto continue_search;
527
528 // must be two bmodels in the same leaf; sort on 1/z
529 fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000);
530 newzi = surf->d_ziorigin + fv*surf->d_zistepv +
531 fu*surf->d_zistepu;
532 newzibottom = newzi * 0.99;
533
534 testzi = surf2->d_ziorigin + fv*surf2->d_zistepv +
535 fu*surf2->d_zistepu;
536
537 if (newzibottom >= testzi)
538 {
539 goto gotposition;
540 }
541
542 newzitop = newzi * 1.01;
543 if (newzitop >= testzi)
544 {
545 if (surf->d_zistepu >= surf2->d_zistepu)
546 {
547 goto gotposition;
548 }
549 }
550
551 goto continue_search;
552 }
553
554 goto gotposition;
555
556newtop:
557 // emit a span (obscures current top)
558 iu = edge->u >> 20;
559
560 if (iu > surf2->last_u)
561 {
562 span = span_p++;
563 span->u = surf2->last_u;
564 span->count = iu - span->u;
565 span->v = current_iv;
566 span->pnext = surf2->spans;
567 surf2->spans = span;
568 }
569
570 // set last_u on the new span
571 surf->last_u = iu;
572
573gotposition:
574 // insert before surf2
575 surf->next = surf2;
576 surf->prev = surf2->prev;
577 surf2->prev->next = surf;
578 surf2->prev = surf;
579 }
580 }
581}
582
583
584/*
585==============
586R_GenerateSpans
587==============
588*/
589void R_GenerateSpans (void)
590{
591 edge_t *edge;
592 surf_t *surf;
593
594 r_bmodelactive = 0;
595
596// clear active surfaces to just the background surface
597 surfaces[1].next = surfaces[1].prev = &surfaces[1];
598 surfaces[1].last_u = edge_head_u_shift20;
599
600// generate spans
601 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
602 {
603 if (edge->surfs[0])
604 {
605 // it has a left surface, so a surface is going away for this span
606 surf = &surfaces[edge->surfs[0]];
607
608 R_TrailingEdge (surf, edge);
609
610 if (!edge->surfs[1])
611 continue;
612 }
613
614 R_LeadingEdge (edge);
615 }
616
617 R_CleanupSpan ();
618}
619
620#endif // !id386
621
622
623/*
624==============
625R_GenerateSpansBackward
626==============
627*/
628void R_GenerateSpansBackward (void)
629{
630 edge_t *edge;
631
632 r_bmodelactive = 0;
633
634// clear active surfaces to just the background surface
635 surfaces[1].next = surfaces[1].prev = &surfaces[1];
636 surfaces[1].last_u = edge_head_u_shift20;
637
638// generate spans
639 for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next)
640 {
641 if (edge->surfs[0])
642 R_TrailingEdge (&surfaces[edge->surfs[0]], edge);
643
644 if (edge->surfs[1])
645 R_LeadingEdgeBackwards (edge);
646 }
647
648 R_CleanupSpan ();
649}
650
651
652/*
653==============
654R_ScanEdges
655
656Input:
657newedges[] array
658 this has links to edges, which have links to surfaces
659
660Output:
661Each surface has a linked list of its visible spans
662==============
663*/
664void R_ScanEdges (void)
665{
666 int iv, bottom;
667 byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE];
668 espan_t *basespan_p;
669 surf_t *s;
670
671 basespan_p = (espan_t *)
672 ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
673 max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width];
674
675 span_p = basespan_p;
676
677// clear active edges to just the background edges around the whole screen
678// FIXME: most of this only needs to be set up once
679 edge_head.u = r_refdef.vrect.x << 20;
680 edge_head_u_shift20 = edge_head.u >> 20;
681 edge_head.u_step = 0;
682 edge_head.prev = NULL;
683 edge_head.next = &edge_tail;
684 edge_head.surfs[0] = 0;
685 edge_head.surfs[1] = 1;
686
687 edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF;
688 edge_tail_u_shift20 = edge_tail.u >> 20;
689 edge_tail.u_step = 0;
690 edge_tail.prev = &edge_head;
691 edge_tail.next = &edge_aftertail;
692 edge_tail.surfs[0] = 1;
693 edge_tail.surfs[1] = 0;
694
695 edge_aftertail.u = -1; // force a move
696 edge_aftertail.u_step = 0;
697 edge_aftertail.next = &edge_sentinel;
698 edge_aftertail.prev = &edge_tail;
699
700// FIXME: do we need this now that we clamp x in r_draw.c?
701 edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this
702 edge_sentinel.prev = &edge_aftertail;
703
704//
705// process all scan lines
706//
707 bottom = r_refdef.vrectbottom - 1;
708
709 for (iv=r_refdef.vrect.y ; iv<bottom ; iv++)
710 {
711 current_iv = iv;
712 fv = (float)iv;
713
714 // mark that the head (background start) span is pre-included
715 surfaces[1].spanstate = 1;
716
717 if (newedges[iv])
718 {
719 R_InsertNewEdges (newedges[iv], edge_head.next);
720 }
721
722 (*pdrawfunc) ();
723
724 // flush the span list if we can't be sure we have enough spans left for
725 // the next scan
726 if (span_p >= max_span_p)
727 {
728 VID_UnlockBuffer ();
729 S_ExtraUpdate (); // don't let sound get messed up if going slow
730 VID_LockBuffer ();
731
732 if (r_drawculledpolys)
733 {
734 R_DrawCulledPolys ();
735 }
736 else
737 {
738 D_DrawSurfaces ();
739 }
740
741 // clear the surface span pointers
742 for (s = &surfaces[1] ; s<surface_p ; s++)
743 s->spans = NULL;
744
745 span_p = basespan_p;
746 }
747
748 if (removeedges[iv])
749 R_RemoveEdges (removeedges[iv]);
750
751 if (edge_head.next != &edge_tail)
752 R_StepActiveU (edge_head.next);
753 }
754
755// do the last scan (no need to step or sort or remove on the last scan)
756
757 current_iv = iv;
758 fv = (float)iv;
759
760// mark that the head (background start) span is pre-included
761 surfaces[1].spanstate = 1;
762
763 if (newedges[iv])
764 R_InsertNewEdges (newedges[iv], edge_head.next);
765
766 (*pdrawfunc) ();
767
768// draw whatever's left in the span list
769 if (r_drawculledpolys)
770 R_DrawCulledPolys ();
771 else
772 D_DrawSurfaces ();
773}
774
775
diff --git a/apps/plugins/sdl/progs/quake/r_efrag.c b/apps/plugins/sdl/progs/quake/r_efrag.c
new file mode 100644
index 0000000000..5e4d3f9e06
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_efrag.c
@@ -0,0 +1,276 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_efrag.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25mnode_t *r_pefragtopnode;
26
27
28//===========================================================================
29
30/*
31===============================================================================
32
33 ENTITY FRAGMENT FUNCTIONS
34
35===============================================================================
36*/
37
38efrag_t **lastlink;
39
40vec3_t r_emins, r_emaxs;
41
42entity_t *r_addent;
43
44
45/*
46================
47R_RemoveEfrags
48
49Call when removing an object from the world or moving it to another position
50================
51*/
52void R_RemoveEfrags (entity_t *ent)
53{
54 efrag_t *ef, *old, *walk, **prev;
55
56 ef = ent->efrag;
57
58 while (ef)
59 {
60 prev = &ef->leaf->efrags;
61 while (1)
62 {
63 walk = *prev;
64 if (!walk)
65 break;
66 if (walk == ef)
67 { // remove this fragment
68 *prev = ef->leafnext;
69 break;
70 }
71 else
72 prev = &walk->leafnext;
73 }
74
75 old = ef;
76 ef = ef->entnext;
77
78 // put it on the free list
79 old->entnext = cl.free_efrags;
80 cl.free_efrags = old;
81 }
82
83 ent->efrag = NULL;
84}
85
86/*
87===================
88R_SplitEntityOnNode
89===================
90*/
91void R_SplitEntityOnNode (mnode_t *node)
92{
93 efrag_t *ef;
94 mplane_t *splitplane;
95 mleaf_t *leaf;
96 int sides;
97
98 if (node->contents == CONTENTS_SOLID)
99 {
100 return;
101 }
102
103// add an efrag if the node is a leaf
104
105 if ( node->contents < 0)
106 {
107 if (!r_pefragtopnode)
108 r_pefragtopnode = node;
109
110 leaf = (mleaf_t *)node;
111
112// grab an efrag off the free list
113 ef = cl.free_efrags;
114 if (!ef)
115 {
116 Con_Printf ("Too many efrags!\n");
117 return; // no free fragments...
118 }
119 cl.free_efrags = cl.free_efrags->entnext;
120
121 ef->entity = r_addent;
122
123// add the entity link
124 *lastlink = ef;
125 lastlink = &ef->entnext;
126 ef->entnext = NULL;
127
128// set the leaf links
129 ef->leaf = leaf;
130 ef->leafnext = leaf->efrags;
131 leaf->efrags = ef;
132
133 return;
134 }
135
136// NODE_MIXED
137
138 splitplane = node->plane;
139 sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
140
141 if (sides == 3)
142 {
143 // split on this plane
144 // if this is the first splitter of this bmodel, remember it
145 if (!r_pefragtopnode)
146 r_pefragtopnode = node;
147 }
148
149// recurse down the contacted sides
150 if (sides & 1)
151 R_SplitEntityOnNode (node->children[0]);
152
153 if (sides & 2)
154 R_SplitEntityOnNode (node->children[1]);
155}
156
157
158/*
159===================
160R_SplitEntityOnNode2
161===================
162*/
163void R_SplitEntityOnNode2 (mnode_t *node)
164{
165 mplane_t *splitplane;
166 int sides;
167
168 if (node->visframe != r_visframecount)
169 return;
170
171 if (node->contents < 0)
172 {
173 if (node->contents != CONTENTS_SOLID)
174 r_pefragtopnode = node; // we've reached a non-solid leaf, so it's
175 // visible and not BSP clipped
176 return;
177 }
178
179 splitplane = node->plane;
180 sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);
181
182 if (sides == 3)
183 {
184 // remember first splitter
185 r_pefragtopnode = node;
186 return;
187 }
188
189// not split yet; recurse down the contacted side
190 if (sides & 1)
191 R_SplitEntityOnNode2 (node->children[0]);
192 else
193 R_SplitEntityOnNode2 (node->children[1]);
194}
195
196
197/*
198===========
199R_AddEfrags
200===========
201*/
202void R_AddEfrags (entity_t *ent)
203{
204 model_t *entmodel;
205 int i;
206
207 if (!ent->model)
208 return;
209
210 if (ent == cl_entities)
211 return; // never add the world
212
213 r_addent = ent;
214
215 lastlink = &ent->efrag;
216 r_pefragtopnode = NULL;
217
218 entmodel = ent->model;
219
220 for (i=0 ; i<3 ; i++)
221 {
222 r_emins[i] = ent->origin[i] + entmodel->mins[i];
223 r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
224 }
225
226 R_SplitEntityOnNode (cl.worldmodel->nodes);
227
228 ent->topnode = r_pefragtopnode;
229}
230
231
232/*
233================
234R_StoreEfrags
235
236// FIXME: a lot of this goes away with edge-based
237================
238*/
239void R_StoreEfrags (efrag_t **ppefrag)
240{
241 entity_t *pent;
242 model_t *clmodel;
243 efrag_t *pefrag;
244
245
246 while ((pefrag = *ppefrag) != NULL)
247 {
248 pent = pefrag->entity;
249 clmodel = pent->model;
250
251 switch (clmodel->type)
252 {
253 case mod_alias:
254 case mod_brush:
255 case mod_sprite:
256 pent = pefrag->entity;
257
258 if ((pent->visframe != r_framecount) &&
259 (cl_numvisedicts < MAX_VISEDICTS))
260 {
261 cl_visedicts[cl_numvisedicts++] = pent;
262
263 // mark that we've recorded this entity for this frame
264 pent->visframe = r_framecount;
265 }
266
267 ppefrag = &pefrag->leafnext;
268 break;
269
270 default:
271 Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
272 }
273 }
274}
275
276
diff --git a/apps/plugins/sdl/progs/quake/r_light.c b/apps/plugins/sdl/progs/quake/r_light.c
new file mode 100644
index 0000000000..f735d50d84
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_light.c
@@ -0,0 +1,260 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_light.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25int r_dlightframecount;
26
27
28/*
29==================
30R_AnimateLight
31==================
32*/
33void R_AnimateLight (void)
34{
35 int i,j,k;
36
37//
38// light animations
39// 'm' is normal light, 'a' is no light, 'z' is double bright
40 i = (int)(cl.time*10);
41 for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
42 {
43 if (!cl_lightstyle[j].length)
44 {
45 d_lightstylevalue[j] = 256;
46 continue;
47 }
48 k = i % cl_lightstyle[j].length;
49 k = cl_lightstyle[j].map[k] - 'a';
50 k = k*22;
51 d_lightstylevalue[j] = k;
52 }
53}
54
55
56/*
57=============================================================================
58
59DYNAMIC LIGHTS
60
61=============================================================================
62*/
63
64/*
65=============
66R_MarkLights
67=============
68*/
69void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
70{
71 mplane_t *splitplane;
72 float dist;
73 msurface_t *surf;
74 int i;
75
76 if (node->contents < 0)
77 return;
78
79 splitplane = node->plane;
80 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
81
82 if (dist > light->radius)
83 {
84 R_MarkLights (light, bit, node->children[0]);
85 return;
86 }
87 if (dist < -light->radius)
88 {
89 R_MarkLights (light, bit, node->children[1]);
90 return;
91 }
92
93// mark the polygons
94 surf = cl.worldmodel->surfaces + node->firstsurface;
95 for (i=0 ; i<node->numsurfaces ; i++, surf++)
96 {
97 if (surf->dlightframe != r_dlightframecount)
98 {
99 surf->dlightbits = 0;
100 surf->dlightframe = r_dlightframecount;
101 }
102 surf->dlightbits |= bit;
103 }
104
105 R_MarkLights (light, bit, node->children[0]);
106 R_MarkLights (light, bit, node->children[1]);
107}
108
109
110/*
111=============
112R_PushDlights
113=============
114*/
115void R_PushDlights (void)
116{
117 int i;
118 dlight_t *l;
119
120 r_dlightframecount = r_framecount + 1; // because the count hasn't
121 // advanced yet for this frame
122 l = cl_dlights;
123
124 for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
125 {
126 if (l->die < cl.time || !l->radius)
127 continue;
128 R_MarkLights ( l, 1<<i, cl.worldmodel->nodes );
129 }
130}
131
132
133/*
134=============================================================================
135
136LIGHT SAMPLING
137
138=============================================================================
139*/
140
141int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
142{
143 int r;
144 float front, back, frac;
145 int side;
146 mplane_t *plane;
147 vec3_t mid;
148 msurface_t *surf;
149 int s, t, ds, dt;
150 int i;
151 mtexinfo_t *tex;
152 byte *lightmap;
153 unsigned scale;
154 int maps;
155
156 if (node->contents < 0)
157 return -1; // didn't hit anything
158
159// calculate mid point
160
161// FIXME: optimize for axial
162 plane = node->plane;
163 front = DotProduct (start, plane->normal) - plane->dist;
164 back = DotProduct (end, plane->normal) - plane->dist;
165 side = front < 0;
166
167 if ( (back < 0) == side)
168 return RecursiveLightPoint (node->children[side], start, end);
169
170 frac = front / (front-back);
171 mid[0] = start[0] + (end[0] - start[0])*frac;
172 mid[1] = start[1] + (end[1] - start[1])*frac;
173 mid[2] = start[2] + (end[2] - start[2])*frac;
174
175// go down front side
176 r = RecursiveLightPoint (node->children[side], start, mid);
177 if (r >= 0)
178 return r; // hit something
179
180 if ( (back < 0) == side )
181 return -1; // didn't hit anuthing
182
183// check for impact on this node
184
185 surf = cl.worldmodel->surfaces + node->firstsurface;
186 for (i=0 ; i<node->numsurfaces ; i++, surf++)
187 {
188 if (surf->flags & SURF_DRAWTILED)
189 continue; // no lightmaps
190
191 tex = surf->texinfo;
192
193 s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
194 t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
195
196 if (s < surf->texturemins[0] ||
197 t < surf->texturemins[1])
198 continue;
199
200 ds = s - surf->texturemins[0];
201 dt = t - surf->texturemins[1];
202
203 if ( ds > surf->extents[0] || dt > surf->extents[1] )
204 continue;
205
206 if (!surf->samples)
207 return 0;
208
209 ds >>= 4;
210 dt >>= 4;
211
212 lightmap = surf->samples;
213 r = 0;
214 if (lightmap)
215 {
216
217 lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
218
219 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
220 maps++)
221 {
222 scale = d_lightstylevalue[surf->styles[maps]];
223 r += *lightmap * scale;
224 lightmap += ((surf->extents[0]>>4)+1) *
225 ((surf->extents[1]>>4)+1);
226 }
227
228 r >>= 8;
229 }
230
231 return r;
232 }
233
234// go down back side
235 return RecursiveLightPoint (node->children[!side], mid, end);
236}
237
238int R_LightPoint (vec3_t p)
239{
240 vec3_t end;
241 int r;
242
243 if (!cl.worldmodel->lightdata)
244 return 255;
245
246 end[0] = p[0];
247 end[1] = p[1];
248 end[2] = p[2] - 2048;
249
250 r = RecursiveLightPoint (cl.worldmodel->nodes, p, end);
251
252 if (r == -1)
253 r = 0;
254
255 if (r < r_refdef.ambientlight)
256 r = r_refdef.ambientlight;
257
258 return r;
259}
260
diff --git a/apps/plugins/sdl/progs/quake/r_local.h b/apps/plugins/sdl/progs/quake/r_local.h
new file mode 100644
index 0000000000..910bdbffc9
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_local.h
@@ -0,0 +1,316 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_local.h -- private refresh defs
21
22#ifndef GLQUAKE
23#include "r_shared.h"
24
25#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0)
26 // normalizing factor so player model works out to about
27 // 1 pixel per triangle
28
29#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox ()
30 // if bbox is trivially rejected
31
32//===========================================================================
33// viewmodel lighting
34
35typedef struct {
36 int ambientlight;
37 int shadelight;
38 float *plightvec;
39} alight_t;
40
41//===========================================================================
42// clipped bmodel edges
43
44typedef struct bedge_s
45{
46 mvertex_t *v[2];
47 struct bedge_s *pnext;
48} bedge_t;
49
50typedef struct {
51 float fv[3]; // viewspace x, y
52} auxvert_t;
53
54//===========================================================================
55
56extern cvar_t r_draworder;
57extern cvar_t r_speeds;
58extern cvar_t r_timegraph;
59extern cvar_t r_graphheight;
60extern cvar_t r_clearcolor;
61extern cvar_t r_waterwarp;
62extern cvar_t r_fullbright;
63extern cvar_t r_drawentities;
64extern cvar_t r_aliasstats;
65extern cvar_t r_dspeeds;
66extern cvar_t r_drawflat;
67extern cvar_t r_ambient;
68extern cvar_t r_reportsurfout;
69extern cvar_t r_maxsurfs;
70extern cvar_t r_numsurfs;
71extern cvar_t r_reportedgeout;
72extern cvar_t r_maxedges;
73extern cvar_t r_numedges;
74
75#define XCENTERING (1.0 / 2.0)
76#define YCENTERING (1.0 / 2.0)
77
78#define CLIP_EPSILON 0.001
79
80#define BACKFACE_EPSILON 0.01
81
82//===========================================================================
83
84#define DIST_NOT_SET 98765
85
86// !!! if this is changed, it must be changed in asm_draw.h too !!!
87typedef struct clipplane_s
88{
89 vec3_t normal;
90 float dist;
91 struct clipplane_s *next;
92 byte leftedge;
93 byte rightedge;
94 byte reserved[2];
95} clipplane_t;
96
97extern clipplane_t view_clipplanes[4];
98
99//=============================================================================
100
101void R_RenderWorld (void);
102
103//=============================================================================
104
105extern mplane_t screenedge[4];
106
107extern vec3_t r_origin;
108
109extern vec3_t r_entorigin;
110
111extern float screenAspect;
112extern float verticalFieldOfView;
113extern float xOrigin, yOrigin;
114
115extern int r_visframecount;
116
117//=============================================================================
118
119extern int vstartscan;
120
121
122void R_ClearPolyList (void);
123void R_DrawPolyList (void);
124
125//
126// current entity info
127//
128extern qboolean insubmodel;
129extern vec3_t r_worldmodelorg;
130
131
132void R_DrawSprite (void);
133void R_RenderFace (msurface_t *fa, int clipflags);
134void R_RenderPoly (msurface_t *fa, int clipflags);
135void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);
136void R_TransformPlane (mplane_t *p, float *normal, float *dist);
137void R_TransformFrustum (void);
138void R_SetSkyFrame (void);
139void R_DrawSurfaceBlock16 (void);
140void R_DrawSurfaceBlock8 (void);
141texture_t *R_TextureAnimation (texture_t *base);
142
143#if id386
144
145void R_DrawSurfaceBlock8_mip0 (void);
146void R_DrawSurfaceBlock8_mip1 (void);
147void R_DrawSurfaceBlock8_mip2 (void);
148void R_DrawSurfaceBlock8_mip3 (void);
149
150#endif
151
152void R_GenSkyTile (void *pdest);
153void R_GenSkyTile16 (void *pdest);
154void R_Surf8Patch (void);
155void R_Surf16Patch (void);
156void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags);
157void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel);
158
159void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);
160surf_t *R_GetSurf (void);
161void R_AliasDrawModel (alight_t *plighting);
162void R_BeginEdgeFrame (void);
163void R_ScanEdges (void);
164void D_DrawSurfaces (void);
165void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);
166void R_StepActiveU (edge_t *pedge);
167void R_RemoveEdges (edge_t *pedge);
168
169extern void R_Surf8Start (void);
170extern void R_Surf8End (void);
171extern void R_Surf16Start (void);
172extern void R_Surf16End (void);
173extern void R_EdgeCodeStart (void);
174extern void R_EdgeCodeEnd (void);
175
176extern void R_RotateBmodel (void);
177
178extern int c_faceclip;
179extern int r_polycount;
180extern int r_wholepolycount;
181
182extern model_t *cl_worldmodel;
183
184extern int *pfrustum_indexes[4];
185
186// !!! if this is changed, it must be changed in asm_draw.h too !!!
187#define NEAR_CLIP 0.01
188
189extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
190extern int vstartscan;
191
192extern fixed16_t sadjust, tadjust;
193extern fixed16_t bbextents, bbextentt;
194
195#define MAXBVERTINDEXES 1000 // new clipped vertices when clipping bmodels
196 // to the world BSP
197extern mvertex_t *r_ptverts, *r_ptvertsmax;
198
199extern vec3_t sbaseaxis[3], tbaseaxis[3];
200extern float entity_rotation[3][3];
201
202extern int reinit_surfcache;
203
204extern int r_currentkey;
205extern int r_currentbkey;
206
207typedef struct btofpoly_s {
208 int clipflags;
209 msurface_t *psurf;
210} btofpoly_t;
211
212#define MAX_BTOFPOLYS 5000 // FIXME: tune this
213
214extern int numbtofpolys;
215extern btofpoly_t *pbtofpolys;
216
217void R_InitTurb (void);
218void R_ZDrawSubmodelPolys (model_t *clmodel);
219
220//=========================================================
221// Alias models
222//=========================================================
223
224#define MAXALIASVERTS 2000 // TODO: tune this
225#define ALIAS_Z_CLIP_PLANE 5
226
227extern int numverts;
228extern int a_skinwidth;
229extern mtriangle_t *ptriangles;
230extern int numtriangles;
231extern aliashdr_t *paliashdr;
232extern mdl_t *pmdl;
233extern float leftclip, topclip, rightclip, bottomclip;
234extern int r_acliptype;
235extern finalvert_t *pfinalverts;
236extern auxvert_t *pauxverts;
237
238qboolean R_AliasCheckBBox (void);
239
240//=========================================================
241// turbulence stuff
242
243#define AMP 8*0x10000
244#define AMP2 3
245#define SPEED 20
246
247//=========================================================
248// particle stuff
249
250void R_DrawParticles (void);
251void R_InitParticles (void);
252void R_ClearParticles (void);
253void R_ReadPointFile_f (void);
254void R_SurfacePatch (void);
255
256extern int r_amodels_drawn;
257extern edge_t *auxedges;
258extern int r_numallocatededges;
259extern edge_t *r_edges, *edge_p, *edge_max;
260
261extern edge_t *newedges[MAXHEIGHT];
262extern edge_t *removeedges[MAXHEIGHT];
263
264extern int screenwidth;
265
266// FIXME: make stack vars when debugging done
267extern edge_t edge_head;
268extern edge_t edge_tail;
269extern edge_t edge_aftertail;
270extern int r_bmodelactive;
271extern vrect_t *pconupdate;
272
273extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
274extern float r_aliastransition, r_resfudge;
275
276extern int r_outofsurfaces;
277extern int r_outofedges;
278
279extern mvertex_t *r_pcurrentvertbase;
280extern int r_maxvalidedgeoffset;
281
282void R_AliasClipTriangle (mtriangle_t *ptri);
283
284extern float r_time1;
285extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
286extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
287extern int r_frustum_indexes[4*6];
288extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
289extern qboolean r_surfsonstack;
290extern cshift_t cshift_water;
291extern qboolean r_dowarpold, r_viewchanged;
292
293extern mleaf_t *r_viewleaf, *r_oldviewleaf;
294
295extern vec3_t r_emins, r_emaxs;
296extern mnode_t *r_pefragtopnode;
297extern int r_clipflags;
298extern int r_dlightframecount;
299extern qboolean r_fov_greater_than_90;
300
301void R_StoreEfrags (efrag_t **ppefrag);
302void R_TimeRefresh_f (void);
303void R_TimeGraph (void);
304void R_PrintAliasStats (void);
305void R_PrintTimes (void);
306void R_PrintDSpeeds (void);
307void R_AnimateLight (void);
308int R_LightPoint (vec3_t p);
309void R_SetupFrame (void);
310void R_cshift_f (void);
311void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);
312//void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);
313void R_SplitEntityOnNode2 (mnode_t *node);
314void R_MarkLights (dlight_t *light, int bit, mnode_t *node);
315
316#endif \ No newline at end of file
diff --git a/apps/plugins/sdl/progs/quake/r_main.c b/apps/plugins/sdl/progs/quake/r_main.c
new file mode 100644
index 0000000000..dc785a850d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_main.c
@@ -0,0 +1,1089 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_main.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25//define PASSAGES
26
27void *colormap;
28vec3_t viewlightvec;
29alight_t r_viewlighting = {128, 192, viewlightvec};
30float r_time1;
31int r_numallocatededges;
32qboolean r_drawpolys;
33qboolean r_drawculledpolys;
34qboolean r_worldpolysbacktofront;
35qboolean r_recursiveaffinetriangles = true;
36int r_pixbytes = 1;
37float r_aliasuvscale = 1.0;
38int r_outofsurfaces;
39int r_outofedges;
40
41qboolean r_dowarp, r_dowarpold, r_viewchanged;
42
43int numbtofpolys;
44btofpoly_t *pbtofpolys;
45mvertex_t *r_pcurrentvertbase;
46
47int c_surf;
48int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
49qboolean r_surfsonstack;
50int r_clipflags;
51
52byte *r_warpbuffer;
53
54byte *r_stack_start;
55
56qboolean r_fov_greater_than_90;
57
58//
59// view origin
60//
61vec3_t vup, base_vup;
62vec3_t vpn, base_vpn;
63vec3_t vright, base_vright;
64vec3_t r_origin;
65
66//
67// screen size info
68//
69refdef_t r_refdef;
70float xcenter, ycenter;
71float xscale, yscale;
72float xscaleinv, yscaleinv;
73float xscaleshrink, yscaleshrink;
74float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
75
76int screenwidth;
77
78float pixelAspect;
79float screenAspect;
80float verticalFieldOfView;
81float xOrigin, yOrigin;
82
83mplane_t screenedge[4];
84
85//
86// refresh flags
87//
88int r_framecount = 1; // so frame counts initialized to 0 don't match
89int r_visframecount;
90int d_spanpixcount;
91int r_polycount;
92int r_drawnpolycount;
93int r_wholepolycount;
94
95#define VIEWMODNAME_LENGTH 256
96char viewmodname[VIEWMODNAME_LENGTH+1];
97int modcount;
98
99int *pfrustum_indexes[4];
100int r_frustum_indexes[4*6];
101
102int reinit_surfcache = 1; // if 1, surface cache is currently empty and
103 // must be reinitialized for current cache size
104
105mleaf_t *r_viewleaf, *r_oldviewleaf;
106
107texture_t *r_notexture_mip;
108
109float r_aliastransition, r_resfudge;
110
111int d_lightstylevalue[256]; // 8.8 fraction of base light value
112
113float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
114float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
115
116void R_MarkLeaves (void);
117
118cvar_t r_draworder = {"r_draworder","0"};
119cvar_t r_speeds = {"r_speeds","0"};
120cvar_t r_timegraph = {"r_timegraph","0"};
121cvar_t r_graphheight = {"r_graphheight","10"};
122cvar_t r_clearcolor = {"r_clearcolor","2"};
123cvar_t r_waterwarp = {"r_waterwarp","1"};
124cvar_t r_fullbright = {"r_fullbright","0"};
125cvar_t r_drawentities = {"r_drawentities","1"};
126cvar_t r_drawviewmodel = {"r_drawviewmodel","1"};
127cvar_t r_aliasstats = {"r_polymodelstats","0"};
128cvar_t r_dspeeds = {"r_dspeeds","0"};
129cvar_t r_drawflat = {"r_drawflat", "0"};
130cvar_t r_ambient = {"r_ambient", "0"};
131cvar_t r_reportsurfout = {"r_reportsurfout", "0"};
132cvar_t r_maxsurfs = {"r_maxsurfs", "0"};
133cvar_t r_numsurfs = {"r_numsurfs", "0"};
134cvar_t r_reportedgeout = {"r_reportedgeout", "0"};
135cvar_t r_maxedges = {"r_maxedges", "0"};
136cvar_t r_numedges = {"r_numedges", "0"};
137cvar_t r_aliastransbase = {"r_aliastransbase", "200"};
138cvar_t r_aliastransadj = {"r_aliastransadj", "100"};
139
140extern cvar_t scr_fov;
141
142void CreatePassages (void);
143void SetVisibilityByPassages (void);
144
145/*
146==================
147R_InitTextures
148==================
149*/
150void R_InitTextures (void)
151{
152 int x,y, m;
153 byte *dest;
154
155// create a simple checkerboard texture for the default
156 r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
157
158 r_notexture_mip->width = r_notexture_mip->height = 16;
159 r_notexture_mip->offsets[0] = sizeof(texture_t);
160 r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
161 r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
162 r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
163
164 for (m=0 ; m<4 ; m++)
165 {
166 dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
167 for (y=0 ; y< (16>>m) ; y++)
168 for (x=0 ; x< (16>>m) ; x++)
169 {
170 if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
171 *dest++ = 0;
172 else
173 *dest++ = 0xff;
174 }
175 }
176}
177
178/*
179===============
180R_Init
181===============
182*/
183void R_Init (void)
184{
185 int dummy;
186
187// get stack position so we can guess if we are going to overflow
188 r_stack_start = (byte *)&dummy;
189
190 R_InitTurb ();
191
192 Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
193 Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
194
195 Cvar_RegisterVariable (&r_draworder);
196 Cvar_RegisterVariable (&r_speeds);
197 Cvar_RegisterVariable (&r_timegraph);
198 Cvar_RegisterVariable (&r_graphheight);
199 Cvar_RegisterVariable (&r_drawflat);
200 Cvar_RegisterVariable (&r_ambient);
201 Cvar_RegisterVariable (&r_clearcolor);
202 Cvar_RegisterVariable (&r_waterwarp);
203 Cvar_RegisterVariable (&r_fullbright);
204 Cvar_RegisterVariable (&r_drawentities);
205 Cvar_RegisterVariable (&r_drawviewmodel);
206 Cvar_RegisterVariable (&r_aliasstats);
207 Cvar_RegisterVariable (&r_dspeeds);
208 Cvar_RegisterVariable (&r_reportsurfout);
209 Cvar_RegisterVariable (&r_maxsurfs);
210 Cvar_RegisterVariable (&r_numsurfs);
211 Cvar_RegisterVariable (&r_reportedgeout);
212 Cvar_RegisterVariable (&r_maxedges);
213 Cvar_RegisterVariable (&r_numedges);
214 Cvar_RegisterVariable (&r_aliastransbase);
215 Cvar_RegisterVariable (&r_aliastransadj);
216
217 Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES);
218 Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES);
219
220 view_clipplanes[0].leftedge = true;
221 view_clipplanes[1].rightedge = true;
222 view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
223 view_clipplanes[3].leftedge = false;
224 view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
225 view_clipplanes[3].rightedge = false;
226
227 r_refdef.xOrigin = XCENTERING;
228 r_refdef.yOrigin = YCENTERING;
229
230 R_InitParticles ();
231
232// TODO: collect 386-specific code in one place
233#if id386
234 Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
235 (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
236#endif // id386
237
238 D_Init ();
239}
240
241/*
242===============
243R_NewMap
244===============
245*/
246void R_NewMap (void)
247{
248 int i;
249
250// clear out efrags in case the level hasn't been reloaded
251// FIXME: is this one short?
252 for (i=0 ; i<cl.worldmodel->numleafs ; i++)
253 cl.worldmodel->leafs[i].efrags = NULL;
254
255 r_viewleaf = NULL;
256 R_ClearParticles ();
257
258 r_cnumsurfs = r_maxsurfs.value;
259
260 if (r_cnumsurfs <= MINSURFACES)
261 r_cnumsurfs = MINSURFACES;
262
263 if (r_cnumsurfs > NUMSTACKSURFACES)
264 {
265 surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces");
266 surface_p = surfaces;
267 surf_max = &surfaces[r_cnumsurfs];
268 r_surfsonstack = false;
269 // surface 0 doesn't really exist; it's just a dummy because index 0
270 // is used to indicate no edge attached to surface
271 surfaces--;
272 R_SurfacePatch ();
273 }
274 else
275 {
276 r_surfsonstack = true;
277 }
278
279 r_maxedgesseen = 0;
280 r_maxsurfsseen = 0;
281
282 r_numallocatededges = r_maxedges.value;
283
284 if (r_numallocatededges < MINEDGES)
285 r_numallocatededges = MINEDGES;
286
287 if (r_numallocatededges <= NUMSTACKEDGES)
288 {
289 auxedges = NULL;
290 }
291 else
292 {
293 auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t),
294 "edges");
295 }
296
297 r_dowarpold = false;
298 r_viewchanged = false;
299#ifdef PASSAGES
300CreatePassages ();
301#endif
302}
303
304
305/*
306===============
307R_SetVrect
308===============
309*/
310void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj)
311{
312 int h;
313 float size;
314
315 size = scr_viewsize.value > 100 ? 100 : scr_viewsize.value;
316 if (cl.intermission)
317 {
318 size = 100;
319 lineadj = 0;
320 }
321 size /= 100;
322
323 h = pvrectin->height - lineadj;
324 pvrect->width = pvrectin->width * size;
325 if (pvrect->width < 96)
326 {
327 size = 96.0 / pvrectin->width;
328 pvrect->width = 96; // min for icons
329 }
330 pvrect->width &= ~7;
331 pvrect->height = pvrectin->height * size;
332 if (pvrect->height > pvrectin->height - lineadj)
333 pvrect->height = pvrectin->height - lineadj;
334
335 pvrect->height &= ~1;
336
337 pvrect->x = (pvrectin->width - pvrect->width)/2;
338 pvrect->y = (h - pvrect->height)/2;
339
340 {
341 if (lcd_x.value)
342 {
343 pvrect->y >>= 1;
344 pvrect->height >>= 1;
345 }
346 }
347}
348
349
350/*
351===============
352R_ViewChanged
353
354Called every time the vid structure or r_refdef changes.
355Guaranteed to be called before the first refresh
356===============
357*/
358void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect)
359{
360 int i;
361 float res_scale;
362
363 r_viewchanged = true;
364
365 R_SetVrect (pvrect, &r_refdef.vrect, lineadj);
366
367 r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x/360*M_PI);
368 r_refdef.fvrectx = (float)r_refdef.vrect.x;
369 r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
370 r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
371 r_refdef.fvrecty = (float)r_refdef.vrect.y;
372 r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
373 r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
374 r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
375 r_refdef.fvrectright = (float)r_refdef.vrectright;
376 r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
377 r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
378 r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
379 r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
380 r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
381
382 r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
383 r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
384 r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
385 r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
386 r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
387 r_refdef.aliasvrect.width;
388 r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
389 r_refdef.aliasvrect.height;
390
391 pixelAspect = aspect;
392 xOrigin = r_refdef.xOrigin;
393 yOrigin = r_refdef.yOrigin;
394
395 screenAspect = r_refdef.vrect.width*pixelAspect /
396 r_refdef.vrect.height;
397// 320*200 1.0 pixelAspect = 1.6 screenAspect
398// 320*240 1.0 pixelAspect = 1.3333 screenAspect
399// proper 320*200 pixelAspect = 0.8333333
400
401 verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect;
402
403// values for perspective projection
404// if math were exact, the values would range from 0.5 to to range+0.5
405// hopefully they wll be in the 0.000001 to range+.999999 and truncate
406// the polygon rasterization will never render in the first row or column
407// but will definately render in the [range] row and column, so adjust the
408// buffer origin to get an exact edge to edge fill
409 xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
410 r_refdef.vrect.x - 0.5;
411 aliasxcenter = xcenter * r_aliasuvscale;
412 ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
413 r_refdef.vrect.y - 0.5;
414 aliasycenter = ycenter * r_aliasuvscale;
415
416 xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
417 aliasxscale = xscale * r_aliasuvscale;
418 xscaleinv = 1.0 / xscale;
419 yscale = xscale * pixelAspect;
420 aliasyscale = yscale * r_aliasuvscale;
421 yscaleinv = 1.0 / yscale;
422 xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
423 yscaleshrink = xscaleshrink*pixelAspect;
424
425// left side clip
426 screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
427 screenedge[0].normal[1] = 0;
428 screenedge[0].normal[2] = 1;
429 screenedge[0].type = PLANE_ANYZ;
430
431// right side clip
432 screenedge[1].normal[0] =
433 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
434 screenedge[1].normal[1] = 0;
435 screenedge[1].normal[2] = 1;
436 screenedge[1].type = PLANE_ANYZ;
437
438// top side clip
439 screenedge[2].normal[0] = 0;
440 screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
441 screenedge[2].normal[2] = 1;
442 screenedge[2].type = PLANE_ANYZ;
443
444// bottom side clip
445 screenedge[3].normal[0] = 0;
446 screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
447 screenedge[3].normal[2] = 1;
448 screenedge[3].type = PLANE_ANYZ;
449
450 for (i=0 ; i<4 ; i++)
451 VectorNormalizeNoRet (screenedge[i].normal);
452
453 res_scale = sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) /
454 (320.0 * 152.0)) *
455 (2.0 / r_refdef.horizontalFieldOfView);
456 r_aliastransition = r_aliastransbase.value * res_scale;
457 r_resfudge = r_aliastransadj.value * res_scale;
458
459 if (scr_fov.value <= 90.0)
460 r_fov_greater_than_90 = false;
461 else
462 r_fov_greater_than_90 = true;
463
464// TODO: collect 386-specific code in one place
465#if id386
466 if (r_pixbytes == 1)
467 {
468 Sys_MakeCodeWriteable ((long)R_Surf8Start,
469 (long)R_Surf8End - (long)R_Surf8Start);
470 colormap = vid.colormap;
471 R_Surf8Patch ();
472 }
473 else
474 {
475 Sys_MakeCodeWriteable ((long)R_Surf16Start,
476 (long)R_Surf16End - (long)R_Surf16Start);
477 colormap = vid.colormap16;
478 R_Surf16Patch ();
479 }
480#endif // id386
481
482 D_ViewChanged ();
483}
484
485
486/*
487===============
488R_MarkLeaves
489===============
490*/
491void R_MarkLeaves (void)
492{
493 byte *vis;
494 mnode_t *node;
495 int i;
496
497 if (r_oldviewleaf == r_viewleaf)
498 return;
499
500 r_visframecount++;
501 r_oldviewleaf = r_viewleaf;
502
503 vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
504
505 for (i=0 ; i<cl.worldmodel->numleafs ; i++)
506 {
507 if (vis[i>>3] & (1<<(i&7)))
508 {
509 node = (mnode_t *)&cl.worldmodel->leafs[i+1];
510 do
511 {
512 if (node->visframe == r_visframecount)
513 break;
514 node->visframe = r_visframecount;
515 node = node->parent;
516 } while (node);
517 }
518 }
519}
520
521
522/*
523=============
524R_DrawEntitiesOnList
525=============
526*/
527void R_DrawEntitiesOnList (void)
528{
529 int i, j;
530 int lnum;
531 alight_t lighting;
532// FIXME: remove and do real lighting
533 float lightvec[3] = {-1, 0, 0};
534 vec3_t dist;
535 float add;
536
537 if (!r_drawentities.value)
538 return;
539
540 for (i=0 ; i<cl_numvisedicts ; i++)
541 {
542 currententity = cl_visedicts[i];
543
544 if (currententity == &cl_entities[cl.viewentity])
545 continue; // don't draw the player
546
547 switch (currententity->model->type)
548 {
549 case mod_sprite:
550 VectorCopy (currententity->origin, r_entorigin);
551 VectorSubtract (r_origin, r_entorigin, modelorg);
552 R_DrawSprite ();
553 break;
554
555 case mod_alias:
556 VectorCopy (currententity->origin, r_entorigin);
557 VectorSubtract (r_origin, r_entorigin, modelorg);
558
559 // see if the bounding box lets us trivially reject, also sets
560 // trivial accept status
561 if (R_AliasCheckBBox ())
562 {
563 j = R_LightPoint (currententity->origin);
564
565 lighting.ambientlight = j;
566 lighting.shadelight = j;
567
568 lighting.plightvec = lightvec;
569
570 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
571 {
572 if (cl_dlights[lnum].die >= cl.time)
573 {
574 VectorSubtract (currententity->origin,
575 cl_dlights[lnum].origin,
576 dist);
577 add = cl_dlights[lnum].radius - Length(dist);
578
579 if (add > 0)
580 lighting.ambientlight += add;
581 }
582 }
583
584 // clamp lighting so it doesn't overbright as much
585 if (lighting.ambientlight > 128)
586 lighting.ambientlight = 128;
587 if (lighting.ambientlight + lighting.shadelight > 192)
588 lighting.shadelight = 192 - lighting.ambientlight;
589
590 R_AliasDrawModel (&lighting);
591 }
592
593 break;
594
595 default:
596 break;
597 }
598 }
599}
600
601/*
602=============
603R_DrawViewModel
604=============
605*/
606void R_DrawViewModel (void)
607{
608// FIXME: remove and do real lighting
609 float lightvec[3] = {-1, 0, 0};
610 int j;
611 int lnum;
612 vec3_t dist;
613 float add;
614 dlight_t *dl;
615
616 if (!r_drawviewmodel.value || r_fov_greater_than_90)
617 return;
618
619 if (cl.items & IT_INVISIBILITY)
620 return;
621
622 if (cl.stats[STAT_HEALTH] <= 0)
623 return;
624
625 currententity = &cl.viewent;
626 if (!currententity->model)
627 return;
628
629 VectorCopy (currententity->origin, r_entorigin);
630 VectorSubtract (r_origin, r_entorigin, modelorg);
631
632 VectorCopy (vup, viewlightvec);
633 VectorInverse (viewlightvec);
634
635 j = R_LightPoint (currententity->origin);
636
637 if (j < 24)
638 j = 24; // allways give some light on gun
639 r_viewlighting.ambientlight = j;
640 r_viewlighting.shadelight = j;
641
642// add dynamic lights
643 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
644 {
645 dl = &cl_dlights[lnum];
646 if (!dl->radius)
647 continue;
648 if (!dl->radius)
649 continue;
650 if (dl->die < cl.time)
651 continue;
652
653 VectorSubtract (currententity->origin, dl->origin, dist);
654 add = dl->radius - Length(dist);
655 if (add > 0)
656 r_viewlighting.ambientlight += add;
657 }
658
659// clamp lighting so it doesn't overbright as much
660 if (r_viewlighting.ambientlight > 128)
661 r_viewlighting.ambientlight = 128;
662 if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192)
663 r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight;
664
665 r_viewlighting.plightvec = lightvec;
666
667#ifdef QUAKE2
668 cl.light_level = r_viewlighting.ambientlight;
669#endif
670
671 R_AliasDrawModel (&r_viewlighting);
672}
673
674
675/*
676=============
677R_BmodelCheckBBox
678=============
679*/
680int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
681{
682 int i, *pindex, clipflags;
683 vec3_t acceptpt, rejectpt;
684 double d;
685
686 clipflags = 0;
687
688 if (currententity->angles[0] || currententity->angles[1]
689 || currententity->angles[2])
690 {
691 for (i=0 ; i<4 ; i++)
692 {
693 d = DotProduct (currententity->origin, view_clipplanes[i].normal);
694 d -= view_clipplanes[i].dist;
695
696 if (d <= -clmodel->radius)
697 return BMODEL_FULLY_CLIPPED;
698
699 if (d <= clmodel->radius)
700 clipflags |= (1<<i);
701 }
702 }
703 else
704 {
705 for (i=0 ; i<4 ; i++)
706 {
707 // generate accept and reject points
708 // FIXME: do with fast look-ups or integer tests based on the sign bit
709 // of the floating point values
710
711 pindex = pfrustum_indexes[i];
712
713 rejectpt[0] = minmaxs[pindex[0]];
714 rejectpt[1] = minmaxs[pindex[1]];
715 rejectpt[2] = minmaxs[pindex[2]];
716
717 d = DotProduct (rejectpt, view_clipplanes[i].normal);
718 d -= view_clipplanes[i].dist;
719
720 if (d <= 0)
721 return BMODEL_FULLY_CLIPPED;
722
723 acceptpt[0] = minmaxs[pindex[3+0]];
724 acceptpt[1] = minmaxs[pindex[3+1]];
725 acceptpt[2] = minmaxs[pindex[3+2]];
726
727 d = DotProduct (acceptpt, view_clipplanes[i].normal);
728 d -= view_clipplanes[i].dist;
729
730 if (d <= 0)
731 clipflags |= (1<<i);
732 }
733 }
734
735 return clipflags;
736}
737
738
739/*
740=============
741R_DrawBEntitiesOnList
742=============
743*/
744void R_DrawBEntitiesOnList (void)
745{
746 int i, j, k, clipflags;
747 vec3_t oldorigin;
748 model_t *clmodel;
749 float minmaxs[6];
750
751 if (!r_drawentities.value)
752 return;
753
754 VectorCopy (modelorg, oldorigin);
755 insubmodel = true;
756 r_dlightframecount = r_framecount;
757
758 for (i=0 ; i<cl_numvisedicts ; i++)
759 {
760 currententity = cl_visedicts[i];
761
762 switch (currententity->model->type)
763 {
764 case mod_brush:
765
766 clmodel = currententity->model;
767
768 // see if the bounding box lets us trivially reject, also sets
769 // trivial accept status
770 for (j=0 ; j<3 ; j++)
771 {
772 minmaxs[j] = currententity->origin[j] +
773 clmodel->mins[j];
774 minmaxs[3+j] = currententity->origin[j] +
775 clmodel->maxs[j];
776 }
777
778 clipflags = R_BmodelCheckBBox (clmodel, minmaxs);
779
780 if (clipflags != BMODEL_FULLY_CLIPPED)
781 {
782 VectorCopy (currententity->origin, r_entorigin);
783 VectorSubtract (r_origin, r_entorigin, modelorg);
784 // FIXME: is this needed?
785 VectorCopy (modelorg, r_worldmodelorg);
786
787 r_pcurrentvertbase = clmodel->vertexes;
788
789 // FIXME: stop transforming twice
790 R_RotateBmodel ();
791
792 // calculate dynamic lighting for bmodel if it's not an
793 // instanced model
794 if (clmodel->firstmodelsurface != 0)
795 {
796 for (k=0 ; k<MAX_DLIGHTS ; k++)
797 {
798 if ((cl_dlights[k].die < cl.time) ||
799 (!cl_dlights[k].radius))
800 {
801 continue;
802 }
803
804 R_MarkLights (&cl_dlights[k], 1<<k,
805 clmodel->nodes + clmodel->hulls[0].firstclipnode);
806 }
807 }
808
809 // if the driver wants polygons, deliver those. Z-buffering is on
810 // at this point, so no clipping to the world tree is needed, just
811 // frustum clipping
812 if (r_drawpolys | r_drawculledpolys)
813 {
814 R_ZDrawSubmodelPolys (clmodel);
815 }
816 else
817 {
818 r_pefragtopnode = NULL;
819
820 for (j=0 ; j<3 ; j++)
821 {
822 r_emins[j] = minmaxs[j];
823 r_emaxs[j] = minmaxs[3+j];
824 }
825
826 R_SplitEntityOnNode2 (cl.worldmodel->nodes);
827
828 if (r_pefragtopnode)
829 {
830 currententity->topnode = r_pefragtopnode;
831
832 if (r_pefragtopnode->contents >= 0)
833 {
834 // not a leaf; has to be clipped to the world BSP
835 r_clipflags = clipflags;
836 R_DrawSolidClippedSubmodelPolygons (clmodel);
837 }
838 else
839 {
840 // falls entirely in one leaf, so we just put all the
841 // edges in the edge list and let 1/z sorting handle
842 // drawing order
843 R_DrawSubmodelPolygons (clmodel, clipflags);
844 }
845
846 currententity->topnode = NULL;
847 }
848 }
849
850 // put back world rotation and frustum clipping
851 // FIXME: R_RotateBmodel should just work off base_vxx
852 VectorCopy (base_vpn, vpn);
853 VectorCopy (base_vup, vup);
854 VectorCopy (base_vright, vright);
855 VectorCopy (base_modelorg, modelorg);
856 VectorCopy (oldorigin, modelorg);
857 R_TransformFrustum ();
858 }
859
860 break;
861
862 default:
863 break;
864 }
865 }
866
867 insubmodel = false;
868}
869
870
871/*
872================
873R_EdgeDrawing
874================
875*/
876void R_EdgeDrawing (void)
877{
878 edge_t ledges[NUMSTACKEDGES +
879 ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
880 surf_t lsurfs[NUMSTACKSURFACES +
881 ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
882
883 if (auxedges)
884 {
885 r_edges = auxedges;
886 }
887 else
888 {
889 r_edges = (edge_t *)
890 (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
891 }
892
893 if (r_surfsonstack)
894 {
895 surfaces = (surf_t *)
896 (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
897 surf_max = &surfaces[r_cnumsurfs];
898 // surface 0 doesn't really exist; it's just a dummy because index 0
899 // is used to indicate no edge attached to surface
900 surfaces--;
901 R_SurfacePatch ();
902 }
903
904 R_BeginEdgeFrame ();
905
906 if (r_dspeeds.value)
907 {
908 rw_time1 = Sys_FloatTime ();
909 }
910
911 R_RenderWorld ();
912
913 if (r_drawculledpolys)
914 R_ScanEdges ();
915
916// only the world can be drawn back to front with no z reads or compares, just
917// z writes, so have the driver turn z compares on now
918 D_TurnZOn ();
919
920 if (r_dspeeds.value)
921 {
922 rw_time2 = Sys_FloatTime ();
923 db_time1 = rw_time2;
924 }
925
926 R_DrawBEntitiesOnList ();
927
928 if (r_dspeeds.value)
929 {
930 db_time2 = Sys_FloatTime ();
931 se_time1 = db_time2;
932 }
933
934 if (!r_dspeeds.value)
935 {
936 VID_UnlockBuffer ();
937 S_ExtraUpdate (); // don't let sound get messed up if going slow
938 VID_LockBuffer ();
939 }
940
941 if (!(r_drawpolys | r_drawculledpolys))
942 R_ScanEdges ();
943}
944
945
946/*
947================
948R_RenderView
949
950r_refdef must be set before the first call
951================
952*/
953void R_RenderView_ (void)
954{
955 byte warpbuffer[WARP_WIDTH * WARP_HEIGHT];
956
957 r_warpbuffer = warpbuffer;
958
959 if (r_timegraph.value || r_speeds.value || r_dspeeds.value)
960 r_time1 = Sys_FloatTime ();
961
962 R_SetupFrame ();
963
964#ifdef PASSAGES
965SetVisibilityByPassages ();
966#else
967 R_MarkLeaves (); // done here so we know if we're in water
968#endif
969
970// make FDIV fast. This reduces timing precision after we've been running for a
971// while, so we don't do it globally. This also sets chop mode, and we do it
972// here so that setup stuff like the refresh area calculations match what's
973// done in screen.c
974 Sys_LowFPPrecision ();
975
976 if (!cl_entities[0].model || !cl.worldmodel)
977 Sys_Error ("R_RenderView: NULL worldmodel");
978
979 if (!r_dspeeds.value)
980 {
981 VID_UnlockBuffer ();
982 S_ExtraUpdate (); // don't let sound get messed up if going slow
983 VID_LockBuffer ();
984 }
985
986 R_EdgeDrawing ();
987
988 rb->yield(); // let sound run
989
990 if (!r_dspeeds.value)
991 {
992 VID_UnlockBuffer ();
993 S_ExtraUpdate (); // don't let sound get messed up if going slow
994 VID_LockBuffer ();
995 }
996
997 if (r_dspeeds.value)
998 {
999 se_time2 = Sys_FloatTime ();
1000 de_time1 = se_time2;
1001 }
1002
1003 R_DrawEntitiesOnList ();
1004
1005 if (r_dspeeds.value)
1006 {
1007 de_time2 = Sys_FloatTime ();
1008 dv_time1 = de_time2;
1009 }
1010
1011 R_DrawViewModel ();
1012
1013 if (r_dspeeds.value)
1014 {
1015 dv_time2 = Sys_FloatTime ();
1016 dp_time1 = Sys_FloatTime ();
1017 }
1018
1019 R_DrawParticles ();
1020
1021 rb->yield(); // let sound run
1022
1023 if (r_dspeeds.value)
1024 dp_time2 = Sys_FloatTime ();
1025
1026 if (r_dowarp)
1027 D_WarpScreen ();
1028
1029 V_SetContentsColor (r_viewleaf->contents);
1030
1031 if (r_timegraph.value)
1032 R_TimeGraph ();
1033
1034 if (r_aliasstats.value)
1035 R_PrintAliasStats ();
1036
1037 if (r_speeds.value)
1038 R_PrintTimes ();
1039
1040 if (r_dspeeds.value)
1041 R_PrintDSpeeds ();
1042
1043 if (r_reportsurfout.value && r_outofsurfaces)
1044 Con_Printf ("Short %d surfaces\n", r_outofsurfaces);
1045
1046 if (r_reportedgeout.value && r_outofedges)
1047 Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3);
1048
1049// back to high floating-point precision
1050 Sys_HighFPPrecision ();
1051}
1052
1053void R_RenderView (void)
1054{
1055 int dummy;
1056 int delta;
1057
1058 delta = (byte *)&dummy - r_stack_start;
1059 if (delta < -10000 || delta > 10000)
1060 Sys_Error ("R_RenderView: called without enough stack");
1061
1062 if ( Hunk_LowMark() & 3 )
1063 Sys_Error ("Hunk is missaligned");
1064
1065 if ( (long)(&dummy) & 3 )
1066 Sys_Error ("Stack is missaligned");
1067
1068 if ( (long)(&r_warpbuffer) & 3 )
1069 Sys_Error ("Globals are missaligned");
1070
1071 R_RenderView_ ();
1072}
1073
1074/*
1075================
1076R_InitTurb
1077================
1078*/
1079void R_InitTurb (void)
1080{
1081 int i;
1082
1083 for (i=0 ; i<(SIN_BUFFER_SIZE) ; i++)
1084 {
1085 sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
1086 intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
1087 }
1088}
1089
diff --git a/apps/plugins/sdl/progs/quake/r_misc.c b/apps/plugins/sdl/progs/quake/r_misc.c
new file mode 100644
index 0000000000..c0aa7e991d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_misc.c
@@ -0,0 +1,523 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_misc.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25
26/*
27===============
28R_CheckVariables
29===============
30*/
31void R_CheckVariables (void)
32{
33 static float oldbright;
34
35 if (r_fullbright.value != oldbright)
36 {
37 oldbright = r_fullbright.value;
38 D_FlushCaches (); // so all lighting changes
39 }
40}
41
42
43/*
44============
45Show
46
47Debugging use
48============
49*/
50void Show (void)
51{
52 vrect_t vr;
53
54 vr.x = vr.y = 0;
55 vr.width = vid.width;
56 vr.height = vid.height;
57 vr.pnext = NULL;
58 VID_Update (&vr);
59}
60
61
62/*
63====================
64R_TimeRefresh_f
65
66For program optimization
67====================
68*/
69void R_TimeRefresh_f (void)
70{
71 int i;
72 float start, stop, time;
73 int startangle;
74 vrect_t vr;
75
76 startangle = r_refdef.viewangles[1];
77
78 start = Sys_FloatTime ();
79 for (i=0 ; i<128 ; i++)
80 {
81 r_refdef.viewangles[1] = i/128.0*360.0;
82
83 VID_LockBuffer ();
84
85 R_RenderView ();
86
87 VID_UnlockBuffer ();
88
89 vr.x = r_refdef.vrect.x;
90 vr.y = r_refdef.vrect.y;
91 vr.width = r_refdef.vrect.width;
92 vr.height = r_refdef.vrect.height;
93 vr.pnext = NULL;
94 VID_Update (&vr);
95 }
96 stop = Sys_FloatTime ();
97 time = stop-start;
98 Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
99
100 r_refdef.viewangles[1] = startangle;
101}
102
103
104/*
105================
106R_LineGraph
107
108Only called by R_DisplayTime
109================
110*/
111void R_LineGraph (int x, int y, int h)
112{
113 int i;
114 byte *dest;
115 int s;
116
117// FIXME: should be disabled on no-buffer adapters, or should be in the driver
118
119 x += r_refdef.vrect.x;
120 y += r_refdef.vrect.y;
121
122 dest = vid.buffer + vid.rowbytes*y + x;
123
124 s = r_graphheight.value;
125
126 if (h>s)
127 h = s;
128
129 for (i=0 ; i<h ; i++, dest -= vid.rowbytes*2)
130 {
131 dest[0] = 0xff;
132 *(dest-vid.rowbytes) = 0x30;
133 }
134 for ( ; i<s ; i++, dest -= vid.rowbytes*2)
135 {
136 dest[0] = 0x30;
137 *(dest-vid.rowbytes) = 0x30;
138 }
139}
140
141/*
142==============
143R_TimeGraph
144
145Performance monitoring tool
146==============
147*/
148#define MAX_TIMINGS 100
149extern float mouse_x, mouse_y;
150void R_TimeGraph (void)
151{
152 static int timex;
153 int a;
154 float r_time2;
155 static byte r_timings[MAX_TIMINGS];
156 int x;
157
158 r_time2 = Sys_FloatTime ();
159
160 a = (r_time2-r_time1)/0.01;
161//a = fabs(mouse_y * 0.05);
162//a = (int)((r_refdef.vieworg[2] + 1024)/1)%(int)r_graphheight.value;
163//a = fabs(velocity[0])/20;
164//a = ((int)fabs(origin[0])/8)%20;
165//a = (cl.idealpitch + 30)/5;
166 r_timings[timex] = a;
167 a = timex;
168
169 if (r_refdef.vrect.width <= MAX_TIMINGS)
170 x = r_refdef.vrect.width-1;
171 else
172 x = r_refdef.vrect.width -
173 (r_refdef.vrect.width - MAX_TIMINGS)/2;
174 do
175 {
176 R_LineGraph (x, r_refdef.vrect.height-2, r_timings[a]);
177 if (x==0)
178 break; // screen too small to hold entire thing
179 x--;
180 a--;
181 if (a == -1)
182 a = MAX_TIMINGS-1;
183 } while (a != timex);
184
185 timex = (timex+1)%MAX_TIMINGS;
186}
187
188
189/*
190=============
191R_PrintTimes
192=============
193*/
194void R_PrintTimes (void)
195{
196 float r_time2;
197 float ms;
198
199 r_time2 = Sys_FloatTime ();
200
201 ms = 1000* (r_time2 - r_time1);
202
203 Con_Printf ("%5.1f ms %3i/%3i/%3i poly %3i surf\n",
204 ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
205 c_surf = 0;
206}
207
208
209/*
210=============
211R_PrintDSpeeds
212=============
213*/
214void R_PrintDSpeeds (void)
215{
216 float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, dv_time;
217
218 r_time2 = Sys_FloatTime ();
219
220 dp_time = (dp_time2 - dp_time1) * 1000;
221 rw_time = (rw_time2 - rw_time1) * 1000;
222 db_time = (db_time2 - db_time1) * 1000;
223 se_time = (se_time2 - se_time1) * 1000;
224 de_time = (de_time2 - de_time1) * 1000;
225 dv_time = (dv_time2 - dv_time1) * 1000;
226 ms = (r_time2 - r_time1) * 1000;
227
228 Con_Printf ("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
229 (int)ms, dp_time, (int)rw_time, db_time, (int)se_time, de_time,
230 dv_time);
231}
232
233
234/*
235=============
236R_PrintAliasStats
237=============
238*/
239void R_PrintAliasStats (void)
240{
241 Con_Printf ("%3i polygon model drawn\n", r_amodels_drawn);
242}
243
244
245void WarpPalette (void)
246{
247 int i,j;
248 byte newpalette[768];
249 int basecolor[3];
250
251 basecolor[0] = 130;
252 basecolor[1] = 80;
253 basecolor[2] = 50;
254
255// pull the colors halfway to bright brown
256 for (i=0 ; i<256 ; i++)
257 {
258 for (j=0 ; j<3 ; j++)
259 {
260 newpalette[i*3+j] = (host_basepal[i*3+j] + basecolor[j])/2;
261 }
262 }
263
264 VID_ShiftPalette (newpalette);
265}
266
267
268/*
269===================
270R_TransformFrustum
271===================
272*/
273void R_TransformFrustum (void)
274{
275 int i;
276 vec3_t v, v2;
277
278 for (i=0 ; i<4 ; i++)
279 {
280 v[0] = screenedge[i].normal[2];
281 v[1] = -screenedge[i].normal[0];
282 v[2] = screenedge[i].normal[1];
283
284 v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
285 v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
286 v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
287
288 VectorCopy (v2, view_clipplanes[i].normal);
289
290 view_clipplanes[i].dist = DotProduct (modelorg, v2);
291 }
292}
293
294
295#if !id386
296
297/*
298================
299TransformVector
300================
301*/
302void TransformVector (vec3_t in, vec3_t out)
303{
304 out[0] = DotProduct(in,vright);
305 out[1] = DotProduct(in,vup);
306 out[2] = DotProduct(in,vpn);
307}
308
309#endif
310
311
312/*
313================
314R_TransformPlane
315================
316*/
317void R_TransformPlane (mplane_t *p, float *normal, float *dist)
318{
319 float d;
320
321 d = DotProduct (r_origin, p->normal);
322 *dist = p->dist - d;
323// TODO: when we have rotating entities, this will need to use the view matrix
324 TransformVector (p->normal, normal);
325}
326
327
328/*
329===============
330R_SetUpFrustumIndexes
331===============
332*/
333void R_SetUpFrustumIndexes (void)
334{
335 int i, j, *pindex;
336
337 pindex = r_frustum_indexes;
338
339 for (i=0 ; i<4 ; i++)
340 {
341 for (j=0 ; j<3 ; j++)
342 {
343 if (view_clipplanes[i].normal[j] < 0)
344 {
345 pindex[j] = j;
346 pindex[j+3] = j+3;
347 }
348 else
349 {
350 pindex[j] = j+3;
351 pindex[j+3] = j;
352 }
353 }
354
355 // FIXME: do just once at start
356 pfrustum_indexes[i] = pindex;
357 pindex += 6;
358 }
359}
360
361
362/*
363===============
364R_SetupFrame
365===============
366*/
367void R_SetupFrame (void)
368{
369 int edgecount;
370 vrect_t vrect;
371 float w, h;
372
373// don't allow cheats in multiplayer
374 if (cl.maxclients > 1)
375 {
376 Cvar_Set ("r_draworder", "0");
377 Cvar_Set ("r_fullbright", "0");
378 Cvar_Set ("r_ambient", "0");
379 Cvar_Set ("r_drawflat", "0");
380 }
381
382 if (r_numsurfs.value)
383 {
384 if ((surface_p - surfaces) > r_maxsurfsseen)
385 r_maxsurfsseen = surface_p - surfaces;
386
387 Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces,
388 surf_max - surfaces, r_maxsurfsseen);
389 }
390
391 if (r_numedges.value)
392 {
393 edgecount = edge_p - r_edges;
394
395 if (edgecount > r_maxedgesseen)
396 r_maxedgesseen = edgecount;
397
398 Con_Printf ("Used %d of %d edges; %d max\n", edgecount,
399 r_numallocatededges, r_maxedgesseen);
400 }
401
402 r_refdef.ambientlight = r_ambient.value;
403
404 if (r_refdef.ambientlight < 0)
405 r_refdef.ambientlight = 0;
406
407 if (!sv.active)
408 r_draworder.value = 0; // don't let cheaters look behind walls
409
410 R_CheckVariables ();
411
412 R_AnimateLight ();
413
414 r_framecount++;
415
416 numbtofpolys = 0;
417
418// debugging
419#if 0
420r_refdef.vieworg[0]= 80;
421r_refdef.vieworg[1]= 64;
422r_refdef.vieworg[2]= 40;
423r_refdef.viewangles[0]= 0;
424r_refdef.viewangles[1]= 46.763641357;
425r_refdef.viewangles[2]= 0;
426#endif
427
428// build the transformation matrix for the given view angles
429 VectorCopy (r_refdef.vieworg, modelorg);
430 VectorCopy (r_refdef.vieworg, r_origin);
431
432 AngleVectors (r_refdef.viewangles, vpn, vright, vup);
433
434// current viewleaf
435 r_oldviewleaf = r_viewleaf;
436 r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
437
438 r_dowarpold = r_dowarp;
439 r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER);
440
441 if ((r_dowarp != r_dowarpold) || r_viewchanged || lcd_x.value)
442 {
443 if (r_dowarp)
444 {
445 if ((vid.width <= vid.maxwarpwidth) &&
446 (vid.height <= vid.maxwarpheight))
447 {
448 vrect.x = 0;
449 vrect.y = 0;
450 vrect.width = vid.width;
451 vrect.height = vid.height;
452
453 R_ViewChanged (&vrect, sb_lines, vid.aspect);
454 }
455 else
456 {
457 w = vid.width;
458 h = vid.height;
459
460 if (w > vid.maxwarpwidth)
461 {
462 h *= (float)vid.maxwarpwidth / w;
463 w = vid.maxwarpwidth;
464 }
465
466 if (h > vid.maxwarpheight)
467 {
468 h = vid.maxwarpheight;
469 w *= (float)vid.maxwarpheight / h;
470 }
471
472 vrect.x = 0;
473 vrect.y = 0;
474 vrect.width = (int)w;
475 vrect.height = (int)h;
476
477 R_ViewChanged (&vrect,
478 (int)((float)sb_lines * (h/(float)vid.height)),
479 vid.aspect * (h / w) *
480 ((float)vid.width / (float)vid.height));
481 }
482 }
483 else
484 {
485 vrect.x = 0;
486 vrect.y = 0;
487 vrect.width = vid.width;
488 vrect.height = vid.height;
489
490 R_ViewChanged (&vrect, sb_lines, vid.aspect);
491 }
492
493 r_viewchanged = false;
494 }
495
496// start off with just the four screen edge clip planes
497 R_TransformFrustum ();
498
499// save base values
500 VectorCopy (vpn, base_vpn);
501 VectorCopy (vright, base_vright);
502 VectorCopy (vup, base_vup);
503 VectorCopy (modelorg, base_modelorg);
504
505 R_SetSkyFrame ();
506
507 R_SetUpFrustumIndexes ();
508
509 r_cache_thrash = false;
510
511// clear frame counts
512 c_faceclip = 0;
513 d_spanpixcount = 0;
514 r_polycount = 0;
515 r_drawnpolycount = 0;
516 r_wholepolycount = 0;
517 r_amodels_drawn = 0;
518 r_outofsurfaces = 0;
519 r_outofedges = 0;
520
521 D_SetupFrame ();
522}
523
diff --git a/apps/plugins/sdl/progs/quake/r_part.c b/apps/plugins/sdl/progs/quake/r_part.c
new file mode 100644
index 0000000000..8c0dcff5e8
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_part.c
@@ -0,0 +1,802 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21#include "quakedef.h"
22#include "r_local.h"
23
24#define MAX_PARTICLES 2048 // default max # of particles at one
25 // time
26#define ABSOLUTE_MIN_PARTICLES 512 // no fewer than this no matter what's
27 // on the command line
28
29int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};
30int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};
31int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3};
32
33particle_t *active_particles, *free_particles;
34
35particle_t *particles;
36int r_numparticles;
37
38vec3_t r_pright, r_pup, r_ppn;
39
40
41/*
42===============
43R_InitParticles
44===============
45*/
46void R_InitParticles (void)
47{
48 int i;
49
50 i = COM_CheckParm ("-particles");
51
52 if (i)
53 {
54 r_numparticles = (int)(Q_atoi(com_argv[i+1]));
55 if (r_numparticles < ABSOLUTE_MIN_PARTICLES)
56 r_numparticles = ABSOLUTE_MIN_PARTICLES;
57 }
58 else
59 {
60 r_numparticles = MAX_PARTICLES;
61 }
62
63 particles = (particle_t *)
64 Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles");
65}
66
67#ifdef QUAKE2
68void R_DarkFieldParticles (entity_t *ent)
69{
70 int i, j, k;
71 particle_t *p;
72 float vel;
73 vec3_t dir;
74 vec3_t org;
75
76 org[0] = ent->origin[0];
77 org[1] = ent->origin[1];
78 org[2] = ent->origin[2];
79 for (i=-16 ; i<16 ; i+=8)
80 for (j=-16 ; j<16 ; j+=8)
81 for (k=0 ; k<32 ; k+=8)
82 {
83 if (!free_particles)
84 return;
85 p = free_particles;
86 free_particles = p->next;
87 p->next = active_particles;
88 active_particles = p;
89
90 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
91 p->color = 150 + rand()%6;
92 p->type = pt_slowgrav;
93
94 dir[0] = j*8;
95 dir[1] = i*8;
96 dir[2] = k*8;
97
98 p->org[0] = org[0] + i + (rand()&3);
99 p->org[1] = org[1] + j + (rand()&3);
100 p->org[2] = org[2] + k + (rand()&3);
101
102 VectorNormalizeNoRet (dir);
103 vel = 50 + (rand()&63);
104 VectorScale (dir, vel, p->vel);
105 }
106}
107#endif
108
109
110/*
111===============
112R_EntityParticles
113===============
114*/
115
116#define NUMVERTEXNORMALS 162
117extern float r_avertexnormals[NUMVERTEXNORMALS][3];
118vec3_t avelocities[NUMVERTEXNORMALS];
119float beamlength = 16;
120vec3_t avelocity = {23, 7, 3};
121float partstep = 0.01;
122float timescale = 0.01;
123
124void R_EntityParticles (entity_t *ent)
125{
126 int count;
127 int i;
128 particle_t *p;
129 float angle;
130 float sr, sp, sy, cr, cp, cy;
131 vec3_t forward;
132 float dist;
133
134 dist = 64;
135 count = 50;
136
137if (!avelocities[0][0])
138{
139for (i=0 ; i<NUMVERTEXNORMALS*3 ; i++)
140avelocities[0][i] = (rand()&255) * 0.01;
141}
142
143
144 for (i=0 ; i<NUMVERTEXNORMALS ; i++)
145 {
146 angle = cl.time * avelocities[i][0];
147 sy = sin(angle);
148 cy = cos(angle);
149 angle = cl.time * avelocities[i][1];
150 sp = sin(angle);
151 cp = cos(angle);
152 angle = cl.time * avelocities[i][2];
153 sr = sin(angle);
154 cr = cos(angle);
155
156 forward[0] = cp*cy;
157 forward[1] = cp*sy;
158 forward[2] = -sp;
159
160 if (!free_particles)
161 return;
162 p = free_particles;
163 free_particles = p->next;
164 p->next = active_particles;
165 active_particles = p;
166
167 p->die = cl.time + 0.01;
168 p->color = 0x6f;
169 p->type = pt_explode;
170
171 p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;
172 p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;
173 p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;
174 }
175}
176
177
178/*
179===============
180R_ClearParticles
181===============
182*/
183void R_ClearParticles (void)
184{
185 int i;
186
187 free_particles = &particles[0];
188 active_particles = NULL;
189
190 for (i=0 ;i<r_numparticles ; i++)
191 particles[i].next = &particles[i+1];
192 particles[r_numparticles-1].next = NULL;
193}
194
195
196void R_ReadPointFile_f (void)
197{
198 FILE *f;
199 vec3_t org;
200 int r;
201 int c;
202 particle_t *p;
203 char name[MAX_OSPATH];
204
205 sprintf (name,"maps/%s.pts", sv.name);
206
207 COM_FOpenFile (name, &f);
208 if (!f)
209 {
210 Con_Printf ("couldn't open %s\n", name);
211 return;
212 }
213
214 Con_Printf ("Reading %s...\n", name);
215 c = 0;
216 for ( ;; )
217 {
218 r = fscanf (f,"%f ", &org[0]);
219 r += fscanf (f,"%f ", &org[1]);
220 r += fscanf (f,"%f\n", &org[2]);
221 if (r != 3)
222 break;
223 c++;
224
225 if (!free_particles)
226 {
227 Con_Printf ("Not enough free particles\n");
228 break;
229 }
230 p = free_particles;
231 free_particles = p->next;
232 p->next = active_particles;
233 active_particles = p;
234
235 p->die = 99999;
236 p->color = (-c)&15;
237 p->type = pt_static;
238 VectorCopy (vec3_origin, p->vel);
239 VectorCopy (org, p->org);
240 }
241
242 fclose (f);
243 Con_Printf ("%i points read\n", c);
244}
245
246/*
247===============
248R_ParseParticleEffect
249
250Parse an effect out of the server message
251===============
252*/
253void R_ParseParticleEffect (void)
254{
255 vec3_t org, dir;
256 int i, count, msgcount, color;
257
258 for (i=0 ; i<3 ; i++)
259 org[i] = MSG_ReadCoord ();
260 for (i=0 ; i<3 ; i++)
261 dir[i] = MSG_ReadChar () * (1.0/16);
262 msgcount = MSG_ReadByte ();
263 color = MSG_ReadByte ();
264
265if (msgcount == 255)
266 count = 1024;
267else
268 count = msgcount;
269
270 R_RunParticleEffect (org, dir, color, count);
271}
272
273/*
274===============
275R_ParticleExplosion
276
277===============
278*/
279void R_ParticleExplosion (vec3_t org)
280{
281 int i, j;
282 particle_t *p;
283
284 for (i=0 ; i<1024 ; i++)
285 {
286 if (!free_particles)
287 return;
288 p = free_particles;
289 free_particles = p->next;
290 p->next = active_particles;
291 active_particles = p;
292
293 p->die = cl.time + 5;
294 p->color = ramp1[0];
295 p->ramp = rand()&3;
296 if (i & 1)
297 {
298 p->type = pt_explode;
299 for (j=0 ; j<3 ; j++)
300 {
301 p->org[j] = org[j] + ((rand()%32)-16);
302 p->vel[j] = (rand()%512)-256;
303 }
304 }
305 else
306 {
307 p->type = pt_explode2;
308 for (j=0 ; j<3 ; j++)
309 {
310 p->org[j] = org[j] + ((rand()%32)-16);
311 p->vel[j] = (rand()%512)-256;
312 }
313 }
314 }
315}
316
317/*
318===============
319R_ParticleExplosion2
320
321===============
322*/
323void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)
324{
325 int i, j;
326 particle_t *p;
327 int colorMod = 0;
328
329 for (i=0; i<512; i++)
330 {
331 if (!free_particles)
332 return;
333 p = free_particles;
334 free_particles = p->next;
335 p->next = active_particles;
336 active_particles = p;
337
338 p->die = cl.time + 0.3;
339 p->color = colorStart + (colorMod % colorLength);
340 colorMod++;
341
342 p->type = pt_blob;
343 for (j=0 ; j<3 ; j++)
344 {
345 p->org[j] = org[j] + ((rand()%32)-16);
346 p->vel[j] = (rand()%512)-256;
347 }
348 }
349}
350
351/*
352===============
353R_BlobExplosion
354
355===============
356*/
357void R_BlobExplosion (vec3_t org)
358{
359 int i, j;
360 particle_t *p;
361
362 for (i=0 ; i<1024 ; i++)
363 {
364 if (!free_particles)
365 return;
366 p = free_particles;
367 free_particles = p->next;
368 p->next = active_particles;
369 active_particles = p;
370
371 p->die = cl.time + 1 + (rand()&8)*0.05;
372
373 if (i & 1)
374 {
375 p->type = pt_blob;
376 p->color = 66 + rand()%6;
377 for (j=0 ; j<3 ; j++)
378 {
379 p->org[j] = org[j] + ((rand()%32)-16);
380 p->vel[j] = (rand()%512)-256;
381 }
382 }
383 else
384 {
385 p->type = pt_blob2;
386 p->color = 150 + rand()%6;
387 for (j=0 ; j<3 ; j++)
388 {
389 p->org[j] = org[j] + ((rand()%32)-16);
390 p->vel[j] = (rand()%512)-256;
391 }
392 }
393 }
394}
395
396/*
397===============
398R_RunParticleEffect
399
400===============
401*/
402void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)
403{
404 int i, j;
405 particle_t *p;
406
407 for (i=0 ; i<count ; i++)
408 {
409 if (!free_particles)
410 return;
411 p = free_particles;
412 free_particles = p->next;
413 p->next = active_particles;
414 active_particles = p;
415
416 if (count == 1024)
417 { // rocket explosion
418 p->die = cl.time + 5;
419 p->color = ramp1[0];
420 p->ramp = rand()&3;
421 if (i & 1)
422 {
423 p->type = pt_explode;
424 for (j=0 ; j<3 ; j++)
425 {
426 p->org[j] = org[j] + ((rand()%32)-16);
427 p->vel[j] = (rand()%512)-256;
428 }
429 }
430 else
431 {
432 p->type = pt_explode2;
433 for (j=0 ; j<3 ; j++)
434 {
435 p->org[j] = org[j] + ((rand()%32)-16);
436 p->vel[j] = (rand()%512)-256;
437 }
438 }
439 }
440 else
441 {
442 p->die = cl.time + 0.1*(rand()%5);
443 p->color = (color&~7) + (rand()&7);
444 p->type = pt_slowgrav;
445 for (j=0 ; j<3 ; j++)
446 {
447 p->org[j] = org[j] + ((rand()&15)-8);
448 p->vel[j] = dir[j]*15;// + (rand()%300)-150;
449 }
450 }
451 }
452}
453
454
455/*
456===============
457R_LavaSplash
458
459===============
460*/
461void R_LavaSplash (vec3_t org)
462{
463 int i, j, k;
464 particle_t *p;
465 float vel;
466 vec3_t dir;
467
468 for (i=-16 ; i<16 ; i++)
469 for (j=-16 ; j<16 ; j++)
470 for (k=0 ; k<1 ; k++)
471 {
472 if (!free_particles)
473 return;
474 p = free_particles;
475 free_particles = p->next;
476 p->next = active_particles;
477 active_particles = p;
478
479 p->die = cl.time + 2 + (rand()&31) * 0.02;
480 p->color = 224 + (rand()&7);
481 p->type = pt_slowgrav;
482
483 dir[0] = j*8 + (rand()&7);
484 dir[1] = i*8 + (rand()&7);
485 dir[2] = 256;
486
487 p->org[0] = org[0] + dir[0];
488 p->org[1] = org[1] + dir[1];
489 p->org[2] = org[2] + (rand()&63);
490
491 VectorNormalizeNoRet (dir);
492 vel = 50 + (rand()&63);
493 VectorScale (dir, vel, p->vel);
494 }
495}
496
497/*
498===============
499R_TeleportSplash
500
501===============
502*/
503void R_TeleportSplash (vec3_t org)
504{
505 int i, j, k;
506 particle_t *p;
507 float vel;
508 vec3_t dir;
509
510 for (i=-16 ; i<16 ; i+=4)
511 for (j=-16 ; j<16 ; j+=4)
512 for (k=-24 ; k<32 ; k+=4)
513 {
514 if (!free_particles)
515 return;
516 p = free_particles;
517 free_particles = p->next;
518 p->next = active_particles;
519 active_particles = p;
520
521 p->die = cl.time + 0.2 + (rand()&7) * 0.02;
522 p->color = 7 + (rand()&7);
523 p->type = pt_slowgrav;
524
525 dir[0] = j*8;
526 dir[1] = i*8;
527 dir[2] = k*8;
528
529 p->org[0] = org[0] + i + (rand()&3);
530 p->org[1] = org[1] + j + (rand()&3);
531 p->org[2] = org[2] + k + (rand()&3);
532
533 VectorNormalizeNoRet (dir);
534 vel = 50 + (rand()&63);
535 VectorScale (dir, vel, p->vel);
536 }
537}
538
539void R_RocketTrail (vec3_t start, vec3_t end, int type)
540{
541 vec3_t vec;
542 float len;
543 int j;
544 particle_t *p;
545 int dec;
546 static int tracercount;
547
548 VectorSubtract (end, start, vec);
549 len = VectorNormalize (vec);
550 if (type < 128)
551 dec = 3;
552 else
553 {
554 dec = 1;
555 type -= 128;
556 }
557
558 while (len > 0)
559 {
560 len -= dec;
561
562 if (!free_particles)
563 return;
564 p = free_particles;
565 free_particles = p->next;
566 p->next = active_particles;
567 active_particles = p;
568
569 VectorCopy (vec3_origin, p->vel);
570 p->die = cl.time + 2;
571
572 switch (type)
573 {
574 case 0: // rocket trail
575 p->ramp = (rand()&3);
576 p->color = ramp3[(int)p->ramp];
577 p->type = pt_fire;
578 for (j=0 ; j<3 ; j++)
579 p->org[j] = start[j] + ((rand()%6)-3);
580 break;
581
582 case 1: // smoke smoke
583 p->ramp = (rand()&3) + 2;
584 p->color = ramp3[(int)p->ramp];
585 p->type = pt_fire;
586 for (j=0 ; j<3 ; j++)
587 p->org[j] = start[j] + ((rand()%6)-3);
588 break;
589
590 case 2: // blood
591 p->type = pt_grav;
592 p->color = 67 + (rand()&3);
593 for (j=0 ; j<3 ; j++)
594 p->org[j] = start[j] + ((rand()%6)-3);
595 break;
596
597 case 3:
598 case 5: // tracer
599 p->die = cl.time + 0.5;
600 p->type = pt_static;
601 if (type == 3)
602 p->color = 52 + ((tracercount&4)<<1);
603 else
604 p->color = 230 + ((tracercount&4)<<1);
605
606 tracercount++;
607
608 VectorCopy (start, p->org);
609 if (tracercount & 1)
610 {
611 p->vel[0] = 30*vec[1];
612 p->vel[1] = 30*-vec[0];
613 }
614 else
615 {
616 p->vel[0] = 30*-vec[1];
617 p->vel[1] = 30*vec[0];
618 }
619 break;
620
621 case 4: // slight blood
622 p->type = pt_grav;
623 p->color = 67 + (rand()&3);
624 for (j=0 ; j<3 ; j++)
625 p->org[j] = start[j] + ((rand()%6)-3);
626 len -= 3;
627 break;
628
629 case 6: // voor trail
630 p->color = 9*16 + 8 + (rand()&3);
631 p->type = pt_static;
632 p->die = cl.time + 0.3;
633 for (j=0 ; j<3 ; j++)
634 p->org[j] = start[j] + ((rand()&15)-8);
635 break;
636 }
637
638
639 VectorAdd (start, vec, start);
640 }
641}
642
643
644/*
645===============
646R_DrawParticles
647===============
648*/
649extern cvar_t sv_gravity;
650
651void R_DrawParticles (void)
652{
653 particle_t *p, *kill;
654 float grav;
655 int i;
656 float time2, time3;
657 float time1;
658 float dvel;
659 float frametime;
660
661#ifdef GLQUAKE
662 vec3_t up, right;
663 float scale;
664
665 GL_Bind(particletexture);
666 glEnable (GL_BLEND);
667 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
668 glBegin (GL_TRIANGLES);
669
670 VectorScale (vup, 1.5, up);
671 VectorScale (vright, 1.5, right);
672#else
673 D_StartParticles ();
674
675 VectorScale (vright, xscaleshrink, r_pright);
676 VectorScale (vup, yscaleshrink, r_pup);
677 VectorCopy (vpn, r_ppn);
678#endif
679 frametime = cl.time - cl.oldtime;
680 time3 = frametime * 15;
681 time2 = frametime * 10; // 15;
682 time1 = frametime * 5;
683 grav = frametime * sv_gravity.value * 0.05;
684 dvel = 4*frametime;
685
686 for ( ;; )
687 {
688 kill = active_particles;
689 if (kill && kill->die < cl.time)
690 {
691 active_particles = kill->next;
692 kill->next = free_particles;
693 free_particles = kill;
694 continue;
695 }
696 break;
697 }
698
699 for (p=active_particles ; p ; p=p->next)
700 {
701 for ( ;; )
702 {
703 kill = p->next;
704 if (kill && kill->die < cl.time)
705 {
706 p->next = kill->next;
707 kill->next = free_particles;
708 free_particles = kill;
709 continue;
710 }
711 break;
712 }
713
714#ifdef GLQUAKE
715 // hack a scale up to keep particles from disapearing
716 scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
717 + (p->org[2] - r_origin[2])*vpn[2];
718 if (scale < 20)
719 scale = 1;
720 else
721 scale = 1 + scale * 0.004;
722 glColor3ubv ((byte *)&d_8to24table[(int)p->color]);
723 glTexCoord2f (0,0);
724 glVertex3fv (p->org);
725 glTexCoord2f (1,0);
726 glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale);
727 glTexCoord2f (0,1);
728 glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale);
729#else
730 D_DrawParticle (p);
731#endif
732 p->org[0] += p->vel[0]*frametime;
733 p->org[1] += p->vel[1]*frametime;
734 p->org[2] += p->vel[2]*frametime;
735
736 switch (p->type)
737 {
738 case pt_static:
739 break;
740 case pt_fire:
741 p->ramp += time1;
742 if (p->ramp >= 6)
743 p->die = -1;
744 else
745 p->color = ramp3[(int)p->ramp];
746 p->vel[2] += grav;
747 break;
748
749 case pt_explode:
750 p->ramp += time2;
751 if (p->ramp >=8)
752 p->die = -1;
753 else
754 p->color = ramp1[(int)p->ramp];
755 for (i=0 ; i<3 ; i++)
756 p->vel[i] += p->vel[i]*dvel;
757 p->vel[2] -= grav;
758 break;
759
760 case pt_explode2:
761 p->ramp += time3;
762 if (p->ramp >=8)
763 p->die = -1;
764 else
765 p->color = ramp2[(int)p->ramp];
766 for (i=0 ; i<3 ; i++)
767 p->vel[i] -= p->vel[i]*frametime;
768 p->vel[2] -= grav;
769 break;
770
771 case pt_blob:
772 for (i=0 ; i<3 ; i++)
773 p->vel[i] += p->vel[i]*dvel;
774 p->vel[2] -= grav;
775 break;
776
777 case pt_blob2:
778 for (i=0 ; i<2 ; i++)
779 p->vel[i] -= p->vel[i]*dvel;
780 p->vel[2] -= grav;
781 break;
782
783 case pt_grav:
784#ifdef QUAKE2
785 p->vel[2] -= grav * 20;
786 break;
787#endif
788 case pt_slowgrav:
789 p->vel[2] -= grav;
790 break;
791 }
792 }
793
794#ifdef GLQUAKE
795 glEnd ();
796 glDisable (GL_BLEND);
797 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
798#else
799 D_EndParticles ();
800#endif
801}
802
diff --git a/apps/plugins/sdl/progs/quake/r_shared.h b/apps/plugins/sdl/progs/quake/r_shared.h
new file mode 100644
index 0000000000..f2a6db3096
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_shared.h
@@ -0,0 +1,157 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#ifndef GLQUAKE
21// r_shared.h: general refresh-related stuff shared between the refresh and the
22// driver
23
24// FIXME: clean up and move into d_iface.h
25
26#ifndef _R_SHARED_H_
27#define _R_SHARED_H_
28
29#define MAXVERTS 16 // max points in a surface polygon
30#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate
31 // polygon (while processing)
32// !!! if this is changed, it must be changed in d_ifacea.h too !!!
33#define MAXHEIGHT 1024
34#define MAXWIDTH 1280
35#define MAXDIMENSION ((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH)
36
37#define SIN_BUFFER_SIZE (MAXDIMENSION+CYCLE)
38
39#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to
40 // be farther away than anything in
41 // the scene
42
43//===================================================================
44
45extern void R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1);
46
47extern int cachewidth;
48extern pixel_t *cacheblock;
49extern int screenwidth;
50
51extern float pixelAspect;
52
53extern int r_drawnpolycount;
54
55extern cvar_t r_clearcolor;
56
57extern int sintable[SIN_BUFFER_SIZE];
58extern int intsintable[SIN_BUFFER_SIZE];
59
60extern vec3_t vup, base_vup;
61extern vec3_t vpn, base_vpn;
62extern vec3_t vright, base_vright;
63extern entity_t *currententity;
64
65#define NUMSTACKEDGES 2400
66#define MINEDGES NUMSTACKEDGES
67#define NUMSTACKSURFACES 800
68#define MINSURFACES NUMSTACKSURFACES
69#define MAXSPANS 3000
70
71// !!! if this is changed, it must be changed in asm_draw.h too !!!
72typedef struct espan_s
73{
74 int u, v, count;
75 struct espan_s *pnext;
76} espan_t;
77
78// FIXME: compress, make a union if that will help
79// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte
80typedef struct surf_s
81{
82 struct surf_s *next; // active surface stack in r_edge.c
83 struct surf_s *prev; // used in r_edge.c for active surf stack
84 struct espan_s *spans; // pointer to linked list of spans to draw
85 int key; // sorting key (BSP order)
86 int last_u; // set during tracing
87 int spanstate; // 0 = not in span
88 // 1 = in span
89 // -1 = in inverted span (end before
90 // start)
91 int flags; // currentface flags
92 void *data; // associated data like msurface_t
93 entity_t *entity;
94 float nearzi; // nearest 1/z on surface, for mipmapping
95 qboolean insubmodel;
96 float d_ziorigin, d_zistepu, d_zistepv;
97
98 int pad[2]; // to 64 bytes
99} surf_t;
100
101extern surf_t *surfaces, *surface_p, *surf_max;
102
103// surfaces are generated in back to front order by the bsp, so if a surf
104// pointer is greater than another one, it should be drawn in front
105// surfaces[1] is the background, and is used as the active surface stack.
106// surfaces[0] is a dummy, because index 0 is used to indicate no surface
107// attached to an edge_t
108
109//===================================================================
110
111extern vec3_t sxformaxis[4]; // s axis transformed into viewspace
112extern vec3_t txformaxis[4]; // t axis transformed into viewspac
113
114extern vec3_t modelorg, base_modelorg;
115
116extern float xcenter, ycenter;
117extern float xscale, yscale;
118extern float xscaleinv, yscaleinv;
119extern float xscaleshrink, yscaleshrink;
120
121extern int d_lightstylevalue[256]; // 8.8 frac of base light value
122
123extern void TransformVector (vec3_t in, vec3_t out);
124extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,
125 fixed8_t endvertu, fixed8_t endvertv);
126
127extern int r_skymade;
128extern void R_MakeSky (void);
129
130extern int ubasestep, errorterm, erroradjustup, erroradjustdown;
131
132// flags in finalvert_t.flags
133#define ALIAS_LEFT_CLIP 0x0001
134#define ALIAS_TOP_CLIP 0x0002
135#define ALIAS_RIGHT_CLIP 0x0004
136#define ALIAS_BOTTOM_CLIP 0x0008
137#define ALIAS_Z_CLIP 0x0010
138// !!! if this is changed, it must be changed in d_ifacea.h too !!!
139#define ALIAS_ONSEAM 0x0020 // also defined in modelgen.h;
140 // must be kept in sync
141#define ALIAS_XY_CLIP_MASK 0x000F
142
143// !!! if this is changed, it must be changed in asm_draw.h too !!!
144typedef struct edge_s
145{
146 fixed16_t u;
147 fixed16_t u_step;
148 struct edge_s *prev, *next;
149 unsigned short surfs[2];
150 struct edge_s *nextremove;
151 float nearzi;
152 medge_t *owner;
153} edge_t;
154
155#endif // _R_SHARED_H_
156
157#endif // GLQUAKE
diff --git a/apps/plugins/sdl/progs/quake/r_sky.c b/apps/plugins/sdl/progs/quake/r_sky.c
new file mode 100644
index 0000000000..c8bfffd2c5
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_sky.c
@@ -0,0 +1,280 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_sky.c
21
22#include "quakedef.h"
23#include "r_local.h"
24#include "d_local.h"
25
26
27int iskyspeed = 8;
28int iskyspeed2 = 2;
29float skyspeed, skyspeed2;
30
31float skytime;
32
33byte *r_skysource;
34
35int r_skymade;
36int r_skydirect; // not used?
37
38
39// TODO: clean up these routines
40
41byte bottomsky[128*131];
42byte bottommask[128*131];
43byte newsky[128*256]; // newsky and topsky both pack in here, 128 bytes
44 // of newsky on the left of each scan, 128 bytes
45 // of topsky on the right, because the low-level
46 // drawers need 256-byte scan widths
47
48
49/*
50=============
51R_InitSky
52
53A sky texture is 256*128, with the right side being a masked overlay
54==============
55*/
56void R_InitSky (texture_t *mt)
57{
58 int i, j;
59 byte *src;
60
61 src = (byte *)mt + mt->offsets[0];
62
63 for (i=0 ; i<128 ; i++)
64 {
65 for (j=0 ; j<128 ; j++)
66 {
67 newsky[(i*256) + j + 128] = src[i*256 + j + 128];
68 }
69 }
70
71 for (i=0 ; i<128 ; i++)
72 {
73 for (j=0 ; j<131 ; j++)
74 {
75 if (src[i*256 + (j & 0x7F)])
76 {
77 bottomsky[(i*131) + j] = src[i*256 + (j & 0x7F)];
78 bottommask[(i*131) + j] = 0;
79 }
80 else
81 {
82 bottomsky[(i*131) + j] = 0;
83 bottommask[(i*131) + j] = 0xff;
84 }
85 }
86 }
87
88 r_skysource = newsky;
89}
90
91
92/*
93=================
94R_MakeSky
95=================
96*/
97void R_MakeSky (void)
98{
99 int x, y;
100 int ofs, baseofs;
101 int xshift, yshift;
102 unsigned *pnewsky;
103 static int xlast = -1, ylast = -1;
104
105 xshift = skytime*skyspeed;
106 yshift = skytime*skyspeed;
107
108 if ((xshift == xlast) && (yshift == ylast))
109 return;
110
111 xlast = xshift;
112 ylast = yshift;
113
114 pnewsky = (unsigned *)&newsky[0];
115
116 for (y=0 ; y<SKYSIZE ; y++)
117 {
118 baseofs = ((y+yshift) & SKYMASK) * 131;
119
120// FIXME: clean this up
121#if UNALIGNED_OK
122
123 for (x=0 ; x<SKYSIZE ; x += 4)
124 {
125 ofs = baseofs + ((x+xshift) & SKYMASK);
126
127 // PORT: unaligned dword access to bottommask and bottomsky
128
129 *pnewsky = (*(pnewsky + (128 / sizeof (unsigned))) &
130 *(unsigned *)&bottommask[ofs]) |
131 *(unsigned *)&bottomsky[ofs];
132 pnewsky++;
133 }
134
135#else
136
137 for (x=0 ; x<SKYSIZE ; x++)
138 {
139 ofs = baseofs + ((x+xshift) & SKYMASK);
140
141 *(byte *)pnewsky = (*((byte *)pnewsky + 128) &
142 *(byte *)&bottommask[ofs]) |
143 *(byte *)&bottomsky[ofs];
144 pnewsky = (unsigned *)((byte *)pnewsky + 1);
145 }
146
147#endif
148
149 pnewsky += 128 / sizeof (unsigned);
150 }
151
152 r_skymade = 1;
153}
154
155
156/*
157=================
158R_GenSkyTile
159=================
160*/
161void R_GenSkyTile (void *pdest)
162{
163 int x, y;
164 int ofs, baseofs;
165 int xshift, yshift;
166 unsigned *pnewsky;
167 unsigned *pd;
168
169 xshift = skytime*skyspeed;
170 yshift = skytime*skyspeed;
171
172 pnewsky = (unsigned *)&newsky[0];
173 pd = (unsigned *)pdest;
174
175 for (y=0 ; y<SKYSIZE ; y++)
176 {
177 baseofs = ((y+yshift) & SKYMASK) * 131;
178
179// FIXME: clean this up
180#if UNALIGNED_OK
181
182 for (x=0 ; x<SKYSIZE ; x += 4)
183 {
184 ofs = baseofs + ((x+xshift) & SKYMASK);
185
186 // PORT: unaligned dword access to bottommask and bottomsky
187
188 *pd = (*(pnewsky + (128 / sizeof (unsigned))) &
189 *(unsigned *)&bottommask[ofs]) |
190 *(unsigned *)&bottomsky[ofs];
191 pnewsky++;
192 pd++;
193 }
194
195#else
196
197 for (x=0 ; x<SKYSIZE ; x++)
198 {
199 ofs = baseofs + ((x+xshift) & SKYMASK);
200
201 *(byte *)pd = (*((byte *)pnewsky + 128) &
202 *(byte *)&bottommask[ofs]) |
203 *(byte *)&bottomsky[ofs];
204 pnewsky = (unsigned *)((byte *)pnewsky + 1);
205 pd = (unsigned *)((byte *)pd + 1);
206 }
207
208#endif
209
210 pnewsky += 128 / sizeof (unsigned);
211 }
212}
213
214
215/*
216=================
217R_GenSkyTile16
218=================
219*/
220void R_GenSkyTile16 (void *pdest)
221{
222 int x, y;
223 int ofs, baseofs;
224 int xshift, yshift;
225 byte *pnewsky;
226 unsigned short *pd;
227
228 xshift = skytime * skyspeed;
229 yshift = skytime * skyspeed;
230
231 pnewsky = (byte *)&newsky[0];
232 pd = (unsigned short *)pdest;
233
234 for (y=0 ; y<SKYSIZE ; y++)
235 {
236 baseofs = ((y+yshift) & SKYMASK) * 131;
237
238// FIXME: clean this up
239// FIXME: do faster unaligned version?
240 for (x=0 ; x<SKYSIZE ; x++)
241 {
242 ofs = baseofs + ((x+xshift) & SKYMASK);
243
244 *pd = d_8to16table[(*(pnewsky + 128) &
245 *(byte *)&bottommask[ofs]) |
246 *(byte *)&bottomsky[ofs]];
247 pnewsky++;
248 pd++;
249 }
250
251 pnewsky += TILE_SIZE;
252 }
253}
254
255
256/*
257=============
258R_SetSkyFrame
259==============
260*/
261void R_SetSkyFrame (void)
262{
263 int g, s1, s2;
264 float temp;
265
266 skyspeed = iskyspeed;
267 skyspeed2 = iskyspeed2;
268
269 g = GreatestCommonDivisor (iskyspeed, iskyspeed2);
270 s1 = iskyspeed / g;
271 s2 = iskyspeed2 / g;
272 temp = SKYSIZE * s1 * s2;
273
274 skytime = cl.time - ((int)(cl.time / temp) * temp);
275
276
277 r_skymade = 0;
278}
279
280
diff --git a/apps/plugins/sdl/progs/quake/r_sprite.c b/apps/plugins/sdl/progs/quake/r_sprite.c
new file mode 100644
index 0000000000..4ab8e0ef4d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_sprite.c
@@ -0,0 +1,401 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_sprite.c
21
22#include "quakedef.h"
23#include "r_local.h"
24
25static int clip_current;
26static vec5_t clip_verts[2][MAXWORKINGVERTS];
27static int sprite_width, sprite_height;
28
29spritedesc_t r_spritedesc;
30
31
32/*
33================
34R_RotateSprite
35================
36*/
37void R_RotateSprite (float beamlength)
38{
39 vec3_t vec;
40
41 if (beamlength == 0.0)
42 return;
43
44 VectorScale (r_spritedesc.vpn, -beamlength, vec);
45 VectorAdd (r_entorigin, vec, r_entorigin);
46 VectorSubtract (modelorg, vec, modelorg);
47}
48
49
50/*
51=============
52R_ClipSpriteFace
53
54Clips the winding at clip_verts[clip_current] and changes clip_current
55Throws out the back side
56==============
57*/
58int R_ClipSpriteFace (int nump, clipplane_t *pclipplane)
59{
60 int i, outcount;
61 float dists[MAXWORKINGVERTS+1];
62 float frac, clipdist, *pclipnormal;
63 float *in, *instep, *outstep, *vert2;
64
65 clipdist = pclipplane->dist;
66 pclipnormal = pclipplane->normal;
67
68// calc dists
69 if (clip_current)
70 {
71 in = clip_verts[1][0];
72 outstep = clip_verts[0][0];
73 clip_current = 0;
74 }
75 else
76 {
77 in = clip_verts[0][0];
78 outstep = clip_verts[1][0];
79 clip_current = 1;
80 }
81
82 instep = in;
83 for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
84 {
85 dists[i] = DotProduct (instep, pclipnormal) - clipdist;
86 }
87
88// handle wraparound case
89 dists[nump] = dists[0];
90 Q_memcpy (instep, in, sizeof (vec5_t));
91
92
93// clip the winding
94 instep = in;
95 outcount = 0;
96
97 for (i=0 ; i<nump ; i++, instep += sizeof (vec5_t) / sizeof (float))
98 {
99 if (dists[i] >= 0)
100 {
101 Q_memcpy (outstep, instep, sizeof (vec5_t));
102 outstep += sizeof (vec5_t) / sizeof (float);
103 outcount++;
104 }
105
106 if (dists[i] == 0 || dists[i+1] == 0)
107 continue;
108
109 if ( (dists[i] > 0) == (dists[i+1] > 0) )
110 continue;
111
112 // split it into a new vertex
113 frac = dists[i] / (dists[i] - dists[i+1]);
114
115 vert2 = instep + sizeof (vec5_t) / sizeof (float);
116
117 outstep[0] = instep[0] + frac*(vert2[0] - instep[0]);
118 outstep[1] = instep[1] + frac*(vert2[1] - instep[1]);
119 outstep[2] = instep[2] + frac*(vert2[2] - instep[2]);
120 outstep[3] = instep[3] + frac*(vert2[3] - instep[3]);
121 outstep[4] = instep[4] + frac*(vert2[4] - instep[4]);
122
123 outstep += sizeof (vec5_t) / sizeof (float);
124 outcount++;
125 }
126
127 return outcount;
128}
129
130
131/*
132================
133R_SetupAndDrawSprite
134================
135*/
136void R_SetupAndDrawSprite ()
137{
138 int i, nump;
139 float dot, scale, *pv;
140 vec5_t *pverts;
141 vec3_t left, up, right, down, transformed, local;
142 emitpoint_t outverts[MAXWORKINGVERTS+1], *pout;
143
144 dot = DotProduct (r_spritedesc.vpn, modelorg);
145
146// backface cull
147 if (dot >= 0)
148 return;
149
150// build the sprite poster in worldspace
151 VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right);
152 VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up);
153 VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left);
154 VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down);
155
156 pverts = clip_verts[0];
157
158 pverts[0][0] = r_entorigin[0] + up[0] + left[0];
159 pverts[0][1] = r_entorigin[1] + up[1] + left[1];
160 pverts[0][2] = r_entorigin[2] + up[2] + left[2];
161 pverts[0][3] = 0;
162 pverts[0][4] = 0;
163
164 pverts[1][0] = r_entorigin[0] + up[0] + right[0];
165 pverts[1][1] = r_entorigin[1] + up[1] + right[1];
166 pverts[1][2] = r_entorigin[2] + up[2] + right[2];
167 pverts[1][3] = sprite_width;
168 pverts[1][4] = 0;
169
170 pverts[2][0] = r_entorigin[0] + down[0] + right[0];
171 pverts[2][1] = r_entorigin[1] + down[1] + right[1];
172 pverts[2][2] = r_entorigin[2] + down[2] + right[2];
173 pverts[2][3] = sprite_width;
174 pverts[2][4] = sprite_height;
175
176 pverts[3][0] = r_entorigin[0] + down[0] + left[0];
177 pverts[3][1] = r_entorigin[1] + down[1] + left[1];
178 pverts[3][2] = r_entorigin[2] + down[2] + left[2];
179 pverts[3][3] = 0;
180 pverts[3][4] = sprite_height;
181
182// clip to the frustum in worldspace
183 nump = 4;
184 clip_current = 0;
185
186 for (i=0 ; i<4 ; i++)
187 {
188 nump = R_ClipSpriteFace (nump, &view_clipplanes[i]);
189 if (nump < 3)
190 return;
191 if (nump >= MAXWORKINGVERTS)
192 Sys_Error("R_SetupAndDrawSprite: too many points");
193 }
194
195// transform vertices into viewspace and project
196 pv = &clip_verts[clip_current][0][0];
197 r_spritedesc.nearzi = -999999;
198
199 for (i=0 ; i<nump ; i++)
200 {
201 VectorSubtract (pv, r_origin, local);
202 TransformVector (local, transformed);
203
204 if (transformed[2] < NEAR_CLIP)
205 transformed[2] = NEAR_CLIP;
206
207 pout = &outverts[i];
208 pout->zi = 1.0 / transformed[2];
209 if (pout->zi > r_spritedesc.nearzi)
210 r_spritedesc.nearzi = pout->zi;
211
212 pout->s = pv[3];
213 pout->t = pv[4];
214
215 scale = xscale * pout->zi;
216 pout->u = (xcenter + scale * transformed[0]);
217
218 scale = yscale * pout->zi;
219 pout->v = (ycenter - scale * transformed[1]);
220
221 pv += sizeof (vec5_t) / sizeof (*pv);
222 }
223
224// draw it
225 r_spritedesc.nump = nump;
226 r_spritedesc.pverts = outverts;
227 D_DrawSprite ();
228}
229
230
231/*
232================
233R_GetSpriteframe
234================
235*/
236mspriteframe_t *R_GetSpriteframe (msprite_t *psprite)
237{
238 mspritegroup_t *pspritegroup;
239 mspriteframe_t *pspriteframe;
240 int i, numframes, frame;
241 float *pintervals, fullinterval, targettime, time;
242
243 frame = currententity->frame;
244
245 if ((frame >= psprite->numframes) || (frame < 0))
246 {
247 Con_Printf ("R_DrawSprite: no such frame %d\n", frame);
248 frame = 0;
249 }
250
251 if (psprite->frames[frame].type == SPR_SINGLE)
252 {
253 pspriteframe = psprite->frames[frame].frameptr;
254 }
255 else
256 {
257 pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
258 pintervals = pspritegroup->intervals;
259 numframes = pspritegroup->numframes;
260 fullinterval = pintervals[numframes-1];
261
262 time = cl.time + currententity->syncbase;
263
264 // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
265 // are positive, so we don't have to worry about division by 0
266 targettime = time - ((int)(time / fullinterval)) * fullinterval;
267
268 for (i=0 ; i<(numframes-1) ; i++)
269 {
270 if (pintervals[i] > targettime)
271 break;
272 }
273
274 pspriteframe = pspritegroup->frames[i];
275 }
276
277 return pspriteframe;
278}
279
280
281/*
282================
283R_DrawSprite
284================
285*/
286void R_DrawSprite (void)
287{
288 int i;
289 msprite_t *psprite;
290 vec3_t tvec;
291 float dot, angle, sr, cr;
292
293 psprite = currententity->model->cache.data;
294
295 r_spritedesc.pspriteframe = R_GetSpriteframe (psprite);
296
297 sprite_width = r_spritedesc.pspriteframe->width;
298 sprite_height = r_spritedesc.pspriteframe->height;
299
300// TODO: make this caller-selectable
301 if (psprite->type == SPR_FACING_UPRIGHT)
302 {
303 // generate the sprite's axes, with vup straight up in worldspace, and
304 // r_spritedesc.vright perpendicular to modelorg.
305 // This will not work if the view direction is very close to straight up or
306 // down, because the cross product will be between two nearly parallel
307 // vectors and starts to approach an undefined state, so we don't draw if
308 // the two vectors are less than 1 degree apart
309 tvec[0] = -modelorg[0];
310 tvec[1] = -modelorg[1];
311 tvec[2] = -modelorg[2];
312 VectorNormalizeNoRet (tvec);
313 dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
314 // r_spritedesc.vup is 0, 0, 1
315 if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
316 return;
317 r_spritedesc.vup[0] = 0;
318 r_spritedesc.vup[1] = 0;
319 r_spritedesc.vup[2] = 1;
320 r_spritedesc.vright[0] = tvec[1];
321 // CrossProduct(r_spritedesc.vup, -modelorg,
322 r_spritedesc.vright[1] = -tvec[0];
323 // r_spritedesc.vright)
324 r_spritedesc.vright[2] = 0;
325 VectorNormalizeNoRet (r_spritedesc.vright);
326 r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
327 r_spritedesc.vpn[1] = r_spritedesc.vright[0];
328 r_spritedesc.vpn[2] = 0;
329 // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
330 // r_spritedesc.vpn)
331 }
332 else if (psprite->type == SPR_VP_PARALLEL)
333 {
334 // generate the sprite's axes, completely parallel to the viewplane. There
335 // are no problem situations, because the sprite is always in the same
336 // position relative to the viewer
337 for (i=0 ; i<3 ; i++)
338 {
339 r_spritedesc.vup[i] = vup[i];
340 r_spritedesc.vright[i] = vright[i];
341 r_spritedesc.vpn[i] = vpn[i];
342 }
343 }
344 else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT)
345 {
346 // generate the sprite's axes, with vup straight up in worldspace, and
347 // r_spritedesc.vright parallel to the viewplane.
348 // This will not work if the view direction is very close to straight up or
349 // down, because the cross product will be between two nearly parallel
350 // vectors and starts to approach an undefined state, so we don't draw if
351 // the two vectors are less than 1 degree apart
352 dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
353 // r_spritedesc.vup is 0, 0, 1
354 if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
355 return;
356 r_spritedesc.vup[0] = 0;
357 r_spritedesc.vup[1] = 0;
358 r_spritedesc.vup[2] = 1;
359 r_spritedesc.vright[0] = vpn[1];
360 // CrossProduct (r_spritedesc.vup, vpn,
361 r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright)
362 r_spritedesc.vright[2] = 0;
363 VectorNormalizeNoRet (r_spritedesc.vright);
364 r_spritedesc.vpn[0] = -r_spritedesc.vright[1];
365 r_spritedesc.vpn[1] = r_spritedesc.vright[0];
366 r_spritedesc.vpn[2] = 0;
367 // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
368 // r_spritedesc.vpn)
369 }
370 else if (psprite->type == SPR_ORIENTED)
371 {
372 // generate the sprite's axes, according to the sprite's world orientation
373 AngleVectors (currententity->angles, r_spritedesc.vpn,
374 r_spritedesc.vright, r_spritedesc.vup);
375 }
376 else if (psprite->type == SPR_VP_PARALLEL_ORIENTED)
377 {
378 // generate the sprite's axes, parallel to the viewplane, but rotated in
379 // that plane around the center according to the sprite entity's roll
380 // angle. So vpn stays the same, but vright and vup rotate
381 angle = currententity->angles[ROLL] * (M_PI*2 / 360);
382 sr = sin(angle);
383 cr = cos(angle);
384
385 for (i=0 ; i<3 ; i++)
386 {
387 r_spritedesc.vpn[i] = vpn[i];
388 r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr;
389 r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr;
390 }
391 }
392 else
393 {
394 Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type);
395 }
396
397 R_RotateSprite (psprite->beamlength);
398
399 R_SetupAndDrawSprite ();
400}
401
diff --git a/apps/plugins/sdl/progs/quake/r_surf.c b/apps/plugins/sdl/progs/quake/r_surf.c
new file mode 100644
index 0000000000..a2436d51b2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_surf.c
@@ -0,0 +1,678 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_surf.c: surface-related refresh code
21
22#include "quakedef.h"
23#include "r_local.h"
24
25drawsurf_t r_drawsurf;
26
27int lightleft, sourcesstep, blocksize, sourcetstep;
28int lightdelta, lightdeltastep;
29int lightright, lightleftstep, lightrightstep, blockdivshift;
30unsigned blockdivmask;
31void *prowdestbase;
32unsigned char *pbasesource;
33int surfrowbytes; // used by ASM files
34unsigned *r_lightptr;
35int r_stepback;
36int r_lightwidth;
37int r_numhblocks, r_numvblocks;
38unsigned char *r_source, *r_sourcemax;
39
40void R_DrawSurfaceBlock8_mip0 (void);
41void R_DrawSurfaceBlock8_mip1 (void);
42void R_DrawSurfaceBlock8_mip2 (void);
43void R_DrawSurfaceBlock8_mip3 (void);
44
45static void (*surfmiptable[4])(void) = {
46 R_DrawSurfaceBlock8_mip0,
47 R_DrawSurfaceBlock8_mip1,
48 R_DrawSurfaceBlock8_mip2,
49 R_DrawSurfaceBlock8_mip3
50};
51
52
53
54unsigned blocklights[18*18];
55
56/*
57===============
58R_AddDynamicLights
59===============
60*/
61void R_AddDynamicLights (void)
62{
63 msurface_t *surf;
64 int lnum;
65 int sd, td;
66 float dist, rad, minlight;
67 vec3_t impact, local;
68 int s, t;
69 int i;
70 int smax, tmax;
71 mtexinfo_t *tex;
72
73 surf = r_drawsurf.surf;
74 smax = (surf->extents[0]>>4)+1;
75 tmax = (surf->extents[1]>>4)+1;
76 tex = surf->texinfo;
77
78 for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
79 {
80 if ( !(surf->dlightbits & (1<<lnum) ) )
81 continue; // not lit by this light
82
83 rad = cl_dlights[lnum].radius;
84 dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
85 surf->plane->dist;
86 rad -= fabs(dist);
87 minlight = cl_dlights[lnum].minlight;
88 if (rad < minlight)
89 continue;
90 minlight = rad - minlight;
91
92 for (i=0 ; i<3 ; i++)
93 {
94 impact[i] = cl_dlights[lnum].origin[i] -
95 surf->plane->normal[i]*dist;
96 }
97
98 local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
99 local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
100
101 local[0] -= surf->texturemins[0];
102 local[1] -= surf->texturemins[1];
103
104 for (t = 0 ; t<tmax ; t++)
105 {
106 td = local[1] - t*16;
107 if (td < 0)
108 td = -td;
109 for (s=0 ; s<smax ; s++)
110 {
111 sd = local[0] - s*16;
112 if (sd < 0)
113 sd = -sd;
114 if (sd > td)
115 dist = sd + (td>>1);
116 else
117 dist = td + (sd>>1);
118 if (dist < minlight)
119#ifdef QUAKE2
120 {
121 unsigned temp;
122 temp = (rad - dist)*256;
123 i = t*smax + s;
124 if (!cl_dlights[lnum].dark)
125 blocklights[i] += temp;
126 else
127 {
128 if (blocklights[i] > temp)
129 blocklights[i] -= temp;
130 else
131 blocklights[i] = 0;
132 }
133 }
134#else
135 blocklights[t*smax + s] += (rad - dist)*256;
136#endif
137 }
138 }
139 }
140}
141
142/*
143===============
144R_BuildLightMap
145
146Combine and scale multiple lightmaps into the 8.8 format in blocklights
147===============
148*/
149void R_BuildLightMap (void)
150{
151 int smax, tmax;
152 int t;
153 int i, size;
154 byte *lightmap;
155 unsigned scale;
156 int maps;
157 msurface_t *surf;
158
159 surf = r_drawsurf.surf;
160
161 smax = (surf->extents[0]>>4)+1;
162 tmax = (surf->extents[1]>>4)+1;
163 size = smax*tmax;
164 lightmap = surf->samples;
165
166 if (r_fullbright.value || !cl.worldmodel->lightdata)
167 {
168 for (i=0 ; i<size ; i++)
169 blocklights[i] = 0;
170 return;
171 }
172
173// clear to ambient
174 for (i=0 ; i<size ; i++)
175 blocklights[i] = r_refdef.ambientlight<<8;
176
177
178// add all the lightmaps
179 if (lightmap)
180 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
181 maps++)
182 {
183 scale = r_drawsurf.lightadj[maps]; // 8.8 fraction
184 for (i=0 ; i<size ; i++)
185 blocklights[i] += lightmap[i] * scale;
186 lightmap += size; // skip to next lightmap
187 }
188
189// add all the dynamic lights
190 if (surf->dlightframe == r_framecount)
191 R_AddDynamicLights ();
192
193// bound, invert, and shift
194 for (i=0 ; i<size ; i++)
195 {
196 t = (255*256 - (int)blocklights[i]) >> (8 - VID_CBITS);
197
198 if (t < (1 << 6))
199 t = (1 << 6);
200
201 blocklights[i] = t;
202 }
203}
204
205
206/*
207===============
208R_TextureAnimation
209
210Returns the proper texture for a given time and base texture
211===============
212*/
213texture_t *R_TextureAnimation (texture_t *base)
214{
215 int reletive;
216 int count;
217
218 if (currententity->frame)
219 {
220 if (base->alternate_anims)
221 base = base->alternate_anims;
222 }
223
224 if (!base->anim_total)
225 return base;
226
227 reletive = (int)(cl.time*10) % base->anim_total;
228
229 count = 0;
230 while (base->anim_min > reletive || base->anim_max <= reletive)
231 {
232 base = base->anim_next;
233 if (!base)
234 Sys_Error ("R_TextureAnimation: broken cycle");
235 if (++count > 100)
236 Sys_Error ("R_TextureAnimation: infinite cycle");
237 }
238
239 return base;
240}
241
242
243/*
244===============
245R_DrawSurface
246===============
247*/
248void R_DrawSurface (void)
249{
250 unsigned char *basetptr;
251 int smax, tmax, twidth;
252 int u;
253 int soffset, basetoffset, texwidth;
254 int horzblockstep;
255 unsigned char *pcolumndest;
256 void (*pblockdrawer)(void);
257 texture_t *mt;
258
259// calculate the lightings
260 R_BuildLightMap ();
261
262 surfrowbytes = r_drawsurf.rowbytes;
263
264 mt = r_drawsurf.texture;
265
266 r_source = (byte *)mt + mt->offsets[r_drawsurf.surfmip];
267
268// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
269// from a source range of 0 - 255
270
271 texwidth = mt->width >> r_drawsurf.surfmip;
272
273 blocksize = 16 >> r_drawsurf.surfmip;
274 blockdivshift = 4 - r_drawsurf.surfmip;
275 blockdivmask = (1 << blockdivshift) - 1;
276
277 r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
278
279 r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
280 r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
281
282//==============================
283
284 if (r_pixbytes == 1)
285 {
286 pblockdrawer = surfmiptable[r_drawsurf.surfmip];
287 // TODO: only needs to be set when there is a display settings change
288 horzblockstep = blocksize;
289 }
290 else
291 {
292 pblockdrawer = R_DrawSurfaceBlock16;
293 // TODO: only needs to be set when there is a display settings change
294 horzblockstep = blocksize << 1;
295 }
296
297 smax = mt->width >> r_drawsurf.surfmip;
298 twidth = texwidth;
299 tmax = mt->height >> r_drawsurf.surfmip;
300 sourcetstep = texwidth;
301 r_stepback = tmax * twidth;
302
303 r_sourcemax = r_source + (tmax * smax);
304
305 soffset = r_drawsurf.surf->texturemins[0];
306 basetoffset = r_drawsurf.surf->texturemins[1];
307
308// << 16 components are to guarantee positive values for %
309 soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
310 basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
311 + (tmax << 16)) % tmax) * twidth)];
312
313 pcolumndest = r_drawsurf.surfdat;
314
315 for (u=0 ; u<r_numhblocks; u++)
316 {
317 r_lightptr = blocklights + u;
318
319 prowdestbase = pcolumndest;
320
321 pbasesource = basetptr + soffset;
322
323 (*pblockdrawer)();
324
325 soffset = soffset + blocksize;
326 if (soffset >= smax)
327 soffset = 0;
328
329 pcolumndest += horzblockstep;
330 }
331}
332
333
334//=============================================================================
335
336#if !id386
337
338/*
339================
340R_DrawSurfaceBlock8_mip0
341================
342*/
343void R_DrawSurfaceBlock8_mip0 (void)
344{
345 int v, i, b, lightstep, lighttemp, light;
346 unsigned char pix, *psource, *prowdest;
347
348 psource = pbasesource;
349 prowdest = prowdestbase;
350
351 for (v=0 ; v<r_numvblocks ; v++)
352 {
353 // FIXME: make these locals?
354 // FIXME: use delta rather than both right and left, like ASM?
355 lightleft = r_lightptr[0];
356 lightright = r_lightptr[1];
357 r_lightptr += r_lightwidth;
358 lightleftstep = (r_lightptr[0] - lightleft) >> 4;
359 lightrightstep = (r_lightptr[1] - lightright) >> 4;
360
361 for (i=0 ; i<16 ; i++)
362 {
363 lighttemp = lightleft - lightright;
364 lightstep = lighttemp >> 4;
365
366 light = lightright;
367
368 for (b=15; b>=0; b--)
369 {
370 pix = psource[b];
371 prowdest[b] = ((unsigned char *)vid.colormap)
372 [(light & 0xFF00) + pix];
373 light += lightstep;
374 }
375
376 psource += sourcetstep;
377 lightright += lightrightstep;
378 lightleft += lightleftstep;
379 prowdest += surfrowbytes;
380 }
381
382 if (psource >= r_sourcemax)
383 psource -= r_stepback;
384 }
385}
386
387
388/*
389================
390R_DrawSurfaceBlock8_mip1
391================
392*/
393void R_DrawSurfaceBlock8_mip1 (void)
394{
395 int v, i, b, lightstep, lighttemp, light;
396 unsigned char pix, *psource, *prowdest;
397
398 psource = pbasesource;
399 prowdest = prowdestbase;
400
401 for (v=0 ; v<r_numvblocks ; v++)
402 {
403 // FIXME: make these locals?
404 // FIXME: use delta rather than both right and left, like ASM?
405 lightleft = r_lightptr[0];
406 lightright = r_lightptr[1];
407 r_lightptr += r_lightwidth;
408 lightleftstep = (r_lightptr[0] - lightleft) >> 3;
409 lightrightstep = (r_lightptr[1] - lightright) >> 3;
410
411 for (i=0 ; i<8 ; i++)
412 {
413 lighttemp = lightleft - lightright;
414 lightstep = lighttemp >> 3;
415
416 light = lightright;
417
418 for (b=7; b>=0; b--)
419 {
420 pix = psource[b];
421 prowdest[b] = ((unsigned char *)vid.colormap)
422 [(light & 0xFF00) + pix];
423 light += lightstep;
424 }
425
426 psource += sourcetstep;
427 lightright += lightrightstep;
428 lightleft += lightleftstep;
429 prowdest += surfrowbytes;
430 }
431
432 if (psource >= r_sourcemax)
433 psource -= r_stepback;
434 }
435}
436
437
438/*
439================
440R_DrawSurfaceBlock8_mip2
441================
442*/
443void R_DrawSurfaceBlock8_mip2 (void)
444{
445 int v, i, b, lightstep, lighttemp, light;
446 unsigned char pix, *psource, *prowdest;
447
448 psource = pbasesource;
449 prowdest = prowdestbase;
450
451 for (v=0 ; v<r_numvblocks ; v++)
452 {
453 // FIXME: make these locals?
454 // FIXME: use delta rather than both right and left, like ASM?
455 lightleft = r_lightptr[0];
456 lightright = r_lightptr[1];
457 r_lightptr += r_lightwidth;
458 lightleftstep = (r_lightptr[0] - lightleft) >> 2;
459 lightrightstep = (r_lightptr[1] - lightright) >> 2;
460
461 for (i=0 ; i<4 ; i++)
462 {
463 lighttemp = lightleft - lightright;
464 lightstep = lighttemp >> 2;
465
466 light = lightright;
467
468 for (b=3; b>=0; b--)
469 {
470 pix = psource[b];
471 prowdest[b] = ((unsigned char *)vid.colormap)
472 [(light & 0xFF00) + pix];
473 light += lightstep;
474 }
475
476 psource += sourcetstep;
477 lightright += lightrightstep;
478 lightleft += lightleftstep;
479 prowdest += surfrowbytes;
480 }
481
482 if (psource >= r_sourcemax)
483 psource -= r_stepback;
484 }
485}
486
487
488/*
489================
490R_DrawSurfaceBlock8_mip3
491================
492*/
493void R_DrawSurfaceBlock8_mip3 (void)
494{
495 int v, i, b, lightstep, lighttemp, light;
496 unsigned char pix, *psource, *prowdest;
497
498 psource = pbasesource;
499 prowdest = prowdestbase;
500
501 for (v=0 ; v<r_numvblocks ; v++)
502 {
503 // FIXME: make these locals?
504 // FIXME: use delta rather than both right and left, like ASM?
505 lightleft = r_lightptr[0];
506 lightright = r_lightptr[1];
507 r_lightptr += r_lightwidth;
508 lightleftstep = (r_lightptr[0] - lightleft) >> 1;
509 lightrightstep = (r_lightptr[1] - lightright) >> 1;
510
511 for (i=0 ; i<2 ; i++)
512 {
513 lighttemp = lightleft - lightright;
514 lightstep = lighttemp >> 1;
515
516 light = lightright;
517
518 for (b=1; b>=0; b--)
519 {
520 pix = psource[b];
521 prowdest[b] = ((unsigned char *)vid.colormap)
522 [(light & 0xFF00) + pix];
523 light += lightstep;
524 }
525
526 psource += sourcetstep;
527 lightright += lightrightstep;
528 lightleft += lightleftstep;
529 prowdest += surfrowbytes;
530 }
531
532 if (psource >= r_sourcemax)
533 psource -= r_stepback;
534 }
535}
536
537
538/*
539================
540R_DrawSurfaceBlock16
541
542FIXME: make this work
543================
544*/
545void R_DrawSurfaceBlock16 (void)
546{
547 int k;
548 unsigned char *psource;
549 int lighttemp, lightstep, light;
550 unsigned short *prowdest;
551
552 prowdest = (unsigned short *)prowdestbase;
553
554 for (k=0 ; k<blocksize ; k++)
555 {
556 unsigned short *pdest;
557 unsigned char pix;
558 int b;
559
560 psource = pbasesource;
561 lighttemp = lightright - lightleft;
562 lightstep = lighttemp >> blockdivshift;
563
564 light = lightleft;
565 pdest = prowdest;
566
567 for (b=0; b<blocksize; b++)
568 {
569 pix = *psource;
570 *pdest = vid.colormap16[(light & 0xFF00) + pix];
571 psource += sourcesstep;
572 pdest++;
573 light += lightstep;
574 }
575
576 pbasesource += sourcetstep;
577 lightright += lightrightstep;
578 lightleft += lightleftstep;
579 prowdest = (unsigned short *)((long)prowdest + surfrowbytes);
580 }
581
582 prowdestbase = prowdest;
583}
584
585#endif
586
587
588//============================================================================
589
590/*
591================
592R_GenTurbTile
593================
594*/
595void R_GenTurbTile (pixel_t *pbasetex, void *pdest)
596{
597 int *turb;
598 int i, j, s, t;
599 byte *pd;
600
601 turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
602 pd = (byte *)pdest;
603
604 for (i=0 ; i<TILE_SIZE ; i++)
605 {
606 for (j=0 ; j<TILE_SIZE ; j++)
607 {
608 s = (((j << 16) + turb[i & (CYCLE-1)]) >> 16) & 63;
609 t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63;
610 *pd++ = *(pbasetex + (t<<6) + s);
611 }
612 }
613}
614
615
616/*
617================
618R_GenTurbTile16
619================
620*/
621void R_GenTurbTile16 (pixel_t *pbasetex, void *pdest)
622{
623 int *turb;
624 int i, j, s, t;
625 unsigned short *pd;
626
627 turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1));
628 pd = (unsigned short *)pdest;
629
630 for (i=0 ; i<TILE_SIZE ; i++)
631 {
632 for (j=0 ; j<TILE_SIZE ; j++)
633 {
634 s = (((j << 16) + turb[i & (CYCLE-1)]) >> 16) & 63;
635 t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63;
636 *pd++ = d_8to16table[*(pbasetex + (t<<6) + s)];
637 }
638 }
639}
640
641
642/*
643================
644R_GenTile
645================
646*/
647void R_GenTile (msurface_t *psurf, void *pdest)
648{
649 if (psurf->flags & SURF_DRAWTURB)
650 {
651 if (r_pixbytes == 1)
652 {
653 R_GenTurbTile ((pixel_t *)
654 ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest);
655 }
656 else
657 {
658 R_GenTurbTile16 ((pixel_t *)
659 ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest);
660 }
661 }
662 else if (psurf->flags & SURF_DRAWSKY)
663 {
664 if (r_pixbytes == 1)
665 {
666 R_GenSkyTile (pdest);
667 }
668 else
669 {
670 R_GenSkyTile16 (pdest);
671 }
672 }
673 else
674 {
675 Sys_Error ("Unknown tile type");
676 }
677}
678
diff --git a/apps/plugins/sdl/progs/quake/r_vars.c b/apps/plugins/sdl/progs/quake/r_vars.c
new file mode 100644
index 0000000000..eb41290e9b
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_vars.c
@@ -0,0 +1,39 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// r_vars.c: global refresh variables
21
22#include "quakedef.h"
23
24#if !id386
25
26// all global and static refresh variables are collected in a contiguous block
27// to avoid cache conflicts.
28
29//-------------------------------------------------------
30// global refresh variables
31//-------------------------------------------------------
32
33// FIXME: make into one big structure, like cl or sv
34// FIXME: do separately for refresh engine and driver
35
36int r_bmodelactive;
37
38#endif // !id386
39
diff --git a/apps/plugins/sdl/progs/quake/r_varsa.S b/apps/plugins/sdl/progs/quake/r_varsa.S
new file mode 100644
index 0000000000..2c3f9e5411
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/r_varsa.S
@@ -0,0 +1,64 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// r_varsa.s
22//
23
24#include "asm_i386.h"
25#include "quakeasm.h"
26#include "asm_draw.h"
27#include "d_ifacea.h"
28
29#if id386
30
31 .data
32
33//-------------------------------------------------------
34// ASM-only variables
35//-------------------------------------------------------
36.globl float_1, float_particle_z_clip, float_point5
37.globl float_minus_1, float_0
38float_0: .single 0.0
39float_1: .single 1.0
40float_minus_1: .single -1.0
41float_particle_z_clip: .single PARTICLE_Z_CLIP
42float_point5: .single 0.5
43
44.globl fp_16, fp_64k, fp_1m, fp_64kx64k
45.globl fp_1m_minus_1
46.globl fp_8
47fp_1m: .single 1048576.0
48fp_1m_minus_1: .single 1048575.0
49fp_64k: .single 65536.0
50fp_8: .single 8.0
51fp_16: .single 16.0
52fp_64kx64k: .long 0x4f000000 // (float)0x8000*0x10000
53
54
55.globl FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd
56FloatZero: .long 0
57Float2ToThe31nd: .long 0x4f000000
58FloatMinus2ToThe31nd: .long 0xcf000000
59
60.globl C(r_bmodelactive)
61C(r_bmodelactive): .long 0
62
63#endif // id386
64
diff --git a/apps/plugins/sdl/progs/quake/render.h b/apps/plugins/sdl/progs/quake/render.h
new file mode 100644
index 0000000000..b5f8382c31
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/render.h
@@ -0,0 +1,158 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// refresh.h -- public interface to refresh functions
22
23#define MAXCLIPPLANES 11
24
25#define TOP_RANGE 16 // soldier uniform colors
26#define BOTTOM_RANGE 96
27
28//=============================================================================
29
30typedef struct efrag_s
31{
32 struct mleaf_s *leaf;
33 struct efrag_s *leafnext;
34 struct entity_s *entity;
35 struct efrag_s *entnext;
36} efrag_t;
37
38
39typedef struct entity_s
40{
41 qboolean forcelink; // model changed
42
43 int update_type;
44
45 entity_state_t baseline; // to fill in defaults in updates
46
47 double msgtime; // time of last update
48 vec3_t msg_origins[2]; // last two updates (0 is newest)
49 vec3_t origin;
50 vec3_t msg_angles[2]; // last two updates (0 is newest)
51 vec3_t angles;
52 struct model_s *model; // NULL = no model
53 struct efrag_s *efrag; // linked list of efrags
54 int frame;
55 float syncbase; // for client-side animations
56 byte *colormap;
57 int effects; // light, particals, etc
58 int skinnum; // for Alias models
59 int visframe; // last frame this entity was
60 // found in an active leaf
61
62 int dlightframe; // dynamic lighting
63 int dlightbits;
64
65// FIXME: could turn these into a union
66 int trivial_accept;
67 struct mnode_s *topnode; // for bmodels, first world node
68 // that splits bmodel, or NULL if
69 // not split
70} entity_t;
71
72// !!! if this is changed, it must be changed in asm_draw.h too !!!
73typedef struct
74{
75 vrect_t vrect; // subwindow in video for refresh
76 // FIXME: not need vrect next field here?
77 vrect_t aliasvrect; // scaled Alias version
78 int vrectright, vrectbottom; // right & bottom screen coords
79 int aliasvrectright, aliasvrectbottom; // scaled Alias versions
80 float vrectrightedge; // rightmost right edge we care about,
81 // for use in edge list
82 float fvrectx, fvrecty; // for floating-point compares
83 float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping
84 int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20
85 int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20
86 float fvrectright_adj, fvrectbottom_adj;
87 // right and bottom edges, for clamping
88 float fvrectright; // rightmost edge, for Alias clamping
89 float fvrectbottom; // bottommost edge, for Alias clamping
90 float horizontalFieldOfView; // at Z = 1.0, this many X is visible
91 // 2.0 = 90 degrees
92 float xOrigin; // should probably allways be 0.5
93 float yOrigin; // between be around 0.3 to 0.5
94
95 vec3_t vieworg;
96 vec3_t viewangles;
97
98 float fov_x, fov_y;
99
100 int ambientlight;
101} refdef_t;
102
103
104//
105// refresh
106//
107extern int reinit_surfcache;
108
109
110extern refdef_t r_refdef;
111extern vec3_t r_origin, vpn, vright, vup;
112
113extern struct texture_s *r_notexture_mip;
114
115
116void R_Init (void);
117void R_InitTextures (void);
118void R_InitEfrags (void);
119void R_RenderView (void); // must set r_refdef first
120void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect);
121 // called whenever r_refdef or vid change
122void R_InitSky (struct texture_s *mt); // called at level load
123
124void R_AddEfrags (entity_t *ent);
125void R_RemoveEfrags (entity_t *ent);
126
127void R_NewMap (void);
128
129
130void R_ParseParticleEffect (void);
131void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);
132void R_RocketTrail (vec3_t start, vec3_t end, int type);
133
134#ifdef QUAKE2
135void R_DarkFieldParticles (entity_t *ent);
136#endif
137void R_EntityParticles (entity_t *ent);
138void R_BlobExplosion (vec3_t org);
139void R_ParticleExplosion (vec3_t org);
140void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);
141void R_LavaSplash (vec3_t org);
142void R_TeleportSplash (vec3_t org);
143
144void R_PushDlights (void);
145
146
147//
148// surface cache related
149//
150extern int reinit_surfcache; // if 1, surface cache is currently empty and
151extern qboolean r_cache_thrash; // set if thrashing the surface cache
152
153int D_SurfaceCacheForRes (int width, int height);
154void D_FlushCaches (void);
155void D_DeleteSurfaceCache (void);
156void D_InitCaches (void *buffer, int size);
157void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj);
158
diff --git a/apps/plugins/sdl/progs/quake/resource.h b/apps/plugins/sdl/progs/quake/resource.h
new file mode 100644
index 0000000000..afabb2eb23
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/resource.h
@@ -0,0 +1,20 @@
1//{{NO_DEPENDENCIES}}
2// Microsoft Developer Studio generated include file.
3// Used by winquake.rc
4//
5#define IDS_STRING1 1
6#define IDI_ICON2 1
7#define IDD_DIALOG1 108
8#define IDD_PROGRESS 109
9#define IDC_PROGRESS 1000
10
11// Next default values for new objects
12//
13#ifdef APSTUDIO_INVOKED
14#ifndef APSTUDIO_READONLY_SYMBOLS
15#define _APS_NEXT_RESOURCE_VALUE 111
16#define _APS_NEXT_COMMAND_VALUE 40001
17#define _APS_NEXT_CONTROL_VALUE 1004
18#define _APS_NEXT_SYMED_VALUE 101
19#endif
20#endif
diff --git a/apps/plugins/sdl/progs/quake/sbar.c b/apps/plugins/sdl/progs/quake/sbar.c
new file mode 100644
index 0000000000..be9ec9cd75
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sbar.c
@@ -0,0 +1,1323 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sbar.c -- status bar code
21
22#include "quakedef.h"
23
24
25int sb_updates; // if >= vid.numpages, no update needed
26
27#define STAT_MINUS 10 // num frame for '-' stats digit
28qpic_t *sb_nums[2][11];
29qpic_t *sb_colon, *sb_slash;
30qpic_t *sb_ibar;
31qpic_t *sb_sbar;
32qpic_t *sb_scorebar;
33
34qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes
35qpic_t *sb_ammo[4];
36qpic_t *sb_sigil[4];
37qpic_t *sb_armor[3];
38qpic_t *sb_items[32];
39
40qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive
41 // 0 is static, 1 is temporary animation
42qpic_t *sb_face_invis;
43qpic_t *sb_face_quad;
44qpic_t *sb_face_invuln;
45qpic_t *sb_face_invis_invuln;
46
47qboolean sb_showscores;
48
49int sb_lines; // scan lines to draw
50
51qpic_t *rsb_invbar[2];
52qpic_t *rsb_weapons[5];
53qpic_t *rsb_items[2];
54qpic_t *rsb_ammo[3];
55qpic_t *rsb_teambord; // PGM 01/19/97 - team color border
56
57//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher
58qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes
59//MED 01/04/97 added array to simplify weapon parsing
60int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};
61//MED 01/04/97 added hipnotic items array
62qpic_t *hsb_items[2];
63
64void Sbar_MiniDeathmatchOverlay (void);
65void Sbar_DeathmatchOverlay (void);
66void M_DrawPic (int x, int y, qpic_t *pic);
67
68/*
69===============
70Sbar_ShowScores
71
72Tab key down
73===============
74*/
75void Sbar_ShowScores (void)
76{
77 if (sb_showscores)
78 return;
79 sb_showscores = true;
80 sb_updates = 0;
81}
82
83/*
84===============
85Sbar_DontShowScores
86
87Tab key up
88===============
89*/
90void Sbar_DontShowScores (void)
91{
92 sb_showscores = false;
93 sb_updates = 0;
94}
95
96/*
97===============
98Sbar_Changed
99===============
100*/
101void Sbar_Changed (void)
102{
103 sb_updates = 0; // update next frame
104}
105
106/*
107===============
108Sbar_Init
109===============
110*/
111void Sbar_Init (void)
112{
113 int i;
114
115 for (i=0 ; i<10 ; i++)
116 {
117 sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i));
118 sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i));
119 }
120
121 sb_nums[0][10] = Draw_PicFromWad ("num_minus");
122 sb_nums[1][10] = Draw_PicFromWad ("anum_minus");
123
124 sb_colon = Draw_PicFromWad ("num_colon");
125 sb_slash = Draw_PicFromWad ("num_slash");
126
127 sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun");
128 sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun");
129 sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun");
130 sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun");
131 sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch");
132 sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch");
133 sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng");
134
135 sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun");
136 sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun");
137 sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun");
138 sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun");
139 sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch");
140 sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch");
141 sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng");
142
143 for (i=0 ; i<5 ; i++)
144 {
145 sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1));
146 sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1));
147 sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1));
148 sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1));
149 sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1));
150 sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1));
151 sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1));
152 }
153
154 sb_ammo[0] = Draw_PicFromWad ("sb_shells");
155 sb_ammo[1] = Draw_PicFromWad ("sb_nails");
156 sb_ammo[2] = Draw_PicFromWad ("sb_rocket");
157 sb_ammo[3] = Draw_PicFromWad ("sb_cells");
158
159 sb_armor[0] = Draw_PicFromWad ("sb_armor1");
160 sb_armor[1] = Draw_PicFromWad ("sb_armor2");
161 sb_armor[2] = Draw_PicFromWad ("sb_armor3");
162
163 sb_items[0] = Draw_PicFromWad ("sb_key1");
164 sb_items[1] = Draw_PicFromWad ("sb_key2");
165 sb_items[2] = Draw_PicFromWad ("sb_invis");
166 sb_items[3] = Draw_PicFromWad ("sb_invuln");
167 sb_items[4] = Draw_PicFromWad ("sb_suit");
168 sb_items[5] = Draw_PicFromWad ("sb_quad");
169
170 sb_sigil[0] = Draw_PicFromWad ("sb_sigil1");
171 sb_sigil[1] = Draw_PicFromWad ("sb_sigil2");
172 sb_sigil[2] = Draw_PicFromWad ("sb_sigil3");
173 sb_sigil[3] = Draw_PicFromWad ("sb_sigil4");
174
175 sb_faces[4][0] = Draw_PicFromWad ("face1");
176 sb_faces[4][1] = Draw_PicFromWad ("face_p1");
177 sb_faces[3][0] = Draw_PicFromWad ("face2");
178 sb_faces[3][1] = Draw_PicFromWad ("face_p2");
179 sb_faces[2][0] = Draw_PicFromWad ("face3");
180 sb_faces[2][1] = Draw_PicFromWad ("face_p3");
181 sb_faces[1][0] = Draw_PicFromWad ("face4");
182 sb_faces[1][1] = Draw_PicFromWad ("face_p4");
183 sb_faces[0][0] = Draw_PicFromWad ("face5");
184 sb_faces[0][1] = Draw_PicFromWad ("face_p5");
185
186 sb_face_invis = Draw_PicFromWad ("face_invis");
187 sb_face_invuln = Draw_PicFromWad ("face_invul2");
188 sb_face_invis_invuln = Draw_PicFromWad ("face_inv2");
189 sb_face_quad = Draw_PicFromWad ("face_quad");
190
191 Cmd_AddCommand ("+showscores", Sbar_ShowScores);
192 Cmd_AddCommand ("-showscores", Sbar_DontShowScores);
193
194 sb_sbar = Draw_PicFromWad ("sbar");
195 sb_ibar = Draw_PicFromWad ("ibar");
196 sb_scorebar = Draw_PicFromWad ("scorebar");
197
198//MED 01/04/97 added new hipnotic weapons
199 if (hipnotic)
200 {
201 hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser");
202 hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir");
203 hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox");
204 hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren");
205 hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox");
206
207 hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser");
208 hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir");
209 hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox");
210 hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren");
211 hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox");
212
213 for (i=0 ; i<5 ; i++)
214 {
215 hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1));
216 hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1));
217 hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1));
218 hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1));
219 hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1));
220 }
221
222 hsb_items[0] = Draw_PicFromWad ("sb_wsuit");
223 hsb_items[1] = Draw_PicFromWad ("sb_eshld");
224 }
225
226 if (rogue)
227 {
228 rsb_invbar[0] = Draw_PicFromWad ("r_invbar1");
229 rsb_invbar[1] = Draw_PicFromWad ("r_invbar2");
230
231 rsb_weapons[0] = Draw_PicFromWad ("r_lava");
232 rsb_weapons[1] = Draw_PicFromWad ("r_superlava");
233 rsb_weapons[2] = Draw_PicFromWad ("r_gren");
234 rsb_weapons[3] = Draw_PicFromWad ("r_multirock");
235 rsb_weapons[4] = Draw_PicFromWad ("r_plasma");
236
237 rsb_items[0] = Draw_PicFromWad ("r_shield1");
238 rsb_items[1] = Draw_PicFromWad ("r_agrav1");
239
240// PGM 01/19/97 - team color border
241 rsb_teambord = Draw_PicFromWad ("r_teambord");
242// PGM 01/19/97 - team color border
243
244 rsb_ammo[0] = Draw_PicFromWad ("r_ammolava");
245 rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti");
246 rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma");
247 }
248}
249
250
251//=============================================================================
252
253// drawing routines are relative to the status bar location
254
255/*
256=============
257Sbar_DrawPic
258=============
259*/
260void Sbar_DrawPic (int x, int y, qpic_t *pic)
261{
262 if (cl.gametype == GAME_DEATHMATCH)
263 Draw_Pic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
264 else
265 Draw_Pic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
266}
267
268/*
269=============
270Sbar_DrawTransPic
271=============
272*/
273void Sbar_DrawTransPic (int x, int y, qpic_t *pic)
274{
275 if (cl.gametype == GAME_DEATHMATCH)
276 Draw_TransPic (x /*+ ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic);
277 else
278 Draw_TransPic (x + ((vid.width - 320)>>1), y + (vid.height-SBAR_HEIGHT), pic);
279}
280
281/*
282================
283Sbar_DrawCharacter
284
285Draws one solid graphics character
286================
287*/
288void Sbar_DrawCharacter (int x, int y, int num)
289{
290 if (cl.gametype == GAME_DEATHMATCH)
291 Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num);
292 else
293 Draw_Character ( x + ((vid.width - 320)>>1) + 4 , y + vid.height-SBAR_HEIGHT, num);
294}
295
296/*
297================
298Sbar_DrawString
299================
300*/
301void Sbar_DrawString (int x, int y, char *str)
302{
303 if (cl.gametype == GAME_DEATHMATCH)
304 Draw_String (x /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str);
305 else
306 Draw_String (x + ((vid.width - 320)>>1), y+ vid.height-SBAR_HEIGHT, str);
307}
308
309/*
310=============
311Sbar_itoa
312=============
313*/
314int Sbar_itoa (int num, char *buf)
315{
316 char *str;
317 int pow10;
318 int dig;
319
320 str = buf;
321
322 if (num < 0)
323 {
324 *str++ = '-';
325 num = -num;
326 }
327
328 for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
329 ;
330
331 do
332 {
333 pow10 /= 10;
334 dig = num/pow10;
335 *str++ = '0'+dig;
336 num -= dig*pow10;
337 } while (pow10 != 1);
338
339 *str = 0;
340
341 return str-buf;
342}
343
344
345/*
346=============
347Sbar_DrawNum
348=============
349*/
350void Sbar_DrawNum (int x, int y, int num, int digits, int color)
351{
352 char str[12];
353 char *ptr;
354 int l, frame;
355
356 l = Sbar_itoa (num, str);
357 ptr = str;
358 if (l > digits)
359 ptr += (l-digits);
360 if (l < digits)
361 x += (digits-l)*24;
362
363 while (*ptr)
364 {
365 if (*ptr == '-')
366 frame = STAT_MINUS;
367 else
368 frame = *ptr -'0';
369
370 Sbar_DrawTransPic (x,y,sb_nums[color][frame]);
371 x += 24;
372 ptr++;
373 }
374}
375
376//=============================================================================
377
378int fragsort[MAX_SCOREBOARD];
379
380char scoreboardtext[MAX_SCOREBOARD][20];
381int scoreboardtop[MAX_SCOREBOARD];
382int scoreboardbottom[MAX_SCOREBOARD];
383int scoreboardcount[MAX_SCOREBOARD];
384int scoreboardlines;
385
386/*
387===============
388Sbar_SortFrags
389===============
390*/
391void Sbar_SortFrags (void)
392{
393 int i, j, k;
394
395// sort by frags
396 scoreboardlines = 0;
397 for (i=0 ; i<cl.maxclients ; i++)
398 {
399 if (cl.scores[i].name[0])
400 {
401 fragsort[scoreboardlines] = i;
402 scoreboardlines++;
403 }
404 }
405
406 for (i=0 ; i<scoreboardlines ; i++)
407 for (j=0 ; j<scoreboardlines-1-i ; j++)
408 if (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)
409 {
410 k = fragsort[j];
411 fragsort[j] = fragsort[j+1];
412 fragsort[j+1] = k;
413 }
414}
415
416int Sbar_ColorForMap (int m)
417{
418 return m < 128 ? m + 8 : m + 8;
419}
420
421/*
422===============
423Sbar_UpdateScoreboard
424===============
425*/
426void Sbar_UpdateScoreboard (void)
427{
428 int i, k;
429 int top, bottom;
430 scoreboard_t *s;
431
432 Sbar_SortFrags ();
433
434// draw the text
435 memset (scoreboardtext, 0, sizeof(scoreboardtext));
436
437 for (i=0 ; i<scoreboardlines; i++)
438 {
439 k = fragsort[i];
440 s = &cl.scores[k];
441 sprintf (&scoreboardtext[i][1], "%3i %s", s->frags, s->name);
442
443 top = s->colors & 0xf0;
444 bottom = (s->colors & 15) <<4;
445 scoreboardtop[i] = Sbar_ColorForMap (top);
446 scoreboardbottom[i] = Sbar_ColorForMap (bottom);
447 }
448}
449
450
451
452/*
453===============
454Sbar_SoloScoreboard
455===============
456*/
457void Sbar_SoloScoreboard (void)
458{
459 char str[80];
460 int minutes, seconds, tens, units;
461 int l;
462
463 sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
464 Sbar_DrawString (8, 4, str);
465
466 sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);
467 Sbar_DrawString (8, 12, str);
468
469// time
470 minutes = cl.time / 60;
471 seconds = cl.time - 60*minutes;
472 tens = seconds / 10;
473 units = seconds - 10*tens;
474 sprintf (str,"Time :%3i:%i%i", minutes, tens, units);
475 Sbar_DrawString (184, 4, str);
476
477// draw level name
478 l = strlen (cl.levelname);
479 Sbar_DrawString (232 - l*4, 12, cl.levelname);
480}
481
482/*
483===============
484Sbar_DrawScoreboard
485===============
486*/
487void Sbar_DrawScoreboard (void)
488{
489 Sbar_SoloScoreboard ();
490 if (cl.gametype == GAME_DEATHMATCH)
491 Sbar_DeathmatchOverlay ();
492#if 0
493 int i, j, c;
494 int x, y;
495 int l;
496 int top, bottom;
497 scoreboard_t *s;
498
499 if (cl.gametype != GAME_DEATHMATCH)
500 {
501 Sbar_SoloScoreboard ();
502 return;
503 }
504
505 Sbar_UpdateScoreboard ();
506
507 l = scoreboardlines <= 6 ? scoreboardlines : 6;
508
509 for (i=0 ; i<l ; i++)
510 {
511 x = 20*(i&1);
512 y = i/2 * 8;
513
514 s = &cl.scores[fragsort[i]];
515 if (!s->name[0])
516 continue;
517
518 // draw background
519 top = s->colors & 0xf0;
520 bottom = (s->colors & 15)<<4;
521 top = Sbar_ColorForMap (top);
522 bottom = Sbar_ColorForMap (bottom);
523
524 Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y + vid.height - SBAR_HEIGHT, 28, 4, top);
525 Draw_Fill ( x*8+10 + ((vid.width - 320)>>1), y+4 + vid.height - SBAR_HEIGHT, 28, 4, bottom);
526
527 // draw text
528 for (j=0 ; j<20 ; j++)
529 {
530 c = scoreboardtext[i][j];
531 if (c == 0 || c == ' ')
532 continue;
533 Sbar_DrawCharacter ( (x+j)*8, y, c);
534 }
535 }
536#endif
537}
538
539//=============================================================================
540
541/*
542===============
543Sbar_DrawInventory
544===============
545*/
546void Sbar_DrawInventory (void)
547{
548 int i;
549 char num[6];
550 float time;
551 int flashon;
552
553 if (rogue)
554 {
555 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
556 Sbar_DrawPic (0, -24, rsb_invbar[0]);
557 else
558 Sbar_DrawPic (0, -24, rsb_invbar[1]);
559 }
560 else
561 {
562 Sbar_DrawPic (0, -24, sb_ibar);
563 }
564
565// weapons
566 for (i=0 ; i<7 ; i++)
567 {
568 if (cl.items & (IT_SHOTGUN<<i) )
569 {
570 time = cl.item_gettime[i];
571 flashon = (int)((cl.time - time)*10);
572 if (flashon >= 10)
573 {
574 if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i) )
575 flashon = 1;
576 else
577 flashon = 0;
578 }
579 else
580 flashon = (flashon%5) + 2;
581
582 Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);
583
584 if (flashon > 1)
585 sb_updates = 0; // force update to remove flash
586 }
587 }
588
589// MED 01/04/97
590// hipnotic weapons
591 if (hipnotic)
592 {
593 int grenadeflashing=0;
594 for (i=0 ; i<4 ; i++)
595 {
596 if (cl.items & (1<<hipweapons[i]) )
597 {
598 time = cl.item_gettime[hipweapons[i]];
599 flashon = (int)((cl.time - time)*10);
600 if (flashon >= 10)
601 {
602 if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i]) )
603 flashon = 1;
604 else
605 flashon = 0;
606 }
607 else
608 flashon = (flashon%5) + 2;
609
610 // check grenade launcher
611 if (i==2)
612 {
613 if (cl.items & HIT_PROXIMITY_GUN)
614 {
615 if (flashon)
616 {
617 grenadeflashing = 1;
618 Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);
619 }
620 }
621 }
622 else if (i==3)
623 {
624 if (cl.items & (IT_SHOTGUN<<4))
625 {
626 if (flashon && !grenadeflashing)
627 {
628 Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);
629 }
630 else if (!grenadeflashing)
631 {
632 Sbar_DrawPic (96, -16, hsb_weapons[0][3]);
633 }
634 }
635 else
636 Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);
637 }
638 else
639 Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);
640 if (flashon > 1)
641 sb_updates = 0; // force update to remove flash
642 }
643 }
644 }
645
646 if (rogue)
647 {
648 // check for powered up weapon.
649 if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )
650 {
651 for (i=0;i<5;i++)
652 {
653 if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))
654 {
655 Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);
656 }
657 }
658 }
659 }
660
661// ammo counts
662 for (i=0 ; i<4 ; i++)
663 {
664 sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] );
665 if (num[0] != ' ')
666 Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');
667 if (num[1] != ' ')
668 Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');
669 if (num[2] != ' ')
670 Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');
671 }
672
673 flashon = 0;
674 // items
675 for (i=0 ; i<6 ; i++)
676 if (cl.items & (1<<(17+i)))
677 {
678 time = cl.item_gettime[17+i];
679 if (time && time > cl.time - 2 && flashon )
680 { // flash frame
681 sb_updates = 0;
682 }
683 else
684 {
685 //MED 01/04/97 changed keys
686 if (!hipnotic || (i>1))
687 {
688 Sbar_DrawPic (192 + i*16, -16, sb_items[i]);
689 }
690 }
691 if (time && time > cl.time - 2)
692 sb_updates = 0;
693 }
694 //MED 01/04/97 added hipnotic items
695 // hipnotic items
696 if (hipnotic)
697 {
698 for (i=0 ; i<2 ; i++)
699 if (cl.items & (1<<(24+i)))
700 {
701 time = cl.item_gettime[24+i];
702 if (time && time > cl.time - 2 && flashon )
703 { // flash frame
704 sb_updates = 0;
705 }
706 else
707 {
708 Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);
709 }
710 if (time && time > cl.time - 2)
711 sb_updates = 0;
712 }
713 }
714
715 if (rogue)
716 {
717 // new rogue items
718 for (i=0 ; i<2 ; i++)
719 {
720 if (cl.items & (1<<(29+i)))
721 {
722 time = cl.item_gettime[29+i];
723
724 if (time && time > cl.time - 2 && flashon )
725 { // flash frame
726 sb_updates = 0;
727 }
728 else
729 {
730 Sbar_DrawPic (288 + i*16, -16, rsb_items[i]);
731 }
732
733 if (time && time > cl.time - 2)
734 sb_updates = 0;
735 }
736 }
737 }
738 else
739 {
740 // sigils
741 for (i=0 ; i<4 ; i++)
742 {
743 if (cl.items & (1<<(28+i)))
744 {
745 time = cl.item_gettime[28+i];
746 if (time && time > cl.time - 2 && flashon )
747 { // flash frame
748 sb_updates = 0;
749 }
750 else
751 Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);
752 if (time && time > cl.time - 2)
753 sb_updates = 0;
754 }
755 }
756 }
757}
758
759//=============================================================================
760
761/*
762===============
763Sbar_DrawFrags
764===============
765*/
766void Sbar_DrawFrags (void)
767{
768 int i, k, l;
769 int top, bottom;
770 int x, y, f;
771 int xofs;
772 char num[12];
773 scoreboard_t *s;
774
775 Sbar_SortFrags ();
776
777// draw the text
778 l = scoreboardlines <= 4 ? scoreboardlines : 4;
779
780 x = 23;
781 if (cl.gametype == GAME_DEATHMATCH)
782 xofs = 0;
783 else
784 xofs = (vid.width - 320)>>1;
785 y = vid.height - SBAR_HEIGHT - 23;
786
787 for (i=0 ; i<l ; i++)
788 {
789 k = fragsort[i];
790 s = &cl.scores[k];
791 if (!s->name[0])
792 continue;
793
794 // draw background
795 top = s->colors & 0xf0;
796 bottom = (s->colors & 15)<<4;
797 top = Sbar_ColorForMap (top);
798 bottom = Sbar_ColorForMap (bottom);
799
800 Draw_Fill (xofs + x*8 + 10, y, 28, 4, top);
801 Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom);
802
803 // draw number
804 f = s->frags;
805 sprintf (num, "%3i",f);
806
807 Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]);
808 Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]);
809 Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]);
810
811 if (k == cl.viewentity - 1)
812 {
813 Sbar_DrawCharacter (x*8+2, -24, 16);
814 Sbar_DrawCharacter ( (x+4)*8-4, -24, 17);
815 }
816 x+=4;
817 }
818}
819
820//=============================================================================
821
822
823/*
824===============
825Sbar_DrawFace
826===============
827*/
828void Sbar_DrawFace (void)
829{
830 int f, anim;
831
832// PGM 01/19/97 - team color drawing
833// PGM 03/02/97 - fixed so color swatch only appears in CTF modes
834 if (rogue &&
835 (cl.maxclients != 1) &&
836 (teamplay.value>3) &&
837 (teamplay.value<7))
838 {
839 int top, bottom;
840 int xofs;
841 char num[12];
842 scoreboard_t *s;
843
844 s = &cl.scores[cl.viewentity - 1];
845 // draw background
846 top = s->colors & 0xf0;
847 bottom = (s->colors & 15)<<4;
848 top = Sbar_ColorForMap (top);
849 bottom = Sbar_ColorForMap (bottom);
850
851 if (cl.gametype == GAME_DEATHMATCH)
852 xofs = 113;
853 else
854 xofs = ((vid.width - 320)>>1) + 113;
855
856 Sbar_DrawPic (112, 0, rsb_teambord);
857 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top);
858 Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom);
859
860 // draw number
861 f = s->frags;
862 sprintf (num, "%3i",f);
863
864 if (top==8)
865 {
866 if (num[0] != ' ')
867 Sbar_DrawCharacter(109, 3, 18 + num[0] - '0');
868 if (num[1] != ' ')
869 Sbar_DrawCharacter(116, 3, 18 + num[1] - '0');
870 if (num[2] != ' ')
871 Sbar_DrawCharacter(123, 3, 18 + num[2] - '0');
872 }
873 else
874 {
875 Sbar_DrawCharacter ( 109, 3, num[0]);
876 Sbar_DrawCharacter ( 116, 3, num[1]);
877 Sbar_DrawCharacter ( 123, 3, num[2]);
878 }
879
880 return;
881 }
882// PGM 01/19/97 - team color drawing
883
884 if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )
885 == (IT_INVISIBILITY | IT_INVULNERABILITY) )
886 {
887 Sbar_DrawPic (112, 0, sb_face_invis_invuln);
888 return;
889 }
890 if (cl.items & IT_QUAD)
891 {
892 Sbar_DrawPic (112, 0, sb_face_quad );
893 return;
894 }
895 if (cl.items & IT_INVISIBILITY)
896 {
897 Sbar_DrawPic (112, 0, sb_face_invis );
898 return;
899 }
900 if (cl.items & IT_INVULNERABILITY)
901 {
902 Sbar_DrawPic (112, 0, sb_face_invuln);
903 return;
904 }
905
906 if (cl.stats[STAT_HEALTH] >= 100)
907 f = 4;
908 else
909 f = cl.stats[STAT_HEALTH] / 20;
910
911 if (cl.time <= cl.faceanimtime)
912 {
913 anim = 1;
914 sb_updates = 0; // make sure the anim gets drawn over
915 }
916 else
917 anim = 0;
918 Sbar_DrawPic (112, 0, sb_faces[f][anim]);
919}
920
921/*
922===============
923Sbar_Draw
924===============
925*/
926void Sbar_Draw (void)
927{
928 if (scr_con_current == vid.height)
929 return; // console is full screen
930
931 if (sb_updates >= vid.numpages)
932 return;
933
934 scr_copyeverything = 1;
935
936 sb_updates++;
937
938 if (sb_lines && vid.width > 320)
939 Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines);
940
941 if (sb_lines > 24)
942 {
943 Sbar_DrawInventory ();
944 if (cl.maxclients != 1)
945 Sbar_DrawFrags ();
946 }
947
948 if (sb_showscores || cl.stats[STAT_HEALTH] <= 0)
949 {
950 Sbar_DrawPic (0, 0, sb_scorebar);
951 Sbar_DrawScoreboard ();
952 sb_updates = 0;
953 }
954 else if (sb_lines)
955 {
956 Sbar_DrawPic (0, 0, sb_sbar);
957
958 // keys (hipnotic only)
959 //MED 01/04/97 moved keys here so they would not be overwritten
960 if (hipnotic)
961 {
962 if (cl.items & IT_KEY1)
963 Sbar_DrawPic (209, 3, sb_items[0]);
964 if (cl.items & IT_KEY2)
965 Sbar_DrawPic (209, 12, sb_items[1]);
966 }
967 // armor
968 if (cl.items & IT_INVULNERABILITY)
969 {
970 Sbar_DrawNum (24, 0, 666, 3, 1);
971 Sbar_DrawPic (0, 0, draw_disc);
972 }
973 else
974 {
975 if (rogue)
976 {
977 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,
978 cl.stats[STAT_ARMOR] <= 25);
979 if (cl.items & RIT_ARMOR3)
980 Sbar_DrawPic (0, 0, sb_armor[2]);
981 else if (cl.items & RIT_ARMOR2)
982 Sbar_DrawPic (0, 0, sb_armor[1]);
983 else if (cl.items & RIT_ARMOR1)
984 Sbar_DrawPic (0, 0, sb_armor[0]);
985 }
986 else
987 {
988 Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3
989 , cl.stats[STAT_ARMOR] <= 25);
990 if (cl.items & IT_ARMOR3)
991 Sbar_DrawPic (0, 0, sb_armor[2]);
992 else if (cl.items & IT_ARMOR2)
993 Sbar_DrawPic (0, 0, sb_armor[1]);
994 else if (cl.items & IT_ARMOR1)
995 Sbar_DrawPic (0, 0, sb_armor[0]);
996 }
997 }
998
999 // face
1000 Sbar_DrawFace ();
1001
1002 // health
1003 Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3
1004 , cl.stats[STAT_HEALTH] <= 25);
1005
1006 // ammo icon
1007 if (rogue)
1008 {
1009 if (cl.items & RIT_SHELLS)
1010 Sbar_DrawPic (224, 0, sb_ammo[0]);
1011 else if (cl.items & RIT_NAILS)
1012 Sbar_DrawPic (224, 0, sb_ammo[1]);
1013 else if (cl.items & RIT_ROCKETS)
1014 Sbar_DrawPic (224, 0, sb_ammo[2]);
1015 else if (cl.items & RIT_CELLS)
1016 Sbar_DrawPic (224, 0, sb_ammo[3]);
1017 else if (cl.items & RIT_LAVA_NAILS)
1018 Sbar_DrawPic (224, 0, rsb_ammo[0]);
1019 else if (cl.items & RIT_PLASMA_AMMO)
1020 Sbar_DrawPic (224, 0, rsb_ammo[1]);
1021 else if (cl.items & RIT_MULTI_ROCKETS)
1022 Sbar_DrawPic (224, 0, rsb_ammo[2]);
1023 }
1024 else
1025 {
1026 if (cl.items & IT_SHELLS)
1027 Sbar_DrawPic (224, 0, sb_ammo[0]);
1028 else if (cl.items & IT_NAILS)
1029 Sbar_DrawPic (224, 0, sb_ammo[1]);
1030 else if (cl.items & IT_ROCKETS)
1031 Sbar_DrawPic (224, 0, sb_ammo[2]);
1032 else if (cl.items & IT_CELLS)
1033 Sbar_DrawPic (224, 0, sb_ammo[3]);
1034 }
1035
1036 Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,
1037 cl.stats[STAT_AMMO] <= 10);
1038 }
1039
1040 if (vid.width > 320) {
1041 if (cl.gametype == GAME_DEATHMATCH)
1042 Sbar_MiniDeathmatchOverlay ();
1043 }
1044}
1045
1046//=============================================================================
1047
1048/*
1049==================
1050Sbar_IntermissionNumber
1051
1052==================
1053*/
1054void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)
1055{
1056 char str[12];
1057 char *ptr;
1058 int l, frame;
1059
1060 l = Sbar_itoa (num, str);
1061 ptr = str;
1062 if (l > digits)
1063 ptr += (l-digits);
1064 if (l < digits)
1065 x += (digits-l)*24;
1066
1067 while (*ptr)
1068 {
1069 if (*ptr == '-')
1070 frame = STAT_MINUS;
1071 else
1072 frame = *ptr -'0';
1073
1074 Draw_TransPic (x,y,sb_nums[color][frame]);
1075 x += 24;
1076 ptr++;
1077 }
1078}
1079
1080/*
1081==================
1082Sbar_DeathmatchOverlay
1083
1084==================
1085*/
1086void Sbar_DeathmatchOverlay (void)
1087{
1088 qpic_t *pic;
1089 int i, k, l;
1090 int top, bottom;
1091 int x, y, f;
1092 char num[12];
1093 scoreboard_t *s;
1094
1095 scr_copyeverything = 1;
1096 scr_fullupdate = 0;
1097
1098 pic = Draw_CachePic ("gfx/ranking.lmp");
1099 M_DrawPic ((320-pic->width)/2, 8, pic);
1100
1101// scores
1102 Sbar_SortFrags ();
1103
1104// draw the text
1105 l = scoreboardlines;
1106
1107 x = 80 + ((vid.width - 320)>>1);
1108 y = 40;
1109 for (i=0 ; i<l ; i++)
1110 {
1111 k = fragsort[i];
1112 s = &cl.scores[k];
1113 if (!s->name[0])
1114 continue;
1115
1116 // draw background
1117 top = s->colors & 0xf0;
1118 bottom = (s->colors & 15)<<4;
1119 top = Sbar_ColorForMap (top);
1120 bottom = Sbar_ColorForMap (bottom);
1121
1122 Draw_Fill ( x, y, 40, 4, top);
1123 Draw_Fill ( x, y+4, 40, 4, bottom);
1124
1125 // draw number
1126 f = s->frags;
1127 sprintf (num, "%3i",f);
1128
1129 Draw_Character ( x+8 , y, num[0]);
1130 Draw_Character ( x+16 , y, num[1]);
1131 Draw_Character ( x+24 , y, num[2]);
1132
1133 if (k == cl.viewentity - 1)
1134 Draw_Character ( x - 8, y, 12);
1135
1136#if 0
1137{
1138 int total;
1139 int n, minutes, tens, units;
1140
1141 // draw time
1142 total = cl.completed_time - s->entertime;
1143 minutes = (int)total/60;
1144 n = total - minutes*60;
1145 tens = n/10;
1146 units = n%10;
1147
1148 sprintf (num, "%3i:%i%i", minutes, tens, units);
1149
1150 Draw_String ( x+48 , y, num);
1151}
1152#endif
1153
1154 // draw name
1155 Draw_String (x+64, y, s->name);
1156
1157 y += 10;
1158 }
1159}
1160
1161/*
1162==================
1163Sbar_DeathmatchOverlay
1164
1165==================
1166*/
1167void Sbar_MiniDeathmatchOverlay (void)
1168{
1169 qpic_t *pic;
1170 int i, k, l;
1171 int top, bottom;
1172 int x, y, f;
1173 char num[12];
1174 scoreboard_t *s;
1175 int numlines;
1176
1177 if (vid.width < 512 || !sb_lines)
1178 return;
1179
1180 scr_copyeverything = 1;
1181 scr_fullupdate = 0;
1182
1183// scores
1184 Sbar_SortFrags ();
1185
1186// draw the text
1187 l = scoreboardlines;
1188 y = vid.height - sb_lines;
1189 numlines = sb_lines/8;
1190 if (numlines < 3)
1191 return;
1192
1193 //find us
1194 for (i = 0; i < scoreboardlines; i++)
1195 if (fragsort[i] == cl.viewentity - 1)
1196 break;
1197
1198 if (i == scoreboardlines) // we're not there
1199 i = 0;
1200 else // figure out start
1201 i = i - numlines/2;
1202
1203 if (i > scoreboardlines - numlines)
1204 i = scoreboardlines - numlines;
1205 if (i < 0)
1206 i = 0;
1207
1208 x = 324;
1209 for (/* */; i < scoreboardlines && y < vid.height - 8 ; i++)
1210 {
1211 k = fragsort[i];
1212 s = &cl.scores[k];
1213 if (!s->name[0])
1214 continue;
1215
1216 // draw background
1217 top = s->colors & 0xf0;
1218 bottom = (s->colors & 15)<<4;
1219 top = Sbar_ColorForMap (top);
1220 bottom = Sbar_ColorForMap (bottom);
1221
1222 Draw_Fill ( x, y+1, 40, 3, top);
1223 Draw_Fill ( x, y+4, 40, 4, bottom);
1224
1225 // draw number
1226 f = s->frags;
1227 sprintf (num, "%3i",f);
1228
1229 Draw_Character ( x+8 , y, num[0]);
1230 Draw_Character ( x+16 , y, num[1]);
1231 Draw_Character ( x+24 , y, num[2]);
1232
1233 if (k == cl.viewentity - 1) {
1234 Draw_Character ( x, y, 16);
1235 Draw_Character ( x + 32, y, 17);
1236 }
1237
1238#if 0
1239{
1240 int total;
1241 int n, minutes, tens, units;
1242
1243 // draw time
1244 total = cl.completed_time - s->entertime;
1245 minutes = (int)total/60;
1246 n = total - minutes*60;
1247 tens = n/10;
1248 units = n%10;
1249
1250 sprintf (num, "%3i:%i%i", minutes, tens, units);
1251
1252 Draw_String ( x+48 , y, num);
1253}
1254#endif
1255
1256 // draw name
1257 Draw_String (x+48, y, s->name);
1258
1259 y += 8;
1260 }
1261}
1262
1263/*
1264==================
1265Sbar_IntermissionOverlay
1266
1267==================
1268*/
1269void Sbar_IntermissionOverlay (void)
1270{
1271 qpic_t *pic;
1272 int dig;
1273 int num;
1274
1275 scr_copyeverything = 1;
1276 scr_fullupdate = 0;
1277
1278 if (cl.gametype == GAME_DEATHMATCH)
1279 {
1280 Sbar_DeathmatchOverlay ();
1281 return;
1282 }
1283
1284 pic = Draw_CachePic ("gfx/complete.lmp");
1285 Draw_Pic (64, 24, pic);
1286
1287 pic = Draw_CachePic ("gfx/inter.lmp");
1288 Draw_TransPic (0, 56, pic);
1289
1290// time
1291 dig = cl.completed_time/60;
1292 Sbar_IntermissionNumber (160, 64, dig, 3, 0);
1293 num = cl.completed_time - dig*60;
1294 Draw_TransPic (234,64,sb_colon);
1295 Draw_TransPic (246,64,sb_nums[0][num/10]);
1296 Draw_TransPic (266,64,sb_nums[0][num%10]);
1297
1298 Sbar_IntermissionNumber (160, 104, cl.stats[STAT_SECRETS], 3, 0);
1299 Draw_TransPic (232,104,sb_slash);
1300 Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0);
1301
1302 Sbar_IntermissionNumber (160, 144, cl.stats[STAT_MONSTERS], 3, 0);
1303 Draw_TransPic (232,144,sb_slash);
1304 Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0);
1305
1306}
1307
1308
1309/*
1310==================
1311Sbar_FinaleOverlay
1312
1313==================
1314*/
1315void Sbar_FinaleOverlay (void)
1316{
1317 qpic_t *pic;
1318
1319 scr_copyeverything = 1;
1320
1321 pic = Draw_CachePic ("gfx/finale.lmp");
1322 Draw_TransPic ( (vid.width-pic->width)/2, 16, pic);
1323}
diff --git a/apps/plugins/sdl/progs/quake/sbar.h b/apps/plugins/sdl/progs/quake/sbar.h
new file mode 100644
index 0000000000..286b3b6a7a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sbar.h
@@ -0,0 +1,39 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20
21// the status bar is only redrawn if something has changed, but if anything
22// does, the entire thing will be redrawn for the next vid.numpages frames.
23
24#define SBAR_HEIGHT 24
25
26extern int sb_lines; // scan lines to draw
27
28void Sbar_Init (void);
29
30void Sbar_Changed (void);
31// call whenever any of the client stats represented on the sbar changes
32
33void Sbar_Draw (void);
34// called every frame by screen
35
36void Sbar_IntermissionOverlay (void);
37// called each frame after the level has been completed
38
39void Sbar_FinaleOverlay (void);
diff --git a/apps/plugins/sdl/progs/quake/screen.c b/apps/plugins/sdl/progs/quake/screen.c
new file mode 100644
index 0000000000..8c623c9cad
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/screen.c
@@ -0,0 +1,994 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// screen.c -- master for refresh, status bar, console, chat, notify, etc
21
22#include "quakedef.h"
23#include "r_local.h"
24
25// only the refresh window will be updated unless these variables are flagged
26int scr_copytop;
27int scr_copyeverything;
28
29float scr_con_current;
30float scr_conlines; // lines of console to display
31
32float oldscreensize, oldfov;
33cvar_t scr_viewsize = {"viewsize","100", true};
34cvar_t scr_fov = {"fov","90"}; // 10 - 170
35cvar_t scr_conspeed = {"scr_conspeed","300"};
36cvar_t scr_centertime = {"scr_centertime","2"};
37cvar_t scr_showram = {"showram","1"};
38cvar_t scr_showturtle = {"showturtle","0"};
39cvar_t scr_showpause = {"showpause","1"};
40cvar_t scr_printspeed = {"scr_printspeed","8"};
41
42qboolean scr_initialized; // ready to draw
43
44qpic_t *scr_ram;
45qpic_t *scr_net;
46qpic_t *scr_turtle;
47
48int scr_fullupdate;
49
50int clearconsole;
51int clearnotify;
52
53viddef_t vid; // global video state
54
55vrect_t *pconupdate;
56vrect_t scr_vrect;
57
58qboolean scr_disabled_for_loading;
59qboolean scr_drawloading;
60float scr_disabled_time;
61qboolean scr_skipupdate;
62
63qboolean block_drawing;
64
65void SCR_ScreenShot_f (void);
66
67/*
68===============================================================================
69
70CENTER PRINTING
71
72===============================================================================
73*/
74
75char scr_centerstring[1024];
76float scr_centertime_start; // for slow victory printing
77float scr_centertime_off;
78int scr_center_lines;
79int scr_erase_lines;
80int scr_erase_center;
81
82/*
83==============
84SCR_CenterPrint
85
86Called for important messages that should stay in the center of the screen
87for a few moments
88==============
89*/
90void SCR_CenterPrint (char *str)
91{
92 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
93 scr_centertime_off = scr_centertime.value;
94 scr_centertime_start = cl.time;
95
96// count the number of lines for centering
97 scr_center_lines = 1;
98 while (*str)
99 {
100 if (*str == '\n')
101 scr_center_lines++;
102 str++;
103 }
104}
105
106void SCR_EraseCenterString (void)
107{
108 int y;
109
110 if (scr_erase_center++ > vid.numpages)
111 {
112 scr_erase_lines = 0;
113 return;
114 }
115
116 if (scr_center_lines <= 4)
117 y = vid.height*0.35;
118 else
119 y = 48;
120
121 scr_copytop = 1;
122 Draw_TileClear (0, y,vid.width, 8*scr_erase_lines);
123}
124
125void SCR_DrawCenterString (void)
126{
127 char *start;
128 int l;
129 int j;
130 int x, y;
131 int remaining;
132
133// the finale prints the characters one at a time
134 if (cl.intermission)
135 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
136 else
137 remaining = 9999;
138
139 scr_erase_center = 0;
140 start = scr_centerstring;
141
142 if (scr_center_lines <= 4)
143 y = vid.height*0.35;
144 else
145 y = 48;
146
147 do
148 {
149 // scan the width of the line
150 for (l=0 ; l<40 ; l++)
151 if (start[l] == '\n' || !start[l])
152 break;
153 x = (vid.width - l*8)/2;
154 for (j=0 ; j<l ; j++, x+=8)
155 {
156 Draw_Character (x, y, start[j]);
157 if (!remaining--)
158 return;
159 }
160
161 y += 8;
162
163 while (*start && *start != '\n')
164 start++;
165
166 if (!*start)
167 break;
168 start++; // skip the \n
169 } while (1);
170}
171
172void SCR_CheckDrawCenterString (void)
173{
174 scr_copytop = 1;
175 if (scr_center_lines > scr_erase_lines)
176 scr_erase_lines = scr_center_lines;
177
178 scr_centertime_off -= host_frametime;
179
180 if (scr_centertime_off <= 0 && !cl.intermission)
181 return;
182 if (key_dest != key_game)
183 return;
184
185 SCR_DrawCenterString ();
186}
187
188//=============================================================================
189
190/*
191====================
192CalcFov
193====================
194*/
195float CalcFov (float fov_x, float width, float height)
196{
197 float a;
198 float x;
199
200 if (fov_x < 1 || fov_x > 179)
201 Sys_Error ("Bad fov: %f", fov_x);
202
203 x = width/tan(fov_x/360*M_PI);
204
205 a = atan (height/x);
206
207 a = a*360/M_PI;
208
209 return a;
210}
211
212/*
213=================
214SCR_CalcRefdef
215
216Must be called whenever vid changes
217Internal use only
218=================
219*/
220static void SCR_CalcRefdef (void)
221{
222 vrect_t vrect;
223 float size;
224
225 scr_fullupdate = 0; // force a background redraw
226 vid.recalc_refdef = 0;
227
228// force the status bar to redraw
229 Sbar_Changed ();
230
231//========================================
232
233// bound viewsize
234 if (scr_viewsize.value < 30)
235 Cvar_Set ("viewsize","30");
236 if (scr_viewsize.value > 120)
237 Cvar_Set ("viewsize","120");
238
239// bound field of view
240 if (scr_fov.value < 10)
241 Cvar_Set ("fov","10");
242 if (scr_fov.value > 170)
243 Cvar_Set ("fov","170");
244
245 r_refdef.fov_x = scr_fov.value;
246 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
247
248// intermission is always full screen
249 if (cl.intermission)
250 size = 120;
251 else
252 size = scr_viewsize.value;
253
254 if (size >= 120)
255 sb_lines = 0; // no status bar at all
256 else if (size >= 110)
257 sb_lines = 24; // no inventory
258 else
259 sb_lines = 24+16+8;
260
261// these calculations mirror those in R_Init() for r_refdef, but take no
262// account of water warping
263 vrect.x = 0;
264 vrect.y = 0;
265 vrect.width = vid.width;
266 vrect.height = vid.height;
267
268 R_SetVrect (&vrect, &scr_vrect, sb_lines);
269
270// guard against going from one mode to another that's less than half the
271// vertical resolution
272 if (scr_con_current > vid.height)
273 scr_con_current = vid.height;
274
275// notify the refresh of the change
276 R_ViewChanged (&vrect, sb_lines, vid.aspect);
277}
278
279
280/*
281=================
282SCR_SizeUp_f
283
284Keybinding command
285=================
286*/
287void SCR_SizeUp_f (void)
288{
289 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
290 vid.recalc_refdef = 1;
291}
292
293
294/*
295=================
296SCR_SizeDown_f
297
298Keybinding command
299=================
300*/
301void SCR_SizeDown_f (void)
302{
303 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
304 vid.recalc_refdef = 1;
305}
306
307//============================================================================
308
309/*
310==================
311SCR_Init
312==================
313*/
314void SCR_Init (void)
315{
316 Cvar_RegisterVariable (&scr_fov);
317 Cvar_RegisterVariable (&scr_viewsize);
318 Cvar_RegisterVariable (&scr_conspeed);
319 Cvar_RegisterVariable (&scr_showram);
320 Cvar_RegisterVariable (&scr_showturtle);
321 Cvar_RegisterVariable (&scr_showpause);
322 Cvar_RegisterVariable (&scr_centertime);
323 Cvar_RegisterVariable (&scr_printspeed);
324
325//
326// register our commands
327//
328 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
329 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
330 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
331
332 scr_ram = Draw_PicFromWad ("ram");
333 scr_net = Draw_PicFromWad ("net");
334 scr_turtle = Draw_PicFromWad ("turtle");
335
336 scr_initialized = true;
337}
338
339
340
341/*
342==============
343SCR_DrawRam
344==============
345*/
346void SCR_DrawRam (void)
347{
348 if (!scr_showram.value)
349 return;
350
351 if (!r_cache_thrash)
352 return;
353
354 Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
355}
356
357/*
358==============
359SCR_DrawTurtle
360==============
361*/
362void SCR_DrawTurtle (void)
363{
364 static int count;
365
366 if (!scr_showturtle.value)
367 return;
368
369 if (host_frametime < 0.1)
370 {
371 count = 0;
372 return;
373 }
374
375 count++;
376 if (count < 3)
377 return;
378
379 Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
380}
381
382/*
383==============
384SCR_DrawNet
385==============
386*/
387void SCR_DrawNet (void)
388{
389 if (realtime - cl.last_received_message < 0.3)
390 return;
391 if (cls.demoplayback)
392 return;
393
394 Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
395}
396
397/*
398==============
399DrawPause
400==============
401*/
402void SCR_DrawPause (void)
403{
404 qpic_t *pic;
405
406 if (!scr_showpause.value) // turn off for screenshots
407 return;
408
409 if (!cl.paused)
410 return;
411
412 pic = Draw_CachePic ("gfx/pause.lmp");
413 Draw_Pic ( (vid.width - pic->width)/2,
414 (vid.height - 48 - pic->height)/2, pic);
415}
416
417
418
419/*
420==============
421SCR_DrawLoading
422==============
423*/
424void SCR_DrawLoading (void)
425{
426 qpic_t *pic;
427
428 if (!scr_drawloading)
429 return;
430
431 pic = Draw_CachePic ("gfx/loading.lmp");
432 Draw_Pic ( (vid.width - pic->width)/2,
433 (vid.height - 48 - pic->height)/2, pic);
434}
435
436
437
438//=============================================================================
439
440
441/*
442==================
443SCR_SetUpToDrawConsole
444==================
445*/
446void SCR_SetUpToDrawConsole (void)
447{
448 Con_CheckResize ();
449
450 if (scr_drawloading)
451 return; // never a console with loading plaque
452
453// decide on the height of the console
454 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
455
456 if (con_forcedup)
457 {
458 scr_conlines = vid.height; // full screen
459 scr_con_current = scr_conlines;
460 }
461 else if (key_dest == key_console)
462 scr_conlines = vid.height/2; // half screen
463 else
464 scr_conlines = 0; // none visible
465
466 if (scr_conlines < scr_con_current)
467 {
468 scr_con_current -= scr_conspeed.value*host_frametime;
469 if (scr_conlines > scr_con_current)
470 scr_con_current = scr_conlines;
471
472 }
473 else if (scr_conlines > scr_con_current)
474 {
475 scr_con_current += scr_conspeed.value*host_frametime;
476 if (scr_conlines < scr_con_current)
477 scr_con_current = scr_conlines;
478 }
479
480 if (clearconsole++ < vid.numpages)
481 {
482 scr_copytop = 1;
483 Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);
484 Sbar_Changed ();
485 }
486 else if (clearnotify++ < vid.numpages)
487 {
488 scr_copytop = 1;
489 Draw_TileClear (0,0,vid.width, con_notifylines);
490 }
491 else
492 con_notifylines = 0;
493}
494
495/*
496==================
497SCR_DrawConsole
498==================
499*/
500void SCR_DrawConsole (void)
501{
502 if (scr_con_current)
503 {
504 scr_copyeverything = 1;
505 Con_DrawConsole (scr_con_current, true);
506 clearconsole = 0;
507 }
508 else
509 {
510 if (key_dest == key_game || key_dest == key_message)
511 Con_DrawNotify (); // only draw notify in game
512 }
513}
514
515
516/*
517==============================================================================
518
519 SCREEN SHOTS
520
521==============================================================================
522*/
523
524
525typedef struct
526{
527 char manufacturer;
528 char version;
529 char encoding;
530 char bits_per_pixel;
531 unsigned short xmin,ymin,xmax,ymax;
532 unsigned short hres,vres;
533 unsigned char palette[48];
534 char reserved;
535 char color_planes;
536 unsigned short bytes_per_line;
537 unsigned short palette_type;
538 char filler[58];
539 unsigned char data; // unbounded
540} pcx_t;
541
542/*
543==============
544WritePCXfile
545==============
546*/
547void WritePCXfile (char *filename, byte *data, int width, int height,
548 int rowbytes, byte *palette)
549{
550 int i, j, length;
551 pcx_t *pcx;
552 byte *pack;
553
554 pcx = Hunk_TempAlloc (width*height*2+1000);
555 if (pcx == NULL)
556 {
557 Con_Printf("SCR_ScreenShot_f: not enough memory\n");
558 return;
559 }
560
561 pcx->manufacturer = 0x0a; // PCX id
562 pcx->version = 5; // 256 color
563 pcx->encoding = 1; // uncompressed
564 pcx->bits_per_pixel = 8; // 256 color
565 pcx->xmin = 0;
566 pcx->ymin = 0;
567 pcx->xmax = LittleShort((short)(width-1));
568 pcx->ymax = LittleShort((short)(height-1));
569 pcx->hres = LittleShort((short)width);
570 pcx->vres = LittleShort((short)height);
571 Q_memset (pcx->palette,0,sizeof(pcx->palette));
572 pcx->color_planes = 1; // chunky image
573 pcx->bytes_per_line = LittleShort((short)width);
574 pcx->palette_type = LittleShort(2); // not a grey scale
575 Q_memset (pcx->filler,0,sizeof(pcx->filler));
576
577// pack the image
578 pack = &pcx->data;
579
580 for (i=0 ; i<height ; i++)
581 {
582 for (j=0 ; j<width ; j++)
583 {
584 if ( (*data & 0xc0) != 0xc0)
585 *pack++ = *data++;
586 else
587 {
588 *pack++ = 0xc1;
589 *pack++ = *data++;
590 }
591 }
592
593 data += rowbytes - width;
594 }
595
596// write the palette
597 *pack++ = 0x0c; // palette ID byte
598 for (i=0 ; i<768 ; i++)
599 *pack++ = *palette++;
600
601// write output file
602 length = pack - (byte *)pcx;
603 COM_WriteFile (filename, pcx, length);
604}
605
606
607
608/*
609==================
610SCR_ScreenShot_f
611==================
612*/
613void SCR_ScreenShot_f (void)
614{
615 int i;
616 char pcxname[80];
617 char checkname[MAX_OSPATH];
618
619//
620// find a file name to save it to
621//
622 strcpy(pcxname,"quake00.pcx");
623
624 for (i=0 ; i<=99 ; i++)
625 {
626 pcxname[5] = i/10 + '0';
627 pcxname[6] = i%10 + '0';
628 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
629 if (Sys_FileTime(checkname) == -1)
630 break; // file doesn't exist
631 }
632 if (i==100)
633 {
634 Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n");
635 return;
636 }
637
638//
639// save the pcx file
640//
641 D_EnableBackBufferAccess (); // enable direct drawing of console to back
642 // buffer
643
644 WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
645 host_basepal);
646
647 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
648 // for linear writes all the time
649
650 Con_Printf ("Wrote %s\n", pcxname);
651}
652
653
654//=============================================================================
655
656
657/*
658===============
659SCR_BeginLoadingPlaque
660
661================
662*/
663void SCR_BeginLoadingPlaque (void)
664{
665 S_StopAllSounds (true);
666
667 if (cls.state != ca_connected)
668 return;
669 if (cls.signon != SIGNONS)
670 return;
671
672// redraw with no console and the loading plaque
673 Con_ClearNotify ();
674 scr_centertime_off = 0;
675 scr_con_current = 0;
676
677 scr_drawloading = true;
678 scr_fullupdate = 0;
679 Sbar_Changed ();
680 SCR_UpdateScreen ();
681 scr_drawloading = false;
682
683 scr_disabled_for_loading = true;
684 scr_disabled_time = realtime;
685 scr_fullupdate = 0;
686}
687
688/*
689===============
690SCR_EndLoadingPlaque
691
692================
693*/
694void SCR_EndLoadingPlaque (void)
695{
696 scr_disabled_for_loading = false;
697 scr_fullupdate = 0;
698 Con_ClearNotify ();
699}
700
701//=============================================================================
702
703char *scr_notifystring;
704qboolean scr_drawdialog;
705
706void SCR_DrawNotifyString (void)
707{
708 char *start;
709 int l;
710 int j;
711 int x, y;
712
713 start = scr_notifystring;
714
715 y = vid.height*0.35;
716
717 do
718 {
719 // scan the width of the line
720 for (l=0 ; l<40 ; l++)
721 if (start[l] == '\n' || !start[l])
722 break;
723 x = (vid.width - l*8)/2;
724 for (j=0 ; j<l ; j++, x+=8)
725 Draw_Character (x, y, start[j]);
726
727 y += 8;
728
729 while (*start && *start != '\n')
730 start++;
731
732 if (!*start)
733 break;
734 start++; // skip the \n
735 } while (1);
736}
737
738/*
739==================
740SCR_ModalMessage
741
742Displays a text string in the center of the screen and waits for a Y or N
743keypress.
744==================
745*/
746int SCR_ModalMessage (char *text)
747{
748 if (cls.state == ca_dedicated)
749 return true;
750
751 scr_notifystring = text;
752
753// draw a fresh screen
754 scr_fullupdate = 0;
755 scr_drawdialog = true;
756 SCR_UpdateScreen ();
757 scr_drawdialog = false;
758
759 S_ClearBuffer (); // so dma doesn't loop current sound
760
761 // clear
762 key_lastpress = 0;
763
764 do
765 {
766 key_count = -1; // wait for a key down and up
767 Sys_SendKeyEvents ();
768 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE && key_lastpress != K_ENTER);
769
770 scr_fullupdate = 0;
771 SCR_UpdateScreen ();
772
773 return key_lastpress == K_ENTER;
774}
775
776
777//=============================================================================
778
779/*
780===============
781SCR_BringDownConsole
782
783Brings the console down and fades the palettes back to normal
784================
785*/
786void SCR_BringDownConsole (void)
787{
788 int i;
789
790 scr_centertime_off = 0;
791
792 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
793 SCR_UpdateScreen ();
794
795 cl.cshifts[0].percent = 0; // no area contents palette on next frame
796 VID_SetPalette (host_basepal);
797}
798
799
800/*
801==================
802SCR_UpdateScreen
803
804This is called every frame, and can also be called explicitly to flush
805text to the screen.
806
807WARNING: be very careful calling this from elsewhere, because the refresh
808needs almost the entire 256k of stack space!
809==================
810*/
811void SCR_UpdateScreen (void)
812{
813 static float oldscr_viewsize;
814 static float oldlcd_x;
815 vrect_t vrect;
816
817 if (scr_skipupdate || block_drawing)
818 return;
819
820 scr_copytop = 0;
821 scr_copyeverything = 0;
822
823 if (scr_disabled_for_loading)
824 {
825 if (realtime - scr_disabled_time > 60)
826 {
827 scr_disabled_for_loading = false;
828 Con_Printf ("load failed.\n");
829 }
830 else
831 return;
832 }
833
834 if (cls.state == ca_dedicated)
835 return; // stdout only
836
837 if (!scr_initialized || !con_initialized)
838 return; // not initialized yet
839
840 if (scr_viewsize.value != oldscr_viewsize)
841 {
842 oldscr_viewsize = scr_viewsize.value;
843 vid.recalc_refdef = 1;
844 }
845
846//
847// check for vid changes
848//
849 if (oldfov != scr_fov.value)
850 {
851 oldfov = scr_fov.value;
852 vid.recalc_refdef = true;
853 }
854
855 if (oldlcd_x != lcd_x.value)
856 {
857 oldlcd_x = lcd_x.value;
858 vid.recalc_refdef = true;
859 }
860
861 if (oldscreensize != scr_viewsize.value)
862 {
863 oldscreensize = scr_viewsize.value;
864 vid.recalc_refdef = true;
865 }
866
867 if (vid.recalc_refdef)
868 {
869 // something changed, so reorder the screen
870 SCR_CalcRefdef ();
871 }
872
873//
874// do 3D refresh drawing, and then update the screen
875//
876 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
877
878 if (scr_fullupdate++ < vid.numpages)
879 { // clear the entire screen
880 scr_copyeverything = 1;
881 Draw_TileClear (0,0,vid.width,vid.height);
882 Sbar_Changed ();
883 }
884
885 pconupdate = NULL;
886
887
888 SCR_SetUpToDrawConsole ();
889 SCR_EraseCenterString ();
890
891 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
892 // for linear writes all the time
893
894 VID_LockBuffer ();
895
896 V_RenderView ();
897
898 VID_UnlockBuffer ();
899
900 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
901
902 if (scr_drawdialog)
903 {
904 Sbar_Draw ();
905 Draw_FadeScreen ();
906 SCR_DrawNotifyString ();
907 scr_copyeverything = true;
908 }
909 else if (scr_drawloading)
910 {
911 SCR_DrawLoading ();
912 Sbar_Draw ();
913 }
914 else if (cl.intermission == 1 && key_dest == key_game)
915 {
916 Sbar_IntermissionOverlay ();
917 }
918 else if (cl.intermission == 2 && key_dest == key_game)
919 {
920 Sbar_FinaleOverlay ();
921 SCR_CheckDrawCenterString ();
922 }
923 else if (cl.intermission == 3 && key_dest == key_game)
924 {
925 SCR_CheckDrawCenterString ();
926 }
927 else
928 {
929 SCR_DrawRam ();
930 SCR_DrawNet ();
931 SCR_DrawTurtle ();
932 SCR_DrawPause ();
933 SCR_CheckDrawCenterString ();
934 Sbar_Draw ();
935 SCR_DrawConsole ();
936 M_Draw ();
937 }
938
939 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
940 // for linear writes all the time
941 if (pconupdate)
942 {
943 D_UpdateRects (pconupdate);
944 }
945
946 V_UpdatePalette ();
947
948//
949// update one of three areas
950//
951
952 if (scr_copyeverything)
953 {
954 vrect.x = 0;
955 vrect.y = 0;
956 vrect.width = vid.width;
957 vrect.height = vid.height;
958 vrect.pnext = 0;
959
960 VID_Update (&vrect);
961 }
962 else if (scr_copytop)
963 {
964 vrect.x = 0;
965 vrect.y = 0;
966 vrect.width = vid.width;
967 vrect.height = vid.height - sb_lines;
968 vrect.pnext = 0;
969
970 VID_Update (&vrect);
971 }
972 else
973 {
974 vrect.x = scr_vrect.x;
975 vrect.y = scr_vrect.y;
976 vrect.width = scr_vrect.width;
977 vrect.height = scr_vrect.height;
978 vrect.pnext = 0;
979
980 VID_Update (&vrect);
981 }
982}
983
984
985/*
986==================
987SCR_UpdateWholeScreen
988==================
989*/
990void SCR_UpdateWholeScreen (void)
991{
992 scr_fullupdate = 0;
993 SCR_UpdateScreen ();
994}
diff --git a/apps/plugins/sdl/progs/quake/screen.h b/apps/plugins/sdl/progs/quake/screen.h
new file mode 100644
index 0000000000..845ab55a33
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/screen.h
@@ -0,0 +1,57 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// screen.h
21
22void SCR_Init (void);
23
24void SCR_UpdateScreen (void);
25
26
27void SCR_SizeUp (void);
28void SCR_SizeDown (void);
29void SCR_BringDownConsole (void);
30void SCR_CenterPrint (char *str);
31
32void SCR_BeginLoadingPlaque (void);
33void SCR_EndLoadingPlaque (void);
34
35int SCR_ModalMessage (char *text);
36
37extern float scr_con_current;
38extern float scr_conlines; // lines of console to display
39
40extern int scr_fullupdate; // set to 0 to force full redraw
41extern int sb_lines;
42
43extern int clearnotify; // set to 0 whenever notify text is drawn
44extern qboolean scr_disabled_for_loading;
45extern qboolean scr_skipupdate;
46
47extern cvar_t scr_viewsize;
48
49extern cvar_t scr_viewsize;
50
51// only the refresh window will be updated unless these variables are flagged
52extern int scr_copytop;
53extern int scr_copyeverything;
54
55extern qboolean block_drawing;
56
57void SCR_UpdateWholeScreen (void);
diff --git a/apps/plugins/sdl/progs/quake/server.h b/apps/plugins/sdl/progs/quake/server.h
new file mode 100644
index 0000000000..5fe33deca0
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/server.h
@@ -0,0 +1,258 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// server.h
21
22typedef struct
23{
24 int maxclients;
25 int maxclientslimit;
26 struct client_s *clients; // [maxclients]
27 int serverflags; // episode completion information
28 qboolean changelevel_issued; // cleared when at SV_SpawnServer
29} server_static_t;
30
31//=============================================================================
32
33typedef int server_state_t;
34enum {ss_loading, ss_active};
35
36typedef struct
37{
38 qboolean active; // false if only a net client
39
40 qboolean paused;
41 qboolean loadgame; // handle connections specially
42
43 double time;
44
45 int lastcheck; // used by PF_checkclient
46 double lastchecktime;
47
48 char name[64]; // map name
49#ifdef QUAKE2
50 char startspot[64];
51#endif
52 char modelname[64]; // maps/<name>.bsp, for model_precache[0]
53 struct model_s *worldmodel;
54 char *model_precache[MAX_MODELS]; // NULL terminated
55 struct model_s *models[MAX_MODELS];
56 char *sound_precache[MAX_SOUNDS]; // NULL terminated
57 char *lightstyles[MAX_LIGHTSTYLES];
58 int num_edicts;
59 int max_edicts;
60 edict_t *edicts; // can NOT be array indexed, because
61 // edict_t is variable sized, but can
62 // be used to reference the world ent
63 server_state_t state; // some actions are only valid during load
64
65 sizebuf_t datagram;
66 byte datagram_buf[MAX_DATAGRAM];
67
68 sizebuf_t reliable_datagram; // copied to all clients at end of frame
69 byte reliable_datagram_buf[MAX_DATAGRAM];
70
71 sizebuf_t signon;
72 byte signon_buf[8192];
73} server_t;
74
75
76#define NUM_PING_TIMES 16
77#define NUM_SPAWN_PARMS 16
78
79typedef struct client_s
80{
81 qboolean active; // false = client is free
82 qboolean spawned; // false = don't send datagrams
83 qboolean dropasap; // has been told to go to another level
84 qboolean privileged; // can execute any host command
85 qboolean sendsignon; // only valid before spawned
86
87 double last_message; // reliable messages must be sent
88 // periodically
89
90 struct qsocket_s *netconnection; // communications handle
91
92 usercmd_t cmd; // movement
93 vec3_t wishdir; // intended motion calced from cmd
94
95 sizebuf_t message; // can be added to at any time,
96 // copied and clear once per frame
97 byte msgbuf[MAX_MSGLEN];
98 edict_t *edict; // EDICT_NUM(clientnum+1)
99 char name[32]; // for printing to other people
100 int colors;
101
102 float ping_times[NUM_PING_TIMES];
103 int num_pings; // ping_times[num_pings%NUM_PING_TIMES]
104
105// spawn parms are carried from level to level
106 float spawn_parms[NUM_SPAWN_PARMS];
107
108// client known data for deltas
109 int old_frags;
110} client_t;
111
112
113//=============================================================================
114
115// edict->movetype values
116#define MOVETYPE_NONE 0 // never moves
117#define MOVETYPE_ANGLENOCLIP 1
118#define MOVETYPE_ANGLECLIP 2
119#define MOVETYPE_WALK 3 // gravity
120#define MOVETYPE_STEP 4 // gravity, special edge handling
121#define MOVETYPE_FLY 5
122#define MOVETYPE_TOSS 6 // gravity
123#define MOVETYPE_PUSH 7 // no clip to world, push and crush
124#define MOVETYPE_NOCLIP 8
125#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
126#define MOVETYPE_BOUNCE 10
127#ifdef QUAKE2
128#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity
129#define MOVETYPE_FOLLOW 12 // track movement of aiment
130#endif
131
132// edict->solid values
133#define SOLID_NOT 0 // no interaction with other objects
134#define SOLID_TRIGGER 1 // touch on edge, but not blocking
135#define SOLID_BBOX 2 // touch on edge, block
136#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
137#define SOLID_BSP 4 // bsp clip, touch on edge, block
138
139// edict->deadflag values
140#define DEAD_NO 0
141#define DEAD_DYING 1
142#define DEAD_DEAD 2
143
144#define DAMAGE_NO 0
145#define DAMAGE_YES 1
146#define DAMAGE_AIM 2
147
148// edict->flags
149#define FL_FLY 1
150#define FL_SWIM 2
151//#define FL_GLIMPSE 4
152#define FL_CONVEYOR 4
153#define FL_CLIENT 8
154#define FL_INWATER 16
155#define FL_MONSTER 32
156#define FL_GODMODE 64
157#define FL_NOTARGET 128
158#define FL_ITEM 256
159#define FL_ONGROUND 512
160#define FL_PARTIALGROUND 1024 // not all corners are valid
161#define FL_WATERJUMP 2048 // player jumping out of water
162#define FL_JUMPRELEASED 4096 // for jump debouncing
163#ifdef QUAKE2
164#define FL_FLASHLIGHT 8192
165#define FL_ARCHIVE_OVERRIDE 1048576
166#endif
167
168// entity effects
169
170#define EF_BRIGHTFIELD 1
171#define EF_MUZZLEFLASH 2
172#define EF_BRIGHTLIGHT 4
173#define EF_DIMLIGHT 8
174#ifdef QUAKE2
175#define EF_DARKLIGHT 16
176#define EF_DARKFIELD 32
177#define EF_LIGHT 64
178#define EF_NODRAW 128
179#endif
180
181#define SPAWNFLAG_NOT_EASY 256
182#define SPAWNFLAG_NOT_MEDIUM 512
183#define SPAWNFLAG_NOT_HARD 1024
184#define SPAWNFLAG_NOT_DEATHMATCH 2048
185
186#ifdef QUAKE2
187// server flags
188#define SFL_EPISODE_1 1
189#define SFL_EPISODE_2 2
190#define SFL_EPISODE_3 4
191#define SFL_EPISODE_4 8
192#define SFL_NEW_UNIT 16
193#define SFL_NEW_EPISODE 32
194#define SFL_CROSS_TRIGGERS 65280
195#endif
196
197//============================================================================
198
199extern cvar_t teamplay;
200extern cvar_t skill;
201extern cvar_t deathmatch;
202extern cvar_t coop;
203extern cvar_t fraglimit;
204extern cvar_t timelimit;
205
206extern server_static_t svs; // persistant server info
207extern server_t sv; // local server
208
209extern client_t *host_client;
210
211extern jmp_buf host_abortserver;
212
213extern double host_time;
214
215extern edict_t *sv_player;
216
217//===========================================================
218
219void SV_Init (void);
220
221void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
222void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
223 float attenuation);
224
225void SV_DropClient (qboolean crash);
226
227void SV_SendClientMessages (void);
228void SV_ClearDatagram (void);
229
230int SV_ModelIndex (char *name);
231
232void SV_SetIdealPitch (void);
233
234void SV_AddUpdates (void);
235
236void SV_ClientThink (void);
237void SV_AddClientToServer (struct qsocket_s *ret);
238
239void SV_ClientPrintf (char *fmt, ...);
240void SV_BroadcastPrintf (char *fmt, ...);
241
242void SV_Physics (void);
243
244qboolean SV_CheckBottom (edict_t *ent);
245qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink);
246
247void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);
248
249void SV_MoveToGoal (void);
250
251void SV_CheckForNewClients (void);
252void SV_RunClients (void);
253void SV_SaveSpawnparms ();
254#ifdef QUAKE2
255void SV_SpawnServer (char *server, char *startspot);
256#else
257void SV_SpawnServer (char *server);
258#endif
diff --git a/apps/plugins/sdl/progs/quake/snd_dma.c b/apps/plugins/sdl/progs/quake/snd_dma.c
new file mode 100644
index 0000000000..4c42f32d49
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_dma.c
@@ -0,0 +1,1021 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// snd_dma.c -- main control for any streaming sound output device
21
22#include "quakedef.h"
23
24#ifdef _WIN32
25#include "winquake.h"
26#endif
27
28void S_Play(void);
29void S_PlayVol(void);
30void S_SoundList(void);
31void S_Update_();
32void S_StopAllSounds(qboolean clear);
33void S_StopAllSoundsC(void);
34
35// =======================================================================
36// Internal sound data & structures
37// =======================================================================
38
39channel_t channels[MAX_CHANNELS];
40int total_channels;
41
42int snd_blocked = 0;
43static qboolean snd_ambient = 1;
44qboolean snd_initialized = false;
45
46// pointer should go away
47volatile dma_t *shm = 0;
48volatile dma_t sn;
49
50vec3_t listener_origin;
51vec3_t listener_forward;
52vec3_t listener_right;
53vec3_t listener_up;
54vec_t sound_nominal_clip_dist=1000.0;
55
56int soundtime; // sample PAIRS
57int paintedtime; // sample PAIRS
58
59
60#define MAX_SFX 512
61sfx_t *known_sfx; // hunk allocated [MAX_SFX]
62int num_sfx;
63
64sfx_t *ambient_sfx[NUM_AMBIENTS];
65
66// lowest rockbox supported
67int desired_speed = SAMPR_16;
68int desired_bits = 16;
69
70int sound_started=0;
71
72cvar_t bgmvolume = {"bgmvolume", "1", true};
73cvar_t volume = {"volume", "0.7", true};
74
75cvar_t nosound = {"nosound", "0"};
76cvar_t precache = {"precache", "1"};
77cvar_t loadas8bit = {"loadas8bit", "0"};
78cvar_t bgmbuffer = {"bgmbuffer", "4096"};
79cvar_t ambient_level = {"ambient_level", "0.3"};
80cvar_t ambient_fade = {"ambient_fade", "100"};
81cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"};
82cvar_t snd_show = {"snd_show", "0"};
83cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true};
84
85
86// ====================================================================
87// User-setable variables
88// ====================================================================
89
90
91//
92// Fake dma is a synchronous faking of the DMA progress used for
93// isolating performance in the renderer. The fakedma_updates is
94// number of times S_Update() is called per second.
95//
96
97qboolean fakedma = false;
98int fakedma_updates = 15;
99
100
101void S_AmbientOff (void)
102{
103 snd_ambient = false;
104}
105
106
107void S_AmbientOn (void)
108{
109 snd_ambient = true;
110}
111
112
113void S_SoundInfo_f(void)
114{
115 if (!sound_started || !shm)
116 {
117 Con_Printf ("sound system not started\n");
118 return;
119 }
120
121 Con_Printf("%5d stereo\n", shm->channels - 1);
122 Con_Printf("%5d samples\n", shm->samples);
123 Con_Printf("%5d samplepos\n", shm->samplepos);
124 Con_Printf("%5d samplebits\n", shm->samplebits);
125 Con_Printf("%5d submission_chunk\n", shm->submission_chunk);
126 Con_Printf("%5d speed\n", shm->speed);
127 Con_Printf("0x%x dma buffer\n", shm->buffer);
128 Con_Printf("%5d total_channels\n", total_channels);
129}
130
131
132/*
133================
134S_Startup
135================
136*/
137
138void S_Startup (void)
139{
140 int rc;
141
142 if (!snd_initialized)
143 return;
144
145 if (!fakedma)
146 {
147 rc = SNDDMA_Init();
148
149 if (!rc)
150 {
151#ifndef _WIN32
152 Con_Printf("S_Startup: SNDDMA_Init failed.\n");
153#endif
154 sound_started = 0;
155 return;
156 }
157 }
158
159 sound_started = 1;
160}
161
162
163/*
164================
165S_Init
166================
167*/
168void S_Init (void)
169{
170
171 Con_Printf("\nSound Initialization\n");
172
173 if (COM_CheckParm("-nosound"))
174 return;
175
176 if (COM_CheckParm("-simsound"))
177 fakedma = true;
178
179 Cmd_AddCommand("play", S_Play);
180 Cmd_AddCommand("playvol", S_PlayVol);
181 Cmd_AddCommand("stopsound", S_StopAllSoundsC);
182 Cmd_AddCommand("soundlist", S_SoundList);
183 Cmd_AddCommand("soundinfo", S_SoundInfo_f);
184
185 Cvar_RegisterVariable(&nosound);
186 Cvar_RegisterVariable(&volume);
187 Cvar_RegisterVariable(&precache);
188 Cvar_RegisterVariable(&loadas8bit);
189 Cvar_RegisterVariable(&bgmvolume);
190 Cvar_RegisterVariable(&bgmbuffer);
191 Cvar_RegisterVariable(&ambient_level);
192 Cvar_RegisterVariable(&ambient_fade);
193 Cvar_RegisterVariable(&snd_noextraupdate);
194 Cvar_RegisterVariable(&snd_show);
195 Cvar_RegisterVariable(&_snd_mixahead);
196
197 if (host_parms.memsize < 0x800000)
198 {
199 Cvar_Set ("loadas8bit", "1");
200 Con_Printf ("loading all sounds as 8bit\n");
201 }
202
203
204
205 snd_initialized = true;
206
207 S_Startup ();
208
209 known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t");
210 num_sfx = 0;
211
212// create a piece of DMA memory
213
214 if (fakedma)
215 {
216 shm = (void *) Hunk_AllocName(sizeof(*shm), "shm");
217 shm->splitbuffer = 0;
218 shm->samplebits = 16;
219 shm->speed = 22050;
220 shm->channels = 2;
221 shm->samples = 32768;
222 shm->samplepos = 0;
223 shm->soundalive = true;
224 shm->gamealive = true;
225 shm->submission_chunk = 1;
226 shm->buffer = Hunk_AllocName(1<<16, "shmbuf");
227 }
228
229 if ( shm ) {
230 Con_Printf ("Sound sampling rate: %i\n", shm->speed);
231 }
232
233 // provides a tick sound until washed clean
234
235// if (shm->buffer)
236// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging
237
238 ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav");
239 ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav");
240
241 S_StopAllSounds (true);
242}
243
244
245// =======================================================================
246// Shutdown sound engine
247// =======================================================================
248
249void S_Shutdown(void)
250{
251
252 if (!sound_started)
253 return;
254
255 if (shm)
256 shm->gamealive = 0;
257
258 shm = 0;
259 sound_started = 0;
260
261 if (!fakedma)
262 {
263 SNDDMA_Shutdown();
264 }
265}
266
267
268// =======================================================================
269// Load a sound
270// =======================================================================
271
272/*
273==================
274S_FindName
275
276==================
277*/
278sfx_t *S_FindName (char *name)
279{
280 int i;
281 sfx_t *sfx;
282
283 if (!name)
284 Sys_Error ("S_FindName: NULL\n");
285
286 if (Q_strlen(name) >= MAX_QPATH)
287 Sys_Error ("Sound name too long: %s", name);
288
289// see if already loaded
290 for (i=0 ; i < num_sfx ; i++)
291 if (!Q_strcmp(known_sfx[i].name, name))
292 {
293 return &known_sfx[i];
294 }
295
296 if (num_sfx == MAX_SFX)
297 Sys_Error ("S_FindName: out of sfx_t");
298
299 sfx = &known_sfx[i];
300 strcpy (sfx->name, name);
301
302 num_sfx++;
303
304 return sfx;
305}
306
307
308/*
309==================
310S_TouchSound
311
312==================
313*/
314void S_TouchSound (char *name)
315{
316 sfx_t *sfx;
317
318 if (!sound_started)
319 return;
320
321 sfx = S_FindName (name);
322 Cache_Check (&sfx->cache);
323}
324
325/*
326==================
327S_PrecacheSound
328
329==================
330*/
331sfx_t *S_PrecacheSound (char *name)
332{
333 sfx_t *sfx;
334
335 if (!sound_started || nosound.value)
336 return NULL;
337
338 sfx = S_FindName (name);
339
340// cache it in
341 if (precache.value)
342 S_LoadSound (sfx);
343
344 return sfx;
345}
346
347
348//=============================================================================
349
350/*
351=================
352SND_PickChannel
353=================
354*/
355channel_t *SND_PickChannel(int entnum, int entchannel)
356{
357 int ch_idx;
358 int first_to_die;
359 int life_left;
360
361// Check for replacement sound, or find the best one to replace
362 first_to_die = -1;
363 life_left = 0x7fffffff;
364 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
365 {
366 if (entchannel != 0 // channel 0 never overrides
367 && channels[ch_idx].entnum == entnum
368 && (channels[ch_idx].entchannel == entchannel || entchannel == -1) )
369 { // allways override sound from same entity
370 first_to_die = ch_idx;
371 break;
372 }
373
374 // don't let monster sounds override player sounds
375 if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)
376 continue;
377
378 if (channels[ch_idx].end - paintedtime < life_left)
379 {
380 life_left = channels[ch_idx].end - paintedtime;
381 first_to_die = ch_idx;
382 }
383 }
384
385 if (first_to_die == -1)
386 return NULL;
387
388 if (channels[first_to_die].sfx)
389 channels[first_to_die].sfx = NULL;
390
391 return &channels[first_to_die];
392}
393
394/*
395=================
396SND_Spatialize
397=================
398*/
399void SND_Spatialize(channel_t *ch)
400{
401 vec_t dot;
402 vec_t ldist, rdist, dist;
403 vec_t lscale, rscale, scale;
404 vec3_t source_vec;
405 sfx_t *snd;
406
407// anything coming from the view entity will allways be full volume
408 if (ch->entnum == cl.viewentity)
409 {
410 ch->leftvol = ch->master_vol;
411 ch->rightvol = ch->master_vol;
412 return;
413 }
414
415// calculate stereo seperation and distance attenuation
416
417 snd = ch->sfx;
418 VectorSubtract(ch->origin, listener_origin, source_vec);
419
420 dist = VectorNormalize(source_vec) * ch->dist_mult;
421
422 dot = DotProduct(listener_right, source_vec);
423
424 if (shm->channels == 1)
425 {
426 rscale = 1.0;
427 lscale = 1.0;
428 }
429 else
430 {
431 rscale = 1.0 + dot;
432 lscale = 1.0 - dot;
433 }
434
435// add in distance effect
436 scale = (1.0 - dist) * rscale;
437 ch->rightvol = (int) (ch->master_vol * scale);
438 if (ch->rightvol < 0)
439 ch->rightvol = 0;
440
441 scale = (1.0 - dist) * lscale;
442 ch->leftvol = (int) (ch->master_vol * scale);
443 if (ch->leftvol < 0)
444 ch->leftvol = 0;
445}
446
447
448// =======================================================================
449// Start a sound effect
450// =======================================================================
451
452void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
453{
454 channel_t *target_chan, *check;
455 sfxcache_t *sc;
456 int vol;
457 int ch_idx;
458 int skip;
459
460 if (!sound_started)
461 return;
462
463 if (!sfx)
464 return;
465
466 if (nosound.value)
467 return;
468
469 vol = fvol*255;
470
471// pick a channel to play on
472 target_chan = SND_PickChannel(entnum, entchannel);
473 if (!target_chan)
474 return;
475
476// spatialize
477 memset (target_chan, 0, sizeof(*target_chan));
478 VectorCopy(origin, target_chan->origin);
479 target_chan->dist_mult = attenuation / sound_nominal_clip_dist;
480 target_chan->master_vol = vol;
481 target_chan->entnum = entnum;
482 target_chan->entchannel = entchannel;
483 SND_Spatialize(target_chan);
484
485 if (!target_chan->leftvol && !target_chan->rightvol)
486 return; // not audible at all
487
488// new channel
489 sc = S_LoadSound (sfx);
490 if (!sc)
491 {
492 target_chan->sfx = NULL;
493 return; // couldn't load the sound's data
494 }
495
496 target_chan->sfx = sfx;
497 target_chan->pos = 0.0;
498 target_chan->end = paintedtime + sc->length;
499
500// if an identical sound has also been started this frame, offset the pos
501// a bit to keep it from just making the first one louder
502 check = &channels[NUM_AMBIENTS];
503 for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)
504 {
505 if (check == target_chan)
506 continue;
507 if (check->sfx == sfx && !check->pos)
508 {
509 skip = rand () % (int)(0.1*shm->speed);
510 if (skip >= target_chan->end)
511 skip = target_chan->end - 1;
512 target_chan->pos += skip;
513 target_chan->end -= skip;
514 break;
515 }
516
517 }
518}
519
520void S_StopSound(int entnum, int entchannel)
521{
522 int i;
523
524 for (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)
525 {
526 if (channels[i].entnum == entnum
527 && channels[i].entchannel == entchannel)
528 {
529 channels[i].end = 0;
530 channels[i].sfx = NULL;
531 return;
532 }
533 }
534}
535
536void S_StopAllSounds(qboolean clear)
537{
538 int i;
539
540 if (!sound_started)
541 return;
542
543 total_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; // no statics
544
545 for (i=0 ; i<MAX_CHANNELS ; i++)
546 if (channels[i].sfx)
547 channels[i].sfx = NULL;
548
549 Q_memset(channels, 0, MAX_CHANNELS * sizeof(channel_t));
550
551 if (clear)
552 S_ClearBuffer ();
553}
554
555void S_StopAllSoundsC (void)
556{
557 S_StopAllSounds (true);
558}
559
560void S_ClearBuffer (void)
561{
562 int clear;
563
564#ifdef _WIN32
565 if (!sound_started || !shm || (!shm->buffer && !pDSBuf))
566#else
567 if (!sound_started || !shm || !shm->buffer)
568#endif
569 return;
570
571 if (shm->samplebits == 8)
572 clear = 0x80;
573 else
574 clear = 0;
575
576#ifdef _WIN32
577 if (pDSBuf)
578 {
579 DWORD dwSize;
580 DWORD *pData;
581 int reps;
582 HRESULT hresult;
583
584 reps = 0;
585
586 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)
587 {
588 if (hresult != DSERR_BUFFERLOST)
589 {
590 Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n");
591 S_Shutdown ();
592 return;
593 }
594
595 if (++reps > 10000)
596 {
597 Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n");
598 S_Shutdown ();
599 return;
600 }
601 }
602
603 Q_memset(pData, clear, shm->samples * shm->samplebits/8);
604
605 pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
606
607 }
608 else
609#endif
610 {
611 Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8);
612 }
613}
614
615
616/*
617=================
618S_StaticSound
619=================
620*/
621void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
622{
623 channel_t *ss;
624 sfxcache_t *sc;
625
626 if (!sfx)
627 return;
628
629 if (total_channels == MAX_CHANNELS)
630 {
631 Con_Printf ("total_channels == MAX_CHANNELS\n");
632 return;
633 }
634
635 ss = &channels[total_channels];
636 total_channels++;
637
638 sc = S_LoadSound (sfx);
639 if (!sc)
640 return;
641
642 if (sc->loopstart == -1)
643 {
644 Con_Printf ("Sound %s not looped\n", sfx->name);
645 return;
646 }
647
648 ss->sfx = sfx;
649 VectorCopy (origin, ss->origin);
650 ss->master_vol = vol;
651 ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
652 ss->end = paintedtime + sc->length;
653
654 SND_Spatialize (ss);
655}
656
657
658//=============================================================================
659
660/*
661===================
662S_UpdateAmbientSounds
663===================
664*/
665void S_UpdateAmbientSounds (void)
666{
667 mleaf_t *l;
668 float vol;
669 int ambient_channel;
670 channel_t *chan;
671
672 if (!snd_ambient)
673 return;
674
675// calc ambient sound levels
676 if (!cl.worldmodel)
677 return;
678
679 l = Mod_PointInLeaf (listener_origin, cl.worldmodel);
680 if (!l || !ambient_level.value)
681 {
682 for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
683 channels[ambient_channel].sfx = NULL;
684 return;
685 }
686
687 for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
688 {
689 chan = &channels[ambient_channel];
690 chan->sfx = ambient_sfx[ambient_channel];
691
692 vol = ambient_level.value * l->ambient_sound_level[ambient_channel];
693 if (vol < 8)
694 vol = 0;
695
696 // don't adjust volume too fast
697 if (chan->master_vol < vol)
698 {
699 chan->master_vol += host_frametime * ambient_fade.value;
700 if (chan->master_vol > vol)
701 chan->master_vol = vol;
702 }
703 else if (chan->master_vol > vol)
704 {
705 chan->master_vol -= host_frametime * ambient_fade.value;
706 if (chan->master_vol < vol)
707 chan->master_vol = vol;
708 }
709
710 chan->leftvol = chan->rightvol = chan->master_vol;
711 }
712}
713
714
715/*
716============
717S_Update
718
719Called once each time through the main loop
720============
721*/
722void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)
723{
724 int i, j;
725 int total;
726 channel_t *ch;
727 channel_t *combine;
728
729 if (!sound_started || (snd_blocked > 0))
730 return;
731
732 VectorCopy(origin, listener_origin);
733 VectorCopy(forward, listener_forward);
734 VectorCopy(right, listener_right);
735 VectorCopy(up, listener_up);
736
737// update general area ambient sound sources
738 S_UpdateAmbientSounds ();
739
740 combine = NULL;
741
742// update spatialization for static and dynamic sounds
743 ch = channels+NUM_AMBIENTS;
744 for (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)
745 {
746 if (!ch->sfx)
747 continue;
748 SND_Spatialize(ch); // respatialize channel
749 if (!ch->leftvol && !ch->rightvol)
750 continue;
751
752 // try to combine static sounds with a previous channel of the same
753 // sound effect so we don't mix five torches every frame
754
755 if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
756 {
757 // see if it can just use the last one
758 if (combine && combine->sfx == ch->sfx)
759 {
760 combine->leftvol += ch->leftvol;
761 combine->rightvol += ch->rightvol;
762 ch->leftvol = ch->rightvol = 0;
763 continue;
764 }
765 // search for one
766 combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
767 for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
768 if (combine->sfx == ch->sfx)
769 break;
770
771 if (j == total_channels)
772 {
773 combine = NULL;
774 }
775 else
776 {
777 if (combine != ch)
778 {
779 combine->leftvol += ch->leftvol;
780 combine->rightvol += ch->rightvol;
781 ch->leftvol = ch->rightvol = 0;
782 }
783 continue;
784 }
785 }
786
787
788 }
789
790//
791// debugging output
792//
793 if (snd_show.value)
794 {
795 total = 0;
796 ch = channels;
797 for (i=0 ; i<total_channels; i++, ch++)
798 if (ch->sfx && (ch->leftvol || ch->rightvol) )
799 {
800 //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
801 total++;
802 }
803
804 Con_Printf ("----(%i)----\n", total);
805 }
806
807// mix some sound
808 S_Update_();
809}
810
811void GetSoundtime(void)
812{
813 int samplepos;
814 static int buffers;
815 static int oldsamplepos;
816 int fullsamples;
817
818 fullsamples = shm->samples / shm->channels;
819
820// it is possible to miscount buffers if it has wrapped twice between
821// calls to S_Update. Oh well.
822#ifdef __sun__
823 soundtime = SNDDMA_GetSamples();
824#else
825 samplepos = SNDDMA_GetDMAPos();
826
827
828 if (samplepos < oldsamplepos)
829 {
830 buffers++; // buffer wrapped
831
832 if (paintedtime > 0x40000000)
833 { // time to chop things off to avoid 32 bit limits
834 buffers = 0;
835 paintedtime = fullsamples;
836 S_StopAllSounds (true);
837 }
838 }
839 oldsamplepos = samplepos;
840
841 soundtime = buffers*fullsamples + samplepos/shm->channels;
842#endif
843}
844
845void S_ExtraUpdate (void)
846{
847
848#ifdef _WIN32
849 IN_Accumulate ();
850#endif
851
852 if (snd_noextraupdate.value)
853 return; // don't pollute timings
854 S_Update_();
855}
856
857void S_Update_(void)
858{
859#ifndef SDL
860
861 unsigned endtime;
862 int samps;
863
864 if (!sound_started || (snd_blocked > 0))
865 return;
866
867// Updates DMA time
868 GetSoundtime();
869
870// check to make sure that we haven't overshot
871 if (paintedtime < soundtime)
872 {
873 //Con_Printf ("S_Update_ : overflow\n");
874 paintedtime = soundtime;
875 }
876
877// mix ahead of current position
878 endtime = soundtime + _snd_mixahead.value * shm->speed;
879 samps = shm->samples >> (shm->channels-1);
880 if (endtime - soundtime > samps)
881 endtime = soundtime + samps;
882
883#ifdef _WIN32
884// if the buffer was lost or stopped, restore it and/or restart it
885 {
886 DWORD dwStatus;
887
888 if (pDSBuf)
889 {
890 if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)
891 Con_Printf ("Couldn't get sound buffer status\n");
892
893 if (dwStatus & DSBSTATUS_BUFFERLOST)
894 pDSBuf->lpVtbl->Restore (pDSBuf);
895
896 if (!(dwStatus & DSBSTATUS_PLAYING))
897 pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
898 }
899 }
900#endif
901
902 S_PaintChannels (endtime);
903
904 SNDDMA_Submit ();
905#endif /* ! SDL */
906}
907
908/*
909===============================================================================
910
911console functions
912
913===============================================================================
914*/
915
916void S_Play(void)
917{
918 static int hash=345;
919 int i;
920 char name[256];
921 sfx_t *sfx;
922
923 i = 1;
924 while (i<Cmd_Argc())
925 {
926 if (!Q_strrchr(Cmd_Argv(i), '.'))
927 {
928 Q_strcpy(name, Cmd_Argv(i));
929 Q_strcat(name, ".wav");
930 }
931 else
932 Q_strcpy(name, Cmd_Argv(i));
933 sfx = S_PrecacheSound(name);
934 S_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);
935 i++;
936 }
937}
938
939void S_PlayVol(void)
940{
941 static int hash=543;
942 int i;
943 float vol;
944 char name[256];
945 sfx_t *sfx;
946
947 i = 1;
948 while (i<Cmd_Argc())
949 {
950 if (!Q_strrchr(Cmd_Argv(i), '.'))
951 {
952 Q_strcpy(name, Cmd_Argv(i));
953 Q_strcat(name, ".wav");
954 }
955 else
956 Q_strcpy(name, Cmd_Argv(i));
957 sfx = S_PrecacheSound(name);
958 vol = Q_atof(Cmd_Argv(i+1));
959 S_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);
960 i+=2;
961 }
962}
963
964void S_SoundList(void)
965{
966 int i;
967 sfx_t *sfx;
968 sfxcache_t *sc;
969 int size, total;
970
971 total = 0;
972 for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
973 {
974 sc = Cache_Check (&sfx->cache);
975 if (!sc)
976 continue;
977 size = sc->length*sc->width*(sc->stereo+1);
978 total += size;
979 if (sc->loopstart >= 0)
980 Con_Printf ("L");
981 else
982 Con_Printf (" ");
983 Con_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
984 }
985 Con_Printf ("Total resident: %i\n", total);
986}
987
988
989void S_LocalSound (char *sound)
990{
991 sfx_t *sfx;
992
993 if (nosound.value)
994 return;
995 if (!sound_started)
996 return;
997
998 sfx = S_PrecacheSound (sound);
999 if (!sfx)
1000 {
1001 Con_Printf ("S_LocalSound: can't cache %s\n", sound);
1002 return;
1003 }
1004 S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);
1005}
1006
1007
1008void S_ClearPrecache (void)
1009{
1010}
1011
1012
1013void S_BeginPrecaching (void)
1014{
1015}
1016
1017
1018void S_EndPrecaching (void)
1019{
1020}
1021
diff --git a/apps/plugins/sdl/progs/quake/snd_linux.c b/apps/plugins/sdl/progs/quake/snd_linux.c
new file mode 100644
index 0000000000..4579e40d64
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_linux.c
@@ -0,0 +1,269 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include <unistd.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <sys/ioctl.h>
25#include <sys/mman.h>
26#include <sys/shm.h>
27#include <sys/wait.h>
28#include <linux/soundcard.h>
29#include <stdio.h>
30#include "quakedef.h"
31
32int audio_fd;
33int snd_inited;
34
35static int tryrates[] = { 11025, 22051, 44100, 8000 };
36
37qboolean SNDDMA_Init(void)
38{
39
40 int rc;
41 int fmt;
42 int tmp;
43 int i;
44 char *s;
45 struct audio_buf_info info;
46 int caps;
47
48 snd_inited = 0;
49
50// open /dev/dsp, confirm capability to mmap, and get size of dma buffer
51
52 audio_fd = open("/dev/dsp", O_RDWR);
53 if (audio_fd < 0)
54 {
55 perror("/dev/dsp");
56 Con_Printf("Could not open /dev/dsp\n");
57 return 0;
58 }
59
60 rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
61 if (rc < 0)
62 {
63 perror("/dev/dsp");
64 Con_Printf("Could not reset /dev/dsp\n");
65 close(audio_fd);
66 return 0;
67 }
68
69 if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
70 {
71 perror("/dev/dsp");
72 Con_Printf("Sound driver too old\n");
73 close(audio_fd);
74 return 0;
75 }
76
77 if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP))
78 {
79 Con_Printf("Sorry but your soundcard can't do this\n");
80 close(audio_fd);
81 return 0;
82 }
83
84 if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
85 {
86 perror("GETOSPACE");
87 Con_Printf("Um, can't do GETOSPACE?\n");
88 close(audio_fd);
89 return 0;
90 }
91
92 shm = &sn;
93 shm->splitbuffer = 0;
94
95// set sample bits & speed
96
97 s = getenv("QUAKE_SOUND_SAMPLEBITS");
98 if (s) shm->samplebits = atoi(s);
99 else if ((i = COM_CheckParm("-sndbits")) != 0)
100 shm->samplebits = atoi(com_argv[i+1]);
101 if (shm->samplebits != 16 && shm->samplebits != 8)
102 {
103 ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
104 if (fmt & AFMT_S16_LE) shm->samplebits = 16;
105 else if (fmt & AFMT_U8) shm->samplebits = 8;
106 }
107
108 s = getenv("QUAKE_SOUND_SPEED");
109 if (s) shm->speed = atoi(s);
110 else if ((i = COM_CheckParm("-sndspeed")) != 0)
111 shm->speed = atoi(com_argv[i+1]);
112 else
113 {
114 for (i=0 ; i<sizeof(tryrates)/4 ; i++)
115 if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i])) break;
116 shm->speed = tryrates[i];
117 }
118
119 s = getenv("QUAKE_SOUND_CHANNELS");
120 if (s) shm->channels = atoi(s);
121 else if ((i = COM_CheckParm("-sndmono")) != 0)
122 shm->channels = 1;
123 else if ((i = COM_CheckParm("-sndstereo")) != 0)
124 shm->channels = 2;
125 else shm->channels = 2;
126
127 shm->samples = info.fragstotal * info.fragsize / (shm->samplebits/8);
128 shm->submission_chunk = 1;
129
130// memory map the dma buffer
131
132 shm->buffer = (unsigned char *) mmap(NULL, info.fragstotal
133 * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0);
134 if (!shm->buffer || shm->buffer == (unsigned char *)-1)
135 {
136 perror("/dev/dsp");
137 Con_Printf("Could not mmap /dev/dsp\n");
138 close(audio_fd);
139 return 0;
140 }
141
142 tmp = 0;
143 if (shm->channels == 2)
144 tmp = 1;
145 rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
146 if (rc < 0)
147 {
148 perror("/dev/dsp");
149 Con_Printf("Could not set /dev/dsp to stereo=%d", shm->channels);
150 close(audio_fd);
151 return 0;
152 }
153 if (tmp)
154 shm->channels = 2;
155 else
156 shm->channels = 1;
157
158 rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed);
159 if (rc < 0)
160 {
161 perror("/dev/dsp");
162 Con_Printf("Could not set /dev/dsp speed to %d", shm->speed);
163 close(audio_fd);
164 return 0;
165 }
166
167 if (shm->samplebits == 16)
168 {
169 rc = AFMT_S16_LE;
170 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
171 if (rc < 0)
172 {
173 perror("/dev/dsp");
174 Con_Printf("Could not support 16-bit data. Try 8-bit.\n");
175 close(audio_fd);
176 return 0;
177 }
178 }
179 else if (shm->samplebits == 8)
180 {
181 rc = AFMT_U8;
182 rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
183 if (rc < 0)
184 {
185 perror("/dev/dsp");
186 Con_Printf("Could not support 8-bit data.\n");
187 close(audio_fd);
188 return 0;
189 }
190 }
191 else
192 {
193 perror("/dev/dsp");
194 Con_Printf("%d-bit sound not supported.", shm->samplebits);
195 close(audio_fd);
196 return 0;
197 }
198
199// toggle the trigger & start her up
200
201 tmp = 0;
202 rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
203 if (rc < 0)
204 {
205 perror("/dev/dsp");
206 Con_Printf("Could not toggle.\n");
207 close(audio_fd);
208 return 0;
209 }
210 tmp = PCM_ENABLE_OUTPUT;
211 rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp);
212 if (rc < 0)
213 {
214 perror("/dev/dsp");
215 Con_Printf("Could not toggle.\n");
216 close(audio_fd);
217 return 0;
218 }
219
220 shm->samplepos = 0;
221
222 snd_inited = 1;
223 return 1;
224
225}
226
227int SNDDMA_GetDMAPos(void)
228{
229
230 struct count_info count;
231
232 if (!snd_inited) return 0;
233
234 if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count)==-1)
235 {
236 perror("/dev/dsp");
237 Con_Printf("Uh, sound dead.\n");
238 close(audio_fd);
239 snd_inited = 0;
240 return 0;
241 }
242// shm->samplepos = (count.bytes / (shm->samplebits / 8)) & (shm->samples-1);
243// fprintf(stderr, "%d \r", count.ptr);
244 shm->samplepos = count.ptr / (shm->samplebits / 8);
245
246 return shm->samplepos;
247
248}
249
250void SNDDMA_Shutdown(void)
251{
252 if (snd_inited)
253 {
254 close(audio_fd);
255 snd_inited = 0;
256 }
257}
258
259/*
260==============
261SNDDMA_Submit
262
263Send sound to device if buffer isn't really the dma buffer
264===============
265*/
266void SNDDMA_Submit(void)
267{
268}
269
diff --git a/apps/plugins/sdl/progs/quake/snd_mem.c b/apps/plugins/sdl/progs/quake/snd_mem.c
new file mode 100644
index 0000000000..71e32aa056
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_mem.c
@@ -0,0 +1,341 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// snd_mem.c: sound caching
21
22#include "quakedef.h"
23
24int cache_full_cycle;
25
26byte *S_Alloc (int size);
27
28/*
29================
30ResampleSfx
31================
32*/
33void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
34{
35 int outcount;
36 int srcsample;
37 float stepscale;
38 int i;
39 int sample, samplefrac, fracstep;
40 sfxcache_t *sc;
41
42 sc = Cache_Check (&sfx->cache);
43 if (!sc)
44 return;
45
46 stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2
47
48 outcount = sc->length / stepscale;
49 sc->length = outcount;
50 if (sc->loopstart != -1)
51 sc->loopstart = sc->loopstart / stepscale;
52
53 sc->speed = shm->speed;
54 if (loadas8bit.value)
55 sc->width = 1;
56 else
57 sc->width = inwidth;
58 sc->stereo = 0;
59
60// resample / decimate to the current source rate
61
62 if (stepscale == 1 && inwidth == 1 && sc->width == 1)
63 {
64// fast special case
65 for (i=0 ; i<outcount ; i++)
66 ((signed char *)sc->data)[i]
67 = (int)( (unsigned char)(data[i]) - 128);
68 }
69 else
70 {
71// general case
72 samplefrac = 0;
73 fracstep = stepscale*256;
74 for (i=0 ; i<outcount ; i++)
75 {
76 srcsample = samplefrac >> 8;
77 samplefrac += fracstep;
78 if (inwidth == 2)
79 sample = LittleShort ( ((short *)data)[srcsample] );
80 else
81 sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
82 if (sc->width == 2)
83 ((short *)sc->data)[i] = sample;
84 else
85 ((signed char *)sc->data)[i] = sample >> 8;
86 }
87 }
88}
89
90//=============================================================================
91
92/*
93==============
94S_LoadSound
95==============
96*/
97sfxcache_t *S_LoadSound (sfx_t *s)
98{
99 char namebuffer[256];
100 byte *data;
101 wavinfo_t info;
102 int len;
103 float stepscale;
104 sfxcache_t *sc;
105 byte stackbuf[1*1024]; // avoid dirtying the cache heap
106
107// see if still in memory
108 sc = Cache_Check (&s->cache);
109 if (sc)
110 return sc;
111
112//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
113// load it in
114 Q_strcpy(namebuffer, "sound/");
115 Q_strcat(namebuffer, s->name);
116
117// Con_Printf ("loading %s\n",namebuffer);
118
119 data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
120
121 if (!data)
122 {
123 Con_Printf ("Couldn't load %s\n", namebuffer);
124 return NULL;
125 }
126
127 info = GetWavinfo (s->name, data, com_filesize);
128 if (info.channels != 1)
129 {
130 Con_Printf ("%s is a stereo sample\n",s->name);
131 return NULL;
132 }
133
134 stepscale = (float)info.rate / shm->speed;
135 len = info.samples / stepscale;
136
137 len = len * info.width * info.channels;
138
139 sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
140 if (!sc)
141 return NULL;
142
143 sc->length = info.samples;
144 sc->loopstart = info.loopstart;
145 sc->speed = info.rate;
146 sc->width = info.width;
147 sc->stereo = info.channels;
148
149 ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
150
151 return sc;
152}
153
154
155
156/*
157===============================================================================
158
159WAV loading
160
161===============================================================================
162*/
163
164
165byte *data_p;
166byte *iff_end;
167byte *last_chunk;
168byte *iff_data;
169int iff_chunk_len;
170
171
172short GetLittleShort(void)
173{
174 short val = 0;
175 val = *data_p;
176 val = val + (*(data_p+1)<<8);
177 data_p += 2;
178 return val;
179}
180
181int GetLittleLong(void)
182{
183 int val = 0;
184 val = *data_p;
185 val = val + (*(data_p+1)<<8);
186 val = val + (*(data_p+2)<<16);
187 val = val + (*(data_p+3)<<24);
188 data_p += 4;
189 return val;
190}
191
192void FindNextChunk(char *name)
193{
194 while (1)
195 {
196 data_p=last_chunk;
197
198 if (data_p >= iff_end)
199 { // didn't find the chunk
200 data_p = NULL;
201 return;
202 }
203
204 data_p += 4;
205 iff_chunk_len = GetLittleLong();
206 if (iff_chunk_len < 0)
207 {
208 data_p = NULL;
209 return;
210 }
211// if (iff_chunk_len > 1024*1024)
212// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
213 data_p -= 8;
214 last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
215 if (!Q_strncmp(data_p, name, 4))
216 return;
217 }
218}
219
220void FindChunk(char *name)
221{
222 last_chunk = iff_data;
223 FindNextChunk (name);
224}
225
226
227void DumpChunks(void)
228{
229 char str[5];
230
231 str[4] = 0;
232 data_p=iff_data;
233 do
234 {
235 memcpy (str, data_p, 4);
236 data_p += 4;
237 iff_chunk_len = GetLittleLong();
238 Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
239 data_p += (iff_chunk_len + 1) & ~1;
240 } while (data_p < iff_end);
241}
242
243/*
244============
245GetWavinfo
246============
247*/
248wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
249{
250 wavinfo_t info;
251 int i;
252 int format;
253 int samples;
254
255 memset (&info, 0, sizeof(info));
256
257 if (!wav)
258 return info;
259
260 iff_data = wav;
261 iff_end = wav + wavlength;
262
263// find "RIFF" chunk
264 FindChunk("RIFF");
265 if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
266 {
267 Con_Printf("Missing RIFF/WAVE chunks\n");
268 return info;
269 }
270
271// get "fmt " chunk
272 iff_data = data_p + 12;
273// DumpChunks ();
274
275 FindChunk("fmt ");
276 if (!data_p)
277 {
278 Con_Printf("Missing fmt chunk\n");
279 return info;
280 }
281 data_p += 8;
282 format = GetLittleShort();
283 if (format != 1)
284 {
285 Con_Printf("Microsoft PCM format only\n");
286 return info;
287 }
288
289 info.channels = GetLittleShort();
290 info.rate = GetLittleLong();
291 data_p += 4+2;
292 info.width = GetLittleShort() / 8;
293
294// get cue chunk
295 FindChunk("cue ");
296 if (data_p)
297 {
298 data_p += 32;
299 info.loopstart = GetLittleLong();
300// Con_Printf("loopstart=%d\n", sfx->loopstart);
301
302 // if the next chunk is a LIST chunk, look for a cue length marker
303 FindNextChunk ("LIST");
304 if (data_p)
305 {
306 if (!strncmp (data_p + 28, "mark", 4))
307 { // this is not a proper parse, but it works with cooledit...
308 data_p += 24;
309 i = GetLittleLong (); // samples in loop
310 info.samples = info.loopstart + i;
311// Con_Printf("looped length: %i\n", i);
312 }
313 }
314 }
315 else
316 info.loopstart = -1;
317
318// find data chunk
319 FindChunk("data");
320 if (!data_p)
321 {
322 Con_Printf("Missing data chunk\n");
323 return info;
324 }
325
326 data_p += 4;
327 samples = GetLittleLong () / info.width;
328
329 if (info.samples)
330 {
331 if (samples < info.samples)
332 Sys_Error ("Sound %s has a bad loop length", name);
333 }
334 else
335 info.samples = samples;
336
337 info.dataofs = data_p - wav;
338
339 return info;
340}
341
diff --git a/apps/plugins/sdl/progs/quake/snd_mix.c b/apps/plugins/sdl/progs/quake/snd_mix.c
new file mode 100644
index 0000000000..3f254552b9
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_mix.c
@@ -0,0 +1,132 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// snd_mix.c -- portable code to mix sounds for snd_dma.c
21
22#include "quakedef.h"
23
24#define DWORD unsigned long
25
26// why not write straight to SHM buffer?!?
27//portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
28int16_t *paintbuffer; // stereo interleaved samples
29
30/*
31===============================================================================
32
33CHANNEL MIXING
34
35===============================================================================
36*/
37
38// in snd_mix_*
39
40void SND_PaintChannelFrom8 (int true_lvol, int true_rvol, signed char *sfx, int count);
41void SND_PaintChannelFrom16 (int true_lvol, int true_rvol, signed short *sfx, int count);
42
43void S_PaintChannels(int endtime)
44{
45 int i;
46 int end;
47 channel_t *ch;
48 sfxcache_t *sc;
49 int ltime, count;
50
51 paintbuffer = shm->buffer;
52
53 //while (paintedtime < endtime)
54 //{
55 // if paintbuffer is smaller than DMA buffer
56
57 end = endtime;
58 //if (endtime - paintedtime > PAINTBUFFER_SIZE)
59 //end = paintedtime + PAINTBUFFER_SIZE;
60
61 // clear the paint buffer
62 memset(paintbuffer, 0, (end - paintedtime) * sizeof(int16_t));
63
64 // 0-255
65 int volume_fp = volume.value * 255;
66
67 // paint in the channels.
68 ch = channels;
69 for (i=0; i<total_channels ; i++, ch++)
70 {
71 if (!ch->sfx)
72 continue;
73 if (!ch->leftvol && !ch->rightvol)
74 continue;
75 sc = S_LoadSound (ch->sfx); // sound fx cache
76 if (!sc)
77 continue;
78
79 ltime = paintedtime;
80
81 while (ltime < end)
82 { // paint up to end of sound channel, or end of buffer, whichever is greatest
83 if (ch->end < end)
84 count = ch->end - ltime;
85 else
86 count = end - ltime;
87
88 //if(count == 1)
89 // rb->splashf(HZ, "Potential problem");
90
91 if (count > 0)
92 {
93 int true_lvol, true_rvol;
94 true_lvol = (volume_fp * ch->leftvol) / 256;
95 true_rvol = (volume_fp * ch->rightvol) / 256;
96
97 if (sc->width == 1)
98 {
99 signed char *sfx = (char*)sc->data + ch->pos;
100 SND_PaintChannelFrom8(true_lvol, true_rvol, sfx, count);
101 }
102 else
103 {
104 signed short *sfx = (short*)sc->data + ch->pos;
105 SND_PaintChannelFrom16(true_lvol, true_rvol, sfx, count);
106 }
107
108 ch->pos += count;
109 ltime += count;
110 }
111
112 // if at end of loop, restart
113 if (ltime >= ch->end)
114 {
115 if (sc->loopstart >= 0)
116 {
117 ch->pos = sc->loopstart;
118 ch->end = ltime + sc->length - ch->pos;
119 }
120 else
121 { // channel just stopped
122 ch->sfx = NULL;
123 break;
124 }
125 }
126 }
127 }
128
129 // transfer out according to DMA format
130 //S_TransferPaintBuffer(end);
131 paintedtime = end;
132}
diff --git a/apps/plugins/sdl/progs/quake/snd_mix_arm.S b/apps/plugins/sdl/progs/quake/snd_mix_arm.S
new file mode 100644
index 0000000000..15733d8912
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_mix_arm.S
@@ -0,0 +1,129 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2019 Franklin Wei
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ***************************************************************************/
21
22 /** Sound mixing code for ARM. **/
23 /* Takes 8-bit mono audio and outputs stereo 16-bit samples.
24 * stereo volumes are passed as arguments.
25 *
26 * Bear with me. This is my first ARM assembly, ever.
27 */
28
29 .text
30 .align 2
31 .global SND_PaintChannelFrom8
32 .type SND_PaintChannelFrom8, %function
33
34#if defined(__ARM_ARCH_5TEJ__)
35SND_PaintChannelFrom8:
36 // r0: int true_lvol
37 // r1: int true_rvol
38 // r2: char *sfx
39 // r3: int count
40
41 stmfd sp!, {r4, r5, r6, r7, r8, sl}
42
43 ldr ip, =paintbuffer
44 ldr ip, [ip]
45
46 mov r0, r0, asl #16 // pre-scale both volumes by 2^16
47 mov r1, r1, asl #16
48
49 sub r3, r3, #1 // we'll count backwards
50 // sl = 0xffff0000
51 ldrh sl, =0xffff
52
53.loop:
54 ldrsb r4, [r2, r3] // load *sfx[i] -> r4
55
56 // keep endianness in mind here
57 // buffer looks like [left_0, left_1, right_0, right_1] in memory
58 // but it is loaded as [right1, right0, left1, left0] to registers
59 ldr r8, [ip, r3, lsl #2] // load paintbuffer[0:1] = RIGHTCHANNEL:LEFTCHANNEL
60
61 // handle high half (right channel) first
62 mul r5, r4, r1 // SCALEDRIGHT = SFXI * (true_rvol << 16) -- bottom half is zero
63
64 // r7 holds right channel in high half (dirty bottom half)
65 qadd r7, r5, r8 // RIGHTCHANORIG = SCALEDRIGHT + RIGHTCHANORIG (high half)
66
67 bic r7, r7, sl // zero bottom bits of r7
68
69 // trash r5, r6 and handle left channel
70 mul r5, r4, r0 // SCALEDLEFT = SFXI * (true_rvol << 16)
71
72 mov r8, r8, lsl #16 // extract original left channel from paintbuffer
73
74 // r8 holds left channel in high half with zero bottom half
75 qadd r8, r5, r8
76
77 // combine the two 16-bit samples in r7 as 32-bit [left:right]
78 // (use lsr to not sign-extend the lower half)
79 orr r7, r7, r8, lsr #16
80
81 str r7, [ip, r3, lsl #2] // write 32-bit to paintbuffer
82 subs r3, r3, #1
83 bgt .loop // must use instead of bne because of the corner case count=1
84
85
86
87 ldmfd sp!, {r4, r5, r6, r7, r8, sl}
88
89 bx lr
90
91#elif defined(__ARM_ARCH_6__) // ARMv6 with QADD16 (disabled)
92SND_PaintChannelFrom8:
93 // r0: int true_lvol
94 // r1: int true_rvol
95 // r2: char *sfx
96 // r3: int count
97
98 stmfd sp!, {r4, r5, r6, r7}
99
100 ldr ip, =paintbuffer
101 ldr ip, [ip]
102 sub r3, r3, #1 // we'll count backwards
103.loop:
104 ldrsb r4, [r2, r3] // load *sfx[i] -> r4
105
106 // keep endianness in mind here
107 // buffer looks like [left_0, left_1, right_0, right_1] in memory
108 // but it is loaded as [right1, right0, left1, left0] to registers
109 ldr r7, [ip, r3, lsl #2] // load paintbuffer[0:1] = RIGHTCHANNEL:LEFTCHANNEL
110
111 // handle high half (right channel) first
112 mul r5, r4, r1 // SCALEDRIGHT = SFXI * true_rvol
113 mul r6, r4, r0 // SCALEDLEFT = SFXI * true_rvol
114
115 orr r6, r6, r5, lsl #16
116
117 qadd16 r6, r6, r7
118
119 str r6, [ip, r3, lsl #2] // write 32-bit to paintbuffer
120
121 subs r3, r3, #1
122 bne .loop
123
124 ldmfd sp!, {r4, r5, r6, r7}
125
126 bx lr
127#else
128#error ARMv5/6 only
129#endif
diff --git a/apps/plugins/sdl/progs/quake/snd_mix_generic.c b/apps/plugins/sdl/progs/quake/snd_mix_generic.c
new file mode 100644
index 0000000000..2c4b67b77c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_mix_generic.c
@@ -0,0 +1,69 @@
1/* This file is included from snd_mix.c */
2
3#include "SDL.h"
4
5// allow standalone compilation
6#ifndef QUAKE_SOUND
7extern short *paintbuffer;
8#define INLINE
9#else
10#define INLINE static inline
11#endif
12
13// C version
14static inline short CLAMPADD(short a, short b)
15{
16 int val = (int)a + (int)b;
17 if (val > 32767)
18 {
19 //rb->splashf(HZ, "saturate");
20 return 32767;
21 }
22 else if (val < -32768)
23 {
24 //rb->splashf(HZ, "saturate");
25 return -32768;
26 }
27 else
28 return val;
29}
30
31// if not ARMv5
32#ifndef __ARM_ARCH__5TEJ__
33void SND_PaintChannelFrom8 (int true_lvol, int true_rvol, signed char *sfx, int count)
34{
35 //return;
36 //LOGF("mix8\n");
37 int data;
38 int i;
39
40 // we have 8-bit sound in sfx[], which we want to scale to
41 // 16bit and take the volume into account
42 for (i=0 ; i<count ; i++)
43 {
44 // We could use the QADD16 instruction on ARMv6+
45 // or just 32-bit QADD with pre-shifted arguments
46 data = sfx[i];
47 paintbuffer[2*i+0] = CLAMPADD(paintbuffer[2*i+0], data * true_lvol); // need saturation
48 paintbuffer[2*i+1] = CLAMPADD(paintbuffer[2*i+1], data * true_rvol);
49 }
50}
51#endif
52
53void SND_PaintChannelFrom16 (int true_lvol, int true_rvol, signed short *sfx, int count)
54{
55 //return;
56 //LOGF("mix16\n");
57 int data;
58 int left, right;
59 int i;
60
61 for (i=0 ; i<count ; i+=2)
62 {
63 data = sfx[i];
64 left = ((int)data * true_lvol) >> 8;
65 right = ((int)data * true_rvol) >> 8;
66 paintbuffer[2*i+0] = CLAMPADD(paintbuffer[2*i+0], left); // need saturation
67 paintbuffer[2*i+1] = CLAMPADD(paintbuffer[2*i+1], right);
68 }
69}
diff --git a/apps/plugins/sdl/progs/quake/snd_mix_generic_annotated.s b/apps/plugins/sdl/progs/quake/snd_mix_generic_annotated.s
new file mode 100644
index 0000000000..474b0e93cb
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_mix_generic_annotated.s
@@ -0,0 +1,191 @@
1 .cpu arm926ej-s
2 .fpu softvfp
3 .eabi_attribute 20, 1
4 .eabi_attribute 21, 1
5 .eabi_attribute 23, 3
6 .eabi_attribute 24, 1
7 .eabi_attribute 25, 1
8 .eabi_attribute 26, 1
9 .eabi_attribute 30, 2
10 .eabi_attribute 18, 4
11 .file "snd_mix_generic.c"
12@ GNU C (GCC) version 4.4.4 (arm-elf-eabi)
13@ compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 4.3.2, MPFR version 2.4.2.
14@ GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
15@ options passed: -imultilib arm926ej-s -D__USES_INITFINI__
16@ ./snd_mix_generic.c -mcpu=arm926ej-s -O3 -fverbose-asm
17@ options enabled: -falign-loops -fargument-alias -fauto-inc-dec
18@ -fbranch-count-reg -fcaller-saves -fcommon -fcprop-registers
19@ -fcrossjumping -fcse-follow-jumps -fdefer-pop
20@ -fdelete-null-pointer-checks -fearly-inlining
21@ -feliminate-unused-debug-types -fexpensive-optimizations
22@ -fforward-propagate -ffunction-cse -fgcse -fgcse-after-reload -fgcse-lm
23@ -fguess-branch-probability -fident -fif-conversion -fif-conversion2
24@ -findirect-inlining -finline -finline-functions
25@ -finline-functions-called-once -finline-small-functions -fipa-cp
26@ -fipa-cp-clone -fipa-pure-const -fipa-reference -fira-share-save-slots
27@ -fira-share-spill-slots -fivopts -fkeep-static-consts
28@ -fleading-underscore -fmath-errno -fmerge-constants -fmerge-debug-strings
29@ -fmove-loop-invariants -fomit-frame-pointer -foptimize-register-move
30@ -foptimize-sibling-calls -fpeephole -fpeephole2 -fpredictive-commoning
31@ -freg-struct-return -fregmove -freorder-blocks -freorder-functions
32@ -frerun-cse-after-loop -fsched-interblock -fsched-spec
33@ -fsched-stalled-insns-dep -fschedule-insns -fschedule-insns2
34@ -fsection-anchors -fsigned-zeros -fsplit-ivs-in-unroller
35@ -fsplit-wide-types -fstrict-aliasing -fstrict-overflow -fthread-jumps
36@ -ftoplevel-reorder -ftrapping-math -ftree-builtin-call-dce -ftree-ccp
37@ -ftree-ch -ftree-copy-prop -ftree-copyrename -ftree-cselim -ftree-dce
38@ -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im
39@ -ftree-loop-ivcanon -ftree-loop-optimize -ftree-parallelize-loops=
40@ -ftree-pre -ftree-reassoc -ftree-scev-cprop -ftree-sink -ftree-sra
41@ -ftree-switch-conversion -ftree-ter -ftree-vect-loop-version
42@ -ftree-vectorize -ftree-vrp -funit-at-a-time -funswitch-loops
43@ -fverbose-asm -fzero-initialized-in-bss -mlittle-endian -msched-prolog
44
45@ Compiler executable checksum: 6bc9eb36ed7f27ae4e8601da7e401eb4
46
47 .text
48 .align 2
49 .global SND_PaintChannelFrom8
50 .type SND_PaintChannelFrom8, %function
51SND_PaintChannelFrom8:
52 // r0: true_lvol
53 // r1: true_rvol
54 // r2: *sfx
55 // r3: count
56
57 @ args = 0, pretend = 0, frame = 0
58 @ frame_needed = 0, uses_anonymous_args = 0
59 @ link register save eliminated.
60 cmp r3, #0 @ count
61 stmfd sp!, {r4, r5, r6, r7, r8, sl} @,
62 ble .L10 @, // exit early if count <= 0
63 ldr ip, .L13 @ tmp207, // ip = paintbuffer
64 ldr r5, .L13+4 @ tmp224, // r5 = 32767
65 ldr ip, [ip, #0] @ ivtmp.61, paintbuffer // ip = &paintbuffer
66
67 // this does {rvol,lvol} &= 0xffff in a really convoluted way
68 mov r1, r1, asl #16 @ tmp206, true_rvol, // r1 = rvol << 16
69 mov r0, r0, asl #16 @ tmp205, true_lvol, // r0 = lvol << 16
70 mov r6, r1, lsr #16 @ pretmp.46, tmp206, // rvol_16 = r1 >> 16
71 mov r7, r0, lsr #16 @ pretmp.44, tmp205, // lvol_16 = r0 >> 16
72 mov r1, #0 @ i, // i = 0
73 // loop?
74.L9:
75 ldrsb r0, [r2, r1] @ tmp208,* i // r0 = (byte) sfx[i]
76 ldrsh r8, [ip, #0] @ tmp213,* ivtmp.61 // r8 = (int16) paintbuffer[0]
77
78 // r0 &= 0xffff
79 mov r0, r0, asl #16 @ tmp209, tmp208, // r0 <<= 16
80 mov r0, r0, lsr #16 @ D.1289, tmp209, // r0 >>= 16
81
82
83 mul r4, r0, r7 @ tmp210, D.1289, pretmp.44 // r4 = sfx[i] * (lvol_16)
84
85 mov r4, r4, asl #16 @ tmp212, tmp210, // r4 <<= 16
86
87 add r4, r8, r4, asr #16 @, val, tmp213, tmp212, // r8 += r4 & 0xffff
88
89 // handle saturation
90 cmp r4, r5 @ val, tmp224 // compare r4, 32767
91 ldrgt r8, .L13+4 @ D.1341, // r8 = 32767 if saturated
92 bgt .L4 @, // jump to .L4 if saturated
93 cmn r4, #32768 @ val, // compare r4, -32768
94 movge r4, r4, asl #16 @ tmp216, val, // if not saturated, &= 0xffff
95 movlt r8, #32768 @ D.1341, // r8 = -32768 if saturated
96 movge r8, r4, lsr #16 @ D.1341, tmp216, // r8 = val
97
98 // r8 is final value of paintbuffer[2*i+0]
99
100 // now handle right channel
101.L4:
102 // sl is scaled right channel
103
104 // this does paintbuffer[1] += rvol * sfx[i]
105 mul sl, r0, r6 @ tmp217, D.1289, pretmp.46 // sl = sfx[i] * rvol_16
106 ldrsh r4, [ip, #2] @ tmp220, // r4 = paintbuffer[1]
107 mov r0, sl, asl #16 @ tmp219, tmp217, // r0 = sl << 16
108 add r0, r4, r0, asr #16 @, val, tmp220, tmp219, // r0 = r4 + (r0 >> 16)
109
110 // now saturate
111 cmp r0, r5 @ val, tmp224 // compare final right channel to 32767
112
113 strh r8, [ip, #0] @ movhi @ D.1341,* ivtmp.61 // write left channel back to paintbuffer
114 ldrgt r0, .L13+4 @ D.1348, // r0 = 32767 if saturated
115 bgt .L7 @, // skip to .L7
116 cmn r0, #32768 @ val, // check < -32768
117 movge r0, r0, asl #16 @ tmp223, val, // <<= 16 if not saturated
118 movlt r0, #32768 @ D.1348, // if < -32768, saturate
119 movge r0, r0, lsr #16 @ D.1348, tmp223, // >>= 16 if not saturated
120.L7:
121 add r1, r1, #1 @ i, i, // i++
122 cmp r1, r3 @ i, count // i =? count
123 strh r0, [ip, #2] @ movhi @ D.1348 , // store right channel to paintbuffer
124 add ip, ip, #4 @ ivtmp.61, ivtmp.61, // paintbuffer += 4 bytes
125 bne .L9 @, // restart if i != count
126.L10:
127 ldmfd sp!, {r4, r5, r6, r7, r8, sl} // pop stack
128 bx lr // return
129.L14:
130 .align 2
131.L13:
132 .word paintbuffer
133 .word 32767
134 .size SND_PaintChannelFrom8, .-SND_PaintChannelFrom8
135 .align 2
136 .global SND_PaintChannelFrom16
137 .type SND_PaintChannelFrom16, %function
138SND_PaintChannelFrom16:
139 @ args = 0, pretend = 0, frame = 0
140 @ frame_needed = 0, uses_anonymous_args = 0
141 @ link register save eliminated.
142 cmp r3, #0 @ count
143 stmfd sp!, {r4, r5, r6, r7, r8, sl} @,
144 ble .L24 @,
145 ldr ip, .L26 @ tmp146,
146 ldr r7, .L26+4 @ tmp164,
147 ldr ip, [ip, #0] @ ivtmp.119, paintbuffer
148 mov r4, #0 @ i,
149.L23:
150 mov r5, r4, asl #1 @ tmp147, i,
151 ldrsh r5, [r2, r5] @ data,
152 ldrsh r8, [ip, #0] @ tmp152,* ivtmp.119
153 mul r6, r5, r0 @ tmp148, data, true_lvol
154 mov r6, r6, asl #8 @ tmp151, tmp148,
155 add r6, r8, r6, asr #16 @, val, tmp152, tmp151,
156 cmp r6, r7 @ val, tmp164
157 ldrgt r8, .L26+4 @ D.1355,
158 bgt .L18 @,
159 cmn r6, #32768 @ val,
160 movge r6, r6, asl #16 @ tmp155, val,
161 movlt r8, #32768 @ D.1355,
162 movge r8, r6, lsr #16 @ D.1355, tmp155,
163.L18:
164 mul sl, r5, r1 @ tmp156, data, true_rvol
165 ldrsh r6, [ip, #2] @ tmp160,
166 mov r5, sl, asl #8 @ tmp159, tmp156,
167 add r5, r6, r5, asr #16 @, val, tmp160, tmp159,
168 cmp r5, r7 @ val, tmp164
169 strh r8, [ip, #0] @ movhi @ D.1355,* ivtmp.119
170 ldrgt r5, .L26+4 @ D.1362,
171 bgt .L21 @,
172 cmn r5, #32768 @ val,
173 movge r5, r5, asl #16 @ tmp163, val,
174 movlt r5, #32768 @ D.1362,
175 movge r5, r5, lsr #16 @ D.1362, tmp163,
176.L21:
177 add r4, r4, #2 @ i, i,
178 cmp r3, r4 @ count, i
179 strh r5, [ip, #2] @ movhi @ D.1362,
180 add ip, ip, #8 @ ivtmp.119, ivtmp.119,
181 bgt .L23 @,
182.L24:
183 ldmfd sp!, {r4, r5, r6, r7, r8, sl}
184 bx lr
185.L27:
186 .align 2
187.L26:
188 .word paintbuffer
189 .word 32767
190 .size SND_PaintChannelFrom16, .-SND_PaintChannelFrom16
191 .ident "GCC: (GNU) 4.4.4"
diff --git a/apps/plugins/sdl/progs/quake/snd_null.c b/apps/plugins/sdl/progs/quake/snd_null.c
new file mode 100644
index 0000000000..9db2ebcea0
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_null.c
@@ -0,0 +1,97 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// snd_null.c -- include this instead of all the other snd_* files to have
21// no sound code whatsoever
22
23#include "quakedef.h"
24
25cvar_t bgmvolume = {"bgmvolume", "1", true};
26cvar_t volume = {"volume", "0.7", true};
27
28
29void S_Init (void)
30{
31}
32
33void S_AmbientOff (void)
34{
35}
36
37void S_AmbientOn (void)
38{
39}
40
41void S_Shutdown (void)
42{
43}
44
45void S_TouchSound (char *sample)
46{
47}
48
49void S_ClearBuffer (void)
50{
51}
52
53void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
54{
55}
56
57void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
58{
59}
60
61void S_StopSound (int entnum, int entchannel)
62{
63}
64
65sfx_t *S_PrecacheSound (char *sample)
66{
67 return NULL;
68}
69
70void S_ClearPrecache (void)
71{
72}
73
74void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up)
75{
76}
77
78void S_StopAllSounds (qboolean clear)
79{
80}
81
82void S_BeginPrecaching (void)
83{
84}
85
86void S_EndPrecaching (void)
87{
88}
89
90void S_ExtraUpdate (void)
91{
92}
93
94void S_LocalSound (char *s)
95{
96}
97
diff --git a/apps/plugins/sdl/progs/quake/snd_sdl.c b/apps/plugins/sdl/progs/quake/snd_sdl.c
new file mode 100644
index 0000000000..644d4e1acf
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/snd_sdl.c
@@ -0,0 +1,113 @@
1
2#include <stdio.h>
3#include "SDL_audio.h"
4#include "SDL_byteorder.h"
5#include "quakedef.h"
6
7static dma_t the_shm;
8static int snd_inited;
9
10extern int desired_speed;
11extern int desired_bits;
12
13// SDL hereby demands `len' samples in stream, *NOW*!
14static void paint_audio(void *unused, Uint8 *stream, int len)
15{
16 if ( shm ) {
17 shm->buffer = stream;
18 shm->samplepos += len/(shm->samplebits/8)/2;
19 // Check for samplepos overflow?
20 S_PaintChannels (shm->samplepos);
21 }
22}
23
24qboolean SNDDMA_Init(void)
25{
26 SDL_AudioSpec desired, obtained;
27
28 snd_inited = 0;
29
30 /* Set up the desired format */
31 desired.freq = desired_speed;
32 switch (desired_bits) {
33 case 8:
34 desired.format = AUDIO_U8;
35 break;
36 case 16:
37 if ( SDL_BYTEORDER == SDL_BIG_ENDIAN )
38 desired.format = AUDIO_S16MSB;
39 else
40 desired.format = AUDIO_S16LSB;
41 break;
42 default:
43 Con_Printf("Unknown number of audio bits: %d\n",
44 desired_bits);
45 return 0;
46 }
47 desired.channels = 2;
48 desired.samples = 1024;
49 desired.callback = paint_audio;
50
51 /* Open the audio device */
52 if ( SDL_OpenAudio(&desired, &obtained) < 0 ) {
53 Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError());
54 return 0;
55 }
56
57 /* Make sure we can support the audio format */
58 switch (obtained.format) {
59 case AUDIO_U8:
60 /* Supported */
61 break;
62 case AUDIO_S16LSB:
63 case AUDIO_S16MSB:
64 if ( ((obtained.format == AUDIO_S16LSB) &&
65 (SDL_BYTEORDER == SDL_LIL_ENDIAN)) ||
66 ((obtained.format == AUDIO_S16MSB) &&
67 (SDL_BYTEORDER == SDL_BIG_ENDIAN)) ) {
68 /* Supported */
69 break;
70 }
71 /* Unsupported, fall through */;
72 default:
73 /* Not supported -- force SDL to do our bidding */
74 SDL_CloseAudio();
75 if ( SDL_OpenAudio(&desired, NULL) < 0 ) {
76 Con_Printf("Couldn't open SDL audio: %s\n",
77 SDL_GetError());
78 return 0;
79 }
80 memcpy(&obtained, &desired, sizeof(desired));
81 break;
82 }
83 SDL_PauseAudio(0);
84
85 /* Fill the audio DMA information block */
86 shm = &the_shm;
87 shm->splitbuffer = 0;
88 shm->samplebits = (obtained.format & 0xFF);
89 shm->speed = obtained.freq;
90 shm->channels = obtained.channels;
91 shm->samples = obtained.samples*shm->channels;
92 shm->samplepos = 0;
93 shm->submission_chunk = 1;
94 shm->buffer = NULL;
95
96 snd_inited = 1;
97 return 1;
98}
99
100int SNDDMA_GetDMAPos(void)
101{
102 return shm->samplepos;
103}
104
105void SNDDMA_Shutdown(void)
106{
107 if (snd_inited)
108 {
109 SDL_CloseAudio();
110 snd_inited = 0;
111 }
112}
113
diff --git a/apps/plugins/sdl/progs/quake/spritegn.h b/apps/plugins/sdl/progs/quake/spritegn.h
new file mode 100644
index 0000000000..8e35c23823
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/spritegn.h
@@ -0,0 +1,114 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// spritegn.h: header file for sprite generation program
22//
23
24// **********************************************************
25// * This file must be identical in the spritegen directory *
26// * and in the Quake directory, because it's used to *
27// * pass data from one to the other via .spr files. *
28// **********************************************************
29
30//-------------------------------------------------------
31// This program generates .spr sprite package files.
32// The format of the files is as follows:
33//
34// dsprite_t file header structure
35// <repeat dsprite_t.numframes times>
36// <if spritegroup, repeat dspritegroup_t.numframes times>
37// dspriteframe_t frame header structure
38// sprite bitmap
39// <else (single sprite frame)>
40// dspriteframe_t frame header structure
41// sprite bitmap
42// <endrepeat>
43//-------------------------------------------------------
44
45#ifdef INCLUDELIBS
46
47#include <stdlib.h>
48#include <stdio.h>
49#include <math.h>
50#include <string.h>
51
52#include "cmdlib.h"
53#include "scriplib.h"
54#include "dictlib.h"
55#include "trilib.h"
56#include "lbmlib.h"
57#include "mathlib.h"
58
59#endif
60
61#define SPRITE_VERSION 1
62
63// must match definition in modelgen.h
64#ifndef SYNCTYPE_T
65#define SYNCTYPE_T
66typedef int synctime_t;
67
68enum {ST_SYNC=0, ST_RAND };
69#endif
70
71// TODO: shorten these?
72typedef struct {
73 int ident;
74 int version;
75 int type;
76 float boundingradius;
77 int width;
78 int height;
79 int numframes;
80 float beamlength;
81 synctype_t synctype;
82} dsprite_t;
83
84#define SPR_VP_PARALLEL_UPRIGHT 0
85#define SPR_FACING_UPRIGHT 1
86#define SPR_VP_PARALLEL 2
87#define SPR_ORIENTED 3
88#define SPR_VP_PARALLEL_ORIENTED 4
89
90typedef struct {
91 int origin[2];
92 int width;
93 int height;
94} dspriteframe_t;
95
96typedef struct {
97 int numframes;
98} dspritegroup_t;
99
100typedef struct {
101 float interval;
102} dspriteinterval_t;
103
104typedef int spriteframetype_t;
105
106enum { SPR_SINGLE=0, SPR_GROUP };
107
108typedef struct {
109 spriteframetype_t type;
110} dspriteframetype_t;
111
112#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I')
113 // little-endian "IDSP"
114
diff --git a/apps/plugins/sdl/progs/quake/sv_main.c b/apps/plugins/sdl/progs/quake/sv_main.c
new file mode 100644
index 0000000000..5ea62f1efa
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_main.c
@@ -0,0 +1,1209 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_main.c -- server main program
21
22#include "quakedef.h"
23
24server_t sv;
25server_static_t svs;
26
27char localmodels[MAX_MODELS][5]; // inline model names for precache
28
29//============================================================================
30
31/*
32===============
33SV_Init
34===============
35*/
36void SV_Init (void)
37{
38 int i;
39 extern cvar_t sv_maxvelocity;
40 extern cvar_t sv_gravity;
41 extern cvar_t sv_nostep;
42 extern cvar_t sv_friction;
43 extern cvar_t sv_edgefriction;
44 extern cvar_t sv_stopspeed;
45 extern cvar_t sv_maxspeed;
46 extern cvar_t sv_accelerate;
47 extern cvar_t sv_idealpitchscale;
48 extern cvar_t sv_aim;
49
50 Cvar_RegisterVariable (&sv_maxvelocity);
51 Cvar_RegisterVariable (&sv_gravity);
52 Cvar_RegisterVariable (&sv_friction);
53 Cvar_RegisterVariable (&sv_edgefriction);
54 Cvar_RegisterVariable (&sv_stopspeed);
55 Cvar_RegisterVariable (&sv_maxspeed);
56 Cvar_RegisterVariable (&sv_accelerate);
57 Cvar_RegisterVariable (&sv_idealpitchscale);
58 Cvar_RegisterVariable (&sv_aim);
59 Cvar_RegisterVariable (&sv_nostep);
60
61 for (i=0 ; i<MAX_MODELS ; i++)
62 sprintf (localmodels[i], "*%i", i);
63}
64
65/*
66=============================================================================
67
68EVENT MESSAGES
69
70=============================================================================
71*/
72
73/*
74==================
75SV_StartParticle
76
77Make sure the event gets sent to all clients
78==================
79*/
80void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
81{
82 int i, v;
83
84 if (sv.datagram.cursize > MAX_DATAGRAM-16)
85 return;
86 MSG_WriteByte (&sv.datagram, svc_particle);
87 MSG_WriteCoord (&sv.datagram, org[0]);
88 MSG_WriteCoord (&sv.datagram, org[1]);
89 MSG_WriteCoord (&sv.datagram, org[2]);
90 for (i=0 ; i<3 ; i++)
91 {
92 v = dir[i]*16;
93 if (v > 127)
94 v = 127;
95 else if (v < -128)
96 v = -128;
97 MSG_WriteChar (&sv.datagram, v);
98 }
99 MSG_WriteByte (&sv.datagram, count);
100 MSG_WriteByte (&sv.datagram, color);
101}
102
103/*
104==================
105SV_StartSound
106
107Each entity can have eight independant sound sources, like voice,
108weapon, feet, etc.
109
110Channel 0 is an auto-allocate channel, the others override anything
111allready running on that entity/channel pair.
112
113An attenuation of 0 will play full volume everywhere in the level.
114Larger attenuations will drop off. (max 4 attenuation)
115
116==================
117*/
118void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
119 float attenuation)
120{
121 int sound_num;
122 int field_mask;
123 int i;
124 int ent;
125
126 if (volume < 0 || volume > 255)
127 Sys_Error ("SV_StartSound: volume = %i", volume);
128
129 if (attenuation < 0 || attenuation > 4)
130 Sys_Error ("SV_StartSound: attenuation = %f", attenuation);
131
132 if (channel < 0 || channel > 7)
133 Sys_Error ("SV_StartSound: channel = %i", channel);
134
135 if (sv.datagram.cursize > MAX_DATAGRAM-16)
136 return;
137
138// find precache number for sound
139 for (sound_num=1 ; sound_num<MAX_SOUNDS
140 && sv.sound_precache[sound_num] ; sound_num++)
141 if (!strcmp(sample, sv.sound_precache[sound_num]))
142 break;
143
144 if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )
145 {
146 Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
147 return;
148 }
149
150 ent = NUM_FOR_EDICT(entity);
151
152 channel = (ent<<3) | channel;
153
154 field_mask = 0;
155 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
156 field_mask |= SND_VOLUME;
157 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
158 field_mask |= SND_ATTENUATION;
159
160// directed messages go only to the entity the are targeted on
161 MSG_WriteByte (&sv.datagram, svc_sound);
162 MSG_WriteByte (&sv.datagram, field_mask);
163 if (field_mask & SND_VOLUME)
164 MSG_WriteByte (&sv.datagram, volume);
165 if (field_mask & SND_ATTENUATION)
166 MSG_WriteByte (&sv.datagram, attenuation*64);
167 MSG_WriteShort (&sv.datagram, channel);
168 MSG_WriteByte (&sv.datagram, sound_num);
169 for (i=0 ; i<3 ; i++)
170 MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
171}
172
173/*
174==============================================================================
175
176CLIENT SPAWNING
177
178==============================================================================
179*/
180
181/*
182================
183SV_SendServerinfo
184
185Sends the first message from the server to a connected client.
186This will be sent on the initial connection and upon each server load.
187================
188*/
189void SV_SendServerinfo (client_t *client)
190{
191 char **s;
192 char message[2048];
193
194 MSG_WriteByte (&client->message, svc_print);
195 sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc);
196 MSG_WriteString (&client->message,message);
197
198 MSG_WriteByte (&client->message, svc_serverinfo);
199 MSG_WriteLong (&client->message, PROTOCOL_VERSION);
200 MSG_WriteByte (&client->message, svs.maxclients);
201
202 if (!coop.value && deathmatch.value)
203 MSG_WriteByte (&client->message, GAME_DEATHMATCH);
204 else
205 MSG_WriteByte (&client->message, GAME_COOP);
206
207 sprintf (message, pr_strings+sv.edicts->v.message);
208
209 MSG_WriteString (&client->message,message);
210
211 for (s = sv.model_precache+1 ; *s ; s++)
212 MSG_WriteString (&client->message, *s);
213 MSG_WriteByte (&client->message, 0);
214
215 for (s = sv.sound_precache+1 ; *s ; s++)
216 MSG_WriteString (&client->message, *s);
217 MSG_WriteByte (&client->message, 0);
218
219// send music
220 MSG_WriteByte (&client->message, svc_cdtrack);
221 MSG_WriteByte (&client->message, sv.edicts->v.sounds);
222 MSG_WriteByte (&client->message, sv.edicts->v.sounds);
223
224// set view
225 MSG_WriteByte (&client->message, svc_setview);
226 MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict));
227
228 MSG_WriteByte (&client->message, svc_signonnum);
229 MSG_WriteByte (&client->message, 1);
230
231 client->sendsignon = true;
232 client->spawned = false; // need prespawn, spawn, etc
233}
234
235/*
236================
237SV_ConnectClient
238
239Initializes a client_t for a new net connection. This will only be called
240once for a player each game, not once for each level change.
241================
242*/
243void SV_ConnectClient (int clientnum)
244{
245 edict_t *ent;
246 client_t *client;
247 int edictnum;
248 struct qsocket_s *netconnection;
249 int i;
250 float spawn_parms[NUM_SPAWN_PARMS];
251
252 client = svs.clients + clientnum;
253
254 Con_DPrintf ("Client %s connected\n", client->netconnection->address);
255
256 edictnum = clientnum+1;
257
258 ent = EDICT_NUM(edictnum);
259
260// set up the client_t
261 netconnection = client->netconnection;
262
263 if (sv.loadgame)
264 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
265 memset (client, 0, sizeof(*client));
266 client->netconnection = netconnection;
267
268 strcpy (client->name, "unconnected");
269 client->active = true;
270 client->spawned = false;
271 client->edict = ent;
272 client->message.data = client->msgbuf;
273 client->message.maxsize = sizeof(client->msgbuf);
274 client->message.allowoverflow = true; // we can catch it
275
276#ifdef IDGODS
277 client->privileged = IsID(&client->netconnection->addr);
278#else
279 client->privileged = false;
280#endif
281
282 if (sv.loadgame)
283 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
284 else
285 {
286 // call the progs to get default spawn parms for the new client
287 PR_ExecuteProgram (pr_global_struct->SetNewParms);
288 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
289 client->spawn_parms[i] = (&pr_global_struct->parm1)[i];
290 }
291
292 SV_SendServerinfo (client);
293}
294
295
296/*
297===================
298SV_CheckForNewClients
299
300===================
301*/
302void SV_CheckForNewClients (void)
303{
304 struct qsocket_s *ret;
305 int i;
306
307//
308// check for new connections
309//
310 while (1)
311 {
312 ret = NET_CheckNewConnections ();
313 if (!ret)
314 break;
315
316 //
317 // init a new client structure
318 //
319 for (i=0 ; i<svs.maxclients ; i++)
320 if (!svs.clients[i].active)
321 break;
322 if (i == svs.maxclients)
323 Sys_Error ("Host_CheckForNewClients: no free clients");
324
325 svs.clients[i].netconnection = ret;
326 SV_ConnectClient (i);
327
328 net_activeconnections++;
329 }
330}
331
332
333
334/*
335===============================================================================
336
337FRAME UPDATES
338
339===============================================================================
340*/
341
342/*
343==================
344SV_ClearDatagram
345
346==================
347*/
348void SV_ClearDatagram (void)
349{
350 SZ_Clear (&sv.datagram);
351}
352
353/*
354=============================================================================
355
356The PVS must include a small area around the client to allow head bobbing
357or other small motion on the client side. Otherwise, a bob might cause an
358entity that should be visible to not show up, especially when the bob
359crosses a waterline.
360
361=============================================================================
362*/
363
364int fatbytes;
365byte fatpvs[MAX_MAP_LEAFS/8];
366
367void SV_AddToFatPVS (vec3_t org, mnode_t *node)
368{
369 int i;
370 byte *pvs;
371 mplane_t *plane;
372 float d;
373
374 while (1)
375 {
376 // if this is a leaf, accumulate the pvs bits
377 if (node->contents < 0)
378 {
379 if (node->contents != CONTENTS_SOLID)
380 {
381 pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);
382 for (i=0 ; i<fatbytes ; i++)
383 fatpvs[i] |= pvs[i];
384 }
385 return;
386 }
387
388 plane = node->plane;
389 d = DotProduct (org, plane->normal) - plane->dist;
390 if (d > 8)
391 node = node->children[0];
392 else if (d < -8)
393 node = node->children[1];
394 else
395 { // go down both
396 SV_AddToFatPVS (org, node->children[0]);
397 node = node->children[1];
398 }
399 }
400}
401
402/*
403=============
404SV_FatPVS
405
406Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
407given point.
408=============
409*/
410byte *SV_FatPVS (vec3_t org)
411{
412 fatbytes = (sv.worldmodel->numleafs+31)>>3;
413 Q_memset (fatpvs, 0, fatbytes);
414 SV_AddToFatPVS (org, sv.worldmodel->nodes);
415 return fatpvs;
416}
417
418//=============================================================================
419
420
421/*
422=============
423SV_WriteEntitiesToClient
424
425=============
426*/
427void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
428{
429 int e, i;
430 int bits;
431 byte *pvs;
432 vec3_t org;
433 float miss;
434 edict_t *ent;
435
436// find the client's PVS
437 VectorAdd (clent->v.origin, clent->v.view_ofs, org);
438 pvs = SV_FatPVS (org);
439
440// send over all entities (excpet the client) that touch the pvs
441 ent = NEXT_EDICT(sv.edicts);
442 for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
443 {
444#ifdef QUAKE2
445 // don't send if flagged for NODRAW and there are no lighting effects
446 if (ent->v.effects == EF_NODRAW)
447 continue;
448#endif
449
450// ignore if not touching a PV leaf
451 if (ent != clent) // clent is ALLWAYS sent
452 {
453// ignore ents without visible models
454 if (!ent->v.modelindex || !pr_strings[ent->v.model])
455 continue;
456
457 for (i=0 ; i < ent->num_leafs ; i++)
458 if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
459 break;
460
461 if (i == ent->num_leafs)
462 continue; // not visible
463 }
464
465 if (msg->maxsize - msg->cursize < 16)
466 {
467 Con_Printf ("packet overflow\n");
468 return;
469 }
470
471// send an update
472 bits = 0;
473
474 for (i=0 ; i<3 ; i++)
475 {
476 miss = ent->v.origin[i] - ent->baseline.origin[i];
477 if ( miss < -0.1 || miss > 0.1 )
478 bits |= U_ORIGIN1<<i;
479 }
480
481 if ( ent->v.angles[0] != ent->baseline.angles[0] )
482 bits |= U_ANGLE1;
483
484 if ( ent->v.angles[1] != ent->baseline.angles[1] )
485 bits |= U_ANGLE2;
486
487 if ( ent->v.angles[2] != ent->baseline.angles[2] )
488 bits |= U_ANGLE3;
489
490 if (ent->v.movetype == MOVETYPE_STEP)
491 bits |= U_NOLERP; // don't mess up the step animation
492
493 if (ent->baseline.colormap != ent->v.colormap)
494 bits |= U_COLORMAP;
495
496 if (ent->baseline.skin != ent->v.skin)
497 bits |= U_SKIN;
498
499 if (ent->baseline.frame != ent->v.frame)
500 bits |= U_FRAME;
501
502 if (ent->baseline.effects != ent->v.effects)
503 bits |= U_EFFECTS;
504
505 if (ent->baseline.modelindex != ent->v.modelindex)
506 bits |= U_MODEL;
507
508 if (e >= 256)
509 bits |= U_LONGENTITY;
510
511 if (bits >= 256)
512 bits |= U_MOREBITS;
513
514 //
515 // write the message
516 //
517 MSG_WriteByte (msg,bits | U_SIGNAL);
518
519 if (bits & U_MOREBITS)
520 MSG_WriteByte (msg, bits>>8);
521 if (bits & U_LONGENTITY)
522 MSG_WriteShort (msg,e);
523 else
524 MSG_WriteByte (msg,e);
525
526 if (bits & U_MODEL)
527 MSG_WriteByte (msg, ent->v.modelindex);
528 if (bits & U_FRAME)
529 MSG_WriteByte (msg, ent->v.frame);
530 if (bits & U_COLORMAP)
531 MSG_WriteByte (msg, ent->v.colormap);
532 if (bits & U_SKIN)
533 MSG_WriteByte (msg, ent->v.skin);
534 if (bits & U_EFFECTS)
535 MSG_WriteByte (msg, ent->v.effects);
536 if (bits & U_ORIGIN1)
537 MSG_WriteCoord (msg, ent->v.origin[0]);
538 if (bits & U_ANGLE1)
539 MSG_WriteAngle(msg, ent->v.angles[0]);
540 if (bits & U_ORIGIN2)
541 MSG_WriteCoord (msg, ent->v.origin[1]);
542 if (bits & U_ANGLE2)
543 MSG_WriteAngle(msg, ent->v.angles[1]);
544 if (bits & U_ORIGIN3)
545 MSG_WriteCoord (msg, ent->v.origin[2]);
546 if (bits & U_ANGLE3)
547 MSG_WriteAngle(msg, ent->v.angles[2]);
548 }
549}
550
551/*
552=============
553SV_CleanupEnts
554
555=============
556*/
557void SV_CleanupEnts (void)
558{
559 int e;
560 edict_t *ent;
561
562 ent = NEXT_EDICT(sv.edicts);
563 for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
564 {
565 ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;
566 }
567
568}
569
570/*
571==================
572SV_WriteClientdataToMessage
573
574==================
575*/
576void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
577{
578 int bits;
579 int i;
580 edict_t *other;
581 int items;
582#ifndef QUAKE2
583 eval_t *val;
584#endif
585
586//
587// send a damage message
588//
589 if (ent->v.dmg_take || ent->v.dmg_save)
590 {
591 other = PROG_TO_EDICT(ent->v.dmg_inflictor);
592 MSG_WriteByte (msg, svc_damage);
593 MSG_WriteByte (msg, ent->v.dmg_save);
594 MSG_WriteByte (msg, ent->v.dmg_take);
595 for (i=0 ; i<3 ; i++)
596 MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
597
598 ent->v.dmg_take = 0;
599 ent->v.dmg_save = 0;
600 }
601
602//
603// send the current viewpos offset from the view entity
604//
605 SV_SetIdealPitch (); // how much to look up / down ideally
606
607// a fixangle might get lost in a dropped packet. Oh well.
608 if ( ent->v.fixangle )
609 {
610 MSG_WriteByte (msg, svc_setangle);
611 for (i=0 ; i < 3 ; i++)
612 MSG_WriteAngle (msg, ent->v.angles[i] );
613 ent->v.fixangle = 0;
614 }
615
616 bits = 0;
617
618 if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
619 bits |= SU_VIEWHEIGHT;
620
621 if (ent->v.idealpitch)
622 bits |= SU_IDEALPITCH;
623
624// stuff the sigil bits into the high bits of items for sbar, or else
625// mix in items2
626#ifdef QUAKE2
627 items = (int)ent->v.items | ((int)ent->v.items2 << 23);
628#else
629 val = GetEdictFieldValue(ent, "items2");
630
631 if (val)
632 items = (int)ent->v.items | ((int)val->_float << 23);
633 else
634 items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
635#endif
636
637 bits |= SU_ITEMS;
638
639 if ( (int)ent->v.flags & FL_ONGROUND)
640 bits |= SU_ONGROUND;
641
642 if ( ent->v.waterlevel >= 2)
643 bits |= SU_INWATER;
644
645 for (i=0 ; i<3 ; i++)
646 {
647 if (ent->v.punchangle[i])
648 bits |= (SU_PUNCH1<<i);
649 if (ent->v.velocity[i])
650 bits |= (SU_VELOCITY1<<i);
651 }
652
653 if (ent->v.weaponframe)
654 bits |= SU_WEAPONFRAME;
655
656 if (ent->v.armorvalue)
657 bits |= SU_ARMOR;
658
659// if (ent->v.weapon)
660 bits |= SU_WEAPON;
661
662// send the data
663
664 MSG_WriteByte (msg, svc_clientdata);
665 MSG_WriteShort (msg, bits);
666
667 if (bits & SU_VIEWHEIGHT)
668 MSG_WriteChar (msg, ent->v.view_ofs[2]);
669
670 if (bits & SU_IDEALPITCH)
671 MSG_WriteChar (msg, ent->v.idealpitch);
672
673 for (i=0 ; i<3 ; i++)
674 {
675 if (bits & (SU_PUNCH1<<i))
676 MSG_WriteChar (msg, ent->v.punchangle[i]);
677 if (bits & (SU_VELOCITY1<<i))
678 MSG_WriteChar (msg, ent->v.velocity[i]/16);
679 }
680
681// [always sent] if (bits & SU_ITEMS)
682 MSG_WriteLong (msg, items);
683
684 if (bits & SU_WEAPONFRAME)
685 MSG_WriteByte (msg, ent->v.weaponframe);
686 if (bits & SU_ARMOR)
687 MSG_WriteByte (msg, ent->v.armorvalue);
688 if (bits & SU_WEAPON)
689 MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel));
690
691 MSG_WriteShort (msg, ent->v.health);
692 MSG_WriteByte (msg, ent->v.currentammo);
693 MSG_WriteByte (msg, ent->v.ammo_shells);
694 MSG_WriteByte (msg, ent->v.ammo_nails);
695 MSG_WriteByte (msg, ent->v.ammo_rockets);
696 MSG_WriteByte (msg, ent->v.ammo_cells);
697
698 if (standard_quake)
699 {
700 MSG_WriteByte (msg, ent->v.weapon);
701 }
702 else
703 {
704 for(i=0;i<32;i++)
705 {
706 if ( ((int)ent->v.weapon) & (1<<i) )
707 {
708 MSG_WriteByte (msg, i);
709 break;
710 }
711 }
712 }
713}
714
715/*
716=======================
717SV_SendClientDatagram
718=======================
719*/
720qboolean SV_SendClientDatagram (client_t *client)
721{
722 byte buf[MAX_DATAGRAM];
723 sizebuf_t msg;
724
725 msg.data = buf;
726 msg.maxsize = sizeof(buf);
727 msg.cursize = 0;
728
729 MSG_WriteByte (&msg, svc_time);
730 MSG_WriteFloat (&msg, sv.time);
731
732// add the client specific data to the datagram
733 SV_WriteClientdataToMessage (client->edict, &msg);
734
735 SV_WriteEntitiesToClient (client->edict, &msg);
736
737// copy the server datagram if there is space
738 if (msg.cursize + sv.datagram.cursize < msg.maxsize)
739 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
740
741// send the datagram
742 if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
743 {
744 SV_DropClient (true);// if the message couldn't send, kick off
745 return false;
746 }
747
748 return true;
749}
750
751/*
752=======================
753SV_UpdateToReliableMessages
754=======================
755*/
756void SV_UpdateToReliableMessages (void)
757{
758 int i, j;
759 client_t *client;
760
761// check for changes to be sent over the reliable streams
762 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
763 {
764 if (host_client->old_frags != host_client->edict->v.frags)
765 {
766 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
767 {
768 if (!client->active)
769 continue;
770 MSG_WriteByte (&client->message, svc_updatefrags);
771 MSG_WriteByte (&client->message, i);
772 MSG_WriteShort (&client->message, host_client->edict->v.frags);
773 }
774
775 host_client->old_frags = host_client->edict->v.frags;
776 }
777 }
778
779 for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
780 {
781 if (!client->active)
782 continue;
783 SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
784 }
785
786 SZ_Clear (&sv.reliable_datagram);
787}
788
789
790/*
791=======================
792SV_SendNop
793
794Send a nop message without trashing or sending the accumulated client
795message buffer
796=======================
797*/
798void SV_SendNop (client_t *client)
799{
800 sizebuf_t msg;
801 byte buf[4];
802
803 msg.data = buf;
804 msg.maxsize = sizeof(buf);
805 msg.cursize = 0;
806
807 MSG_WriteChar (&msg, svc_nop);
808
809 if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)
810 SV_DropClient (true); // if the message couldn't send, kick off
811 client->last_message = realtime;
812}
813
814/*
815=======================
816SV_SendClientMessages
817=======================
818*/
819void SV_SendClientMessages (void)
820{
821 int i;
822
823// update frags, names, etc
824 SV_UpdateToReliableMessages ();
825
826// build individual updates
827 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
828 {
829 if (!host_client->active)
830 continue;
831
832 if (host_client->spawned)
833 {
834 if (!SV_SendClientDatagram (host_client))
835 continue;
836 }
837 else
838 {
839 // the player isn't totally in the game yet
840 // send small keepalive messages if too much time has passed
841 // send a full message when the next signon stage has been requested
842 // some other message data (name changes, etc) may accumulate
843 // between signon stages
844 if (!host_client->sendsignon)
845 {
846 if (realtime - host_client->last_message > 5)
847 SV_SendNop (host_client);
848 continue; // don't send out non-signon messages
849 }
850 }
851
852 // check for an overflowed message. Should only happen
853 // on a very fucked up connection that backs up a lot, then
854 // changes level
855 if (host_client->message.overflowed)
856 {
857 SV_DropClient (true);
858 host_client->message.overflowed = false;
859 continue;
860 }
861
862 if (host_client->message.cursize || host_client->dropasap)
863 {
864 if (!NET_CanSendMessage (host_client->netconnection))
865 {
866// I_Printf ("can't write\n");
867 continue;
868 }
869
870 if (host_client->dropasap)
871 SV_DropClient (false); // went to another level
872 else
873 {
874 if (NET_SendMessage (host_client->netconnection
875 , &host_client->message) == -1)
876 SV_DropClient (true); // if the message couldn't send, kick off
877 SZ_Clear (&host_client->message);
878 host_client->last_message = realtime;
879 host_client->sendsignon = false;
880 }
881 }
882 }
883
884
885// clear muzzle flashes
886 SV_CleanupEnts ();
887}
888
889
890/*
891==============================================================================
892
893SERVER SPAWNING
894
895==============================================================================
896*/
897
898/*
899================
900SV_ModelIndex
901
902================
903*/
904int SV_ModelIndex (char *name)
905{
906 int i;
907
908 if (!name || !name[0])
909 return 0;
910
911 for (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)
912 if (!strcmp(sv.model_precache[i], name))
913 return i;
914 if (i==MAX_MODELS || !sv.model_precache[i])
915 Sys_Error ("SV_ModelIndex: model %s not precached", name);
916 return i;
917}
918
919/*
920================
921SV_CreateBaseline
922
923================
924*/
925void SV_CreateBaseline (void)
926{
927 int i;
928 edict_t *svent;
929 int entnum;
930
931 for (entnum = 0; entnum < sv.num_edicts ; entnum++)
932 {
933 // get the current server version
934 svent = EDICT_NUM(entnum);
935 if (svent->free)
936 continue;
937 if (entnum > svs.maxclients && !svent->v.modelindex)
938 continue;
939
940 //
941 // create entity baseline
942 //
943 VectorCopy (svent->v.origin, svent->baseline.origin);
944 VectorCopy (svent->v.angles, svent->baseline.angles);
945 svent->baseline.frame = svent->v.frame;
946 svent->baseline.skin = svent->v.skin;
947 if (entnum > 0 && entnum <= svs.maxclients)
948 {
949 svent->baseline.colormap = entnum;
950 svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
951 }
952 else
953 {
954 svent->baseline.colormap = 0;
955 svent->baseline.modelindex =
956 SV_ModelIndex(pr_strings + svent->v.model);
957 }
958
959 //
960 // add to the message
961 //
962 MSG_WriteByte (&sv.signon,svc_spawnbaseline);
963 MSG_WriteShort (&sv.signon,entnum);
964
965 MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
966 MSG_WriteByte (&sv.signon, svent->baseline.frame);
967 MSG_WriteByte (&sv.signon, svent->baseline.colormap);
968 MSG_WriteByte (&sv.signon, svent->baseline.skin);
969 for (i=0 ; i<3 ; i++)
970 {
971 MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);
972 MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
973 }
974 }
975}
976
977
978/*
979================
980SV_SendReconnect
981
982Tell all the clients that the server is changing levels
983================
984*/
985void SV_SendReconnect (void)
986{
987 char data[128];
988 sizebuf_t msg;
989
990 msg.data = data;
991 msg.cursize = 0;
992 msg.maxsize = sizeof(data);
993
994 MSG_WriteChar (&msg, svc_stufftext);
995 MSG_WriteString (&msg, "reconnect\n");
996 NET_SendToAll (&msg, 5);
997
998 if (cls.state != ca_dedicated)
999#ifdef QUAKE2
1000 Cbuf_InsertText ("reconnect\n");
1001#else
1002 Cmd_ExecuteString ("reconnect\n", src_command);
1003#endif
1004}
1005
1006
1007/*
1008================
1009SV_SaveSpawnparms
1010
1011Grabs the current state of each client for saving across the
1012transition to another level
1013================
1014*/
1015void SV_SaveSpawnparms (void)
1016{
1017 int i, j;
1018
1019 svs.serverflags = pr_global_struct->serverflags;
1020
1021 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
1022 {
1023 if (!host_client->active)
1024 continue;
1025
1026 // call the progs to get default spawn parms for the new client
1027 pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
1028 PR_ExecuteProgram (pr_global_struct->SetChangeParms);
1029 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1030 host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];
1031 }
1032}
1033
1034
1035/*
1036================
1037SV_SpawnServer
1038
1039This is called at the start of each level
1040================
1041*/
1042extern float scr_centertime_off;
1043
1044#ifdef QUAKE2
1045void SV_SpawnServer (char *server, char *startspot)
1046#else
1047void SV_SpawnServer (char *server)
1048#endif
1049{
1050 edict_t *ent;
1051 int i;
1052
1053 // let's not have any servers with no name
1054 if (hostname.string[0] == 0)
1055 Cvar_Set ("hostname", "UNNAMED");
1056 scr_centertime_off = 0;
1057
1058 Con_DPrintf ("SpawnServer: %s\n",server);
1059 svs.changelevel_issued = false; // now safe to issue another
1060
1061//
1062// tell all connected clients that we are going to a new level
1063//
1064 if (sv.active)
1065 {
1066 SV_SendReconnect ();
1067 }
1068
1069//
1070// make cvars consistant
1071//
1072 if (coop.value)
1073 Cvar_SetValue ("deathmatch", 0);
1074 current_skill = (int)(skill.value + 0.5);
1075 if (current_skill < 0)
1076 current_skill = 0;
1077 if (current_skill > 3)
1078 current_skill = 3;
1079
1080 Cvar_SetValue ("skill", (float)current_skill);
1081
1082//
1083// set up the new server
1084//
1085 Host_ClearMemory ();
1086
1087 memset (&sv, 0, sizeof(sv));
1088
1089 strcpy (sv.name, server);
1090#ifdef QUAKE2
1091 if (startspot)
1092 strcpy(sv.startspot, startspot);
1093#endif
1094
1095// load progs to get entity field count
1096 //printf("progs 1");
1097 PR_LoadProgs ();
1098 //printf("progs 2");
1099
1100// allocate server memory
1101 sv.max_edicts = MAX_EDICTS;
1102
1103 sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts");
1104
1105 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1106 sv.datagram.cursize = 0;
1107 sv.datagram.data = sv.datagram_buf;
1108
1109 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1110 sv.reliable_datagram.cursize = 0;
1111 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1112
1113 sv.signon.maxsize = sizeof(sv.signon_buf);
1114 sv.signon.cursize = 0;
1115 sv.signon.data = sv.signon_buf;
1116
1117 //printf("progs 3");
1118// leave slots at start for clients only
1119 sv.num_edicts = svs.maxclients+1;
1120 for (i=0 ; i<svs.maxclients ; i++)
1121 {
1122 ent = EDICT_NUM(i+1);
1123 svs.clients[i].edict = ent;
1124 }
1125
1126 sv.state = ss_loading;
1127 sv.paused = false;
1128
1129 sv.time = 1.0;
1130
1131 strcpy (sv.name, server);
1132 sprintf (sv.modelname,"maps/%s.bsp", server);
1133 sv.worldmodel = Mod_ForName (sv.modelname, false);
1134 if (!sv.worldmodel)
1135 {
1136 Con_Printf ("Couldn't spawn server %s\n", sv.modelname);
1137 sv.active = false;
1138 return;
1139 }
1140 sv.models[1] = sv.worldmodel;
1141
1142//
1143// clear world interaction links
1144//
1145 //printf("progs 4");
1146 SV_ClearWorld ();
1147 //printf("progs 5");
1148
1149 sv.sound_precache[0] = pr_strings;
1150
1151 sv.model_precache[0] = pr_strings;
1152 sv.model_precache[1] = sv.modelname;
1153 for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
1154 {
1155 sv.model_precache[1+i] = localmodels[i];
1156 sv.models[i+1] = Mod_ForName (localmodels[i], false);
1157 }
1158
1159//
1160// load the rest of the entities
1161//
1162 //printf("progs 6");
1163 ent = EDICT_NUM(0);
1164 memset (&ent->v, 0, progs->entityfields * 4);
1165 //printf("progs 7");
1166 ent->free = false;
1167 ent->v.model = sv.worldmodel->name - pr_strings;
1168 ent->v.modelindex = 1; // world model
1169 ent->v.solid = SOLID_BSP;
1170 ent->v.movetype = MOVETYPE_PUSH;
1171
1172 if (coop.value)
1173 pr_global_struct->coop = coop.value;
1174 else
1175 pr_global_struct->deathmatch = deathmatch.value;
1176
1177 pr_global_struct->mapname = sv.name - pr_strings;
1178#ifdef QUAKE2
1179 pr_global_struct->startspot = sv.startspot - pr_strings;
1180#endif
1181
1182// serverflags are for cross level information (sigils)
1183 pr_global_struct->serverflags = svs.serverflags;
1184
1185 //printf("progs 8");
1186 ED_LoadFromFile (sv.worldmodel->entities);
1187
1188 //printf("progs 9");
1189 sv.active = true;
1190
1191// all setup is completed, any further precache statements are errors
1192 sv.state = ss_active;
1193
1194// run two frames to allow everything to settle
1195 host_frametime = 0.1;
1196 SV_Physics ();
1197 SV_Physics ();
1198
1199// create a baseline for more efficient communications
1200 SV_CreateBaseline ();
1201
1202// send serverinfo to all connected clients
1203 for (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
1204 if (host_client->active)
1205 SV_SendServerinfo (host_client);
1206
1207 Con_DPrintf ("Server spawned.\n");
1208}
1209
diff --git a/apps/plugins/sdl/progs/quake/sv_move.c b/apps/plugins/sdl/progs/quake/sv_move.c
new file mode 100644
index 0000000000..a0078b941a
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_move.c
@@ -0,0 +1,427 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_move.c -- monster movement
21
22#include "quakedef.h"
23
24#define STEPSIZE 18
25
26/*
27=============
28SV_CheckBottom
29
30Returns false if any part of the bottom of the entity is off an edge that
31is not a staircase.
32
33=============
34*/
35int c_yes, c_no;
36
37qboolean SV_CheckBottom (edict_t *ent)
38{
39 vec3_t mins, maxs, start, stop;
40 trace_t trace;
41 int x, y;
42 float mid, bottom;
43
44 VectorAdd (ent->v.origin, ent->v.mins, mins);
45 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
46
47// if all of the points under the corners are solid world, don't bother
48// with the tougher checks
49// the corners must be within 16 of the midpoint
50 start[2] = mins[2] - 1;
51 for (x=0 ; x<=1 ; x++)
52 for (y=0 ; y<=1 ; y++)
53 {
54 start[0] = x ? maxs[0] : mins[0];
55 start[1] = y ? maxs[1] : mins[1];
56 if (SV_PointContents (start) != CONTENTS_SOLID)
57 goto realcheck;
58 }
59
60 c_yes++;
61 return true; // we got out easy
62
63realcheck:
64 c_no++;
65//
66// check it for real...
67//
68 start[2] = mins[2];
69
70// the midpoint must be within 16 of the bottom
71 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
72 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
73 stop[2] = start[2] - 2*STEPSIZE;
74 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
75
76 if (trace.fraction == 1.0)
77 return false;
78 mid = bottom = trace.endpos[2];
79
80// the corners must be within 16 of the midpoint
81 for (x=0 ; x<=1 ; x++)
82 for (y=0 ; y<=1 ; y++)
83 {
84 start[0] = stop[0] = x ? maxs[0] : mins[0];
85 start[1] = stop[1] = y ? maxs[1] : mins[1];
86
87 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);
88
89 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
90 bottom = trace.endpos[2];
91 if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
92 return false;
93 }
94
95 c_yes++;
96 return true;
97}
98
99
100/*
101=============
102SV_movestep
103
104Called by monster program code.
105The move will be adjusted for slopes and stairs, but if the move isn't
106possible, no move is done, false is returned, and
107pr_global_struct->trace_normal is set to the normal of the blocking wall
108=============
109*/
110qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
111{
112 float dz;
113 vec3_t oldorg, neworg, end;
114 trace_t trace;
115 int i;
116 edict_t *enemy;
117
118// try the move
119 VectorCopy (ent->v.origin, oldorg);
120 VectorAdd (ent->v.origin, move, neworg);
121
122// flying monsters don't step up
123 if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
124 {
125 // try one move with vertical motion, then one without
126 for (i=0 ; i<2 ; i++)
127 {
128 VectorAdd (ent->v.origin, move, neworg);
129 enemy = PROG_TO_EDICT(ent->v.enemy);
130 if (i == 0 && enemy != sv.edicts)
131 {
132 dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
133 if (dz > 40)
134 neworg[2] -= 8;
135 if (dz < 30)
136 neworg[2] += 8;
137 }
138 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);
139
140 if (trace.fraction == 1)
141 {
142 if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
143 return false; // swim monster left water
144
145 VectorCopy (trace.endpos, ent->v.origin);
146 if (relink)
147 SV_LinkEdict (ent, true);
148 return true;
149 }
150
151 if (enemy == sv.edicts)
152 break;
153 }
154
155 return false;
156 }
157
158// push down from a step height above the wished position
159 neworg[2] += STEPSIZE;
160 VectorCopy (neworg, end);
161 end[2] -= STEPSIZE*2;
162
163 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);
164
165 if (trace.allsolid)
166 return false;
167
168 if (trace.startsolid)
169 {
170 neworg[2] -= STEPSIZE;
171 trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);
172 if (trace.allsolid || trace.startsolid)
173 return false;
174 }
175 if (trace.fraction == 1)
176 {
177 // if monster had the ground pulled out, go ahead and fall
178 if ( (int)ent->v.flags & FL_PARTIALGROUND )
179 {
180 VectorAdd (ent->v.origin, move, ent->v.origin);
181 if (relink)
182 SV_LinkEdict (ent, true);
183 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
184// Con_Printf ("fall down\n");
185 return true;
186 }
187
188 return false; // walked off an edge
189 }
190
191// check point traces down for dangling corners
192 VectorCopy (trace.endpos, ent->v.origin);
193
194 if (!SV_CheckBottom (ent))
195 {
196 if ( (int)ent->v.flags & FL_PARTIALGROUND )
197 { // entity had floor mostly pulled out from underneath it
198 // and is trying to correct
199 if (relink)
200 SV_LinkEdict (ent, true);
201 return true;
202 }
203 VectorCopy (oldorg, ent->v.origin);
204 return false;
205 }
206
207 if ( (int)ent->v.flags & FL_PARTIALGROUND )
208 {
209// Con_Printf ("back on ground\n");
210 ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
211 }
212 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
213
214// the move is ok
215 if (relink)
216 SV_LinkEdict (ent, true);
217 return true;
218}
219
220
221//============================================================================
222
223/*
224======================
225SV_StepDirection
226
227Turns to the movement direction, and walks the current distance if
228facing it.
229
230======================
231*/
232void PF_changeyaw (void);
233qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
234{
235 vec3_t move, oldorigin;
236 float delta;
237
238 ent->v.ideal_yaw = yaw;
239 PF_changeyaw();
240
241 yaw = yaw*M_PI*2 / 360;
242 move[0] = cos(yaw)*dist;
243 move[1] = sin(yaw)*dist;
244 move[2] = 0;
245
246 VectorCopy (ent->v.origin, oldorigin);
247 if (SV_movestep (ent, move, false))
248 {
249 delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
250 if (delta > 45 && delta < 315)
251 { // not turned far enough, so don't take the step
252 VectorCopy (oldorigin, ent->v.origin);
253 }
254 SV_LinkEdict (ent, true);
255 return true;
256 }
257 SV_LinkEdict (ent, true);
258
259 return false;
260}
261
262/*
263======================
264SV_FixCheckBottom
265
266======================
267*/
268void SV_FixCheckBottom (edict_t *ent)
269{
270// Con_Printf ("SV_FixCheckBottom\n");
271
272 ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
273}
274
275
276
277/*
278================
279SV_NewChaseDir
280
281================
282*/
283#define DI_NODIR -1
284void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
285{
286 float deltax,deltay;
287 float d[3];
288 float tdir, olddir, turnaround;
289
290 olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 );
291 turnaround = anglemod(olddir - 180);
292
293 deltax = enemy->v.origin[0] - actor->v.origin[0];
294 deltay = enemy->v.origin[1] - actor->v.origin[1];
295 if (deltax>10)
296 d[1]= 0;
297 else if (deltax<-10)
298 d[1]= 180;
299 else
300 d[1]= DI_NODIR;
301 if (deltay<-10)
302 d[2]= 270;
303 else if (deltay>10)
304 d[2]= 90;
305 else
306 d[2]= DI_NODIR;
307
308// try direct route
309 if (d[1] != DI_NODIR && d[2] != DI_NODIR)
310 {
311 if (d[1] == 0)
312 tdir = d[2] == 90 ? 45 : 315;
313 else
314 tdir = d[2] == 90 ? 135 : 215;
315
316 if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
317 return;
318 }
319
320// try other directions
321 if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax))
322 {
323 tdir=d[1];
324 d[1]=d[2];
325 d[2]=tdir;
326 }
327
328 if (d[1]!=DI_NODIR && d[1]!=turnaround
329 && SV_StepDirection(actor, d[1], dist))
330 return;
331
332 if (d[2]!=DI_NODIR && d[2]!=turnaround
333 && SV_StepDirection(actor, d[2], dist))
334 return;
335
336/* there is no direct path to the player, so pick another direction */
337
338 if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
339 return;
340
341 if (rand()&1) /*randomly determine direction of search*/
342 {
343 for (tdir=0 ; tdir<=315 ; tdir += 45)
344 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
345 return;
346 }
347 else
348 {
349 for (tdir=315 ; tdir >=0 ; tdir -= 45)
350 if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
351 return;
352 }
353
354 if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
355 return;
356
357 actor->v.ideal_yaw = olddir; // can't move
358
359// if a bridge was pulled out from underneath a monster, it may not have
360// a valid standing position at all
361
362 if (!SV_CheckBottom (actor))
363 SV_FixCheckBottom (actor);
364
365}
366
367/*
368======================
369SV_CloseEnough
370
371======================
372*/
373qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
374{
375 int i;
376
377 for (i=0 ; i<3 ; i++)
378 {
379 if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
380 return false;
381 if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
382 return false;
383 }
384 return true;
385}
386
387/*
388======================
389SV_MoveToGoal
390
391======================
392*/
393void SV_MoveToGoal (void)
394{
395 edict_t *ent, *goal;
396 float dist;
397#ifdef QUAKE2
398 edict_t *enemy;
399#endif
400
401 ent = PROG_TO_EDICT(pr_global_struct->self);
402 goal = PROG_TO_EDICT(ent->v.goalentity);
403 dist = G_FLOAT(OFS_PARM0);
404
405 if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
406 {
407 G_FLOAT(OFS_RETURN) = 0;
408 return;
409 }
410
411// if the next step hits the enemy, return immediately
412#ifdef QUAKE2
413 enemy = PROG_TO_EDICT(ent->v.enemy);
414 if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) )
415#else
416 if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
417#endif
418 return;
419
420// bump around...
421 if ( (rand()&3)==1 ||
422 !SV_StepDirection (ent, ent->v.ideal_yaw, dist))
423 {
424 SV_NewChaseDir (ent, goal, dist);
425 }
426}
427
diff --git a/apps/plugins/sdl/progs/quake/sv_phys.c b/apps/plugins/sdl/progs/quake/sv_phys.c
new file mode 100644
index 0000000000..e13c0e443d
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_phys.c
@@ -0,0 +1,1617 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_phys.c
21
22#include "quakedef.h"
23
24/*
25
26
27pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
28
29onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
30
31doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33corpses are SOLID_NOT and MOVETYPE_TOSS
34crates are SOLID_BBOX and MOVETYPE_TOSS
35walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38solid_edge items only clip against bsp models.
39
40*/
41
42cvar_t sv_friction = {"sv_friction","4",false,true};
43cvar_t sv_stopspeed = {"sv_stopspeed","100"};
44cvar_t sv_gravity = {"sv_gravity","800",false,true};
45cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
46cvar_t sv_nostep = {"sv_nostep","0"};
47
48#ifdef QUAKE2
49static vec3_t vec_origin = {0.0, 0.0, 0.0};
50#endif
51
52#define MOVE_EPSILON 0.01
53
54void SV_Physics_Toss (edict_t *ent);
55
56/*
57================
58SV_CheckAllEnts
59================
60*/
61void SV_CheckAllEnts (void)
62{
63 int e;
64 edict_t *check;
65
66// see if any solid entities are inside the final position
67 check = NEXT_EDICT(sv.edicts);
68 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
69 {
70 if (check->free)
71 continue;
72 if (check->v.movetype == MOVETYPE_PUSH
73 || check->v.movetype == MOVETYPE_NONE
74#ifdef QUAKE2
75 || check->v.movetype == MOVETYPE_FOLLOW
76#endif
77 || check->v.movetype == MOVETYPE_NOCLIP)
78 continue;
79
80 if (SV_TestEntityPosition (check))
81 Con_Printf ("entity in invalid position\n");
82 }
83}
84
85/*
86================
87SV_CheckVelocity
88================
89*/
90void SV_CheckVelocity (edict_t *ent)
91{
92 int i;
93
94//
95// bound velocity
96//
97 for (i=0 ; i<3 ; i++)
98 {
99 if (IS_NAN(ent->v.velocity[i]))
100 {
101 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
102 ent->v.velocity[i] = 0;
103 }
104 if (IS_NAN(ent->v.origin[i]))
105 {
106 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
107 ent->v.origin[i] = 0;
108 }
109 if (ent->v.velocity[i] > sv_maxvelocity.value)
110 ent->v.velocity[i] = sv_maxvelocity.value;
111 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
112 ent->v.velocity[i] = -sv_maxvelocity.value;
113 }
114}
115
116/*
117=============
118SV_RunThink
119
120Runs thinking code if time. There is some play in the exact time the think
121function will be called, because it is called before any movement is done
122in a frame. Not used for pushmove objects, because they must be exact.
123Returns false if the entity removed itself.
124=============
125*/
126qboolean SV_RunThink (edict_t *ent)
127{
128 float thinktime;
129
130 thinktime = ent->v.nextthink;
131 if (thinktime <= 0 || thinktime > sv.time + host_frametime)
132 return true;
133
134 if (thinktime < sv.time)
135 thinktime = sv.time; // don't let things stay in the past.
136 // it is possible to start that way
137 // by a trigger with a local time.
138 ent->v.nextthink = 0;
139 pr_global_struct->time = thinktime;
140 pr_global_struct->self = EDICT_TO_PROG(ent);
141 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
142 PR_ExecuteProgram (ent->v.think);
143 return !ent->free;
144}
145
146/*
147==================
148SV_Impact
149
150Two entities have touched, so run their touch functions
151==================
152*/
153void SV_Impact (edict_t *e1, edict_t *e2)
154{
155 int old_self, old_other;
156
157 old_self = pr_global_struct->self;
158 old_other = pr_global_struct->other;
159
160 pr_global_struct->time = sv.time;
161 if (e1->v.touch && e1->v.solid != SOLID_NOT)
162 {
163 pr_global_struct->self = EDICT_TO_PROG(e1);
164 pr_global_struct->other = EDICT_TO_PROG(e2);
165 PR_ExecuteProgram (e1->v.touch);
166 }
167
168 if (e2->v.touch && e2->v.solid != SOLID_NOT)
169 {
170 pr_global_struct->self = EDICT_TO_PROG(e2);
171 pr_global_struct->other = EDICT_TO_PROG(e1);
172 PR_ExecuteProgram (e2->v.touch);
173 }
174
175 pr_global_struct->self = old_self;
176 pr_global_struct->other = old_other;
177}
178
179
180/*
181==================
182ClipVelocity
183
184Slide off of the impacting object
185returns the blocked flags (1 = floor, 2 = step / wall)
186==================
187*/
188#define STOP_EPSILON 0.1
189
190int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
191{
192 float backoff;
193 float change;
194 int i, blocked;
195
196 blocked = 0;
197 if (normal[2] > 0)
198 blocked |= 1; // floor
199 if (!normal[2])
200 blocked |= 2; // step
201
202 backoff = DotProduct (in, normal) * overbounce;
203
204 for (i=0 ; i<3 ; i++)
205 {
206 change = normal[i]*backoff;
207 out[i] = in[i] - change;
208 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
209 out[i] = 0;
210 }
211
212 return blocked;
213}
214
215
216/*
217============
218SV_FlyMove
219
220The basic solid body movement clip that slides along multiple planes
221Returns the clipflags if the velocity was modified (hit something solid)
2221 = floor
2232 = wall / step
2244 = dead stop
225If steptrace is not NULL, the trace of any vertical wall hit will be stored
226============
227*/
228#define MAX_CLIP_PLANES 5
229int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
230{
231 int bumpcount, numbumps;
232 vec3_t dir;
233 float d;
234 int numplanes;
235 vec3_t planes[MAX_CLIP_PLANES];
236 vec3_t primal_velocity, original_velocity, new_velocity;
237 int i, j;
238 trace_t trace;
239 vec3_t end;
240 float time_left;
241 int blocked;
242
243 numbumps = 4;
244
245 blocked = 0;
246 VectorCopy (ent->v.velocity, original_velocity);
247 VectorCopy (ent->v.velocity, primal_velocity);
248 numplanes = 0;
249
250 time_left = time;
251
252 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
253 {
254 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
255 break;
256
257 for (i=0 ; i<3 ; i++)
258 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
259
260 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
261
262 if (trace.allsolid)
263 { // entity is trapped in another solid
264 VectorCopy (vec3_origin, ent->v.velocity);
265 return 3;
266 }
267
268 if (trace.fraction > 0)
269 { // actually covered some distance
270 VectorCopy (trace.endpos, ent->v.origin);
271 VectorCopy (ent->v.velocity, original_velocity);
272 numplanes = 0;
273 }
274
275 if (trace.fraction == 1)
276 break; // moved the entire distance
277
278 if (!trace.ent)
279 Sys_Error ("SV_FlyMove: !trace.ent");
280
281 if (trace.plane.normal[2] > 0.7)
282 {
283 blocked |= 1; // floor
284 if (trace.ent->v.solid == SOLID_BSP)
285 {
286 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
287 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
288 }
289 }
290 if (!trace.plane.normal[2])
291 {
292 blocked |= 2; // step
293 if (steptrace)
294 *steptrace = trace; // save for player extrafriction
295 }
296
297//
298// run the impact function
299//
300 SV_Impact (ent, trace.ent);
301 if (ent->free)
302 break; // removed by the impact function
303
304
305 time_left -= time_left * trace.fraction;
306
307 // cliped to another plane
308 if (numplanes >= MAX_CLIP_PLANES)
309 { // this shouldn't really happen
310 VectorCopy (vec3_origin, ent->v.velocity);
311 return 3;
312 }
313
314 VectorCopy (trace.plane.normal, planes[numplanes]);
315 numplanes++;
316
317//
318// modify original_velocity so it parallels all of the clip planes
319//
320 for (i=0 ; i<numplanes ; i++)
321 {
322 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
323 for (j=0 ; j<numplanes ; j++)
324 if (j != i)
325 {
326 if (DotProduct (new_velocity, planes[j]) < 0)
327 break; // not ok
328 }
329 if (j == numplanes)
330 break;
331 }
332
333 if (i != numplanes)
334 { // go along this plane
335 VectorCopy (new_velocity, ent->v.velocity);
336 }
337 else
338 { // go along the crease
339 if (numplanes != 2)
340 {
341// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
342 VectorCopy (vec3_origin, ent->v.velocity);
343 return 7;
344 }
345 CrossProduct (planes[0], planes[1], dir);
346 d = DotProduct (dir, ent->v.velocity);
347 VectorScale (dir, d, ent->v.velocity);
348 }
349
350//
351// if original velocity is against the original velocity, stop dead
352// to avoid tiny occilations in sloping corners
353//
354 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
355 {
356 VectorCopy (vec3_origin, ent->v.velocity);
357 return blocked;
358 }
359 }
360
361 return blocked;
362}
363
364
365/*
366============
367SV_AddGravity
368
369============
370*/
371void SV_AddGravity (edict_t *ent)
372{
373 float ent_gravity;
374
375#ifdef QUAKE2
376 if (ent->v.gravity)
377 ent_gravity = ent->v.gravity;
378 else
379 ent_gravity = 1.0;
380#else
381 eval_t *val;
382
383 val = GetEdictFieldValue(ent, "gravity");
384 if (val && val->_float)
385 ent_gravity = val->_float;
386 else
387 ent_gravity = 1.0;
388#endif
389 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
390}
391
392
393/*
394===============================================================================
395
396PUSHMOVE
397
398===============================================================================
399*/
400
401/*
402============
403SV_PushEntity
404
405Does not change the entities velocity at all
406============
407*/
408trace_t SV_PushEntity (edict_t *ent, vec3_t push)
409{
410 trace_t trace;
411 vec3_t end;
412
413 VectorAdd (ent->v.origin, push, end);
414
415 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
416 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
417 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
418 // only clip against bmodels
419 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
420 else
421 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
422
423 VectorCopy (trace.endpos, ent->v.origin);
424 SV_LinkEdict (ent, true);
425
426 if (trace.ent)
427 SV_Impact (ent, trace.ent);
428
429 return trace;
430}
431
432
433/*
434============
435SV_PushMove
436
437============
438*/
439void SV_PushMove (edict_t *pusher, float movetime)
440{
441 int i, e;
442 edict_t *check, *block;
443 vec3_t mins, maxs, move;
444 vec3_t entorig, pushorig;
445 int num_moved;
446 edict_t *moved_edict[MAX_EDICTS];
447 vec3_t moved_from[MAX_EDICTS];
448
449 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
450 {
451 pusher->v.ltime += movetime;
452 return;
453 }
454
455 for (i=0 ; i<3 ; i++)
456 {
457 move[i] = pusher->v.velocity[i] * movetime;
458 mins[i] = pusher->v.absmin[i] + move[i];
459 maxs[i] = pusher->v.absmax[i] + move[i];
460 }
461
462 VectorCopy (pusher->v.origin, pushorig);
463
464// move the pusher to it's final position
465
466 VectorAdd (pusher->v.origin, move, pusher->v.origin);
467 pusher->v.ltime += movetime;
468 SV_LinkEdict (pusher, false);
469
470
471// see if any solid entities are inside the final position
472 num_moved = 0;
473 check = NEXT_EDICT(sv.edicts);
474 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
475 {
476 if (check->free)
477 continue;
478 if (check->v.movetype == MOVETYPE_PUSH
479 || check->v.movetype == MOVETYPE_NONE
480#ifdef QUAKE2
481 || check->v.movetype == MOVETYPE_FOLLOW
482#endif
483 || check->v.movetype == MOVETYPE_NOCLIP)
484 continue;
485
486 // if the entity is standing on the pusher, it will definately be moved
487 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
488 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
489 {
490 if ( check->v.absmin[0] >= maxs[0]
491 || check->v.absmin[1] >= maxs[1]
492 || check->v.absmin[2] >= maxs[2]
493 || check->v.absmax[0] <= mins[0]
494 || check->v.absmax[1] <= mins[1]
495 || check->v.absmax[2] <= mins[2] )
496 continue;
497
498 // see if the ent's bbox is inside the pusher's final position
499 if (!SV_TestEntityPosition (check))
500 continue;
501 }
502
503 // remove the onground flag for non-players
504 if (check->v.movetype != MOVETYPE_WALK)
505 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
506
507 VectorCopy (check->v.origin, entorig);
508 VectorCopy (check->v.origin, moved_from[num_moved]);
509 moved_edict[num_moved] = check;
510 num_moved++;
511
512 // try moving the contacted entity
513 pusher->v.solid = SOLID_NOT;
514 SV_PushEntity (check, move);
515 pusher->v.solid = SOLID_BSP;
516
517 // if it is still inside the pusher, block
518 block = SV_TestEntityPosition (check);
519 if (block)
520 { // fail the move
521 if (check->v.mins[0] == check->v.maxs[0])
522 continue;
523 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
524 { // corpse
525 check->v.mins[0] = check->v.mins[1] = 0;
526 VectorCopy (check->v.mins, check->v.maxs);
527 continue;
528 }
529
530 VectorCopy (entorig, check->v.origin);
531 SV_LinkEdict (check, true);
532
533 VectorCopy (pushorig, pusher->v.origin);
534 SV_LinkEdict (pusher, false);
535 pusher->v.ltime -= movetime;
536
537 // if the pusher has a "blocked" function, call it
538 // otherwise, just stay in place until the obstacle is gone
539 if (pusher->v.blocked)
540 {
541 pr_global_struct->self = EDICT_TO_PROG(pusher);
542 pr_global_struct->other = EDICT_TO_PROG(check);
543 PR_ExecuteProgram (pusher->v.blocked);
544 }
545
546 // move back any entities we already moved
547 for (i=0 ; i<num_moved ; i++)
548 {
549 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
550 SV_LinkEdict (moved_edict[i], false);
551 }
552 return;
553 }
554 }
555
556
557}
558
559#ifdef QUAKE2
560/*
561============
562SV_PushRotate
563
564============
565*/
566void SV_PushRotate (edict_t *pusher, float movetime)
567{
568 int i, e;
569 edict_t *check, *block;
570 vec3_t move, a, amove;
571 vec3_t entorig, pushorig;
572 int num_moved;
573 edict_t *moved_edict[MAX_EDICTS];
574 vec3_t moved_from[MAX_EDICTS];
575 vec3_t org, org2;
576 vec3_t forward, right, up;
577
578 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
579 {
580 pusher->v.ltime += movetime;
581 return;
582 }
583
584 for (i=0 ; i<3 ; i++)
585 amove[i] = pusher->v.avelocity[i] * movetime;
586
587 VectorSubtract (vec3_origin, amove, a);
588 AngleVectors (a, forward, right, up);
589
590 VectorCopy (pusher->v.angles, pushorig);
591
592// move the pusher to it's final position
593
594 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
595 pusher->v.ltime += movetime;
596 SV_LinkEdict (pusher, false);
597
598
599// see if any solid entities are inside the final position
600 num_moved = 0;
601 check = NEXT_EDICT(sv.edicts);
602 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
603 {
604 if (check->free)
605 continue;
606 if (check->v.movetype == MOVETYPE_PUSH
607 || check->v.movetype == MOVETYPE_NONE
608 || check->v.movetype == MOVETYPE_FOLLOW
609 || check->v.movetype == MOVETYPE_NOCLIP)
610 continue;
611
612 // if the entity is standing on the pusher, it will definately be moved
613 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
614 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
615 {
616 if ( check->v.absmin[0] >= pusher->v.absmax[0]
617 || check->v.absmin[1] >= pusher->v.absmax[1]
618 || check->v.absmin[2] >= pusher->v.absmax[2]
619 || check->v.absmax[0] <= pusher->v.absmin[0]
620 || check->v.absmax[1] <= pusher->v.absmin[1]
621 || check->v.absmax[2] <= pusher->v.absmin[2] )
622 continue;
623
624 // see if the ent's bbox is inside the pusher's final position
625 if (!SV_TestEntityPosition (check))
626 continue;
627 }
628
629 // remove the onground flag for non-players
630 if (check->v.movetype != MOVETYPE_WALK)
631 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
632
633 VectorCopy (check->v.origin, entorig);
634 VectorCopy (check->v.origin, moved_from[num_moved]);
635 moved_edict[num_moved] = check;
636 num_moved++;
637
638 // calculate destination position
639 VectorSubtract (check->v.origin, pusher->v.origin, org);
640 org2[0] = DotProduct (org, forward);
641 org2[1] = -DotProduct (org, right);
642 org2[2] = DotProduct (org, up);
643 VectorSubtract (org2, org, move);
644
645 // try moving the contacted entity
646 pusher->v.solid = SOLID_NOT;
647 SV_PushEntity (check, move);
648 pusher->v.solid = SOLID_BSP;
649
650 // if it is still inside the pusher, block
651 block = SV_TestEntityPosition (check);
652 if (block)
653 { // fail the move
654 if (check->v.mins[0] == check->v.maxs[0])
655 continue;
656 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
657 { // corpse
658 check->v.mins[0] = check->v.mins[1] = 0;
659 VectorCopy (check->v.mins, check->v.maxs);
660 continue;
661 }
662
663 VectorCopy (entorig, check->v.origin);
664 SV_LinkEdict (check, true);
665
666 VectorCopy (pushorig, pusher->v.angles);
667 SV_LinkEdict (pusher, false);
668 pusher->v.ltime -= movetime;
669
670 // if the pusher has a "blocked" function, call it
671 // otherwise, just stay in place until the obstacle is gone
672 if (pusher->v.blocked)
673 {
674 pr_global_struct->self = EDICT_TO_PROG(pusher);
675 pr_global_struct->other = EDICT_TO_PROG(check);
676 PR_ExecuteProgram (pusher->v.blocked);
677 }
678
679 // move back any entities we already moved
680 for (i=0 ; i<num_moved ; i++)
681 {
682 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
683 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
684 SV_LinkEdict (moved_edict[i], false);
685 }
686 return;
687 }
688 else
689 {
690 VectorAdd (check->v.angles, amove, check->v.angles);
691 }
692 }
693
694
695}
696#endif
697
698/*
699================
700SV_Physics_Pusher
701
702================
703*/
704void SV_Physics_Pusher (edict_t *ent)
705{
706 float thinktime;
707 float oldltime;
708 float movetime;
709
710 oldltime = ent->v.ltime;
711
712 thinktime = ent->v.nextthink;
713 if (thinktime < ent->v.ltime + host_frametime)
714 {
715 movetime = thinktime - ent->v.ltime;
716 if (movetime < 0)
717 movetime = 0;
718 }
719 else
720 movetime = host_frametime;
721
722 if (movetime)
723 {
724#ifdef QUAKE2
725 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
726 SV_PushRotate (ent, movetime);
727 else
728#endif
729 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
730 }
731
732 if (thinktime > oldltime && thinktime <= ent->v.ltime)
733 {
734 ent->v.nextthink = 0;
735 pr_global_struct->time = sv.time;
736 pr_global_struct->self = EDICT_TO_PROG(ent);
737 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
738 PR_ExecuteProgram (ent->v.think);
739 if (ent->free)
740 return;
741 }
742
743}
744
745
746/*
747===============================================================================
748
749CLIENT MOVEMENT
750
751===============================================================================
752*/
753
754/*
755=============
756SV_CheckStuck
757
758This is a big hack to try and fix the rare case of getting stuck in the world
759clipping hull.
760=============
761*/
762void SV_CheckStuck (edict_t *ent)
763{
764 int i, j;
765 int z;
766 vec3_t org;
767
768 if (!SV_TestEntityPosition(ent))
769 {
770 VectorCopy (ent->v.origin, ent->v.oldorigin);
771 return;
772 }
773
774 VectorCopy (ent->v.origin, org);
775 VectorCopy (ent->v.oldorigin, ent->v.origin);
776 if (!SV_TestEntityPosition(ent))
777 {
778 Con_DPrintf ("Unstuck.\n");
779 SV_LinkEdict (ent, true);
780 return;
781 }
782
783 for (z=0 ; z< 18 ; z++)
784 for (i=-1 ; i <= 1 ; i++)
785 for (j=-1 ; j <= 1 ; j++)
786 {
787 ent->v.origin[0] = org[0] + i;
788 ent->v.origin[1] = org[1] + j;
789 ent->v.origin[2] = org[2] + z;
790 if (!SV_TestEntityPosition(ent))
791 {
792 Con_DPrintf ("Unstuck.\n");
793 SV_LinkEdict (ent, true);
794 return;
795 }
796 }
797
798 VectorCopy (org, ent->v.origin);
799 Con_DPrintf ("player is stuck.\n");
800}
801
802
803/*
804=============
805SV_CheckWater
806=============
807*/
808qboolean SV_CheckWater (edict_t *ent)
809{
810 vec3_t point;
811 int cont;
812#ifdef QUAKE2
813 int truecont;
814#endif
815
816 point[0] = ent->v.origin[0];
817 point[1] = ent->v.origin[1];
818 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
819
820 ent->v.waterlevel = 0;
821 ent->v.watertype = CONTENTS_EMPTY;
822 cont = SV_PointContents (point);
823 if (cont <= CONTENTS_WATER)
824 {
825#ifdef QUAKE2
826 truecont = SV_TruePointContents (point);
827#endif
828 ent->v.watertype = cont;
829 ent->v.waterlevel = 1;
830 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
831 cont = SV_PointContents (point);
832 if (cont <= CONTENTS_WATER)
833 {
834 ent->v.waterlevel = 2;
835 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
836 cont = SV_PointContents (point);
837 if (cont <= CONTENTS_WATER)
838 ent->v.waterlevel = 3;
839 }
840#ifdef QUAKE2
841 if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
842 {
843 static vec3_t current_table[] =
844 {
845 {1, 0, 0},
846 {0, 1, 0},
847 {-1, 0, 0},
848 {0, -1, 0},
849 {0, 0, 1},
850 {0, 0, -1}
851 };
852
853 VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);
854 }
855#endif
856 }
857
858 return ent->v.waterlevel > 1;
859}
860
861/*
862============
863SV_WallFriction
864
865============
866*/
867void SV_WallFriction (edict_t *ent, trace_t *trace)
868{
869 vec3_t forward, right, up;
870 float d, i;
871 vec3_t into, side;
872
873 AngleVectors (ent->v.v_angle, forward, right, up);
874 d = DotProduct (trace->plane.normal, forward);
875
876 d += 0.5;
877 if (d >= 0)
878 return;
879
880// cut the tangential velocity
881 i = DotProduct (trace->plane.normal, ent->v.velocity);
882 VectorScale (trace->plane.normal, i, into);
883 VectorSubtract (ent->v.velocity, into, side);
884
885 ent->v.velocity[0] = side[0] * (1 + d);
886 ent->v.velocity[1] = side[1] * (1 + d);
887}
888
889/*
890=====================
891SV_TryUnstick
892
893Player has come to a dead stop, possibly due to the problem with limited
894float precision at some angle joins in the BSP hull.
895
896Try fixing by pushing one pixel in each direction.
897
898This is a hack, but in the interest of good gameplay...
899======================
900*/
901int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
902{
903 int i;
904 vec3_t oldorg;
905 vec3_t dir;
906 int clip;
907 trace_t steptrace;
908
909 VectorCopy (ent->v.origin, oldorg);
910 VectorCopy (vec3_origin, dir);
911
912 for (i=0 ; i<8 ; i++)
913 {
914// try pushing a little in an axial direction
915 switch (i)
916 {
917 case 0: dir[0] = 2; dir[1] = 0; break;
918 case 1: dir[0] = 0; dir[1] = 2; break;
919 case 2: dir[0] = -2; dir[1] = 0; break;
920 case 3: dir[0] = 0; dir[1] = -2; break;
921 case 4: dir[0] = 2; dir[1] = 2; break;
922 case 5: dir[0] = -2; dir[1] = 2; break;
923 case 6: dir[0] = 2; dir[1] = -2; break;
924 case 7: dir[0] = -2; dir[1] = -2; break;
925 }
926
927 SV_PushEntity (ent, dir);
928
929// retry the original move
930 ent->v.velocity[0] = oldvel[0];
931 ent->v. velocity[1] = oldvel[1];
932 ent->v. velocity[2] = 0;
933 clip = SV_FlyMove (ent, 0.1, &steptrace);
934
935 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
936 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
937 {
938//Con_DPrintf ("unstuck!\n");
939 return clip;
940 }
941
942// go back to the original pos and try again
943 VectorCopy (oldorg, ent->v.origin);
944 }
945
946 VectorCopy (vec3_origin, ent->v.velocity);
947 return 7; // still not moving
948}
949
950/*
951=====================
952SV_WalkMove
953
954Only used by players
955======================
956*/
957#define STEPSIZE 18
958void SV_WalkMove (edict_t *ent)
959{
960 vec3_t upmove, downmove;
961 vec3_t oldorg, oldvel;
962 vec3_t nosteporg, nostepvel;
963 int clip;
964 int oldonground;
965 trace_t steptrace, downtrace;
966
967//
968// do a regular slide move unless it looks like you ran into a step
969//
970 oldonground = (int)ent->v.flags & FL_ONGROUND;
971 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
972
973 VectorCopy (ent->v.origin, oldorg);
974 VectorCopy (ent->v.velocity, oldvel);
975
976 clip = SV_FlyMove (ent, host_frametime, &steptrace);
977
978 if ( !(clip & 2) )
979 return; // move didn't block on a step
980
981 if (!oldonground && ent->v.waterlevel == 0)
982 return; // don't stair up while jumping
983
984 if (ent->v.movetype != MOVETYPE_WALK)
985 return; // gibbed by a trigger
986
987 if (sv_nostep.value)
988 return;
989
990 if ( (int)sv_player->v.flags & FL_WATERJUMP )
991 return;
992
993 VectorCopy (ent->v.origin, nosteporg);
994 VectorCopy (ent->v.velocity, nostepvel);
995
996//
997// try moving up and forward to go up a step
998//
999 VectorCopy (oldorg, ent->v.origin); // back to start pos
1000
1001 VectorCopy (vec3_origin, upmove);
1002 VectorCopy (vec3_origin, downmove);
1003 upmove[2] = STEPSIZE;
1004 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1005
1006// move up
1007 SV_PushEntity (ent, upmove); // FIXME: don't link?
1008
1009// move forward
1010 ent->v.velocity[0] = oldvel[0];
1011 ent->v. velocity[1] = oldvel[1];
1012 ent->v. velocity[2] = 0;
1013 clip = SV_FlyMove (ent, host_frametime, &steptrace);
1014
1015// check for stuckness, possibly due to the limited precision of floats
1016// in the clipping hulls
1017 if (clip)
1018 {
1019 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1020 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1021 { // stepping up didn't make any progress
1022 clip = SV_TryUnstick (ent, oldvel);
1023 }
1024 }
1025
1026// extra friction based on view angle
1027 if ( clip & 2 )
1028 SV_WallFriction (ent, &steptrace);
1029
1030// move down
1031 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1032
1033 if (downtrace.plane.normal[2] > 0.7)
1034 {
1035 if (ent->v.solid == SOLID_BSP)
1036 {
1037 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1038 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1039 }
1040 }
1041 else
1042 {
1043// if the push down didn't end up on good ground, use the move without
1044// the step up. This happens near wall / slope combinations, and can
1045// cause the player to hop up higher on a slope too steep to climb
1046 VectorCopy (nosteporg, ent->v.origin);
1047 VectorCopy (nostepvel, ent->v.velocity);
1048 }
1049}
1050
1051
1052/*
1053================
1054SV_Physics_Client
1055
1056Player character actions
1057================
1058*/
1059void SV_Physics_Client (edict_t *ent, int num)
1060{
1061 if ( ! svs.clients[num-1].active )
1062 return; // unconnected slot
1063
1064//
1065// call standard client pre-think
1066//
1067 pr_global_struct->time = sv.time;
1068 pr_global_struct->self = EDICT_TO_PROG(ent);
1069 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1070
1071//
1072// do a move
1073//
1074 SV_CheckVelocity (ent);
1075
1076//
1077// decide which move function to call
1078//
1079 switch ((int)ent->v.movetype)
1080 {
1081 case MOVETYPE_NONE:
1082 if (!SV_RunThink (ent))
1083 return;
1084 break;
1085
1086 case MOVETYPE_WALK:
1087 if (!SV_RunThink (ent))
1088 return;
1089 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1090 SV_AddGravity (ent);
1091 SV_CheckStuck (ent);
1092#ifdef QUAKE2
1093 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1094#endif
1095 SV_WalkMove (ent);
1096
1097#ifdef QUAKE2
1098 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1099#endif
1100 break;
1101
1102 case MOVETYPE_TOSS:
1103 case MOVETYPE_BOUNCE:
1104 SV_Physics_Toss (ent);
1105 break;
1106
1107 case MOVETYPE_FLY:
1108 if (!SV_RunThink (ent))
1109 return;
1110 SV_FlyMove (ent, host_frametime, NULL);
1111 break;
1112
1113 case MOVETYPE_NOCLIP:
1114 if (!SV_RunThink (ent))
1115 return;
1116 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1117 break;
1118
1119 default:
1120 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1121 }
1122
1123//
1124// call standard player post-think
1125//
1126 SV_LinkEdict (ent, true);
1127
1128 pr_global_struct->time = sv.time;
1129 pr_global_struct->self = EDICT_TO_PROG(ent);
1130 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1131}
1132
1133//============================================================================
1134
1135/*
1136=============
1137SV_Physics_None
1138
1139Non moving objects can only think
1140=============
1141*/
1142void SV_Physics_None (edict_t *ent)
1143{
1144// regular thinking
1145 SV_RunThink (ent);
1146}
1147
1148#ifdef QUAKE2
1149/*
1150=============
1151SV_Physics_Follow
1152
1153Entities that are "stuck" to another entity
1154=============
1155*/
1156void SV_Physics_Follow (edict_t *ent)
1157{
1158// regular thinking
1159 SV_RunThink (ent);
1160 VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1161 SV_LinkEdict (ent, true);
1162}
1163#endif
1164
1165/*
1166=============
1167SV_Physics_Noclip
1168
1169A moving object that doesn't obey physics
1170=============
1171*/
1172void SV_Physics_Noclip (edict_t *ent)
1173{
1174// regular thinking
1175 if (!SV_RunThink (ent))
1176 return;
1177
1178 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1179 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1180
1181 SV_LinkEdict (ent, false);
1182}
1183
1184/*
1185==============================================================================
1186
1187TOSS / BOUNCE
1188
1189==============================================================================
1190*/
1191
1192/*
1193=============
1194SV_CheckWaterTransition
1195
1196=============
1197*/
1198void SV_CheckWaterTransition (edict_t *ent)
1199{
1200 int cont;
1201#ifdef QUAKE2
1202 vec3_t point;
1203
1204 point[0] = ent->v.origin[0];
1205 point[1] = ent->v.origin[1];
1206 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
1207 cont = SV_PointContents (point);
1208#else
1209 cont = SV_PointContents (ent->v.origin);
1210#endif
1211 if (!ent->v.watertype)
1212 { // just spawned here
1213 ent->v.watertype = cont;
1214 ent->v.waterlevel = 1;
1215 return;
1216 }
1217
1218 if (cont <= CONTENTS_WATER)
1219 {
1220 if (ent->v.watertype == CONTENTS_EMPTY)
1221 { // just crossed into water
1222 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1223 }
1224 ent->v.watertype = cont;
1225 ent->v.waterlevel = 1;
1226 }
1227 else
1228 {
1229 if (ent->v.watertype != CONTENTS_EMPTY)
1230 { // just crossed into water
1231 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1232 }
1233 ent->v.watertype = CONTENTS_EMPTY;
1234 ent->v.waterlevel = cont;
1235 }
1236}
1237
1238/*
1239=============
1240SV_Physics_Toss
1241
1242Toss, bounce, and fly movement. When onground, do nothing.
1243=============
1244*/
1245void SV_Physics_Toss (edict_t *ent)
1246{
1247 trace_t trace;
1248 vec3_t move;
1249 float backoff;
1250#ifdef QUAKE2
1251 edict_t *groundentity;
1252
1253 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1254 if ((int)groundentity->v.flags & FL_CONVEYOR)
1255 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1256 else
1257 VectorCopy(vec_origin, ent->v.basevelocity);
1258 SV_CheckWater (ent);
1259#endif
1260 // regular thinking
1261 if (!SV_RunThink (ent))
1262 return;
1263
1264#ifdef QUAKE2
1265 if (ent->v.velocity[2] > 0)
1266 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1267
1268 if ( ((int)ent->v.flags & FL_ONGROUND) )
1269//@@
1270 if (VectorCompare(ent->v.basevelocity, vec_origin))
1271 return;
1272
1273 SV_CheckVelocity (ent);
1274
1275// add gravity
1276 if (! ((int)ent->v.flags & FL_ONGROUND)
1277 && ent->v.movetype != MOVETYPE_FLY
1278 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE
1279 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1280 SV_AddGravity (ent);
1281
1282#else
1283// if onground, return without moving
1284 if ( ((int)ent->v.flags & FL_ONGROUND) )
1285 return;
1286
1287 SV_CheckVelocity (ent);
1288
1289// add gravity
1290 if (ent->v.movetype != MOVETYPE_FLY
1291 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1292 SV_AddGravity (ent);
1293#endif
1294
1295// move angles
1296 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1297
1298// move origin
1299#ifdef QUAKE2
1300 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1301#endif
1302 VectorScale (ent->v.velocity, host_frametime, move);
1303 trace = SV_PushEntity (ent, move);
1304#ifdef QUAKE2
1305 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1306#endif
1307 if (trace.fraction == 1)
1308 return;
1309 if (ent->free)
1310 return;
1311
1312 if (ent->v.movetype == MOVETYPE_BOUNCE)
1313 backoff = 1.5;
1314#ifdef QUAKE2
1315 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1316 backoff = 2.0;
1317#endif
1318 else
1319 backoff = 1;
1320
1321 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1322
1323// stop if on ground
1324 if (trace.plane.normal[2] > 0.7)
1325 {
1326#ifdef QUAKE2
1327 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1328#else
1329 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)
1330#endif
1331 {
1332 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1333 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1334 VectorCopy (vec3_origin, ent->v.velocity);
1335 VectorCopy (vec3_origin, ent->v.avelocity);
1336 }
1337 }
1338
1339// check for in water
1340 SV_CheckWaterTransition (ent);
1341}
1342
1343/*
1344===============================================================================
1345
1346STEPPING MOVEMENT
1347
1348===============================================================================
1349*/
1350
1351/*
1352=============
1353SV_Physics_Step
1354
1355Monsters freefall when they don't have a ground entity, otherwise
1356all movement is done with discrete steps.
1357
1358This is also used for objects that have become still on the ground, but
1359will fall if the floor is pulled out from under them.
1360=============
1361*/
1362#ifdef QUAKE2
1363void SV_Physics_Step (edict_t *ent)
1364{
1365 qboolean wasonground;
1366 qboolean inwater;
1367 qboolean hitsound = false;
1368 float *vel;
1369 float speed, newspeed, control;
1370 float friction;
1371 edict_t *groundentity;
1372
1373 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1374 if ((int)groundentity->v.flags & FL_CONVEYOR)
1375 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1376 else
1377 VectorCopy(vec_origin, ent->v.basevelocity);
1378//@@
1379 pr_global_struct->time = sv.time;
1380 pr_global_struct->self = EDICT_TO_PROG(ent);
1381 PF_WaterMove();
1382
1383 SV_CheckVelocity (ent);
1384
1385 wasonground = (int)ent->v.flags & FL_ONGROUND;
1386// ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1387
1388 // add gravity except:
1389 // flying monsters
1390 // swimming monsters who are in the water
1391 inwater = SV_CheckWater(ent);
1392 if (! wasonground)
1393 if (!((int)ent->v.flags & FL_FLY))
1394 if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))
1395 {
1396 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1397 hitsound = true;
1398 if (!inwater)
1399 SV_AddGravity (ent);
1400 }
1401
1402 if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))
1403 {
1404 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1405 // apply friction
1406 // let dead monsters who aren't completely onground slide
1407 if (wasonground)
1408 if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))
1409 {
1410 vel = ent->v.velocity;
1411 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
1412 if (speed)
1413 {
1414 friction = sv_friction.value;
1415
1416 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
1417 newspeed = speed - host_frametime*control*friction;
1418
1419 if (newspeed < 0)
1420 newspeed = 0;
1421 newspeed /= speed;
1422
1423 vel[0] = vel[0] * newspeed;
1424 vel[1] = vel[1] * newspeed;
1425 }
1426 }
1427
1428 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1429 SV_FlyMove (ent, host_frametime, NULL);
1430 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1431
1432 // determine if it's on solid ground at all
1433 {
1434 vec3_t mins, maxs, point;
1435 int x, y;
1436
1437 VectorAdd (ent->v.origin, ent->v.mins, mins);
1438 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
1439
1440 point[2] = mins[2] - 1;
1441 for (x=0 ; x<=1 ; x++)
1442 for (y=0 ; y<=1 ; y++)
1443 {
1444 point[0] = x ? maxs[0] : mins[0];
1445 point[1] = y ? maxs[1] : mins[1];
1446 if (SV_PointContents (point) == CONTENTS_SOLID)
1447 {
1448 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1449 break;
1450 }
1451 }
1452
1453 }
1454
1455 SV_LinkEdict (ent, true);
1456
1457 if ((int)ent->v.flags & FL_ONGROUND)
1458 if (!wasonground)
1459 if (hitsound)
1460 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1461 }
1462
1463// regular thinking
1464 SV_RunThink (ent);
1465 SV_CheckWaterTransition (ent);
1466}
1467#else
1468void SV_Physics_Step (edict_t *ent)
1469{
1470 qboolean hitsound;
1471
1472// freefall if not onground
1473 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1474 {
1475 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1476 hitsound = true;
1477 else
1478 hitsound = false;
1479
1480 SV_AddGravity (ent);
1481 SV_CheckVelocity (ent);
1482 SV_FlyMove (ent, host_frametime, NULL);
1483 SV_LinkEdict (ent, true);
1484
1485 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1486 {
1487 if (hitsound)
1488 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1489 }
1490 }
1491
1492// regular thinking
1493 SV_RunThink (ent);
1494
1495 SV_CheckWaterTransition (ent);
1496}
1497#endif
1498
1499//============================================================================
1500
1501/*
1502================
1503SV_Physics
1504
1505================
1506*/
1507void SV_Physics (void)
1508{
1509 int i;
1510 edict_t *ent;
1511
1512// let the progs know that a new frame has started
1513 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1514 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1515 pr_global_struct->time = sv.time;
1516 PR_ExecuteProgram (pr_global_struct->StartFrame);
1517
1518//SV_CheckAllEnts ();
1519
1520//
1521// treat each object in turn
1522//
1523 ent = sv.edicts;
1524 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1525 {
1526 if (ent->free)
1527 continue;
1528
1529 if (pr_global_struct->force_retouch)
1530 {
1531 SV_LinkEdict (ent, true); // force retouch even for stationary
1532 }
1533
1534 if (i > 0 && i <= svs.maxclients)
1535 SV_Physics_Client (ent, i);
1536 else if (ent->v.movetype == MOVETYPE_PUSH)
1537 SV_Physics_Pusher (ent);
1538 else if (ent->v.movetype == MOVETYPE_NONE)
1539 SV_Physics_None (ent);
1540#ifdef QUAKE2
1541 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1542 SV_Physics_Follow (ent);
1543#endif
1544 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1545 SV_Physics_Noclip (ent);
1546 else if (ent->v.movetype == MOVETYPE_STEP)
1547 SV_Physics_Step (ent);
1548 else if (ent->v.movetype == MOVETYPE_TOSS
1549 || ent->v.movetype == MOVETYPE_BOUNCE
1550#ifdef QUAKE2
1551 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1552#endif
1553 || ent->v.movetype == MOVETYPE_FLY
1554 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1555 SV_Physics_Toss (ent);
1556 else
1557 Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1558 }
1559
1560 if (pr_global_struct->force_retouch)
1561 pr_global_struct->force_retouch--;
1562
1563 sv.time += host_frametime;
1564}
1565
1566
1567#ifdef QUAKE2
1568trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1569{
1570 edict_t tempent, *tent;
1571 trace_t trace;
1572 vec3_t move;
1573 vec3_t end;
1574 double save_frametime;
1575// extern particle_t *active_particles, *free_particles;
1576// particle_t *p;
1577
1578
1579 save_frametime = host_frametime;
1580 host_frametime = 0.05;
1581
1582 memcpy(&tempent, ent, sizeof(edict_t));
1583 tent = &tempent;
1584
1585 while (1)
1586 {
1587 SV_CheckVelocity (tent);
1588 SV_AddGravity (tent);
1589 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1590 VectorScale (tent->v.velocity, host_frametime, move);
1591 VectorAdd (tent->v.origin, move, end);
1592 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1593 VectorCopy (trace.endpos, tent->v.origin);
1594
1595// p = free_particles;
1596// if (p)
1597// {
1598// free_particles = p->next;
1599// p->next = active_particles;
1600// active_particles = p;
1601//
1602// p->die = 256;
1603// p->color = 15;
1604// p->type = pt_static;
1605// VectorCopy (vec3_origin, p->vel);
1606// VectorCopy (tent->v.origin, p->org);
1607// }
1608
1609 if (trace.ent)
1610 if (trace.ent != ignore)
1611 break;
1612 }
1613// p->color = 224;
1614 host_frametime = save_frametime;
1615 return trace;
1616}
1617#endif
diff --git a/apps/plugins/sdl/progs/quake/sv_user.c b/apps/plugins/sdl/progs/quake/sv_user.c
new file mode 100644
index 0000000000..b3082a5918
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sv_user.c
@@ -0,0 +1,629 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sv_user.c -- server code for moving users
21
22#include "quakedef.h"
23
24edict_t *sv_player;
25
26extern cvar_t sv_friction;
27cvar_t sv_edgefriction = {"edgefriction", "2"};
28extern cvar_t sv_stopspeed;
29
30static vec3_t forward, right, up;
31
32vec3_t wishdir;
33float wishspeed;
34
35// world
36float *angles;
37float *origin;
38float *velocity;
39
40qboolean onground;
41
42usercmd_t cmd;
43
44cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8"};
45
46
47/*
48===============
49SV_SetIdealPitch
50===============
51*/
52#define MAX_FORWARD 6
53void SV_SetIdealPitch (void)
54{
55 float angleval, sinval, cosval;
56 trace_t tr;
57 vec3_t top, bottom;
58 float z[MAX_FORWARD];
59 int i, j;
60 int step, dir, steps;
61
62 if (!((int)sv_player->v.flags & FL_ONGROUND))
63 return;
64
65 angleval = sv_player->v.angles[YAW] * M_PI*2 / 360;
66 sinval = sin(angleval);
67 cosval = cos(angleval);
68
69 for (i=0 ; i<MAX_FORWARD ; i++)
70 {
71 top[0] = sv_player->v.origin[0] + cosval*(i+3)*12;
72 top[1] = sv_player->v.origin[1] + sinval*(i+3)*12;
73 top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];
74
75 bottom[0] = top[0];
76 bottom[1] = top[1];
77 bottom[2] = top[2] - 160;
78
79 tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);
80 if (tr.allsolid)
81 return; // looking at a wall, leave ideal the way is was
82
83 if (tr.fraction == 1)
84 return; // near a dropoff
85
86 z[i] = top[2] + tr.fraction*(bottom[2]-top[2]);
87 }
88
89 dir = 0;
90 steps = 0;
91 for (j=1 ; j<i ; j++)
92 {
93 step = z[j] - z[j-1];
94 if (step > -ON_EPSILON && step < ON_EPSILON)
95 continue;
96
97 if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )
98 return; // mixed changes
99
100 steps++;
101 dir = step;
102 }
103
104 if (!dir)
105 {
106 sv_player->v.idealpitch = 0;
107 return;
108 }
109
110 if (steps < 2)
111 return;
112 sv_player->v.idealpitch = -dir * sv_idealpitchscale.value;
113}
114
115
116/*
117==================
118SV_UserFriction
119
120==================
121*/
122void SV_UserFriction (void)
123{
124 float *vel;
125 float speed, newspeed, control;
126 vec3_t start, stop;
127 float friction;
128 trace_t trace;
129
130 vel = velocity;
131
132 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
133 if (!speed)
134 return;
135
136// if the leading edge is over a dropoff, increase friction
137 start[0] = stop[0] = origin[0] + vel[0]/speed*16;
138 start[1] = stop[1] = origin[1] + vel[1]/speed*16;
139 start[2] = origin[2] + sv_player->v.mins[2];
140 stop[2] = start[2] - 34;
141
142 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);
143
144 if (trace.fraction == 1.0)
145 friction = sv_friction.value*sv_edgefriction.value;
146 else
147 friction = sv_friction.value;
148
149// apply friction
150 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
151 newspeed = speed - host_frametime*control*friction;
152
153 if (newspeed < 0)
154 newspeed = 0;
155 newspeed /= speed;
156
157 vel[0] = vel[0] * newspeed;
158 vel[1] = vel[1] * newspeed;
159 vel[2] = vel[2] * newspeed;
160}
161
162/*
163==============
164SV_Accelerate
165==============
166*/
167cvar_t sv_maxspeed = {"sv_maxspeed", "320", false, true};
168cvar_t sv_accelerate = {"sv_accelerate", "10"};
169#if 0
170void SV_Accelerate (vec3_t wishvel)
171{
172 int i;
173 float addspeed, accelspeed;
174 vec3_t pushvec;
175
176 if (wishspeed == 0)
177 return;
178
179 VectorSubtract (wishvel, velocity, pushvec);
180 addspeed = VectorNormalize (pushvec);
181
182 accelspeed = sv_accelerate.value*host_frametime*addspeed;
183 if (accelspeed > addspeed)
184 accelspeed = addspeed;
185
186 for (i=0 ; i<3 ; i++)
187 velocity[i] += accelspeed*pushvec[i];
188}
189#endif
190void SV_Accelerate (void)
191{
192 int i;
193 float addspeed, accelspeed, currentspeed;
194
195 currentspeed = DotProduct (velocity, wishdir);
196 addspeed = wishspeed - currentspeed;
197 if (addspeed <= 0)
198 return;
199 accelspeed = sv_accelerate.value*host_frametime*wishspeed;
200 if (accelspeed > addspeed)
201 accelspeed = addspeed;
202
203 for (i=0 ; i<3 ; i++)
204 velocity[i] += accelspeed*wishdir[i];
205}
206
207void SV_AirAccelerate (vec3_t wishveloc)
208{
209 int i;
210 float addspeed, wishspd, accelspeed, currentspeed;
211
212 wishspd = VectorNormalize (wishveloc);
213 if (wishspd > 30)
214 wishspd = 30;
215 currentspeed = DotProduct (velocity, wishveloc);
216 addspeed = wishspd - currentspeed;
217 if (addspeed <= 0)
218 return;
219// accelspeed = sv_accelerate.value * host_frametime;
220 accelspeed = sv_accelerate.value*wishspeed * host_frametime;
221 if (accelspeed > addspeed)
222 accelspeed = addspeed;
223
224 for (i=0 ; i<3 ; i++)
225 velocity[i] += accelspeed*wishveloc[i];
226}
227
228
229void DropPunchAngle (void)
230{
231 float len;
232
233 len = VectorNormalize (sv_player->v.punchangle);
234
235 len -= 10*host_frametime;
236 if (len < 0)
237 len = 0;
238 VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle);
239}
240
241/*
242===================
243SV_WaterMove
244
245===================
246*/
247void SV_WaterMove (void)
248{
249 int i;
250 vec3_t wishvel;
251 float speed, newspeed, wishspeed, addspeed, accelspeed;
252
253//
254// user intentions
255//
256 AngleVectors (sv_player->v.v_angle, forward, right, up);
257
258 for (i=0 ; i<3 ; i++)
259 wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;
260
261 if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)
262 wishvel[2] -= 60; // drift towards bottom
263 else
264 wishvel[2] += cmd.upmove;
265
266 wishspeed = Length(wishvel);
267 if (wishspeed > sv_maxspeed.value)
268 {
269 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
270 wishspeed = sv_maxspeed.value;
271 }
272 wishspeed *= 0.7;
273
274//
275// water friction
276//
277 speed = Length (velocity);
278 if (speed)
279 {
280 newspeed = speed - host_frametime * speed * sv_friction.value;
281 if (newspeed < 0)
282 newspeed = 0;
283 VectorScale (velocity, newspeed/speed, velocity);
284 }
285 else
286 newspeed = 0;
287
288//
289// water acceleration
290//
291 if (!wishspeed)
292 return;
293
294 addspeed = wishspeed - newspeed;
295 if (addspeed <= 0)
296 return;
297
298 VectorNormalizeNoRet (wishvel);
299 accelspeed = sv_accelerate.value * wishspeed * host_frametime;
300 if (accelspeed > addspeed)
301 accelspeed = addspeed;
302
303 for (i=0 ; i<3 ; i++)
304 velocity[i] += accelspeed * wishvel[i];
305}
306
307void SV_WaterJump (void)
308{
309 if (sv.time > sv_player->v.teleport_time
310 || !sv_player->v.waterlevel)
311 {
312 sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;
313 sv_player->v.teleport_time = 0;
314 }
315 sv_player->v.velocity[0] = sv_player->v.movedir[0];
316 sv_player->v.velocity[1] = sv_player->v.movedir[1];
317}
318
319
320/*
321===================
322SV_AirMove
323
324===================
325*/
326void SV_AirMove (void)
327{
328 int i;
329 vec3_t wishvel;
330 float fmove, smove;
331
332 AngleVectors (sv_player->v.angles, forward, right, up);
333
334 fmove = cmd.forwardmove;
335 smove = cmd.sidemove;
336
337// hack to not let you back into teleporter
338 if (sv.time < sv_player->v.teleport_time && fmove < 0)
339 fmove = 0;
340
341 for (i=0 ; i<3 ; i++)
342 wishvel[i] = forward[i]*fmove + right[i]*smove;
343
344 if ( (int)sv_player->v.movetype != MOVETYPE_WALK)
345 wishvel[2] = cmd.upmove;
346 else
347 wishvel[2] = 0;
348
349 VectorCopy (wishvel, wishdir);
350 wishspeed = VectorNormalize(wishdir);
351 if (wishspeed > sv_maxspeed.value)
352 {
353 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);
354 wishspeed = sv_maxspeed.value;
355 }
356
357 if ( sv_player->v.movetype == MOVETYPE_NOCLIP)
358 { // noclip
359 VectorCopy (wishvel, velocity);
360 }
361 else if ( onground )
362 {
363 SV_UserFriction ();
364 SV_Accelerate ();
365 }
366 else
367 { // not on ground, so little effect on velocity
368 SV_AirAccelerate (wishvel);
369 }
370}
371
372/*
373===================
374SV_ClientThink
375
376the move fields specify an intended velocity in pix/sec
377the angle fields specify an exact angular motion in degrees
378===================
379*/
380void SV_ClientThink (void)
381{
382 vec3_t v_angle;
383
384 if (sv_player->v.movetype == MOVETYPE_NONE)
385 return;
386
387 onground = (int)sv_player->v.flags & FL_ONGROUND;
388
389 origin = sv_player->v.origin;
390 velocity = sv_player->v.velocity;
391
392 DropPunchAngle ();
393
394//
395// if dead, behave differently
396//
397 if (sv_player->v.health <= 0)
398 return;
399
400//
401// angles
402// show 1/3 the pitch angle and all the roll angle
403 cmd = host_client->cmd;
404 angles = sv_player->v.angles;
405
406 VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);
407 angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
408 if (!sv_player->v.fixangle)
409 {
410 angles[PITCH] = -v_angle[PITCH]/3;
411 angles[YAW] = v_angle[YAW];
412 }
413
414 if ( (int)sv_player->v.flags & FL_WATERJUMP )
415 {
416 SV_WaterJump ();
417 return;
418 }
419//
420// walk
421//
422 if ( (sv_player->v.waterlevel >= 2)
423 && (sv_player->v.movetype != MOVETYPE_NOCLIP) )
424 {
425 SV_WaterMove ();
426 return;
427 }
428
429 SV_AirMove ();
430}
431
432
433/*
434===================
435SV_ReadClientMove
436===================
437*/
438void SV_ReadClientMove (usercmd_t *move)
439{
440 int i;
441 vec3_t angle;
442 int bits;
443
444// read ping time
445 host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
446 = sv.time - MSG_ReadFloat ();
447 host_client->num_pings++;
448
449// read current angles
450 for (i=0 ; i<3 ; i++)
451 angle[i] = MSG_ReadAngle ();
452
453 VectorCopy (angle, host_client->edict->v.v_angle);
454
455// read movement
456 move->forwardmove = MSG_ReadShort ();
457 move->sidemove = MSG_ReadShort ();
458 move->upmove = MSG_ReadShort ();
459
460// read buttons
461 bits = MSG_ReadByte ();
462 host_client->edict->v.button0 = bits & 1;
463 host_client->edict->v.button2 = (bits & 2)>>1;
464
465 i = MSG_ReadByte ();
466 if (i)
467 host_client->edict->v.impulse = i;
468
469#ifdef QUAKE2
470// read light level
471 host_client->edict->v.light_level = MSG_ReadByte ();
472#endif
473}
474
475/*
476===================
477SV_ReadClientMessage
478
479Returns false if the client should be killed
480===================
481*/
482qboolean SV_ReadClientMessage (void)
483{
484 int ret;
485 int cmd;
486 char *s;
487
488 do
489 {
490nextmsg:
491 ret = NET_GetMessage (host_client->netconnection);
492 if (ret == -1)
493 {
494 Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
495 return false;
496 }
497 if (!ret)
498 return true;
499
500 MSG_BeginReading ();
501
502 while (1)
503 {
504 if (!host_client->active)
505 return false; // a command caused an error
506
507 if (msg_badread)
508 {
509 Sys_Printf ("SV_ReadClientMessage: badread\n");
510 return false;
511 }
512
513 cmd = MSG_ReadChar ();
514
515 switch (cmd)
516 {
517 case -1:
518 goto nextmsg; // end of message
519
520 default:
521 Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
522 return false;
523
524 case clc_nop:
525// Sys_Printf ("clc_nop\n");
526 break;
527
528 case clc_stringcmd:
529 s = MSG_ReadString ();
530 if (host_client->privileged)
531 ret = 2;
532 else
533 ret = 0;
534 if (Q_strncasecmp(s, "status", 6) == 0)
535 ret = 1;
536 else if (Q_strncasecmp(s, "god", 3) == 0)
537 ret = 1;
538 else if (Q_strncasecmp(s, "notarget", 8) == 0)
539 ret = 1;
540 else if (Q_strncasecmp(s, "fly", 3) == 0)
541 ret = 1;
542 else if (Q_strncasecmp(s, "name", 4) == 0)
543 ret = 1;
544 else if (Q_strncasecmp(s, "noclip", 6) == 0)
545 ret = 1;
546 else if (Q_strncasecmp(s, "say", 3) == 0)
547 ret = 1;
548 else if (Q_strncasecmp(s, "say_team", 8) == 0)
549 ret = 1;
550 else if (Q_strncasecmp(s, "tell", 4) == 0)
551 ret = 1;
552 else if (Q_strncasecmp(s, "color", 5) == 0)
553 ret = 1;
554 else if (Q_strncasecmp(s, "kill", 4) == 0)
555 ret = 1;
556 else if (Q_strncasecmp(s, "pause", 5) == 0)
557 ret = 1;
558 else if (Q_strncasecmp(s, "spawn", 5) == 0)
559 ret = 1;
560 else if (Q_strncasecmp(s, "begin", 5) == 0)
561 ret = 1;
562 else if (Q_strncasecmp(s, "prespawn", 8) == 0)
563 ret = 1;
564 else if (Q_strncasecmp(s, "kick", 4) == 0)
565 ret = 1;
566 else if (Q_strncasecmp(s, "ping", 4) == 0)
567 ret = 1;
568 else if (Q_strncasecmp(s, "give", 4) == 0)
569 ret = 1;
570 else if (Q_strncasecmp(s, "ban", 3) == 0)
571 ret = 1;
572 if (ret == 2)
573 Cbuf_InsertText (s);
574 else if (ret == 1)
575 Cmd_ExecuteString (s, src_client);
576 else
577 Con_DPrintf("%s tried to %s\n", host_client->name, s);
578 break;
579
580 case clc_disconnect:
581// Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
582 return false;
583
584 case clc_move:
585 SV_ReadClientMove (&host_client->cmd);
586 break;
587 }
588 }
589 } while (ret == 1);
590
591 return true;
592}
593
594
595/*
596==================
597SV_RunClients
598==================
599*/
600void SV_RunClients (void)
601{
602 int i;
603
604 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
605 {
606 if (!host_client->active)
607 continue;
608
609 sv_player = host_client->edict;
610
611 if (!SV_ReadClientMessage ())
612 {
613 SV_DropClient (false); // client misbehaved...
614 continue;
615 }
616
617 if (!host_client->spawned)
618 {
619 // clear client movement until a new packet is received
620 memset (&host_client->cmd, 0, sizeof(host_client->cmd));
621 continue;
622 }
623
624// always pause in single player if in console or menus
625 if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
626 SV_ClientThink ();
627 }
628}
629
diff --git a/apps/plugins/sdl/progs/quake/sys.h b/apps/plugins/sdl/progs/quake/sys.h
new file mode 100644
index 0000000000..55a97aee19
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sys.h
@@ -0,0 +1,74 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sys.h -- non-portable functions
21
22/* frees file handles */
23void Sys_Shutdown(void);
24
25//
26// file IO
27//
28
29// returns the file size
30// return -1 if file is not present
31// the file should be in BINARY mode for stupid OSs that care
32int Sys_FileOpenRead (char *path, int *hndl);
33
34int Sys_FileOpenWrite (char *path);
35void Sys_FileClose (int handle);
36void Sys_FileSeek (int handle, int position);
37int Sys_FileRead (int handle, void *dest, int count);
38int Sys_FileWrite (int handle, void *data, int count);
39int Sys_FileTime (char *path);
40void Sys_mkdir (char *path);
41
42//
43// memory protection
44//
45void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);
46
47//
48// system IO
49//
50void Sys_DebugLog(char *file, char *fmt, ...);
51
52void Sys_Error (char *error, ...);
53// an error will cause the entire program to exit
54
55void Sys_Printf (char *fmt, ...);
56// send text to the console
57
58void Sys_Quit (void);
59
60double Sys_FloatTime (void);
61
62char *Sys_ConsoleInput (void);
63
64void Sys_Sleep (void);
65// called to yield for a little bit so as
66// not to hog cpu when paused or debugging
67
68void Sys_SendKeyEvents (void);
69// Perform Key_Event () callbacks until the input que is empty
70
71void Sys_LowFPPrecision (void);
72void Sys_HighFPPrecision (void);
73void Sys_SetFPCW (void);
74
diff --git a/apps/plugins/sdl/progs/quake/sys_linux.c b/apps/plugins/sdl/progs/quake/sys_linux.c
new file mode 100644
index 0000000000..8a29cfac76
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sys_linux.c
@@ -0,0 +1,457 @@
1#include <unistd.h>
2#include <signal.h>
3#include <stdlib.h>
4#include <limits.h>
5#include <sys/time.h>
6#include <sys/types.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <stdarg.h>
10#include <stdio.h>
11#include <sys/ipc.h>
12#include <sys/shm.h>
13#include <sys/stat.h>
14#include <string.h>
15#include <ctype.h>
16#include <sys/wait.h>
17#include <sys/mman.h>
18#include <errno.h>
19
20#include "quakedef.h"
21
22qboolean isDedicated;
23
24int nostdout = 0;
25
26char *basedir = ".";
27char *cachedir = "/tmp";
28
29cvar_t sys_linerefresh = {"sys_linerefresh","0"};// set for entity display
30
31// =======================================================================
32// General routines
33// =======================================================================
34
35void Sys_DebugNumber(int y, int val)
36{
37}
38
39/*
40void Sys_Printf (char *fmt, ...)
41{
42 va_list argptr;
43 char text[1024];
44
45 va_start (argptr,fmt);
46 vsprintf (text,fmt,argptr);
47 va_end (argptr);
48 fprintf(stderr, "%s", text);
49
50 Con_Print (text);
51}
52
53void Sys_Printf (char *fmt, ...)
54{
55
56 va_list argptr;
57 char text[1024], *t_p;
58 int l, r;
59
60 if (nostdout)
61 return;
62
63 va_start (argptr,fmt);
64 vsprintf (text,fmt,argptr);
65 va_end (argptr);
66
67 l = strlen(text);
68 t_p = text;
69
70// make sure everything goes through, even though we are non-blocking
71 while (l)
72 {
73 r = write (1, text, l);
74 if (r != l)
75 sleep (0);
76 if (r > 0)
77 {
78 t_p += r;
79 l -= r;
80 }
81 }
82
83}
84*/
85
86void Sys_Printf (char *fmt, ...)
87{
88 va_list argptr;
89 char text[1024];
90 unsigned char *p;
91
92 va_start (argptr,fmt);
93 vsprintf (text,fmt,argptr);
94 va_end (argptr);
95
96 if (strlen(text) > sizeof(text))
97 Sys_Error("memory overwrite in Sys_Printf");
98
99 if (nostdout)
100 return;
101
102 for (p = (unsigned char *)text; *p; p++) {
103 *p &= 0x7f;
104 if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
105 printf("[%02x]", *p);
106 else
107 putc(*p, stdout);
108 }
109}
110
111#if 0
112static char end1[] =
113"\x1b[?7h\x1b[40m\x1b[2J\x1b[0;1;41m\x1b[1;1H QUAKE: The Doomed Dimension \x1b[33mby \x1b[44mid\x1b[41m Software \x1b[2;1H ---------------------------------------------------------------------------- \x1b[3;1H CALL 1-800-IDGAMES TO ORDER OR FOR TECHNICAL SUPPORT \x1b[4;1H PRICE: $45.00 (PRICES MAY VARY OUTSIDE THE US.) \x1b[5;1H \x1b[6;1H \x1b[37mYes! You only have one fourth of this incredible epic. That is because most \x1b[7;1H of you have paid us nothing or at most, very little. You could steal the \x1b[8;1H game from a friend. But we both know you'll be punished by God if you do. \x1b[9;1H \x1b[33mWHY RISK ETERNAL DAMNATION? CALL 1-800-IDGAMES AND BUY NOW! \x1b[10;1H \x1b[37mRemember, we love you almost as much as He does. \x1b[11;1H \x1b[12;1H \x1b[33mProgramming: \x1b[37mJohn Carmack, Michael Abrash, John Cash \x1b[13;1H \x1b[33mDesign: \x1b[37mJohn Romero, Sandy Petersen, American McGee, Tim Willits \x1b[14;1H \x1b[33mArt: \x1b[37mAdrian Carmack, Kevin Cloud \x1b[15;1H \x1b[33mBiz: \x1b[37mJay Wilbur, Mike Wilson, Donna Jackson \x1b[16;1H \x1b[33mProjects: \x1b[37mShawn Green \x1b[33mSupport: \x1b[37mBarrett Alexander \x1b[17;1H \x1b[33mSound Effects: \x1b[37mTrent Reznor and Nine Inch Nails \x1b[18;1H For other information or details on ordering outside the US, check out the \x1b[19;1H files accompanying QUAKE or our website at http://www.idsoftware.com. \x1b[20;1H \x1b[0;41mQuake is a trademark of Id Software, inc., (c)1996 Id Software, inc. \x1b[21;1H All rights reserved. NIN logo is a registered trademark licensed to \x1b[22;1H Nothing Interactive, Inc. All rights reserved. \x1b[40m\x1b[23;1H\x1b[0m";
114static char end2[] =
115"\x1b[?7h\x1b[40m\x1b[2J\x1b[0;1;41m\x1b[1;1H QUAKE \x1b[33mby \x1b[44mid\x1b[41m Software \x1b[2;1H ----------------------------------------------------------------------------- \x1b[3;1H \x1b[37mWhy did you quit from the registered version of QUAKE? Did the \x1b[4;1H scary monsters frighten you? Or did Mr. Sandman tug at your \x1b[5;1H little lids? No matter! What is important is you love our \x1b[6;1H game, and gave us your money. Congratulations, you are probably \x1b[7;1H not a thief. \x1b[8;1H Thank You. \x1b[9;1H \x1b[33;44mid\x1b[41m Software is: \x1b[10;1H PROGRAMMING: \x1b[37mJohn Carmack, Michael Abrash, John Cash \x1b[11;1H \x1b[33mDESIGN: \x1b[37mJohn Romero, Sandy Petersen, American McGee, Tim Willits \x1b[12;1H \x1b[33mART: \x1b[37mAdrian Carmack, Kevin Cloud \x1b[13;1H \x1b[33mBIZ: \x1b[37mJay Wilbur, Mike Wilson \x1b[33mPROJECTS MAN: \x1b[37mShawn Green \x1b[14;1H \x1b[33mBIZ ASSIST: \x1b[37mDonna Jackson \x1b[33mSUPPORT: \x1b[37mBarrett Alexander \x1b[15;1H \x1b[33mSOUND EFFECTS AND MUSIC: \x1b[37mTrent Reznor and Nine Inch Nails \x1b[16;1H \x1b[17;1H If you need help running QUAKE refer to the text files in the \x1b[18;1H QUAKE directory, or our website at http://www.idsoftware.com. \x1b[19;1H If all else fails, call our technical support at 1-800-IDGAMES. \x1b[20;1H \x1b[0;41mQuake is a trademark of Id Software, inc., (c)1996 Id Software, inc. \x1b[21;1H All rights reserved. NIN logo is a registered trademark licensed \x1b[22;1H to Nothing Interactive, Inc. All rights reserved. \x1b[23;1H\x1b[40m\x1b[0m";
116
117#endif
118void Sys_Quit (void)
119{
120 Host_Shutdown();
121 fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
122#if 0
123 if (registered.value)
124 printf("%s", end2);
125 else
126 printf("%s", end1);
127#endif
128 fflush(stdout);
129 exit(0);
130}
131
132void Sys_Init(void)
133{
134#if id386
135 Sys_SetFPCW();
136#endif
137}
138
139void Sys_Error (char *error, ...)
140{
141 va_list argptr;
142 char string[1024];
143
144// change stdin to non blocking
145 fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
146
147 va_start (argptr,error);
148 vsprintf (string,error,argptr);
149 va_end (argptr);
150 fprintf(stderr, "Error: %s\n", string);
151
152 Host_Shutdown ();
153 exit (1);
154
155}
156
157void Sys_Warn (char *warning, ...)
158{
159 va_list argptr;
160 char string[1024];
161
162 va_start (argptr,warning);
163 vsprintf (string,warning,argptr);
164 va_end (argptr);
165 fprintf(stderr, "Warning: %s", string);
166}
167
168/*
169============
170Sys_FileTime
171
172returns -1 if not present
173============
174*/
175int Sys_FileTime (char *path)
176{
177 struct stat buf;
178
179 if (stat (path,&buf) == -1)
180 return -1;
181
182 return buf.st_mtime;
183}
184
185
186void Sys_mkdir (char *path)
187{
188 mkdir (path, 0777);
189}
190
191int Sys_FileOpenRead (char *path, int *handle)
192{
193 int h;
194 struct stat fileinfo;
195
196
197 h = open (path, O_RDONLY, 0666);
198 *handle = h;
199 if (h == -1)
200 return -1;
201
202 if (fstat (h,&fileinfo) == -1)
203 Sys_Error ("Error fstating %s", path);
204
205 return fileinfo.st_size;
206}
207
208int Sys_FileOpenWrite (char *path)
209{
210 int handle;
211
212 umask (0);
213
214 handle = open(path,O_RDWR | O_CREAT | O_TRUNC
215 , 0666);
216
217 if (handle == -1)
218 Sys_Error ("Error opening %s: %s", path,strerror(errno));
219
220 return handle;
221}
222
223int Sys_FileWrite (int handle, void *src, int count)
224{
225 return write (handle, src, count);
226}
227
228void Sys_FileClose (int handle)
229{
230 close (handle);
231}
232
233void Sys_FileSeek (int handle, int position)
234{
235 lseek (handle, position, SEEK_SET);
236}
237
238int Sys_FileRead (int handle, void *dest, int count)
239{
240 return read (handle, dest, count);
241}
242
243void Sys_DebugLog(char *file, char *fmt, ...)
244{
245 va_list argptr;
246 static char data[1024];
247 int fd;
248
249 va_start(argptr, fmt);
250 vsprintf(data, fmt, argptr);
251 va_end(argptr);
252// fd = open(file, O_WRONLY | O_BINARY | O_CREAT | O_APPEND, 0666);
253 fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
254 write(fd, data, strlen(data));
255 close(fd);
256}
257
258void Sys_EditFile(char *filename)
259{
260
261 char cmd[256];
262 char *term;
263 char *editor;
264
265 term = getenv("TERM");
266 if (term && !strcmp(term, "xterm"))
267 {
268 editor = getenv("VISUAL");
269 if (!editor)
270 editor = getenv("EDITOR");
271 if (!editor)
272 editor = getenv("EDIT");
273 if (!editor)
274 editor = "vi";
275 sprintf(cmd, "xterm -e %s %s", editor, filename);
276 system(cmd);
277 }
278
279}
280
281double Sys_FloatTime (void)
282{
283 struct timeval tp;
284 struct timezone tzp;
285 static int secbase;
286
287 gettimeofday(&tp, &tzp);
288
289 if (!secbase)
290 {
291 secbase = tp.tv_sec;
292 return tp.tv_usec/1000000.0;
293 }
294
295 return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
296}
297
298// =======================================================================
299// Sleeps for microseconds
300// =======================================================================
301
302static volatile int oktogo;
303
304void alarm_handler(int x)
305{
306 oktogo=1;
307}
308
309void Sys_LineRefresh(void)
310{
311}
312
313void floating_point_exception_handler(int whatever)
314{
315// Sys_Warn("floating point exception\n");
316 signal(SIGFPE, floating_point_exception_handler);
317}
318
319char *Sys_ConsoleInput(void)
320{
321 static char text[256];
322 int len;
323 fd_set fdset;
324 struct timeval timeout;
325
326 if (cls.state == ca_dedicated) {
327 FD_ZERO(&fdset);
328 FD_SET(0, &fdset); // stdin
329 timeout.tv_sec = 0;
330 timeout.tv_usec = 0;
331 if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
332 return NULL;
333
334 len = read (0, text, sizeof(text));
335 if (len < 1)
336 return NULL;
337 text[len-1] = 0; // rip off the /n and terminate
338
339 return text;
340 }
341 return NULL;
342}
343
344#if !id386
345void Sys_HighFPPrecision (void)
346{
347}
348
349void Sys_LowFPPrecision (void)
350{
351}
352#endif
353
354int main (int c, char **v)
355{
356
357 double time, oldtime, newtime;
358 quakeparms_t parms;
359 extern int vcrFile;
360 extern int recording;
361 int j;
362
363// static char cwd[1024];
364
365// signal(SIGFPE, floating_point_exception_handler);
366 signal(SIGFPE, SIG_IGN);
367
368 memset(&parms, 0, sizeof(parms));
369
370 COM_InitArgv(c, v);
371 parms.argc = com_argc;
372 parms.argv = com_argv;
373
374#ifdef GLQUAKE
375 parms.memsize = 16*1024*1024;
376#else
377 parms.memsize = 8*1024*1024;
378#endif
379
380 j = COM_CheckParm("-mem");
381 if (j)
382 parms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
383 parms.membase = malloc (parms.memsize);
384
385 parms.basedir = basedir;
386// caching is disabled by default, use -cachedir to enable
387// parms.cachedir = cachedir;
388
389 fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
390
391 Host_Init(&parms);
392
393 Sys_Init();
394
395 if (COM_CheckParm("-nostdout"))
396 nostdout = 1;
397 else {
398 fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
399 printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
400 }
401
402 oldtime = Sys_FloatTime () - 0.1;
403 while (1)
404 {
405// find time spent rendering last frame
406 newtime = Sys_FloatTime ();
407 time = newtime - oldtime;
408
409 if (cls.state == ca_dedicated)
410 { // play vcrfiles at max speed
411 if (time < sys_ticrate.value && (vcrFile == -1 || recording) )
412 {
413 usleep(1);
414 continue; // not time to run a server only tic yet
415 }
416 time = sys_ticrate.value;
417 }
418
419 if (time > sys_ticrate.value*2)
420 oldtime = newtime;
421 else
422 oldtime += time;
423
424 Host_Frame (time);
425
426// graphic debugging aids
427 if (sys_linerefresh.value)
428 Sys_LineRefresh ();
429 }
430
431}
432
433
434/*
435================
436Sys_MakeCodeWriteable
437================
438*/
439void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
440{
441
442 int r;
443 unsigned long addr;
444 int psize = getpagesize();
445
446 addr = (startaddr & ~(psize-1)) - psize;
447
448// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
449// addr, startaddr+length, length);
450
451 r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
452
453 if (r < 0)
454 Sys_Error("Protection change failed\n");
455
456}
457
diff --git a/apps/plugins/sdl/progs/quake/sys_null.c b/apps/plugins/sdl/progs/quake/sys_null.c
new file mode 100644
index 0000000000..057d61de72
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sys_null.c
@@ -0,0 +1,232 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// sys_null.h -- null system driver to aid porting efforts
21
22#include "quakedef.h"
23#include "errno.h"
24
25/*
26===============================================================================
27
28FILE IO
29
30===============================================================================
31*/
32
33#define MAX_HANDLES 10
34FILE *sys_handles[MAX_HANDLES];
35
36int findhandle (void)
37{
38 int i;
39
40 for (i=1 ; i<MAX_HANDLES ; i++)
41 if (!sys_handles[i])
42 return i;
43 Sys_Error ("out of handles");
44 return -1;
45}
46
47/*
48================
49filelength
50================
51*/
52int filelength (FILE *f)
53{
54 int pos;
55 int end;
56
57 pos = ftell (f);
58 fseek (f, 0, SEEK_END);
59 end = ftell (f);
60 fseek (f, pos, SEEK_SET);
61
62 return end;
63}
64
65int Sys_FileOpenRead (char *path, int *hndl)
66{
67 FILE *f;
68 int i;
69
70 i = findhandle ();
71
72 f = fopen(path, "rb");
73 if (!f)
74 {
75 *hndl = -1;
76 return -1;
77 }
78 sys_handles[i] = f;
79 *hndl = i;
80
81 return filelength(f);
82}
83
84int Sys_FileOpenWrite (char *path)
85{
86 FILE *f;
87 int i;
88
89 i = findhandle ();
90
91 f = fopen(path, "wb");
92 if (!f)
93 Sys_Error ("Error opening %s: %s", path,strerror(errno));
94 sys_handles[i] = f;
95
96 return i;
97}
98
99void Sys_FileClose (int handle)
100{
101 fclose (sys_handles[handle]);
102 sys_handles[handle] = NULL;
103}
104
105void Sys_FileSeek (int handle, int position)
106{
107 fseek (sys_handles[handle], position, SEEK_SET);
108}
109
110int Sys_FileRead (int handle, void *dest, int count)
111{
112 return fread (dest, 1, count, sys_handles[handle]);
113}
114
115int Sys_FileWrite (int handle, void *data, int count)
116{
117 return fwrite (data, 1, count, sys_handles[handle]);
118}
119
120int Sys_FileTime (char *path)
121{
122 FILE *f;
123
124 f = fopen(path, "rb");
125 if (f)
126 {
127 fclose(f);
128 return 1;
129 }
130
131 return -1;
132}
133
134void Sys_mkdir (char *path)
135{
136}
137
138
139/*
140===============================================================================
141
142SYSTEM IO
143
144===============================================================================
145*/
146
147void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
148{
149}
150
151
152void Sys_Error (char *error, ...)
153{
154 va_list argptr;
155
156 printf ("Sys_Error: ");
157 va_start (argptr,error);
158 vprintf (error,argptr);
159 va_end (argptr);
160 printf ("\n");
161
162 exit (1);
163}
164
165void Sys_Printf (char *fmt, ...)
166{
167 va_list argptr;
168
169 va_start (argptr,fmt);
170 vprintf (fmt,argptr);
171 va_end (argptr);
172}
173
174void Sys_Quit (void)
175{
176 exit (0);
177}
178
179double Sys_FloatTime (void)
180{
181 static double t;
182
183 t += 0.1;
184
185 return t;
186}
187
188char *Sys_ConsoleInput (void)
189{
190 return NULL;
191}
192
193void Sys_Sleep (void)
194{
195}
196
197void Sys_SendKeyEvents (void)
198{
199}
200
201void Sys_HighFPPrecision (void)
202{
203}
204
205void Sys_LowFPPrecision (void)
206{
207}
208
209//=============================================================================
210
211void main (int argc, char **argv)
212{
213 static quakeparms_t parms;
214
215 parms.memsize = 8*1024*1024;
216 parms.membase = malloc (parms.memsize);
217 parms.basedir = ".";
218
219 COM_InitArgv (argc, argv);
220
221 parms.argc = com_argc;
222 parms.argv = com_argv;
223
224 printf ("Host_Init\n");
225 Host_Init (&parms);
226 while (1)
227 {
228 Host_Frame (0.1);
229 }
230}
231
232
diff --git a/apps/plugins/sdl/progs/quake/sys_sdl.c b/apps/plugins/sdl/progs/quake/sys_sdl.c
new file mode 100644
index 0000000000..3cc3122bc2
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/sys_sdl.c
@@ -0,0 +1,436 @@
1#include <limits.h>
2#include <sys/types.h>
3#include <stdarg.h>
4#include <ctype.h>
5
6#include "quakedef.h"
7
8qboolean isDedicated;
9
10int noconinput = 0;
11
12char *basedir = "/.rockbox/quake";
13char *cachedir = NULL;
14
15cvar_t sys_linerefresh = {"sys_linerefresh","0"};// set for entity display
16cvar_t sys_nostdout = {"sys_nostdout","0"};
17
18// =======================================================================
19// General routines
20// =======================================================================
21
22void Sys_DebugNumber(int y, int val)
23{
24}
25
26int enable_printf = 1;
27
28void Sys_Printf (char *fmt, ...)
29{
30 va_list argptr;
31 char text[1024];
32
33 va_start (argptr,fmt);
34 vsprintf (text,fmt,argptr);
35 va_end (argptr);
36 if(enable_printf)
37 {
38 printf("%s", text);
39 }
40 LOGF("%s", text);
41
42 //Con_Print (text);
43}
44
45void Sys_Quit (void)
46{
47 Host_Shutdown();
48 exit(0);
49}
50
51void Sys_Init(void)
52{
53#if id386
54 Sys_SetFPCW();
55#endif
56}
57
58#if !id386
59
60/*
61================
62Sys_LowFPPrecision
63================
64*/
65void Sys_LowFPPrecision (void)
66{
67// causes weird problems on Nextstep
68}
69
70
71/*
72================
73Sys_HighFPPrecision
74================
75*/
76void Sys_HighFPPrecision (void)
77{
78// causes weird problems on Nextstep
79}
80
81#endif // !id386
82
83
84void Sys_Error (char *error, ...)
85{
86 va_list argptr;
87 char string[1024];
88
89 va_start (argptr,error);
90 vsprintf (string,error,argptr);
91 va_end (argptr);
92 rb->splashf(HZ*5, "Error: %s\n", string);
93
94 Host_Shutdown ();
95 exit (1);
96
97}
98
99void Sys_Warn (char *warning, ...)
100{
101 va_list argptr;
102 char string[1024];
103
104 va_start (argptr,warning);
105 vsprintf (string,warning,argptr);
106 va_end (argptr);
107 rb->splashf(HZ*2, "Warning: %s", string);
108}
109
110/*
111===============================================================================
112
113FILE IO
114
115===============================================================================
116*/
117
118#define MAX_HANDLES 10
119static FILE *sys_handles[MAX_HANDLES];
120
121void Sys_Shutdown(void)
122{
123 for(int i = 0; i < MAX_HANDLES; i++)
124 {
125 FILE *f = sys_handles[i];
126 if(f)
127 fclose(f);
128 sys_handles[i] = NULL;
129 }
130}
131
132int findhandle (void)
133{
134 int i;
135
136 for (i=1 ; i<MAX_HANDLES ; i++)
137 if (!sys_handles[i])
138 return i;
139 Sys_Error ("out of handles");
140 return -1;
141}
142
143/*
144================
145Qfilelength
146================
147*/
148static int Qfilelength (FILE *f)
149{
150 int pos;
151 int end;
152
153 pos = ftell (f);
154 fseek (f, 0, SEEK_END);
155 end = ftell (f);
156 fseek (f, pos, SEEK_SET);
157
158 return end;
159}
160
161int Sys_FileOpenRead (char *path, int *hndl)
162{
163 FILE *f;
164 int i;
165
166 i = findhandle ();
167
168 f = fopen(path, "rb");
169 if (!f)
170 {
171 *hndl = -1;
172 return -1;
173 }
174 sys_handles[i] = f;
175 *hndl = i;
176
177 //rb->splashf(HZ*2, "Allocating handle %d to %s", i, path);
178
179
180 return Qfilelength(f);
181}
182
183int Sys_FileOpenWrite (char *path)
184{
185 FILE *f;
186 int i;
187
188 i = findhandle ();
189
190 f = fopen(path, "wb");
191 if (!f)
192 Sys_Error ("Error opening %s: %s", path,strerror(errno));
193 sys_handles[i] = f;
194
195 return i;
196}
197
198void Sys_FileClose (int handle)
199{
200 if ( handle >= 0 ) {
201 //rb->splashf(HZ, "Close handle %d", handle);
202 fclose (sys_handles[handle]);
203 sys_handles[handle] = NULL;
204 }
205}
206
207void Sys_FileSeek (int handle, int position)
208{
209 if ( handle >= 0 ) {
210 fseek (sys_handles[handle], position, SEEK_SET);
211 }
212}
213
214int Sys_FileRead (int handle, void *dst, int count)
215{
216 char *data;
217 int size, done;
218
219 size = 0;
220 if ( handle >= 0 ) {
221 data = dst;
222 while ( count > 0 ) {
223 done = fread (data, 1, count, sys_handles[handle]);
224 if ( done == 0 ) {
225 break;
226 }
227 else if(done < 0)
228 {
229 Sys_Error("stream error %d, file is %d = %d", done, handle, sys_handles[handle]);
230 }
231 data += done;
232 count -= done;
233 size += done;
234 }
235 }
236 return size;
237
238}
239
240int Sys_FileWrite (int handle, void *src, int count)
241{
242 char *data;
243 int size, done;
244
245 size = 0;
246 if ( handle >= 0 ) {
247 data = src;
248 while ( count > 0 ) {
249 done = fread (data, 1, count, sys_handles[handle]);
250 if ( done == 0 ) {
251 break;
252 }
253 data += done;
254 count -= done;
255 size += done;
256 }
257 }
258 return size;
259}
260
261int Sys_FileTime (char *path)
262{
263 FILE *f;
264
265 f = fopen(path, "rb");
266 if (f)
267 {
268 fclose(f);
269 return 1;
270 }
271
272 return -1;
273}
274
275void Sys_mkdir (char *path)
276{
277#ifdef __WIN32__
278 mkdir (path);
279#else
280 mkdir (path);
281#endif
282}
283
284void Sys_DebugLog(char *file, char *fmt, ...)
285{
286 va_list argptr;
287 static char data[1024];
288 FILE *fp;
289
290 va_start(argptr, fmt);
291 vsprintf(data, fmt, argptr);
292 va_end(argptr);
293 fp = fopen(file, "a");
294 fwrite(data, strlen(data), 1, fp);
295 fclose(fp);
296}
297
298double Sys_FloatTime (void)
299{
300 static int starttime = 0;
301
302 if ( ! starttime )
303 starttime = *rb->current_tick;
304
305 return (*rb->current_tick - starttime) / ((double)HZ);
306}
307
308// =======================================================================
309// Sleeps for microseconds
310// =======================================================================
311
312static volatile int oktogo;
313
314void alarm_handler(int x)
315{
316 oktogo=1;
317}
318
319byte *Sys_ZoneBase (int *size)
320{
321
322 char *QUAKEOPT = getenv("QUAKEOPT");
323
324 *size = 0xc00000;
325 if (QUAKEOPT)
326 {
327 while (*QUAKEOPT)
328 if (tolower(*QUAKEOPT++) == 'm')
329 {
330 *size = atof(QUAKEOPT) * 1024*1024;
331 break;
332 }
333 }
334 return malloc (*size);
335
336}
337
338void Sys_LineRefresh(void)
339{
340}
341
342void Sys_Sleep(void)
343{
344 SDL_Delay(1);
345}
346
347void floating_point_exception_handler(int whatever)
348{
349// Sys_Warn("floating point exception\n");
350}
351
352void moncontrol(int x)
353{
354}
355
356int my_main (int c, char **v)
357{
358 double time, oldtime, newtime;
359 quakeparms_t parms;
360 extern int vcrFile;
361 extern int recording;
362 static int frame;
363
364 moncontrol(0);
365
366// signal(SIGFPE, floating_point_exception_handler);
367
368 //rb->splash(0, "quake 1");
369
370 parms.memsize = 8*1024*1024;
371 parms.membase = malloc (parms.memsize);
372 parms.basedir = basedir;
373 parms.cachedir = cachedir;
374
375 COM_InitArgv(c, v);
376 parms.argc = com_argc;
377 parms.argv = com_argv;
378
379 Sys_Init();
380 //rb->splash(0, "quake 2");
381
382 Host_Init(&parms);
383 //rb->splash(0, "quake 3");
384
385 //Cvar_RegisterVariable (&sys_nostdout);
386 //rb->splash(0, "quake 4");
387
388 oldtime = Sys_FloatTime () - 0.1;
389 while (1)
390 {
391// find time spent rendering last frame
392 newtime = Sys_FloatTime ();
393 time = newtime - oldtime;
394
395 if (cls.state == ca_dedicated)
396 { // play vcrfiles at max speed
397 if (time < sys_ticrate.value && (vcrFile == -1 || recording) )
398 {
399 rb->yield();
400 continue; // not time to run a server only tic yet
401 }
402 time = sys_ticrate.value;
403 }
404
405 if (time > sys_ticrate.value*2)
406 oldtime = newtime;
407 else
408 oldtime += time;
409
410 if (++frame > 10)
411 moncontrol(1); // profile only while we do each Quake frame
412 Host_Frame (time);
413 moncontrol(0);
414
415// graphic debugging aids
416 if (sys_linerefresh.value)
417 Sys_LineRefresh ();
418
419 rb->yield();
420 }
421
422}
423
424
425/*
426================
427Sys_MakeCodeWriteable
428================
429*/
430void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
431{
432
433 Sys_Error("Protection change failed\n");
434
435}
436
diff --git a/apps/plugins/sdl/progs/quake/vgamodes.h b/apps/plugins/sdl/progs/quake/vgamodes.h
new file mode 100644
index 0000000000..4d609fc0fa
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vgamodes.h
@@ -0,0 +1,599 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// vgamodes.h: VGA mode set tables
22//
23
24#include "vregset.h"
25
26int VGA_InitMode (viddef_t *vid, vmode_t *pcurrentmode);
27void VGA_SwapBuffers (viddef_t *vid, vmode_t *pcurrentmode, vrect_t *rects);
28void VGA_SetPalette (viddef_t *vid, vmode_t *pcurrentmode,
29 unsigned char *pal);
30
31///////////////////////////////////////////////////////////////////////////
32// the following base mode descriptors plus extra data together provide all
33// the data needed to do VGA mode sets
34///////////////////////////////////////////////////////////////////////////
35
36typedef struct {
37 int vidbuffer;
38 int *pregset;
39} vextra_t;
40
41int vrsnull[] = {
42 VRS_END,
43};
44
45int vrs320x200x256planar[] = {
46//
47// switch to linear, non-chain4 mode
48//
49 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
50 VRS_BYTE_OUT, SC_DATA, 1,
51
52 VRS_BYTE_OUT, SC_INDEX, MEMORY_MODE,
53 VRS_BYTE_RMW, SC_DATA, ~0x08, 0x04,
54 VRS_BYTE_OUT, GC_INDEX, GRAPHICS_MODE,
55 VRS_BYTE_RMW, GC_DATA, ~0x13, 0x00,
56 VRS_BYTE_OUT, GC_INDEX, MISCELLANOUS,
57 VRS_BYTE_RMW, GC_DATA, ~0x02, 0x00,
58
59 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
60 VRS_BYTE_OUT, SC_DATA, 3,
61
62//
63// change the CRTC from doubleword to byte mode
64//
65 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
66 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
67 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
68 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
69
70 VRS_END,
71};
72
73int vrs360x200x256planar[] = {
74//
75// switch to linear, non-chain4 mode
76//
77 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
78 VRS_BYTE_OUT, SC_DATA, 1,
79
80 VRS_WORD_OUT, SC_INDEX, 0x0604,
81 VRS_BYTE_OUT, MISC_OUTPUT, 0x67,
82
83 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
84 VRS_BYTE_OUT, SC_DATA, 3,
85
86//
87// unprotect CRTC0 through CRTC0
88//
89 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
90 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
91
92//
93// change the CRTC from doubleword to byte mode
94//
95 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
96 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
97 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
98 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
99
100//
101// set up the CRT Controller
102//
103 VRS_WORD_OUT, CRTC_INDEX, 0x6B00,
104 VRS_WORD_OUT, CRTC_INDEX, 0x5901,
105 VRS_WORD_OUT, CRTC_INDEX, 0x5A02,
106 VRS_WORD_OUT, CRTC_INDEX, 0x8E03,
107 VRS_WORD_OUT, CRTC_INDEX, 0x5E04,
108 VRS_WORD_OUT, CRTC_INDEX, 0x8A05,
109 VRS_WORD_OUT, CRTC_INDEX, 0x3013,
110
111 VRS_END,
112};
113
114int vrs320x240x256planar[] = {
115//
116// switch to linear, non-chain4 mode
117//
118 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
119 VRS_BYTE_OUT, SC_DATA, 1,
120
121 VRS_BYTE_OUT, SC_INDEX, MEMORY_MODE,
122 VRS_BYTE_RMW, SC_DATA, ~0x08, 0x04,
123 VRS_BYTE_OUT, GC_INDEX, GRAPHICS_MODE,
124 VRS_BYTE_RMW, GC_DATA, ~0x13, 0x00,
125 VRS_BYTE_OUT, GC_INDEX, MISCELLANOUS,
126 VRS_BYTE_RMW, GC_DATA, ~0x02, 0x00,
127
128 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
129 VRS_BYTE_OUT, SC_DATA, 3,
130
131//
132// unprotect CRTC0 through CRTC0
133//
134 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
135 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
136
137//
138// set up the CRT Controller
139//
140 VRS_WORD_OUT, CRTC_INDEX, 0x0D06,
141 VRS_WORD_OUT, CRTC_INDEX, 0x3E07,
142 VRS_WORD_OUT, CRTC_INDEX, 0x4109,
143 VRS_WORD_OUT, CRTC_INDEX, 0xEA10,
144 VRS_WORD_OUT, CRTC_INDEX, 0xAC11,
145 VRS_WORD_OUT, CRTC_INDEX, 0xDF12,
146 VRS_WORD_OUT, CRTC_INDEX, 0x0014,
147 VRS_WORD_OUT, CRTC_INDEX, 0xE715,
148 VRS_WORD_OUT, CRTC_INDEX, 0x0616,
149 VRS_WORD_OUT, CRTC_INDEX, 0xE317,
150
151 VRS_END,
152};
153
154int vrs360x240x256planar[] = {
155//
156// switch to linear, non-chain4 mode
157//
158 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
159 VRS_BYTE_OUT, SC_DATA, 1,
160
161 VRS_WORD_OUT, SC_INDEX, 0x0604,
162 VRS_BYTE_OUT, MISC_OUTPUT, 0xE7,
163
164 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
165 VRS_BYTE_OUT, SC_DATA, 3,
166
167//
168// unprotect CRTC0 through CRTC0
169//
170 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
171 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
172
173//
174// set up the CRT Controller
175//
176 VRS_WORD_OUT, CRTC_INDEX, 0x6B00,
177 VRS_WORD_OUT, CRTC_INDEX, 0x5901,
178 VRS_WORD_OUT, CRTC_INDEX, 0x5A02,
179 VRS_WORD_OUT, CRTC_INDEX, 0x8E03,
180 VRS_WORD_OUT, CRTC_INDEX, 0x5E04,
181 VRS_WORD_OUT, CRTC_INDEX, 0x8A05,
182 VRS_WORD_OUT, CRTC_INDEX, 0x0D06,
183 VRS_WORD_OUT, CRTC_INDEX, 0x3E07,
184 VRS_WORD_OUT, CRTC_INDEX, 0x4109,
185 VRS_WORD_OUT, CRTC_INDEX, 0xEA10,
186 VRS_WORD_OUT, CRTC_INDEX, 0xAC11,
187 VRS_WORD_OUT, CRTC_INDEX, 0xDF12,
188 VRS_WORD_OUT, CRTC_INDEX, 0x3013,
189 VRS_WORD_OUT, CRTC_INDEX, 0x0014,
190 VRS_WORD_OUT, CRTC_INDEX, 0xE715,
191 VRS_WORD_OUT, CRTC_INDEX, 0x0616,
192 VRS_WORD_OUT, CRTC_INDEX, 0xE317,
193
194 VRS_END,
195};
196
197int vrs320x350x256planar[] = {
198//
199// switch to linear, non-chain4 mode
200//
201 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
202 VRS_BYTE_OUT, SC_DATA, 1,
203
204 VRS_BYTE_OUT, SC_INDEX, MEMORY_MODE,
205 VRS_BYTE_RMW, SC_DATA, ~0x08, 0x04,
206 VRS_BYTE_OUT, GC_INDEX, GRAPHICS_MODE,
207 VRS_BYTE_RMW, GC_DATA, ~0x10, 0x00,
208 VRS_BYTE_OUT, GC_INDEX, MISCELLANOUS,
209 VRS_BYTE_RMW, GC_DATA, ~0x02, 0x00,
210 VRS_BYTE_OUT, MISC_OUTPUT, 0xA3, // 350-scan-line scan rate
211
212 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
213 VRS_BYTE_OUT, SC_DATA, 3,
214
215//
216// unprotect CRTC0 through CRTC0
217//
218 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
219 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
220
221//
222// stop scanning each line twice
223//
224 VRS_BYTE_OUT, CRTC_INDEX, MAX_SCAN_LINE,
225 VRS_BYTE_RMW, CRTC_DATA, ~0x1F, 0x00,
226
227//
228// change the CRTC from doubleword to byte mode
229//
230 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
231 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
232 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
233 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
234
235//
236// set the vertical counts for 350-scan-line mode
237//
238 VRS_WORD_OUT, CRTC_INDEX, 0xBF06,
239 VRS_WORD_OUT, CRTC_INDEX, 0x1F07,
240 VRS_WORD_OUT, CRTC_INDEX, 0x8310,
241 VRS_WORD_OUT, CRTC_INDEX, 0x8511,
242 VRS_WORD_OUT, CRTC_INDEX, 0x5D12,
243 VRS_WORD_OUT, CRTC_INDEX, 0x6315,
244 VRS_WORD_OUT, CRTC_INDEX, 0xBA16,
245
246 VRS_END,
247};
248
249int vrs360x350x256planar[] = {
250//
251// switch to linear, non-chain4 mode
252//
253 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
254 VRS_BYTE_OUT, SC_DATA, 1,
255
256 VRS_WORD_OUT, SC_INDEX, 0x0604,
257 VRS_BYTE_OUT, MISC_OUTPUT, 0xA7, // 350-scan-line scan rate
258
259 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
260 VRS_BYTE_OUT, SC_DATA, 3,
261
262//
263// unprotect CRTC0 through CRTC0
264//
265 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
266 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
267
268//
269// stop scanning each line twice
270//
271 VRS_BYTE_OUT, CRTC_INDEX, MAX_SCAN_LINE,
272 VRS_BYTE_RMW, CRTC_DATA, ~0x1F, 0x00,
273
274//
275// change the CRTC from doubleword to byte mode
276//
277 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
278 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
279 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
280 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
281
282//
283// set the vertical counts for 350-scan-line mode and 360 pixels across
284//
285 VRS_WORD_OUT, CRTC_INDEX, 0x6B00,
286 VRS_WORD_OUT, CRTC_INDEX, 0x5901,
287 VRS_WORD_OUT, CRTC_INDEX, 0x5A02,
288 VRS_WORD_OUT, CRTC_INDEX, 0x8E03,
289 VRS_WORD_OUT, CRTC_INDEX, 0x5E04,
290 VRS_WORD_OUT, CRTC_INDEX, 0x8A05,
291 VRS_WORD_OUT, CRTC_INDEX, 0xBF06,
292 VRS_WORD_OUT, CRTC_INDEX, 0x1F07,
293 VRS_WORD_OUT, CRTC_INDEX, 0x8310,
294 VRS_WORD_OUT, CRTC_INDEX, 0x8511,
295 VRS_WORD_OUT, CRTC_INDEX, 0x5D12,
296 VRS_WORD_OUT, CRTC_INDEX, 0x3013,
297 VRS_WORD_OUT, CRTC_INDEX, 0x6315,
298 VRS_WORD_OUT, CRTC_INDEX, 0xBA16,
299
300 VRS_END,
301};
302
303int vrs320x400x256planar[] = {
304//
305// switch to linear, non-chain4 mode
306//
307 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
308 VRS_BYTE_OUT, SC_DATA, 1,
309
310
311 VRS_BYTE_OUT, SC_INDEX, MEMORY_MODE,
312 VRS_BYTE_RMW, SC_DATA, ~0x08, 0x04,
313 VRS_BYTE_OUT, GC_INDEX, GRAPHICS_MODE,
314 VRS_BYTE_RMW, GC_DATA, ~0x10, 0x00,
315 VRS_BYTE_OUT, GC_INDEX, MISCELLANOUS,
316 VRS_BYTE_RMW, GC_DATA, ~0x02, 0x00,
317
318 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
319 VRS_BYTE_OUT, SC_DATA, 3,
320
321//
322// stop scanning each line twice
323//
324 VRS_BYTE_OUT, CRTC_INDEX, MAX_SCAN_LINE,
325 VRS_BYTE_RMW, CRTC_DATA, ~0x1F, 0x00,
326
327//
328// change the CRTC from doubleword to byte mode
329//
330 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
331 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
332 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
333 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
334
335 VRS_END,
336};
337
338int vrs360x400x256planar[] = {
339//
340// switch to linear, non-chain4 mode
341//
342 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
343 VRS_BYTE_OUT, SC_DATA, 1,
344
345 VRS_WORD_OUT, SC_INDEX, 0x0604,
346 VRS_BYTE_OUT, MISC_OUTPUT, 0x67,
347
348 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
349 VRS_BYTE_OUT, SC_DATA, 3,
350
351//
352// unprotect CRTC0 through CRTC0
353//
354 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
355 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
356
357//
358// stop scanning each line twice
359//
360 VRS_BYTE_OUT, CRTC_INDEX, MAX_SCAN_LINE,
361 VRS_BYTE_RMW, CRTC_DATA, ~0x1F, 0x00,
362
363//
364// change the CRTC from doubleword to byte mode
365//
366 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
367 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
368 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
369 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
370
371//
372// set up the CRT Controller
373//
374 VRS_WORD_OUT, CRTC_INDEX, 0x6B00,
375 VRS_WORD_OUT, CRTC_INDEX, 0x5901,
376 VRS_WORD_OUT, CRTC_INDEX, 0x5A02,
377 VRS_WORD_OUT, CRTC_INDEX, 0x8E03,
378 VRS_WORD_OUT, CRTC_INDEX, 0x5E04,
379 VRS_WORD_OUT, CRTC_INDEX, 0x8A05,
380 VRS_WORD_OUT, CRTC_INDEX, 0x3013,
381
382 VRS_END,
383};
384
385int vrs320x480x256planar[] = {
386//
387// switch to linear, non-chain4 mode
388//
389 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
390 VRS_BYTE_OUT, SC_DATA, 1,
391
392 VRS_BYTE_OUT, SC_INDEX, MEMORY_MODE,
393 VRS_BYTE_RMW, SC_DATA, ~0x08, 0x04,
394 VRS_BYTE_OUT, GC_INDEX, GRAPHICS_MODE,
395 VRS_BYTE_RMW, GC_DATA, ~0x10, 0x00,
396 VRS_BYTE_OUT, GC_INDEX, MISCELLANOUS,
397 VRS_BYTE_RMW, GC_DATA, ~0x02, 0x00,
398
399 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
400 VRS_BYTE_OUT, SC_DATA, 3,
401
402//
403// unprotect CRTC0 through CRTC0
404//
405 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
406 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
407
408//
409// stop scanning each line twice
410//
411 VRS_BYTE_OUT, CRTC_INDEX, MAX_SCAN_LINE,
412 VRS_BYTE_RMW, CRTC_DATA, ~0x1F, 0x00,
413
414//
415// change the CRTC from doubleword to byte mode
416//
417 VRS_BYTE_OUT, CRTC_INDEX, UNDERLINE,
418 VRS_BYTE_RMW, CRTC_DATA, ~0x40, 0x00,
419 VRS_BYTE_OUT, CRTC_INDEX, MODE_CONTROL,
420 VRS_BYTE_RMW, CRTC_DATA, ~0x00, 0x40,
421
422//
423// set up the CRT Controller
424//
425 VRS_WORD_OUT, CRTC_INDEX, 0x0D06,
426 VRS_WORD_OUT, CRTC_INDEX, 0x3E07,
427 VRS_WORD_OUT, CRTC_INDEX, 0xEA10,
428 VRS_WORD_OUT, CRTC_INDEX, 0xAC11,
429 VRS_WORD_OUT, CRTC_INDEX, 0xDF12,
430 VRS_WORD_OUT, CRTC_INDEX, 0xE715,
431 VRS_WORD_OUT, CRTC_INDEX, 0x0616,
432
433 VRS_END,
434};
435
436int vrs360x480x256planar[] = {
437//
438// switch to linear, non-chain4 mode
439//
440 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
441 VRS_BYTE_OUT, SC_DATA, 1,
442
443 VRS_WORD_OUT, SC_INDEX, 0x0604,
444 VRS_BYTE_OUT, MISC_OUTPUT, 0xE7,
445
446 VRS_BYTE_OUT, SC_INDEX, SYNC_RESET,
447 VRS_BYTE_OUT, SC_DATA, 3,
448
449//
450// unprotect CRTC0 through CRTC0
451//
452 VRS_BYTE_OUT, CRTC_INDEX, 0x11,
453 VRS_BYTE_RMW, CRTC_DATA, ~0x80, 0x00,
454
455//
456// set up the CRT Controller
457//
458 VRS_WORD_OUT, CRTC_INDEX, 0x6B00,
459 VRS_WORD_OUT, CRTC_INDEX, 0x5901,
460 VRS_WORD_OUT, CRTC_INDEX, 0x5A02,
461 VRS_WORD_OUT, CRTC_INDEX, 0x8E03,
462 VRS_WORD_OUT, CRTC_INDEX, 0x5E04,
463 VRS_WORD_OUT, CRTC_INDEX, 0x8A05,
464 VRS_WORD_OUT, CRTC_INDEX, 0x0D06,
465 VRS_WORD_OUT, CRTC_INDEX, 0x3E07,
466 VRS_WORD_OUT, CRTC_INDEX, 0x4009,
467 VRS_WORD_OUT, CRTC_INDEX, 0xEA10,
468 VRS_WORD_OUT, CRTC_INDEX, 0xAC11,
469 VRS_WORD_OUT, CRTC_INDEX, 0xDF12,
470 VRS_WORD_OUT, CRTC_INDEX, 0x3013,
471 VRS_WORD_OUT, CRTC_INDEX, 0x0014,
472 VRS_WORD_OUT, CRTC_INDEX, 0xE715,
473 VRS_WORD_OUT, CRTC_INDEX, 0x0616,
474 VRS_WORD_OUT, CRTC_INDEX, 0xE317,
475
476 VRS_END,
477};
478
479//
480// extra VGA-specific data for vgavidmodes
481//
482vextra_t extra320x200x256linear = {
483 1, vrsnull
484};
485vextra_t extra320x200x256planar = {
486 1, vrs320x200x256planar
487};
488vextra_t extra360x200x256planar = {
489 1, vrs360x200x256planar
490};
491vextra_t extra320x240x256planar = {
492 1, vrs320x240x256planar
493};
494vextra_t extra360x240x256planar = {
495 1, vrs360x240x256planar
496};
497vextra_t extra320x350x256planar = {
498 1, vrs320x350x256planar
499};
500vextra_t extra360x350x256planar = {
501 1, vrs360x350x256planar
502};
503vextra_t extra320x400x256planar = {
504 1, vrs320x400x256planar
505};
506vextra_t extra360x400x256planar = {
507 1, vrs360x400x256planar
508};
509vextra_t extra320x480x256planar = {
510 1, vrs320x480x256planar
511};
512vextra_t extra360x480x256planar = {
513 1, vrs360x480x256planar
514};
515
516//
517// base mode descriptors, in ascending order of number of pixels
518//
519
520vmode_t vgavidmodes[] = {
521{
522 NULL,
523 "320x200", " ***** standard VGA modes ***** ",
524 320, 200, (200.0/320.0)*(320.0/240.0), 320, 0, 1, &extra320x200x256linear,
525 VGA_InitMode, VGA_SwapBuffers, VGA_SetPalette,
526 VGA_BeginDirectRect, VGA_EndDirectRect
527},
528{
529 NULL,
530 "320x200", " ***** Mode X-style modes ***** ",
531 320, 200, (200.0/320.0)*(320.0/240.0), 320, 1, 1, &extra320x200x256planar,
532 VGA_InitMode, VGA_SwapBuffers, VGA_SetPalette,
533 VGA_BeginDirectRect, VGA_EndDirectRect
534},
535{
536 NULL,
537 "360x200", NULL, 360, 200, (200.0/360.0)*(320.0/240.0),
538 384, 1, 1, &extra360x200x256planar, VGA_InitMode,
539 VGA_SwapBuffers,
540 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
541},
542{
543 NULL,
544 "320x240", NULL, 320, 240, (240.0/320.0)*(320.0/240.0),
545 320, 1, 1, &extra320x240x256planar, VGA_InitMode,
546 VGA_SwapBuffers,
547 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
548},
549{
550 NULL,
551 "360x240", NULL, 360, 240, (240.0/360.0)*(320.0/240.0),
552 384, 1, 1, &extra360x240x256planar,
553 VGA_InitMode, VGA_SwapBuffers, VGA_SetPalette,
554 VGA_BeginDirectRect, VGA_EndDirectRect
555},
556{
557 NULL,
558 "320x350", NULL, 320, 350, (350.0/320.0)*(320.0/240.0),
559 320, 1, 1, &extra320x350x256planar, VGA_InitMode,
560 VGA_SwapBuffers,
561 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
562},
563{
564 NULL,
565 "360x350", NULL, 360, 350, (350.0/360.0)*(320.0/240.0),
566 384, 1, 1, &extra360x350x256planar, VGA_InitMode,
567 VGA_SwapBuffers,
568 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
569},
570{
571 NULL,
572 "320x400", NULL, 320, 400, (400.0/320.0)*(320.0/240.0), 320,
573 1, 1, &extra320x400x256planar, VGA_InitMode,
574 VGA_SwapBuffers,
575 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
576},
577{
578 NULL,
579 "360x400", NULL, 360, 400, (400.0/360.0)*(320.0/240.0),
580 384, 1, 1, &extra360x400x256planar, VGA_InitMode,
581 VGA_SwapBuffers,
582 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
583},
584{
585 NULL,
586 "320x480", NULL, 320, 480, (480.0/320.0)*(320.0/240.0),
587 320, 1, 1, &extra320x480x256planar, VGA_InitMode,
588 VGA_SwapBuffers,
589 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
590},
591{
592 NULL,
593 "360x480", NULL, 360, 480, (480.0/360.0)*(320.0/240.0),
594 384, 1, 1, &extra360x480x256planar, VGA_InitMode,
595 VGA_SwapBuffers,
596 VGA_SetPalette, VGA_BeginDirectRect, VGA_EndDirectRect
597},
598};
599
diff --git a/apps/plugins/sdl/progs/quake/vid.h b/apps/plugins/sdl/progs/quake/vid.h
new file mode 100644
index 0000000000..1708ba825f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid.h
@@ -0,0 +1,85 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// vid.h -- video driver defs
21
22#define VID_CBITS 6
23#define VID_GRADES (1 << VID_CBITS)
24
25// a pixel can be one, two, or four bytes
26typedef byte pixel_t;
27
28typedef struct vrect_s
29{
30 int x,y,width,height;
31 struct vrect_s *pnext;
32} vrect_t;
33
34typedef struct
35{
36 pixel_t *buffer; // invisible buffer
37 pixel_t *colormap; // 256 * VID_GRADES size
38 unsigned short *colormap16; // 256 * VID_GRADES size
39 int fullbright; // index of first fullbright color
40 unsigned rowbytes; // may be > width if displayed in a window
41 unsigned width;
42 unsigned height;
43 float aspect; // width / height -- < 0 is taller than wide
44 int numpages;
45 int recalc_refdef; // if true, recalc vid-based stuff
46 pixel_t *conbuffer;
47 int conrowbytes;
48 unsigned conwidth;
49 unsigned conheight;
50 int maxwarpwidth;
51 int maxwarpheight;
52 pixel_t *direct; // direct drawing to framebuffer, if not
53 // NULL
54} viddef_t;
55
56extern viddef_t vid; // global video state
57extern unsigned short d_8to16table[256];
58extern unsigned d_8to24table[256];
59extern void (*vid_menudrawfn)(void);
60extern void (*vid_menukeyfn)(int key);
61
62void VID_SetPalette (unsigned char *palette);
63// called at startup and after any gamma correction
64
65void VID_ShiftPalette (unsigned char *palette);
66// called for bonus and pain flashes, and for underwater color changes
67
68void VID_Init (unsigned char *palette);
69// Called at startup to set up translation tables, takes 256 8 bit RGB values
70// the palette data will go away after the call, so it must be copied off if
71// the video driver will need it again
72
73void VID_Shutdown (void);
74// Called at shutdown
75
76void VID_Update (vrect_t *rects);
77// flushes the given rectangles from the view buffer to the screen
78
79int VID_SetMode (int modenum, unsigned char *palette);
80// sets the mode; only used by the Quake engine for resetting to mode 0 (the
81// base mode) on memory allocation failures
82
83void VID_HandlePause (qboolean pause);
84// called only on Win32, when pause happens, so the mouse can be released
85
diff --git a/apps/plugins/sdl/progs/quake/vid_null.c b/apps/plugins/sdl/progs/quake/vid_null.c
new file mode 100644
index 0000000000..225691b29f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid_null.c
@@ -0,0 +1,87 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// vid_null.c -- null video driver to aid porting efforts
21
22#include "quakedef.h"
23#include "d_local.h"
24
25viddef_t vid; // global video state
26
27#define BASEWIDTH 320
28#define BASEHEIGHT 200
29
30byte vid_buffer[BASEWIDTH*BASEHEIGHT];
31short zbuffer[BASEWIDTH*BASEHEIGHT];
32byte surfcache[256*1024];
33
34unsigned short d_8to16table[256];
35unsigned d_8to24table[256];
36
37void VID_SetPalette (unsigned char *palette)
38{
39}
40
41void VID_ShiftPalette (unsigned char *palette)
42{
43}
44
45void VID_Init (unsigned char *palette)
46{
47 vid.maxwarpwidth = vid.width = vid.conwidth = BASEWIDTH;
48 vid.maxwarpheight = vid.height = vid.conheight = BASEHEIGHT;
49 vid.aspect = 1.0;
50 vid.numpages = 1;
51 vid.colormap = host_colormap;
52 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
53 vid.buffer = vid.conbuffer = vid_buffer;
54 vid.rowbytes = vid.conrowbytes = BASEWIDTH;
55
56 d_pzbuffer = zbuffer;
57 D_InitCaches (surfcache, sizeof(surfcache));
58}
59
60void VID_Shutdown (void)
61{
62}
63
64void VID_Update (vrect_t *rects)
65{
66}
67
68/*
69================
70D_BeginDirectRect
71================
72*/
73void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
74{
75}
76
77
78/*
79================
80D_EndDirectRect
81================
82*/
83void D_EndDirectRect (int x, int y, int width, int height)
84{
85}
86
87
diff --git a/apps/plugins/sdl/progs/quake/vid_sdl.c b/apps/plugins/sdl/progs/quake/vid_sdl.c
new file mode 100644
index 0000000000..83d6a8486e
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid_sdl.c
@@ -0,0 +1,389 @@
1// vid_sdl.h -- sdl video driver
2
3#include "SDL.h"
4#include "quakedef.h"
5#include "d_local.h"
6
7viddef_t vid; // global video state
8unsigned short d_8to16table[256];
9
10// The original defaults
11//#define BASEWIDTH 320
12//#define BASEHEIGHT 200
13// Much better for high resolution displays
14#define BASEWIDTH LCD_WIDTH
15#define BASEHEIGHT LCD_HEIGHT
16
17int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0;
18byte *VGA_pagebase;
19
20static SDL_Surface *screen = NULL;
21
22static qboolean mouse_avail;
23static float mouse_x, mouse_y;
24static int mouse_oldbuttonstate = 0;
25
26// No support for option menus
27void (*vid_menudrawfn)(void) = NULL;
28void (*vid_menukeyfn)(int key) = NULL;
29
30void VID_SetPalette (unsigned char *palette)
31{
32 int i;
33 SDL_Color colors[256];
34
35 for ( i=0; i<256; ++i )
36 {
37 colors[i].r = *palette++;
38 colors[i].g = *palette++;
39 colors[i].b = *palette++;
40 }
41 SDL_SetColors(screen, colors, 0, 256);
42}
43
44void VID_ShiftPalette (unsigned char *palette)
45{
46 VID_SetPalette(palette);
47}
48
49void VID_Init (unsigned char *palette)
50{
51 int pnum, chunk;
52 byte *cache;
53 int cachesize;
54 Uint8 video_bpp;
55 Uint16 video_w, video_h;
56 Uint32 flags;
57
58 // Load the SDL library
59 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
60 Sys_Error("VID: Couldn't load SDL: %s", SDL_GetError());
61
62 // Set up display mode (width and height)
63 vid.width = BASEWIDTH;
64 vid.height = BASEHEIGHT;
65 vid.maxwarpwidth = WARP_WIDTH;
66 vid.maxwarpheight = WARP_HEIGHT;
67 if ((pnum=COM_CheckParm("-winsize")))
68 {
69 if (pnum >= com_argc-2)
70 Sys_Error("VID: -winsize <width> <height>\n");
71 vid.width = Q_atoi(com_argv[pnum+1]);
72 vid.height = Q_atoi(com_argv[pnum+2]);
73 if (!vid.width || !vid.height)
74 Sys_Error("VID: Bad window width/height\n");
75 }
76
77 // Set video width, height and flags
78 flags = (SDL_SWSURFACE|SDL_HWPALETTE);
79 if ( COM_CheckParm ("-fullscreen") )
80 flags |= SDL_FULLSCREEN;
81
82 // Initialize display
83 if (!(screen = SDL_SetVideoMode(vid.width, vid.height, 8, flags)))
84 Sys_Error("VID: Couldn't set video mode: %s\n", SDL_GetError());
85 VID_SetPalette(palette);
86 SDL_WM_SetCaption("sdlquake","sdlquake");
87 // now know everything we need to know about the buffer
88 VGA_width = vid.conwidth = vid.width;
89 VGA_height = vid.conheight = vid.height;
90 vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
91 vid.numpages = 1;
92 vid.colormap = host_colormap;
93 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
94 VGA_pagebase = vid.buffer = screen->pixels;
95 VGA_rowbytes = vid.rowbytes = screen->pitch;
96 vid.conbuffer = vid.buffer;
97 vid.conrowbytes = vid.rowbytes;
98 vid.direct = 0;
99
100 // allocate z buffer and surface cache
101 chunk = vid.width * vid.height * sizeof (*d_pzbuffer);
102 cachesize = D_SurfaceCacheForRes (vid.width, vid.height);
103 chunk += cachesize;
104 d_pzbuffer = Hunk_HighAllocName(chunk, "video");
105 if (d_pzbuffer == NULL)
106 Sys_Error ("Not enough memory for video mode\n");
107
108 // initialize the cache memory
109 cache = (byte *) d_pzbuffer
110 + vid.width * vid.height * sizeof (*d_pzbuffer);
111 D_InitCaches (cache, cachesize);
112
113 // initialize the mouse
114 SDL_ShowCursor(0);
115}
116
117void VID_Shutdown (void)
118{
119 SDL_Quit();
120}
121
122void VID_Update (vrect_t *rects)
123{
124 SDL_Rect *sdlrects;
125 int n, i;
126 vrect_t *rect;
127
128 // Two-pass system, since Quake doesn't do it the SDL way...
129
130 // First, count the number of rectangles
131 n = 0;
132 for (rect = rects; rect; rect = rect->pnext)
133 ++n;
134
135 // Second, copy them to SDL rectangles and update
136 if (!(sdlrects = (SDL_Rect *)alloca(n*sizeof(*sdlrects))))
137 Sys_Error("Out of memory");
138 i = 0;
139 for (rect = rects; rect; rect = rect->pnext)
140 {
141 sdlrects[i].x = rect->x;
142 sdlrects[i].y = rect->y;
143 sdlrects[i].w = rect->width;
144 sdlrects[i].h = rect->height;
145 ++i;
146 }
147 SDL_UpdateRects(screen, n, sdlrects);
148}
149
150/*
151================
152D_BeginDirectRect
153================
154*/
155void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
156{
157 Uint8 *offset;
158
159
160 if (!screen) return;
161 if ( x < 0 ) x = screen->w+x-1;
162 offset = (Uint8 *)screen->pixels + y*screen->pitch + x;
163 while ( height-- )
164 {
165 memcpy(offset, pbitmap, width);
166 offset += screen->pitch;
167 pbitmap += width;
168 }
169}
170
171
172/*
173================
174D_EndDirectRect
175================
176*/
177void D_EndDirectRect (int x, int y, int width, int height)
178{
179 if (!screen) return;
180 if (x < 0) x = screen->w+x-1;
181 SDL_UpdateRect(screen, x, y, width, height);
182}
183
184
185/*
186================
187Sys_SendKeyEvents
188================
189*/
190
191void Sys_SendKeyEvents(void)
192{
193 SDL_Event event;
194 int sym, state;
195 int modstate;
196
197 while (SDL_PollEvent(&event))
198 {
199 switch (event.type) {
200
201 case SDL_KEYDOWN:
202 case SDL_KEYUP:
203 sym = event.key.keysym.sym;
204 state = event.key.state;
205 modstate = SDL_GetModState();
206 switch(sym)
207 {
208 case SDLK_DELETE: sym = K_DEL; break;
209 case SDLK_BACKSPACE: sym = K_BACKSPACE; break;
210 case SDLK_F1: sym = K_F1; break;
211 case SDLK_F2: sym = K_F2; break;
212 case SDLK_F3: sym = K_F3; break;
213 case SDLK_F4: sym = K_F4; break;
214 case SDLK_F5: sym = K_F5; break;
215 case SDLK_F6: sym = K_F6; break;
216 case SDLK_F7: sym = K_F7; break;
217 case SDLK_F8: sym = K_F8; break;
218 case SDLK_F9: sym = K_F9; break;
219 case SDLK_F10: sym = K_F10; break;
220 case SDLK_F11: sym = K_F11; break;
221 case SDLK_F12: sym = K_F12; break;
222 case SDLK_BREAK:
223 case SDLK_PAUSE: sym = K_PAUSE; break;
224 case SDLK_UP: sym = K_UPARROW; break;
225 case SDLK_DOWN: sym = K_DOWNARROW; break;
226 case SDLK_RIGHT: sym = K_RIGHTARROW; break;
227 case SDLK_LEFT: sym = K_LEFTARROW; break;
228 case SDLK_INSERT: sym = K_INS; break;
229 case SDLK_HOME: sym = K_HOME; break;
230 case SDLK_END: sym = K_END; break;
231 case SDLK_PAGEUP: sym = K_PGUP; break;
232 case SDLK_PAGEDOWN: sym = K_PGDN; break;
233 case SDLK_RSHIFT:
234 case SDLK_LSHIFT: sym = K_SHIFT; break;
235 case SDLK_RCTRL:
236 case SDLK_LCTRL: sym = K_CTRL; break;
237 case SDLK_RALT:
238 case SDLK_LALT: sym = K_ALT; break;
239 case SDLK_KP0:
240 if(modstate & KMOD_NUM) sym = K_INS;
241 else sym = SDLK_0;
242 break;
243 case SDLK_KP1:
244 if(modstate & KMOD_NUM) sym = K_END;
245 else sym = SDLK_1;
246 break;
247 case SDLK_KP2:
248 if(modstate & KMOD_NUM) sym = K_DOWNARROW;
249 else sym = SDLK_2;
250 break;
251 case SDLK_KP3:
252 if(modstate & KMOD_NUM) sym = K_PGDN;
253 else sym = SDLK_3;
254 break;
255 case SDLK_KP4:
256 if(modstate & KMOD_NUM) sym = K_LEFTARROW;
257 else sym = SDLK_4;
258 break;
259 case SDLK_KP5: sym = SDLK_5; break;
260 case SDLK_KP6:
261 if(modstate & KMOD_NUM) sym = K_RIGHTARROW;
262 else sym = SDLK_6;
263 break;
264 case SDLK_KP7:
265 if(modstate & KMOD_NUM) sym = K_HOME;
266 else sym = SDLK_7;
267 break;
268 case SDLK_KP8:
269 if(modstate & KMOD_NUM) sym = K_UPARROW;
270 else sym = SDLK_8;
271 break;
272 case SDLK_KP9:
273 if(modstate & KMOD_NUM) sym = K_PGUP;
274 else sym = SDLK_9;
275 break;
276 case SDLK_KP_PERIOD:
277 if(modstate & KMOD_NUM) sym = K_DEL;
278 else sym = SDLK_PERIOD;
279 break;
280 case SDLK_KP_DIVIDE: sym = SDLK_SLASH; break;
281 case SDLK_KP_MULTIPLY: sym = SDLK_ASTERISK; break;
282 case SDLK_KP_MINUS: sym = SDLK_MINUS; break;
283 case SDLK_KP_PLUS: sym = SDLK_PLUS; break;
284 case SDLK_KP_ENTER: sym = SDLK_RETURN; break;
285 case SDLK_KP_EQUALS: sym = SDLK_EQUALS; break;
286 }
287 // If we're not directly handled and still above 255
288 // just force it to 0
289 if(sym > 255) sym = 0;
290 Key_Event(sym, state);
291 break;
292
293 case SDL_MOUSEMOTION:
294 if ( (event.motion.x != (vid.width/2)) ||
295 (event.motion.y != (vid.height/2)) ) {
296 mouse_x = event.motion.xrel*10;
297 mouse_y = event.motion.yrel*10;
298 if ( (event.motion.x < ((vid.width/2)-(vid.width/4))) ||
299 (event.motion.x > ((vid.width/2)+(vid.width/4))) ||
300 (event.motion.y < ((vid.height/2)-(vid.height/4))) ||
301 (event.motion.y > ((vid.height/2)+(vid.height/4))) ) {
302 SDL_WarpMouse(vid.width/2, vid.height/2);
303 }
304 }
305 break;
306
307 case SDL_QUIT:
308 CL_Disconnect ();
309 Host_ShutdownServer(false);
310 Sys_Quit ();
311 break;
312 default:
313 break;
314 }
315 }
316}
317
318void IN_Init (void)
319{
320 if ( COM_CheckParm ("-nomouse") )
321 return;
322 mouse_x = mouse_y = 0.0;
323 mouse_avail = 1;
324}
325
326void IN_Shutdown (void)
327{
328 mouse_avail = 0;
329}
330
331void IN_Commands (void)
332{
333 int i;
334 int mouse_buttonstate;
335
336 if (!mouse_avail) return;
337
338 i = SDL_GetMouseState(NULL, NULL);
339 /* Quake swaps the second and third buttons */
340 mouse_buttonstate = (i & ~0x06) | ((i & 0x02)<<1) | ((i & 0x04)>>1);
341 for (i=0 ; i<3 ; i++) {
342 if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) )
343 Key_Event (K_MOUSE1 + i, true);
344
345 if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
346 Key_Event (K_MOUSE1 + i, false);
347 }
348 mouse_oldbuttonstate = mouse_buttonstate;
349}
350
351void IN_Move (usercmd_t *cmd)
352{
353 if (!mouse_avail)
354 return;
355
356 mouse_x *= sensitivity.value;
357 mouse_y *= sensitivity.value;
358
359 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
360 cmd->sidemove += m_side.value * mouse_x;
361 else
362 cl.viewangles[YAW] -= m_yaw.value * mouse_x;
363 if (in_mlook.state & 1)
364 V_StopPitchDrift ();
365
366 if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) {
367 cl.viewangles[PITCH] += m_pitch.value * mouse_y;
368 if (cl.viewangles[PITCH] > 80)
369 cl.viewangles[PITCH] = 80;
370 if (cl.viewangles[PITCH] < -70)
371 cl.viewangles[PITCH] = -70;
372 } else {
373 if ((in_strafe.state & 1) && noclip_anglehack)
374 cmd->upmove -= m_forward.value * mouse_y;
375 else
376 cmd->forwardmove -= m_forward.value * mouse_y;
377 }
378 mouse_x = mouse_y = 0.0;
379}
380
381/*
382================
383Sys_ConsoleInput
384================
385*/
386char *Sys_ConsoleInput (void)
387{
388 return 0;
389}
diff --git a/apps/plugins/sdl/progs/quake/vid_svgalib.c b/apps/plugins/sdl/progs/quake/vid_svgalib.c
new file mode 100644
index 0000000000..e0fea3af09
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid_svgalib.c
@@ -0,0 +1,1003 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20#include <termios.h>
21#include <sys/ioctl.h>
22#include <sys/stat.h>
23#include <sys/vt.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <signal.h>
27
28#include <asm/io.h>
29
30#include "vga.h"
31#include "vgakeyboard.h"
32#include "vgamouse.h"
33
34#include "quakedef.h"
35#include "d_local.h"
36
37#define stringify(m) { #m, m }
38
39unsigned short d_8to16table[256];
40static byte *vid_surfcache;
41static int VID_highhunkmark;
42
43int num_modes;
44vga_modeinfo *modes;
45int current_mode;
46
47int num_shades=32;
48
49struct
50{
51 char *name;
52 int num;
53} mice[] =
54{
55 stringify(MOUSE_MICROSOFT),
56 stringify(MOUSE_MOUSESYSTEMS),
57 stringify(MOUSE_MMSERIES),
58 stringify(MOUSE_LOGITECH),
59 stringify(MOUSE_BUSMOUSE),
60 stringify(MOUSE_PS2),
61};
62
63static unsigned char scantokey[128];
64static byte vid_current_palette[768];
65
66int num_mice = sizeof (mice) / sizeof(mice[0]);
67
68int d_con_indirect = 0;
69
70int svgalib_inited=0;
71int UseMouse = 1;
72int UseDisplay = 1;
73int UseKeyboard = 1;
74
75int mouserate = MOUSE_DEFAULTSAMPLERATE;
76
77cvar_t vid_mode = {"vid_mode","5",false};
78cvar_t vid_redrawfull = {"vid_redrawfull","0",false};
79cvar_t vid_waitforrefresh = {"vid_waitforrefresh","0",true};
80
81char *framebuffer_ptr;
82
83cvar_t mouse_button_commands[3] =
84{
85 {"mouse1","+attack"},
86 {"mouse2","+strafe"},
87 {"mouse3","+forward"},
88};
89
90int mouse_buttons;
91int mouse_buttonstate;
92int mouse_oldbuttonstate;
93float mouse_x, mouse_y;
94float old_mouse_x, old_mouse_y;
95int mx, my;
96
97cvar_t m_filter = {"m_filter","0"};
98
99static byte backingbuf[48*24];
100
101int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
102byte *VGA_pagebase;
103
104void VGA_UpdatePlanarScreen (void *srcbuffer);
105
106void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
107{
108 int i, j, k, plane, reps, repshift, offset, vidpage, off;
109
110 if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return;
111
112 if (vid.aspect > 1.5)
113 {
114 reps = 2;
115 repshift = 1;
116 } else {
117 reps = 1;
118 repshift = 0;
119 }
120
121 vidpage = 0;
122 vga_setpage(0);
123
124 if (VGA_planar)
125 {
126 for (plane=0 ; plane<4 ; plane++)
127 {
128 // select the correct plane for reading and writing
129 outb(0x02, 0x3C4);
130 outb(1 << plane, 0x3C5);
131 outb(4, 0x3CE);
132 outb(plane, 0x3CF);
133
134 for (i=0 ; i<(height << repshift) ; i += reps)
135 {
136 for (k=0 ; k<reps ; k++)
137 {
138 for (j=0 ; j<(width >> 2) ; j++)
139 {
140 backingbuf[(i + k) * 24 + (j << 2) + plane] =
141 vid.direct[(y + i + k) * VGA_rowbytes +
142 (x >> 2) + j];
143 vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
144 pbitmap[(i >> repshift) * 24 +
145 (j << 2) + plane];
146 }
147 }
148 }
149 }
150 } else {
151 for (i=0 ; i<(height << repshift) ; i += reps)
152 {
153 for (j=0 ; j<reps ; j++)
154 {
155 offset = x + ((y << repshift) + i + j) * vid.rowbytes;
156 off = offset % 0x10000;
157 if ((offset / 0x10000) != vidpage) {
158 vidpage=offset / 0x10000;
159 vga_setpage(vidpage);
160 }
161 memcpy (&backingbuf[(i + j) * 24],
162 vid.direct + off, width);
163 memcpy (vid.direct + off,
164 &pbitmap[(i >> repshift)*width], width);
165 }
166 }
167 }
168}
169
170void D_EndDirectRect (int x, int y, int width, int height)
171{
172 int i, j, k, plane, reps, repshift, offset, vidpage, off;
173
174 if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return;
175
176 if (vid.aspect > 1.5)
177 {
178 reps = 2;
179 repshift = 1;
180 } else {
181 reps = 1;
182 repshift = 0;
183 }
184
185 vidpage = 0;
186 vga_setpage(0);
187
188 if (VGA_planar)
189 {
190 for (plane=0 ; plane<4 ; plane++)
191 {
192 // select the correct plane for writing
193 outb(2, 0x3C4);
194 outb(1 << plane, 0x3C5);
195 outb(4, 0x3CE);
196 outb(plane, 0x3CF);
197
198 for (i=0 ; i<(height << repshift) ; i += reps)
199 {
200 for (k=0 ; k<reps ; k++)
201 {
202 for (j=0 ; j<(width >> 2) ; j++)
203 {
204 vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
205 backingbuf[(i + k) * 24 + (j << 2) + plane];
206 }
207 }
208 }
209 }
210 } else {
211 for (i=0 ; i<(height << repshift) ; i += reps)
212 {
213 for (j=0 ; j<reps ; j++)
214 {
215 offset = x + ((y << repshift) + i + j) * vid.rowbytes;
216 off = offset % 0x10000;
217 if ((offset / 0x10000) != vidpage) {
218 vidpage=offset / 0x10000;
219 vga_setpage(vidpage);
220 }
221 memcpy (vid.direct + off,
222 &backingbuf[(i +j)*24],
223 width);
224 }
225 }
226 }
227}
228
229/*
230=================
231VID_Gamma_f
232
233Keybinding command
234=================
235*/
236void VID_Gamma_f (void)
237{
238 float gamma, f, inf;
239 unsigned char palette[768];
240 int i;
241
242 if (Cmd_Argc () == 2)
243 {
244 gamma = Q_atof (Cmd_Argv(1));
245
246 for (i=0 ; i<768 ; i++)
247 {
248 f = pow ( (host_basepal[i]+1)/256.0 , gamma );
249 inf = f*255 + 0.5;
250 if (inf < 0)
251 inf = 0;
252 if (inf > 255)
253 inf = 255;
254 palette[i] = inf;
255 }
256
257 VID_SetPalette (palette);
258
259 vid.recalc_refdef = 1; // force a surface cache flush
260 }
261}
262
263void VID_DescribeMode_f (void)
264{
265 int modenum;
266
267 modenum = Q_atoi (Cmd_Argv(1));
268 if ((modenum >= num_modes) || (modenum < 0 ) || !modes[modenum].width)
269 Con_Printf("Invalid video mode: %d!\n",modenum);
270 Con_Printf("%d: %d x %d - ",modenum,modes[modenum].width,modes[modenum].height);
271 if (modes[modenum].bytesperpixel == 0)
272 Con_Printf("ModeX\n");
273 else
274 Con_Printf("%d bpp\n", modes[modenum].bytesperpixel<<3);
275}
276
277void VID_DescribeModes_f (void)
278{
279 int i;
280
281 for (i=0;i<num_modes;i++)
282 if (modes[i].width) {
283 Con_Printf("%d: %d x %d - ", i, modes[i].width,modes[i].height);
284 if (modes[i].bytesperpixel == 0)
285 Con_Printf("ModeX\n");
286 else
287 Con_Printf("%d bpp\n", modes[i].bytesperpixel<<3);
288 }
289}
290
291/*
292================
293VID_NumModes
294================
295*/
296int VID_NumModes ()
297{
298 int i,i1=0;
299
300 for (i=0;i<num_modes;i++)
301 i1+=(modes[i].width?1:0);
302 return (i1);
303}
304
305void VID_NumModes_f (void)
306{
307 Con_Printf("%d modes\n",VID_NumModes());
308}
309
310void VID_Debug_f (void)
311{
312 Con_Printf("mode: %d\n",current_mode);
313 Con_Printf("height x width: %d x %d\n",vid.height,vid.width);
314 Con_Printf("bpp: %d\n",modes[current_mode].bytesperpixel*8);
315 Con_Printf("vid.aspect: %f\n",vid.aspect);
316}
317
318
319
320void VID_InitModes(void)
321{
322
323 int i;
324
325// get complete information on all modes
326
327 num_modes = vga_lastmodenumber()+1;
328 modes = Z_Malloc(num_modes * sizeof(vga_modeinfo));
329 for (i=0 ; i<num_modes ; i++)
330 {
331 if (vga_hasmode(i))
332 Q_memcpy(&modes[i], vga_getmodeinfo(i), sizeof (vga_modeinfo));
333 else
334 modes[i].width = 0; // means not available
335 }
336
337// filter for modes i don't support
338
339 for (i=0 ; i<num_modes ; i++)
340 {
341 if (modes[i].bytesperpixel != 1 && modes[i].colors != 256)
342 modes[i].width = 0;
343 }
344
345}
346
347int get_mode(char *name, int width, int height, int depth)
348{
349
350 int i;
351 int ok, match;
352
353 match = (!!width) + (!!height)*2 + (!!depth)*4;
354
355 if (name)
356 {
357 i = vga_getmodenumber(name);
358 if (!modes[i].width)
359 {
360 Sys_Printf("Mode [%s] not supported\n", name);
361 i = G320x200x256;
362 }
363 }
364 else
365 {
366 for (i=0 ; i<num_modes ; i++)
367 if (modes[i].width)
368 {
369 ok = (modes[i].width == width)
370 + (modes[i].height == height)*2
371 + (modes[i].bytesperpixel == depth/8)*4;
372 if ((ok & match) == ok)
373 break;
374 }
375 if (i==num_modes)
376 {
377 Sys_Printf("Mode %dx%d (%d bits) not supported\n",
378 width, height, depth);
379 i = G320x200x256;
380 }
381 }
382
383 return i;
384
385}
386
387int matchmouse(int mouse, char *name)
388{
389 int i;
390 for (i=0 ; i<num_mice ; i++)
391 if (!strcmp(mice[i].name, name))
392 return i;
393 return mouse;
394}
395
396#if 0
397
398void vtswitch(int newconsole)
399{
400
401 int fd;
402 struct vt_stat x;
403
404// switch consoles and wait until reactivated
405 fd = open("/dev/console", O_RDONLY);
406 ioctl(fd, VT_GETSTATE, &x);
407 ioctl(fd, VT_ACTIVATE, newconsole);
408 ioctl(fd, VT_WAITACTIVE, x.v_active);
409 close(fd);
410
411}
412
413#endif
414
415void keyhandler(int scancode, int state)
416{
417
418 int sc;
419
420 sc = scancode & 0x7f;
421// Con_Printf("scancode=%x (%d%s)\n", scancode, sc, scancode&0x80?"+128":"");
422 Key_Event(scantokey[sc], state == KEY_EVENTPRESS);
423
424}
425
426void VID_Shutdown(void)
427{
428
429 if (!svgalib_inited) return;
430
431// printf("shutdown graphics called\n");
432 if (UseKeyboard)
433 keyboard_close();
434 if (UseDisplay)
435 vga_setmode(TEXT);
436// printf("shutdown graphics finished\n");
437
438 svgalib_inited = 0;
439
440}
441
442void VID_ShiftPalette(unsigned char *p)
443{
444 VID_SetPalette(p);
445}
446
447void VID_SetPalette(byte *palette)
448{
449
450 static int tmppal[256*3];
451 int *tp;
452 int i;
453
454 if (!svgalib_inited)
455 return;
456
457 memcpy(vid_current_palette, palette, sizeof(vid_current_palette));
458
459 if (vga_getcolors() == 256)
460 {
461
462 tp = tmppal;
463 for (i=256*3 ; i ; i--)
464 *(tp++) = *(palette++) >> 2;
465
466 if (UseDisplay && vga_oktowrite())
467 vga_setpalvec(0, 256, tmppal);
468
469 }
470}
471
472int VID_SetMode (int modenum, unsigned char *palette)
473{
474 int bsize, zsize, tsize;
475
476 if ((modenum >= num_modes) || (modenum < 0) || !modes[modenum].width)
477 {
478 Cvar_SetValue ("vid_mode", (float)current_mode);
479
480 Con_Printf("No such video mode: %d\n",modenum);
481
482 return 0;
483 }
484
485 Cvar_SetValue ("vid_mode", (float)modenum);
486
487 current_mode=modenum;
488
489 vid.width = modes[current_mode].width;
490 vid.height = modes[current_mode].height;
491
492 VGA_width = modes[current_mode].width;
493 VGA_height = modes[current_mode].height;
494 VGA_planar = modes[current_mode].bytesperpixel == 0;
495 VGA_rowbytes = modes[current_mode].linewidth;
496 vid.rowbytes = modes[current_mode].linewidth;
497 if (VGA_planar) {
498 VGA_bufferrowbytes = modes[current_mode].linewidth * 4;
499 vid.rowbytes = modes[current_mode].linewidth*4;
500 }
501
502 vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
503 vid.colormap = (pixel_t *) host_colormap;
504 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
505 vid.conrowbytes = vid.rowbytes;
506 vid.conwidth = vid.width;
507 vid.conheight = vid.height;
508 vid.numpages = 1;
509
510 vid.maxwarpwidth = WARP_WIDTH;
511 vid.maxwarpheight = WARP_HEIGHT;
512
513 // alloc zbuffer and surface cache
514 if (d_pzbuffer) {
515 D_FlushCaches();
516 Hunk_FreeToHighMark (VID_highhunkmark);
517 d_pzbuffer = NULL;
518 vid_surfcache = NULL;
519 }
520
521 bsize = vid.rowbytes * vid.height;
522 tsize = D_SurfaceCacheForRes (vid.width, vid.height);
523 zsize = vid.width * vid.height * sizeof(*d_pzbuffer);
524
525 VID_highhunkmark = Hunk_HighMark ();
526
527 d_pzbuffer = Hunk_HighAllocName (bsize+tsize+zsize, "video");
528
529 vid_surfcache = ((byte *)d_pzbuffer) + zsize;
530
531 vid.conbuffer = vid.buffer = (pixel_t *)(((byte *)d_pzbuffer) + zsize + tsize);
532
533 D_InitCaches (vid_surfcache, tsize);
534
535// get goin'
536
537 vga_setmode(current_mode);
538 VID_SetPalette(palette);
539
540 VGA_pagebase = vid.direct = framebuffer_ptr = (char *) vga_getgraphmem();
541// if (vga_setlinearaddressing()>0)
542// framebuffer_ptr = (char *) vga_getgraphmem();
543 if (!framebuffer_ptr)
544 Sys_Error("This mode isn't hapnin'\n");
545
546 vga_setpage(0);
547
548 svgalib_inited=1;
549
550 vid.recalc_refdef = 1; // force a surface cache flush
551
552 return 0;
553}
554
555void VID_Init(unsigned char *palette)
556{
557
558 int i;
559 int w, h, d;
560
561 if (svgalib_inited)
562 return;
563
564// Cmd_AddCommand ("gamma", VID_Gamma_f);
565
566 if (UseDisplay)
567 {
568 vga_init();
569
570 VID_InitModes();
571
572 Cvar_RegisterVariable (&vid_mode);
573 Cvar_RegisterVariable (&vid_redrawfull);
574 Cvar_RegisterVariable (&vid_waitforrefresh);
575
576 Cmd_AddCommand("vid_nummodes", VID_NumModes_f);
577 Cmd_AddCommand("vid_describemode", VID_DescribeMode_f);
578 Cmd_AddCommand("vid_describemodes", VID_DescribeModes_f);
579 Cmd_AddCommand("vid_debug", VID_Debug_f);
580
581 // interpret command-line params
582
583 w = h = d = 0;
584 if (getenv("GSVGAMODE"))
585 current_mode = get_mode(getenv("GSVGAMODE"), w, h, d);
586 else if (COM_CheckParm("-mode"))
587 current_mode = get_mode(com_argv[COM_CheckParm("-mode")+1], w, h, d);
588 else if (COM_CheckParm("-w") || COM_CheckParm("-h")
589 || COM_CheckParm("-d"))
590 {
591 if (COM_CheckParm("-w"))
592 w = Q_atoi(com_argv[COM_CheckParm("-w")+1]);
593 if (COM_CheckParm("-h"))
594 h = Q_atoi(com_argv[COM_CheckParm("-h")+1]);
595 if (COM_CheckParm("-d"))
596 d = Q_atoi(com_argv[COM_CheckParm("-d")+1]);
597 current_mode = get_mode(0, w, h, d);
598 }
599 else
600 current_mode = G320x200x256;
601
602 // set vid parameters
603 VID_SetMode(current_mode, palette);
604
605 VID_SetPalette(palette);
606
607 // we do want to run in the background when switched away
608 vga_runinbackground(1);
609 }
610
611 if (COM_CheckParm("-nokbd")) UseKeyboard = 0;
612
613 if (UseKeyboard)
614 {
615 for (i=0 ; i<128 ; i++)
616 scantokey[i] = ' ';
617
618 scantokey[42] = K_SHIFT;
619 scantokey[54] = K_SHIFT;
620 scantokey[72] = K_UPARROW;
621 scantokey[103] = K_UPARROW;
622 scantokey[80] = K_DOWNARROW;
623 scantokey[108] = K_DOWNARROW;
624 scantokey[75] = K_LEFTARROW;
625 scantokey[105] = K_LEFTARROW;
626 scantokey[77] = K_RIGHTARROW;
627 scantokey[106] = K_RIGHTARROW;
628 scantokey[29] = K_CTRL;
629 scantokey[97] = K_CTRL;
630 scantokey[56] = K_ALT;
631 scantokey[100] = K_ALT;
632// scantokey[58] = JK_CAPS;
633// scantokey[69] = JK_NUM_LOCK;
634 scantokey[71] = K_HOME;
635 scantokey[73] = K_PGUP;
636 scantokey[79] = K_END;
637 scantokey[81] = K_PGDN;
638 scantokey[82] = K_INS;
639 scantokey[83] = K_DEL;
640 scantokey[1 ] = K_ESCAPE;
641 scantokey[28] = K_ENTER;
642 scantokey[15] = K_TAB;
643 scantokey[14] = K_BACKSPACE;
644 scantokey[119] = K_PAUSE;
645 scantokey[57] = ' ';
646
647 scantokey[102] = K_HOME;
648 scantokey[104] = K_PGUP;
649 scantokey[107] = K_END;
650 scantokey[109] = K_PGDN;
651 scantokey[110] = K_INS;
652 scantokey[111] = K_DEL;
653
654 scantokey[2] = '1';
655 scantokey[3] = '2';
656 scantokey[4] = '3';
657 scantokey[5] = '4';
658 scantokey[6] = '5';
659 scantokey[7] = '6';
660 scantokey[8] = '7';
661 scantokey[9] = '8';
662 scantokey[10] = '9';
663 scantokey[11] = '0';
664 scantokey[12] = '-';
665 scantokey[13] = '=';
666 scantokey[41] = '`';
667 scantokey[26] = '[';
668 scantokey[27] = ']';
669 scantokey[39] = ';';
670 scantokey[40] = '\'';
671 scantokey[51] = ',';
672 scantokey[52] = '.';
673 scantokey[53] = '/';
674 scantokey[43] = '\\';
675
676 scantokey[59] = K_F1;
677 scantokey[60] = K_F2;
678 scantokey[61] = K_F3;
679 scantokey[62] = K_F4;
680 scantokey[63] = K_F5;
681 scantokey[64] = K_F6;
682 scantokey[65] = K_F7;
683 scantokey[66] = K_F8;
684 scantokey[67] = K_F9;
685 scantokey[68] = K_F10;
686 scantokey[87] = K_F11;
687 scantokey[88] = K_F12;
688 scantokey[30] = 'a';
689 scantokey[48] = 'b';
690 scantokey[46] = 'c';
691 scantokey[32] = 'd';
692 scantokey[18] = 'e';
693 scantokey[33] = 'f';
694 scantokey[34] = 'g';
695 scantokey[35] = 'h';
696 scantokey[23] = 'i';
697 scantokey[36] = 'j';
698 scantokey[37] = 'k';
699 scantokey[38] = 'l';
700 scantokey[50] = 'm';
701 scantokey[49] = 'n';
702 scantokey[24] = 'o';
703 scantokey[25] = 'p';
704 scantokey[16] = 'q';
705 scantokey[19] = 'r';
706 scantokey[31] = 's';
707 scantokey[20] = 't';
708 scantokey[22] = 'u';
709 scantokey[47] = 'v';
710 scantokey[17] = 'w';
711 scantokey[45] = 'x';
712 scantokey[21] = 'y';
713 scantokey[44] = 'z';
714
715 if (keyboard_init())
716 Sys_Error("keyboard_init() failed");
717 keyboard_seteventhandler(keyhandler);
718 }
719
720}
721
722void VID_Update(vrect_t *rects)
723{
724 if (!svgalib_inited)
725 return;
726
727 if (!vga_oktowrite())
728 return; // can't update screen if it's not active
729
730 if (vid_waitforrefresh.value)
731 vga_waitretrace();
732
733 if (VGA_planar)
734 VGA_UpdatePlanarScreen (vid.buffer);
735
736 else if (vid_redrawfull.value) {
737 int total = vid.rowbytes * vid.height;
738 int offset;
739
740 for (offset=0;offset<total;offset+=0x10000) {
741 vga_setpage(offset/0x10000);
742 memcpy(framebuffer_ptr,
743 vid.buffer + offset,
744 ((total-offset>0x10000)?0x10000:(total-offset)));
745 }
746 } else {
747 int ycount;
748 int offset;
749 int vidpage=0;
750
751 vga_setpage(0);
752
753 while (rects)
754 {
755 ycount = rects->height;
756 offset = rects->y * vid.rowbytes + rects->x;
757 while (ycount--)
758 {
759 register int i = offset % 0x10000;
760
761 if ((offset / 0x10000) != vidpage) {
762 vidpage=offset / 0x10000;
763 vga_setpage(vidpage);
764 }
765 if (rects->width + i > 0x10000) {
766 memcpy(framebuffer_ptr + i,
767 vid.buffer + offset,
768 0x10000 - i);
769 vga_setpage(++vidpage);
770 memcpy(framebuffer_ptr,
771 vid.buffer + offset + 0x10000 - i,
772 rects->width - 0x10000 + i);
773 } else
774 memcpy(framebuffer_ptr + i,
775 vid.buffer + offset,
776 rects->width);
777 offset += vid.rowbytes;
778 }
779
780 rects = rects->pnext;
781 }
782 }
783
784 if (vid_mode.value != current_mode)
785 VID_SetMode ((int)vid_mode.value, vid_current_palette);
786}
787
788static int dither;
789
790void VID_DitherOn(void)
791{
792 if (dither == 0)
793 {
794// R_ViewChanged (&vrect, sb_lines, vid.aspect);
795 dither = 1;
796 }
797}
798
799void VID_DitherOff(void)
800{
801 if (dither)
802 {
803// R_ViewChanged (&vrect, sb_lines, vid.aspect);
804 dither = 0;
805 }
806}
807
808void Sys_SendKeyEvents(void)
809{
810 if (!svgalib_inited)
811 return;
812
813 if (UseKeyboard)
814 while (keyboard_update());
815}
816
817void Force_CenterView_f (void)
818{
819 cl.viewangles[PITCH] = 0;
820}
821
822
823void mousehandler(int buttonstate, int dx, int dy)
824{
825 mouse_buttonstate = buttonstate;
826 mx += dx;
827 my += dy;
828}
829
830void IN_Init(void)
831{
832
833 int mtype;
834 char *mousedev;
835 int mouserate;
836
837 if (UseMouse)
838 {
839
840 Cvar_RegisterVariable (&mouse_button_commands[0]);
841 Cvar_RegisterVariable (&mouse_button_commands[1]);
842 Cvar_RegisterVariable (&mouse_button_commands[2]);
843 Cvar_RegisterVariable (&m_filter);
844 Cmd_AddCommand ("force_centerview", Force_CenterView_f);
845
846 mouse_buttons = 3;
847
848 mtype = vga_getmousetype();
849
850 mousedev = "/dev/mouse";
851 if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV");
852 if (COM_CheckParm("-mdev"))
853 mousedev = com_argv[COM_CheckParm("-mdev")+1];
854
855 mouserate = 1200;
856 if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE"));
857 if (COM_CheckParm("-mrate"))
858 mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]);
859
860// printf("Mouse: dev=%s,type=%s,speed=%d\n",
861// mousedev, mice[mtype].name, mouserate);
862 if (mouse_init(mousedev, mtype, mouserate))
863 {
864 Con_Printf("No mouse found\n");
865 UseMouse = 0;
866 }
867 else
868 mouse_seteventhandler(mousehandler);
869
870 }
871
872}
873
874void IN_Shutdown(void)
875{
876 if (UseMouse)
877 mouse_close();
878}
879
880/*
881===========
882IN_Commands
883===========
884*/
885void IN_Commands (void)
886{
887 if (UseMouse && cls.state != ca_dedicated)
888 {
889 // poll mouse values
890 while (mouse_update())
891 ;
892
893 // perform button actions
894 if ((mouse_buttonstate & MOUSE_LEFTBUTTON) &&
895 !(mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
896 Key_Event (K_MOUSE1, true);
897 else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) &&
898 (mouse_oldbuttonstate & MOUSE_LEFTBUTTON))
899 Key_Event (K_MOUSE1, false);
900
901 if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
902 !(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
903 Key_Event (K_MOUSE2, true);
904 else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) &&
905 (mouse_oldbuttonstate & MOUSE_RIGHTBUTTON))
906 Key_Event (K_MOUSE2, false);
907
908 if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
909 !(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
910 Key_Event (K_MOUSE3, true);
911 else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) &&
912 (mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON))
913 Key_Event (K_MOUSE3, false);
914
915 mouse_oldbuttonstate = mouse_buttonstate;
916 }
917}
918
919/*
920===========
921IN_Move
922===========
923*/
924void IN_MouseMove (usercmd_t *cmd)
925{
926 if (!UseMouse)
927 return;
928
929 // poll mouse values
930 while (mouse_update())
931 ;
932
933 if (m_filter.value)
934 {
935 mouse_x = (mx + old_mouse_x) * 0.5;
936 mouse_y = (my + old_mouse_y) * 0.5;
937 }
938 else
939 {
940 mouse_x = mx;
941 mouse_y = my;
942 }
943 old_mouse_x = mx;
944 old_mouse_y = my;
945 mx = my = 0; // clear for next update
946
947 mouse_x *= sensitivity.value;
948 mouse_y *= sensitivity.value;
949
950// add mouse X/Y movement to cmd
951 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
952 cmd->sidemove += m_side.value * mouse_x;
953 else
954 cl.viewangles[YAW] -= m_yaw.value * mouse_x;
955
956 if (in_mlook.state & 1)
957 V_StopPitchDrift ();
958
959 if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
960 {
961 cl.viewangles[PITCH] += m_pitch.value * mouse_y;
962 if (cl.viewangles[PITCH] > 80)
963 cl.viewangles[PITCH] = 80;
964 if (cl.viewangles[PITCH] < -70)
965 cl.viewangles[PITCH] = -70;
966 }
967 else
968 {
969 if ((in_strafe.state & 1) && noclip_anglehack)
970 cmd->upmove -= m_forward.value * mouse_y;
971 else
972 cmd->forwardmove -= m_forward.value * mouse_y;
973 }
974}
975
976void IN_Move (usercmd_t *cmd)
977{
978 IN_MouseMove(cmd);
979}
980
981
982/*
983================
984VID_ModeInfo
985================
986*/
987char *VID_ModeInfo (int modenum)
988{
989 static char *badmodestr = "Bad mode number";
990 static char modestr[40];
991
992 if (modenum == 0)
993 {
994 sprintf (modestr, "%d x %d, %d bpp",
995 vid.width, vid.height, modes[current_mode].bytesperpixel*8);
996 return (modestr);
997 }
998 else
999 {
1000 return (badmodestr);
1001 }
1002}
1003
diff --git a/apps/plugins/sdl/progs/quake/vid_vga.c b/apps/plugins/sdl/progs/quake/vid_vga.c
new file mode 100644
index 0000000000..6fbec9de5c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid_vga.c
@@ -0,0 +1,478 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20//
21// vid_vga.c: VGA-specific DOS video stuff
22//
23
24// TODO: proper handling of page-swap failure
25
26#include <dos.h>
27
28#include "quakedef.h"
29#include "d_local.h"
30#include "dosisms.h"
31#include "vid_dos.h"
32#include <dpmi.h>
33
34extern regs_t regs;
35
36int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
37byte *VGA_pagebase;
38vmode_t *VGA_pcurmode;
39
40static int VGA_planar;
41static int VGA_numpages;
42static int VGA_buffersize;
43
44void *vid_surfcache;
45int vid_surfcachesize;
46
47int VGA_highhunkmark;
48
49#include "vgamodes.h"
50
51#define NUMVIDMODES (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
52
53void VGA_UpdatePlanarScreen (void *srcbuffer);
54
55static byte backingbuf[48*24];
56
57/*
58================
59VGA_BeginDirectRect
60================
61*/
62void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
63 int y, byte *pbitmap, int width, int height)
64{
65 int i, j, k, plane, reps, repshift;
66
67 if (!lvid->direct)
68 return;
69
70 if (lvid->aspect > 1.5)
71 {
72 reps = 2;
73 repshift = 1;
74 }
75 else
76 {
77 reps = 1;
78 repshift = 0;
79 }
80
81 if (pcurrentmode->planar)
82 {
83 for (plane=0 ; plane<4 ; plane++)
84 {
85 // select the correct plane for reading and writing
86 outportb (SC_INDEX, MAP_MASK);
87 outportb (SC_DATA, 1 << plane);
88 outportb (GC_INDEX, READ_MAP);
89 outportb (GC_DATA, plane);
90
91 for (i=0 ; i<(height << repshift) ; i += reps)
92 {
93 for (k=0 ; k<reps ; k++)
94 {
95 for (j=0 ; j<(width >> 2) ; j++)
96 {
97 backingbuf[(i + k) * 24 + (j << 2) + plane] =
98 lvid->direct[(y + i + k) * VGA_rowbytes +
99 (x >> 2) + j];
100 lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
101 pbitmap[(i >> repshift) * 24 +
102 (j << 2) + plane];
103 }
104 }
105 }
106 }
107 }
108 else
109 {
110 for (i=0 ; i<(height << repshift) ; i += reps)
111 {
112 for (j=0 ; j<reps ; j++)
113 {
114 memcpy (&backingbuf[(i + j) * 24],
115 lvid->direct + x + ((y << repshift) + i + j) *
116 VGA_rowbytes,
117 width);
118 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
119 VGA_rowbytes,
120 &pbitmap[(i >> repshift) * width],
121 width);
122 }
123 }
124 }
125}
126
127
128/*
129================
130VGA_EndDirectRect
131================
132*/
133void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
134 int y, int width, int height)
135{
136 int i, j, k, plane, reps, repshift;
137
138 if (!lvid->direct)
139 return;
140
141 if (lvid->aspect > 1.5)
142 {
143 reps = 2;
144 repshift = 1;
145 }
146 else
147 {
148 reps = 1;
149 repshift = 0;
150 }
151
152 if (pcurrentmode->planar)
153 {
154 for (plane=0 ; plane<4 ; plane++)
155 {
156 // select the correct plane for writing
157 outportb (SC_INDEX, MAP_MASK);
158 outportb (SC_DATA, 1 << plane);
159
160 for (i=0 ; i<(height << repshift) ; i += reps)
161 {
162 for (k=0 ; k<reps ; k++)
163 {
164 for (j=0 ; j<(width >> 2) ; j++)
165 {
166 lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
167 backingbuf[(i + k) * 24 + (j << 2) + plane];
168 }
169 }
170 }
171 }
172 }
173 else
174 {
175 for (i=0 ; i<(height << repshift) ; i += reps)
176 {
177 for (j=0 ; j<reps ; j++)
178 {
179 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
180 VGA_rowbytes,
181 &backingbuf[(i + j) * 24],
182 width);
183 }
184 }
185 }
186}
187
188
189/*
190================
191VGA_Init
192================
193*/
194void VGA_Init (void)
195{
196 int i;
197
198// link together all the VGA modes
199 for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
200 {
201 vgavidmodes[i].pnext = &vgavidmodes[i+1];
202 }
203
204// add the VGA modes at the start of the mode list
205 vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
206 pvidmodes = &vgavidmodes[0];
207
208 numvidmodes += NUMVIDMODES;
209}
210
211
212/*
213================
214VGA_WaitVsync
215================
216*/
217void VGA_WaitVsync (void)
218{
219 while ((inportb (0x3DA) & 0x08) == 0)
220 ;
221}
222
223
224/*
225================
226VGA_ClearVideoMem
227================
228*/
229void VGA_ClearVideoMem (int planar)
230{
231
232 if (planar)
233 {
234 // enable all planes for writing
235 outportb (SC_INDEX, MAP_MASK);
236 outportb (SC_DATA, 0x0F);
237 }
238
239 Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
240}
241
242/*
243================
244VGA_FreeAndAllocVidbuffer
245================
246*/
247qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
248{
249 int tsize, tbuffersize;
250
251 if (allocnewbuffer)
252 {
253 // alloc an extra line in case we want to wrap, and allocate the z-buffer
254 tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
255 (lvid->width * lvid->height * sizeof (*d_pzbuffer));
256 }
257 else
258 {
259 // just allocate the z-buffer
260 tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
261 }
262
263 tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
264
265 tbuffersize += tsize;
266
267// see if there's enough memory, allowing for the normal mode 0x13 pixel,
268// z, and surface buffers
269 if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
270 0x10000 * 3) < minimum_memory)
271 {
272 Con_Printf ("Not enough memory for video mode\n");
273 VGA_pcurmode = NULL; // so no further accesses to the buffer are
274 // attempted, particularly when clearing
275 return false; // not enough memory for mode
276 }
277
278 VGA_buffersize = tbuffersize;
279 vid_surfcachesize = tsize;
280
281 if (d_pzbuffer)
282 {
283 D_FlushCaches ();
284 Hunk_FreeToHighMark (VGA_highhunkmark);
285 d_pzbuffer = NULL;
286 }
287
288 VGA_highhunkmark = Hunk_HighMark ();
289
290 d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
291
292 vid_surfcache = (byte *)d_pzbuffer
293 + lvid->width * lvid->height * sizeof (*d_pzbuffer);
294
295 if (allocnewbuffer)
296 {
297 lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
298 lvid->conbuffer = lvid->buffer;
299 }
300
301 return true;
302}
303
304
305/*
306================
307VGA_CheckAdequateMem
308================
309*/
310qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
311 int allocnewbuffer)
312{
313 int tbuffersize;
314
315 tbuffersize = width * height * sizeof (*d_pzbuffer);
316
317 if (allocnewbuffer)
318 {
319 // alloc an extra line in case we want to wrap, and allocate the z-buffer
320 tbuffersize += (rowbytes * (height + 1));
321 }
322
323 tbuffersize += D_SurfaceCacheForRes (width, height);
324
325// see if there's enough memory, allowing for the normal mode 0x13 pixel,
326// z, and surface buffers
327 if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
328 0x10000 * 3) < minimum_memory)
329 {
330 return false; // not enough memory for mode
331 }
332
333 return true;
334}
335
336
337/*
338================
339VGA_InitMode
340================
341*/
342int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
343{
344 vextra_t *pextra;
345
346 pextra = pcurrentmode->pextradata;
347
348 if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
349 return -1; // memory alloc failed
350
351 if (VGA_pcurmode)
352 VGA_ClearVideoMem (VGA_pcurmode->planar);
353
354// mode 0x13 is the base for all the Mode X-class mode sets
355 regs.h.ah = 0;
356 regs.h.al = 0x13;
357 dos_int86(0x10);
358
359 VGA_pagebase = (void *)real2ptr(0xa0000);
360 lvid->direct = (pixel_t *)VGA_pagebase;
361
362// set additional registers as needed
363 VideoRegisterSet (pextra->pregset);
364
365 VGA_numpages = 1;
366 lvid->numpages = VGA_numpages;
367
368 VGA_width = (lvid->width + 0x1F) & ~0x1F;
369 VGA_height = lvid->height;
370 VGA_planar = pcurrentmode->planar;
371 if (VGA_planar)
372 VGA_rowbytes = lvid->rowbytes / 4;
373 else
374 VGA_rowbytes = lvid->rowbytes;
375 VGA_bufferrowbytes = lvid->rowbytes;
376 lvid->colormap = host_colormap;
377 lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
378
379 lvid->maxwarpwidth = WARP_WIDTH;
380 lvid->maxwarpheight = WARP_HEIGHT;
381
382 lvid->conbuffer = lvid->buffer;
383 lvid->conrowbytes = lvid->rowbytes;
384 lvid->conwidth = lvid->width;
385 lvid->conheight = lvid->height;
386
387 VGA_pcurmode = pcurrentmode;
388
389 VGA_ClearVideoMem (pcurrentmode->planar);
390
391 if (_vid_wait_override.value)
392 {
393 Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
394 }
395 else
396 {
397 Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
398 }
399
400 D_InitCaches (vid_surfcache, vid_surfcachesize);
401
402 return 1;
403}
404
405
406/*
407================
408VGA_SetPalette
409================
410*/
411void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
412{
413 int shiftcomponents=2;
414 int i;
415
416 UNUSED(lvid);
417 UNUSED(pcurrentmode);
418
419 dos_outportb(0x3c8, 0);
420 for (i=0 ; i<768 ; i++)
421 outportb(0x3c9, pal[i]>>shiftcomponents);
422}
423
424
425/*
426================
427VGA_SwapBuffersCopy
428================
429*/
430void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
431 vrect_t *rects)
432{
433
434 UNUSED(pcurrentmode);
435
436// TODO: can write a dword at a time
437// TODO: put in ASM
438// TODO: copy only specified rectangles
439 if (VGA_planar)
440 {
441
442 // TODO: copy only specified rectangles
443
444 VGA_UpdatePlanarScreen (lvid->buffer);
445 }
446 else
447 {
448 while (rects)
449 {
450 VGA_UpdateLinearScreen (
451 lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
452 VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
453 rects->width,
454 rects->height,
455 lvid->rowbytes,
456 VGA_rowbytes);
457
458 rects = rects->pnext;
459 }
460 }
461}
462
463
464/*
465================
466VGA_SwapBuffers
467================
468*/
469void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
470{
471 UNUSED(lvid);
472
473 if (vid_wait.value == VID_WAIT_VSYNC)
474 VGA_WaitVsync ();
475
476 VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
477}
478
diff --git a/apps/plugins/sdl/progs/quake/view.c b/apps/plugins/sdl/progs/quake/view.c
new file mode 100644
index 0000000000..f621c3c428
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/view.c
@@ -0,0 +1,1113 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// view.c -- player eye positioning
21
22#include "quakedef.h"
23#include "r_local.h"
24
25/*
26
27The view is allowed to move slightly from it's true position for bobbing,
28but if it exceeds 8 pixels linear distance (spherical, not box), the list of
29entities sent from the server may not include everything in the pvs, especially
30when crossing a water boudnary.
31
32*/
33
34cvar_t lcd_x = {"lcd_x","0"};
35cvar_t lcd_yaw = {"lcd_yaw","0"};
36
37cvar_t scr_ofsx = {"scr_ofsx","0", false};
38cvar_t scr_ofsy = {"scr_ofsy","0", false};
39cvar_t scr_ofsz = {"scr_ofsz","0", false};
40
41cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
42cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
43
44cvar_t cl_bob = {"cl_bob","0.02", false};
45cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false};
46cvar_t cl_bobup = {"cl_bobup","0.5", false};
47
48cvar_t v_kicktime = {"v_kicktime", "0.5", false};
49cvar_t v_kickroll = {"v_kickroll", "0.6", false};
50cvar_t v_kickpitch = {"v_kickpitch", "0.6", false};
51
52cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false};
53cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false};
54cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false};
55cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false};
56cvar_t v_iroll_level = {"v_iroll_level", "0.1", false};
57cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false};
58
59cvar_t v_idlescale = {"v_idlescale", "0", false};
60
61cvar_t crosshair = {"crosshair", "0", true};
62cvar_t cl_crossx = {"cl_crossx", "0", false};
63cvar_t cl_crossy = {"cl_crossy", "0", false};
64
65cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false};
66
67float v_dmg_time, v_dmg_roll, v_dmg_pitch;
68
69extern int in_forward, in_forward2, in_back;
70
71
72/*
73===============
74V_CalcRoll
75
76Used by view and sv_user
77===============
78*/
79vec3_t forward, right, up;
80
81float V_CalcRoll (vec3_t angles, vec3_t velocity)
82{
83 float sign;
84 float side;
85 float value;
86
87 AngleVectors (angles, forward, right, up);
88 side = DotProduct (velocity, right);
89 sign = side < 0 ? -1 : 1;
90 side = fabs(side);
91
92 value = cl_rollangle.value;
93// if (cl.inwater)
94// value *= 6;
95
96 if (side < cl_rollspeed.value)
97 side = side * value / cl_rollspeed.value;
98 else
99 side = value;
100
101 return side*sign;
102
103}
104
105
106/*
107===============
108V_CalcBob
109
110===============
111*/
112float V_CalcBob (void)
113{
114 float bob;
115 float cycle;
116
117 cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;
118 cycle /= cl_bobcycle.value;
119 if (cycle < cl_bobup.value)
120 cycle = M_PI * cycle / cl_bobup.value;
121 else
122 cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);
123
124// bob is proportional to velocity in the xy plane
125// (don't count Z, or jumping messes it up)
126
127 bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;
128//Con_Printf ("speed: %5.1f\n", Length(cl.velocity));
129 bob = bob*0.3 + bob*0.7*sin(cycle);
130 if (bob > 4)
131 bob = 4;
132 else if (bob < -7)
133 bob = -7;
134 return bob;
135
136}
137
138
139//=============================================================================
140
141
142cvar_t v_centermove = {"v_centermove", "0.15", false};
143cvar_t v_centerspeed = {"v_centerspeed","500"};
144
145
146void V_StartPitchDrift (void)
147{
148#if 1
149 if (cl.laststop == cl.time)
150 {
151 return; // something else is keeping it from drifting
152 }
153#endif
154 if (cl.nodrift || !cl.pitchvel)
155 {
156 cl.pitchvel = v_centerspeed.value;
157 cl.nodrift = false;
158 cl.driftmove = 0;
159 }
160}
161
162void V_StopPitchDrift (void)
163{
164 cl.laststop = cl.time;
165 cl.nodrift = true;
166 cl.pitchvel = 0;
167}
168
169/*
170===============
171V_DriftPitch
172
173Moves the client pitch angle towards cl.idealpitch sent by the server.
174
175If the user is adjusting pitch manually, either with lookup/lookdown,
176mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
177
178Drifting is enabled when the center view key is hit, mlook is released and
179lookspring is non 0, or when
180===============
181*/
182void V_DriftPitch (void)
183{
184 float delta, move;
185
186 if (noclip_anglehack || !cl.onground || cls.demoplayback )
187 {
188 cl.driftmove = 0;
189 cl.pitchvel = 0;
190 return;
191 }
192
193// don't count small mouse motion
194 if (cl.nodrift)
195 {
196 if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)
197 cl.driftmove = 0;
198 else
199 cl.driftmove += host_frametime;
200
201 if ( cl.driftmove > v_centermove.value)
202 {
203 V_StartPitchDrift ();
204 }
205 return;
206 }
207
208 delta = cl.idealpitch - cl.viewangles[PITCH];
209
210 if (!delta)
211 {
212 cl.pitchvel = 0;
213 return;
214 }
215
216 move = host_frametime * cl.pitchvel;
217 cl.pitchvel += host_frametime * v_centerspeed.value;
218
219//Con_Printf ("move: %f (%f)\n", move, host_frametime);
220
221 if (delta > 0)
222 {
223 if (move > delta)
224 {
225 cl.pitchvel = 0;
226 move = delta;
227 }
228 cl.viewangles[PITCH] += move;
229 }
230 else if (delta < 0)
231 {
232 if (move > -delta)
233 {
234 cl.pitchvel = 0;
235 move = -delta;
236 }
237 cl.viewangles[PITCH] -= move;
238 }
239}
240
241
242
243
244
245/*
246==============================================================================
247
248 PALETTE FLASHES
249
250==============================================================================
251*/
252
253
254cshift_t cshift_empty = { {130,80,50}, 0 };
255cshift_t cshift_water = { {130,80,50}, 128 };
256cshift_t cshift_slime = { {0,25,5}, 150 };
257cshift_t cshift_lava = { {255,80,0}, 150 };
258
259cvar_t v_gamma = {"gamma", "1", true};
260
261byte gammatable[256]; // palette is sent through this
262
263#ifdef GLQUAKE
264byte ramps[3][256];
265float v_blend[4]; // rgba 0.0 - 1.0
266#endif // GLQUAKE
267
268void BuildGammaTable (float g)
269{
270 int i, inf;
271
272 if (g == 1.0)
273 {
274 for (i=0 ; i<256 ; i++)
275 gammatable[i] = i;
276 return;
277 }
278
279 for (i=0 ; i<256 ; i++)
280 {
281 inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
282 if (inf < 0)
283 inf = 0;
284 if (inf > 255)
285 inf = 255;
286 gammatable[i] = inf;
287 }
288}
289
290/*
291=================
292V_CheckGamma
293=================
294*/
295qboolean V_CheckGamma (void)
296{
297 static float oldgammavalue;
298
299 if (v_gamma.value == oldgammavalue)
300 return false;
301 oldgammavalue = v_gamma.value;
302
303 BuildGammaTable (v_gamma.value);
304 vid.recalc_refdef = 1; // force a surface cache flush
305
306 return true;
307}
308
309
310
311/*
312===============
313V_ParseDamage
314===============
315*/
316void V_ParseDamage (void)
317{
318 int armor, blood;
319 vec3_t from;
320 int i;
321 vec3_t forward, right, up;
322 entity_t *ent;
323 float side;
324 float count;
325
326 armor = MSG_ReadByte ();
327 blood = MSG_ReadByte ();
328 for (i=0 ; i<3 ; i++)
329 from[i] = MSG_ReadCoord ();
330
331 count = blood*0.5 + armor*0.5;
332 if (count < 10)
333 count = 10;
334
335 cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame
336
337 cl.cshifts[CSHIFT_DAMAGE].percent += 3*count;
338 if (cl.cshifts[CSHIFT_DAMAGE].percent < 0)
339 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
340 if (cl.cshifts[CSHIFT_DAMAGE].percent > 150)
341 cl.cshifts[CSHIFT_DAMAGE].percent = 150;
342
343 if (armor > blood)
344 {
345 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;
346 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;
347 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;
348 }
349 else if (armor)
350 {
351 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;
352 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;
353 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;
354 }
355 else
356 {
357 cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;
358 cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;
359 cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;
360 }
361
362//
363// calculate view angle kicks
364//
365 ent = &cl_entities[cl.viewentity];
366
367 VectorSubtract (from, ent->origin, from);
368 VectorNormalizeNoRet (from);
369
370 AngleVectors (ent->angles, forward, right, up);
371
372 side = DotProduct (from, right);
373 v_dmg_roll = count*side*v_kickroll.value;
374
375 side = DotProduct (from, forward);
376 v_dmg_pitch = count*side*v_kickpitch.value;
377
378 v_dmg_time = v_kicktime.value;
379}
380
381
382/*
383==================
384V_cshift_f
385==================
386*/
387void V_cshift_f (void)
388{
389 cshift_empty.destcolor[0] = atoi(Cmd_Argv(1));
390 cshift_empty.destcolor[1] = atoi(Cmd_Argv(2));
391 cshift_empty.destcolor[2] = atoi(Cmd_Argv(3));
392 cshift_empty.percent = atoi(Cmd_Argv(4));
393}
394
395
396/*
397==================
398V_BonusFlash_f
399
400When you run over an item, the server sends this command
401==================
402*/
403void V_BonusFlash_f (void)
404{
405 cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;
406 cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;
407 cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;
408 cl.cshifts[CSHIFT_BONUS].percent = 50;
409}
410
411/*
412=============
413V_SetContentsColor
414
415Underwater, lava, etc each has a color shift
416=============
417*/
418void V_SetContentsColor (int contents)
419{
420 switch (contents)
421 {
422 case CONTENTS_EMPTY:
423 case CONTENTS_SOLID:
424 cl.cshifts[CSHIFT_CONTENTS] = cshift_empty;
425 break;
426 case CONTENTS_LAVA:
427 cl.cshifts[CSHIFT_CONTENTS] = cshift_lava;
428 break;
429 case CONTENTS_SLIME:
430 cl.cshifts[CSHIFT_CONTENTS] = cshift_slime;
431 break;
432 default:
433 cl.cshifts[CSHIFT_CONTENTS] = cshift_water;
434 }
435}
436
437/*
438=============
439V_CalcPowerupCshift
440=============
441*/
442void V_CalcPowerupCshift (void)
443{
444 if (cl.items & IT_QUAD)
445 {
446 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
447 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;
448 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;
449 cl.cshifts[CSHIFT_POWERUP].percent = 30;
450 }
451 else if (cl.items & IT_SUIT)
452 {
453 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;
454 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
455 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
456 cl.cshifts[CSHIFT_POWERUP].percent = 20;
457 }
458 else if (cl.items & IT_INVISIBILITY)
459 {
460 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;
461 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;
462 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;
463 cl.cshifts[CSHIFT_POWERUP].percent = 100;
464 }
465 else if (cl.items & IT_INVULNERABILITY)
466 {
467 cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;
468 cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;
469 cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;
470 cl.cshifts[CSHIFT_POWERUP].percent = 30;
471 }
472 else
473 cl.cshifts[CSHIFT_POWERUP].percent = 0;
474}
475
476/*
477=============
478V_CalcBlend
479=============
480*/
481#ifdef GLQUAKE
482void V_CalcBlend (void)
483{
484 float r, g, b, a, a2;
485 int j;
486
487 r = 0;
488 g = 0;
489 b = 0;
490 a = 0;
491
492 for (j=0 ; j<NUM_CSHIFTS ; j++)
493 {
494 if (!gl_cshiftpercent.value)
495 continue;
496
497 a2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;
498
499// a2 = cl.cshifts[j].percent/255.0;
500 if (!a2)
501 continue;
502 a = a + a2*(1-a);
503//Con_Printf ("j:%i a:%f\n", j, a);
504 a2 = a2/a;
505 r = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;
506 g = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;
507 b = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;
508 }
509
510 v_blend[0] = r/255.0;
511 v_blend[1] = g/255.0;
512 v_blend[2] = b/255.0;
513 v_blend[3] = a;
514 if (v_blend[3] > 1)
515 v_blend[3] = 1;
516 if (v_blend[3] < 0)
517 v_blend[3] = 0;
518}
519#endif
520
521/*
522=============
523V_UpdatePalette
524=============
525*/
526#ifdef GLQUAKE
527void V_UpdatePalette (void)
528{
529 int i, j;
530 qboolean new;
531 byte *basepal, *newpal;
532 byte pal[768];
533 float r,g,b,a;
534 int ir, ig, ib;
535 qboolean force;
536
537 V_CalcPowerupCshift ();
538
539 new = false;
540
541 for (i=0 ; i<NUM_CSHIFTS ; i++)
542 {
543 if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
544 {
545 new = true;
546 cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
547 }
548 for (j=0 ; j<3 ; j++)
549 if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
550 {
551 new = true;
552 cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
553 }
554 }
555
556// drop the damage value
557 cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
558 if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
559 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
560
561// drop the bonus value
562 cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
563 if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
564 cl.cshifts[CSHIFT_BONUS].percent = 0;
565
566 force = V_CheckGamma ();
567 if (!new && !force)
568 return;
569
570 V_CalcBlend ();
571
572 a = v_blend[3];
573 r = 255*v_blend[0]*a;
574 g = 255*v_blend[1]*a;
575 b = 255*v_blend[2]*a;
576
577 a = 1-a;
578 for (i=0 ; i<256 ; i++)
579 {
580 ir = i*a + r;
581 ig = i*a + g;
582 ib = i*a + b;
583 if (ir > 255)
584 ir = 255;
585 if (ig > 255)
586 ig = 255;
587 if (ib > 255)
588 ib = 255;
589
590 ramps[0][i] = gammatable[ir];
591 ramps[1][i] = gammatable[ig];
592 ramps[2][i] = gammatable[ib];
593 }
594
595 basepal = host_basepal;
596 newpal = pal;
597
598 for (i=0 ; i<256 ; i++)
599 {
600 ir = basepal[0];
601 ig = basepal[1];
602 ib = basepal[2];
603 basepal += 3;
604
605 newpal[0] = ramps[0][ir];
606 newpal[1] = ramps[1][ig];
607 newpal[2] = ramps[2][ib];
608 newpal += 3;
609 }
610
611 VID_ShiftPalette (pal);
612}
613#else // !GLQUAKE
614void V_UpdatePalette (void)
615{
616 int i, j;
617 qboolean new;
618 byte *basepal, *newpal;
619 byte pal[768];
620 int r,g,b;
621 qboolean force;
622
623 V_CalcPowerupCshift ();
624
625 new = false;
626
627 for (i=0 ; i<NUM_CSHIFTS ; i++)
628 {
629 if (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)
630 {
631 new = true;
632 cl.prev_cshifts[i].percent = cl.cshifts[i].percent;
633 }
634 for (j=0 ; j<3 ; j++)
635 if (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])
636 {
637 new = true;
638 cl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];
639 }
640 }
641
642// drop the damage value
643 cl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;
644 if (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)
645 cl.cshifts[CSHIFT_DAMAGE].percent = 0;
646
647// drop the bonus value
648 cl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;
649 if (cl.cshifts[CSHIFT_BONUS].percent <= 0)
650 cl.cshifts[CSHIFT_BONUS].percent = 0;
651
652 force = V_CheckGamma ();
653 if (!new && !force)
654 return;
655
656 basepal = host_basepal;
657 newpal = pal;
658
659 for (i=0 ; i<256 ; i++)
660 {
661 r = basepal[0];
662 g = basepal[1];
663 b = basepal[2];
664 basepal += 3;
665
666 for (j=0 ; j<NUM_CSHIFTS ; j++)
667 {
668 r += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;
669 g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;
670 b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;
671 }
672
673 newpal[0] = gammatable[r];
674 newpal[1] = gammatable[g];
675 newpal[2] = gammatable[b];
676 newpal += 3;
677 }
678
679 VID_ShiftPalette (pal);
680}
681#endif // !GLQUAKE
682
683
684/*
685==============================================================================
686
687 VIEW RENDERING
688
689==============================================================================
690*/
691
692float angledelta (float a)
693{
694 a = anglemod(a);
695 if (a > 180)
696 a -= 360;
697 return a;
698}
699
700/*
701==================
702CalcGunAngle
703==================
704*/
705void CalcGunAngle (void)
706{
707 float yaw, pitch, move;
708 static float oldyaw = 0;
709 static float oldpitch = 0;
710
711 yaw = r_refdef.viewangles[YAW];
712 pitch = -r_refdef.viewangles[PITCH];
713
714 yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;
715 if (yaw > 10)
716 yaw = 10;
717 if (yaw < -10)
718 yaw = -10;
719 pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;
720 if (pitch > 10)
721 pitch = 10;
722 if (pitch < -10)
723 pitch = -10;
724 move = host_frametime*20;
725 if (yaw > oldyaw)
726 {
727 if (oldyaw + move < yaw)
728 yaw = oldyaw + move;
729 }
730 else
731 {
732 if (oldyaw - move > yaw)
733 yaw = oldyaw - move;
734 }
735
736 if (pitch > oldpitch)
737 {
738 if (oldpitch + move < pitch)
739 pitch = oldpitch + move;
740 }
741 else
742 {
743 if (oldpitch - move > pitch)
744 pitch = oldpitch - move;
745 }
746
747 oldyaw = yaw;
748 oldpitch = pitch;
749
750 cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;
751 cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);
752
753 cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
754 cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
755 cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
756}
757
758/*
759==============
760V_BoundOffsets
761==============
762*/
763void V_BoundOffsets (void)
764{
765 entity_t *ent;
766
767 ent = &cl_entities[cl.viewentity];
768
769// absolutely bound refresh reletive to entity clipping hull
770// so the view can never be inside a solid wall
771
772 if (r_refdef.vieworg[0] < ent->origin[0] - 14)
773 r_refdef.vieworg[0] = ent->origin[0] - 14;
774 else if (r_refdef.vieworg[0] > ent->origin[0] + 14)
775 r_refdef.vieworg[0] = ent->origin[0] + 14;
776 if (r_refdef.vieworg[1] < ent->origin[1] - 14)
777 r_refdef.vieworg[1] = ent->origin[1] - 14;
778 else if (r_refdef.vieworg[1] > ent->origin[1] + 14)
779 r_refdef.vieworg[1] = ent->origin[1] + 14;
780 if (r_refdef.vieworg[2] < ent->origin[2] - 22)
781 r_refdef.vieworg[2] = ent->origin[2] - 22;
782 else if (r_refdef.vieworg[2] > ent->origin[2] + 30)
783 r_refdef.vieworg[2] = ent->origin[2] + 30;
784}
785
786/*
787==============
788V_AddIdle
789
790Idle swaying
791==============
792*/
793void V_AddIdle (void)
794{
795 r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
796 r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value;
797 r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value;
798}
799
800
801/*
802==============
803V_CalcViewRoll
804
805Roll is induced by movement and damage
806==============
807*/
808void V_CalcViewRoll (void)
809{
810 float side;
811
812 side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);
813 r_refdef.viewangles[ROLL] += side;
814
815 if (v_dmg_time > 0)
816 {
817 r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;
818 r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;
819 v_dmg_time -= host_frametime;
820 }
821
822 if (cl.stats[STAT_HEALTH] <= 0)
823 {
824 r_refdef.viewangles[ROLL] = 80; // dead view angle
825 return;
826 }
827
828}
829
830
831/*
832==================
833V_CalcIntermissionRefdef
834
835==================
836*/
837void V_CalcIntermissionRefdef (void)
838{
839 entity_t *ent, *view;
840 float old;
841
842// ent is the player model (visible when out of body)
843 ent = &cl_entities[cl.viewentity];
844// view is the weapon model (only visible from inside body)
845 view = &cl.viewent;
846
847 VectorCopy (ent->origin, r_refdef.vieworg);
848 VectorCopy (ent->angles, r_refdef.viewangles);
849 view->model = NULL;
850
851// allways idle in intermission
852 old = v_idlescale.value;
853 v_idlescale.value = 1;
854 V_AddIdle ();
855 v_idlescale.value = old;
856}
857
858/*
859==================
860V_CalcRefdef
861
862==================
863*/
864void V_CalcRefdef (void)
865{
866 entity_t *ent, *view;
867 int i;
868 vec3_t forward, right, up;
869 vec3_t angles;
870 float bob;
871 static float oldz = 0;
872
873 V_DriftPitch ();
874
875// ent is the player model (visible when out of body)
876 ent = &cl_entities[cl.viewentity];
877// view is the weapon model (only visible from inside body)
878 view = &cl.viewent;
879
880
881// transform the view offset by the model's matrix to get the offset from
882// model origin for the view
883 ent->angles[YAW] = cl.viewangles[YAW]; // the model should face
884 // the view dir
885 ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face
886 // the view dir
887
888
889 bob = V_CalcBob ();
890
891// refresh position
892 VectorCopy (ent->origin, r_refdef.vieworg);
893 r_refdef.vieworg[2] += cl.viewheight + bob;
894
895// never let it sit exactly on a node line, because a water plane can
896// dissapear when viewed with the eye exactly on it.
897// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis
898 r_refdef.vieworg[0] += 1.0/32;
899 r_refdef.vieworg[1] += 1.0/32;
900 r_refdef.vieworg[2] += 1.0/32;
901
902 VectorCopy (cl.viewangles, r_refdef.viewangles);
903 V_CalcViewRoll ();
904 V_AddIdle ();
905
906// offsets
907 angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are
908 // actually backward
909 angles[YAW] = ent->angles[YAW];
910 angles[ROLL] = ent->angles[ROLL];
911
912 AngleVectors (angles, forward, right, up);
913
914 for (i=0 ; i<3 ; i++)
915 r_refdef.vieworg[i] += scr_ofsx.value*forward[i]
916 + scr_ofsy.value*right[i]
917 + scr_ofsz.value*up[i];
918
919
920 V_BoundOffsets ();
921
922// set up gun position
923 VectorCopy (cl.viewangles, view->angles);
924
925 CalcGunAngle ();
926
927 VectorCopy (ent->origin, view->origin);
928 view->origin[2] += cl.viewheight;
929
930 for (i=0 ; i<3 ; i++)
931 {
932 view->origin[i] += forward[i]*bob*0.4;
933// view->origin[i] += right[i]*bob*0.4;
934// view->origin[i] += up[i]*bob*0.8;
935 }
936 view->origin[2] += bob;
937
938// fudge position around to keep amount of weapon visible
939// roughly equal with different FOV
940
941#if 0
942 if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl"))
943#endif
944 if (scr_viewsize.value == 110)
945 view->origin[2] += 1;
946 else if (scr_viewsize.value == 100)
947 view->origin[2] += 2;
948 else if (scr_viewsize.value == 90)
949 view->origin[2] += 1;
950 else if (scr_viewsize.value == 80)
951 view->origin[2] += 0.5;
952
953 view->model = cl.model_precache[cl.stats[STAT_WEAPON]];
954 view->frame = cl.stats[STAT_WEAPONFRAME];
955 view->colormap = vid.colormap;
956
957// set up the refresh position
958 VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);
959
960// smooth out stair step ups
961if (cl.onground && ent->origin[2] - oldz > 0)
962{
963 float steptime;
964
965 steptime = cl.time - cl.oldtime;
966 if (steptime < 0)
967//FIXME I_Error ("steptime < 0");
968 steptime = 0;
969
970 oldz += steptime * 80;
971 if (oldz > ent->origin[2])
972 oldz = ent->origin[2];
973 if (ent->origin[2] - oldz > 12)
974 oldz = ent->origin[2] - 12;
975 r_refdef.vieworg[2] += oldz - ent->origin[2];
976 view->origin[2] += oldz - ent->origin[2];
977}
978else
979 oldz = ent->origin[2];
980
981 if (chase_active.value)
982 Chase_Update ();
983}
984
985/*
986==================
987V_RenderView
988
989The player's clipping box goes from (-16 -16 -24) to (16 16 32) from
990the entity origin, so any view position inside that will be valid
991==================
992*/
993extern vrect_t scr_vrect;
994
995void V_RenderView (void)
996{
997 if (con_forcedup)
998 return;
999
1000// don't allow cheats in multiplayer
1001 if (cl.maxclients > 1)
1002 {
1003 Cvar_Set ("scr_ofsx", "0");
1004 Cvar_Set ("scr_ofsy", "0");
1005 Cvar_Set ("scr_ofsz", "0");
1006 }
1007
1008 if (cl.intermission)
1009 { // intermission / finale rendering
1010 V_CalcIntermissionRefdef ();
1011 }
1012 else
1013 {
1014 if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )
1015 V_CalcRefdef ();
1016 }
1017
1018 R_PushDlights ();
1019
1020 if (lcd_x.value)
1021 {
1022 //
1023 // render two interleaved views
1024 //
1025 int i;
1026
1027 vid.rowbytes <<= 1;
1028 vid.aspect *= 0.5;
1029
1030 r_refdef.viewangles[YAW] -= lcd_yaw.value;
1031 for (i=0 ; i<3 ; i++)
1032 r_refdef.vieworg[i] -= right[i]*lcd_x.value;
1033 R_RenderView ();
1034
1035 vid.buffer += vid.rowbytes>>1;
1036
1037 R_PushDlights ();
1038
1039 r_refdef.viewangles[YAW] += lcd_yaw.value*2;
1040 for (i=0 ; i<3 ; i++)
1041 r_refdef.vieworg[i] += 2*right[i]*lcd_x.value;
1042 R_RenderView ();
1043
1044 vid.buffer -= vid.rowbytes>>1;
1045
1046 r_refdef.vrect.height <<= 1;
1047
1048 vid.rowbytes >>= 1;
1049 vid.aspect *= 2;
1050 }
1051 else
1052 {
1053 R_RenderView ();
1054 }
1055
1056#ifndef GLQUAKE
1057 if (crosshair.value)
1058 Draw_Character (scr_vrect.x + scr_vrect.width/2 + cl_crossx.value,
1059 scr_vrect.y + scr_vrect.height/2 + cl_crossy.value, '+');
1060#endif
1061
1062}
1063
1064//============================================================================
1065
1066/*
1067=============
1068V_Init
1069=============
1070*/
1071void V_Init (void)
1072{
1073 Cmd_AddCommand ("v_cshift", V_cshift_f);
1074 Cmd_AddCommand ("bf", V_BonusFlash_f);
1075 Cmd_AddCommand ("centerview", V_StartPitchDrift);
1076
1077 Cvar_RegisterVariable (&lcd_x);
1078 Cvar_RegisterVariable (&lcd_yaw);
1079
1080 Cvar_RegisterVariable (&v_centermove);
1081 Cvar_RegisterVariable (&v_centerspeed);
1082
1083 Cvar_RegisterVariable (&v_iyaw_cycle);
1084 Cvar_RegisterVariable (&v_iroll_cycle);
1085 Cvar_RegisterVariable (&v_ipitch_cycle);
1086 Cvar_RegisterVariable (&v_iyaw_level);
1087 Cvar_RegisterVariable (&v_iroll_level);
1088 Cvar_RegisterVariable (&v_ipitch_level);
1089
1090 Cvar_RegisterVariable (&v_idlescale);
1091 Cvar_RegisterVariable (&crosshair);
1092 Cvar_RegisterVariable (&cl_crossx);
1093 Cvar_RegisterVariable (&cl_crossy);
1094 Cvar_RegisterVariable (&gl_cshiftpercent);
1095
1096 Cvar_RegisterVariable (&scr_ofsx);
1097 Cvar_RegisterVariable (&scr_ofsy);
1098 Cvar_RegisterVariable (&scr_ofsz);
1099 Cvar_RegisterVariable (&cl_rollspeed);
1100 Cvar_RegisterVariable (&cl_rollangle);
1101 Cvar_RegisterVariable (&cl_bob);
1102 Cvar_RegisterVariable (&cl_bobcycle);
1103 Cvar_RegisterVariable (&cl_bobup);
1104
1105 Cvar_RegisterVariable (&v_kicktime);
1106 Cvar_RegisterVariable (&v_kickroll);
1107 Cvar_RegisterVariable (&v_kickpitch);
1108
1109 BuildGammaTable (1.0); // no gamma yet
1110 Cvar_RegisterVariable (&v_gamma);
1111}
1112
1113
diff --git a/apps/plugins/sdl/progs/quake/view.h b/apps/plugins/sdl/progs/quake/view.h
new file mode 100644
index 0000000000..82123a1c11
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/view.h
@@ -0,0 +1,35 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// view.h
21
22extern cvar_t v_gamma;
23
24extern byte gammatable[256]; // palette is sent through this
25extern byte ramps[3][256];
26extern float v_blend[4];
27
28extern cvar_t lcd_x;
29
30
31void V_Init (void);
32void V_RenderView (void);
33float V_CalcRoll (vec3_t angles, vec3_t velocity);
34void V_UpdatePalette (void);
35
diff --git a/apps/plugins/sdl/progs/quake/wad.c b/apps/plugins/sdl/progs/quake/wad.c
new file mode 100644
index 0000000000..c84f72c6d5
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/wad.c
@@ -0,0 +1,158 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// wad.c
21
22#include "quakedef.h"
23
24int wad_numlumps;
25lumpinfo_t *wad_lumps;
26byte *wad_base;
27
28void SwapPic (qpic_t *pic);
29
30/*
31==================
32W_CleanupName
33
34Lowercases name and pads with spaces and a terminating 0 to the length of
35lumpinfo_t->name.
36Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time
37Space padding is so names can be printed nicely in tables.
38Can safely be performed in place.
39==================
40*/
41void W_CleanupName (char *in, char *out)
42{
43 int i;
44 int c;
45
46 for (i=0 ; i<16 ; i++ )
47 {
48 c = in[i];
49 if (!c)
50 break;
51
52 if (c >= 'A' && c <= 'Z')
53 c += ('a' - 'A');
54 out[i] = c;
55 }
56
57 for ( ; i< 16 ; i++ )
58 out[i] = 0;
59}
60
61
62
63/*
64====================
65W_LoadWadFile
66====================
67*/
68void W_LoadWadFile (char *filename)
69{
70 lumpinfo_t *lump_p;
71 wadinfo_t *header;
72 unsigned i;
73 int infotableofs;
74
75 wad_base = COM_LoadHunkFile (filename);
76 if (!wad_base)
77 Sys_Error ("W_LoadWadFile: couldn't load %s", filename);
78
79 header = (wadinfo_t *)wad_base;
80
81 if (header->identification[0] != 'W'
82 || header->identification[1] != 'A'
83 || header->identification[2] != 'D'
84 || header->identification[3] != '2')
85 Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename);
86
87 wad_numlumps = LittleLong(header->numlumps);
88 infotableofs = LittleLong(header->infotableofs);
89 wad_lumps = (lumpinfo_t *)(wad_base + infotableofs);
90
91 for (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)
92 {
93 lump_p->filepos = LittleLong(lump_p->filepos);
94 lump_p->size = LittleLong(lump_p->size);
95 W_CleanupName (lump_p->name, lump_p->name);
96 if (lump_p->type == TYP_QPIC)
97 SwapPic ( (qpic_t *)(wad_base + lump_p->filepos));
98 }
99}
100
101
102/*
103=============
104W_GetLumpinfo
105=============
106*/
107lumpinfo_t *W_GetLumpinfo (char *name)
108{
109 int i;
110 lumpinfo_t *lump_p;
111 char clean[16];
112
113 W_CleanupName (name, clean);
114
115 for (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)
116 {
117 if (!strcmp(clean, lump_p->name))
118 return lump_p;
119 }
120
121 Sys_Error ("W_GetLumpinfo: %s not found", name);
122 return NULL;
123}
124
125void *W_GetLumpName (char *name)
126{
127 lumpinfo_t *lump;
128
129 lump = W_GetLumpinfo (name);
130
131 return (void *)(wad_base + lump->filepos);
132}
133
134void *W_GetLumpNum (int num)
135{
136 lumpinfo_t *lump;
137
138 if (num < 0 || num > wad_numlumps)
139 Sys_Error ("W_GetLumpNum: bad number: %i", num);
140
141 lump = wad_lumps + num;
142
143 return (void *)(wad_base + lump->filepos);
144}
145
146/*
147=============================================================================
148
149automatic byte swapping
150
151=============================================================================
152*/
153
154void SwapPic (qpic_t *pic)
155{
156 pic->width = LittleLong(pic->width);
157 pic->height = LittleLong(pic->height);
158}
diff --git a/apps/plugins/sdl/progs/quake/wad.h b/apps/plugins/sdl/progs/quake/wad.h
new file mode 100644
index 0000000000..9a740d9a76
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/wad.h
@@ -0,0 +1,75 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// wad.h
21
22//===============
23// TYPES
24//===============
25
26#define CMP_NONE 0
27#define CMP_LZSS 1
28
29#define TYP_NONE 0
30#define TYP_LABEL 1
31
32#define TYP_LUMPY 64 // 64 + grab command number
33#define TYP_PALETTE 64
34#define TYP_QTEX 65
35#define TYP_QPIC 66
36#define TYP_SOUND 67
37#define TYP_MIPTEX 68
38
39typedef struct
40{
41 int width, height;
42 byte data[4]; // variably sized
43} qpic_t;
44
45
46
47typedef struct
48{
49 char identification[4]; // should be WAD2 or 2DAW
50 int numlumps;
51 int infotableofs;
52} wadinfo_t;
53
54typedef struct
55{
56 int filepos;
57 int disksize;
58 int size; // uncompressed
59 char type;
60 char compression;
61 char pad1, pad2;
62 char name[16]; // must be null terminated
63} lumpinfo_t;
64
65extern int wad_numlumps;
66extern lumpinfo_t *wad_lumps;
67extern byte *wad_base;
68
69void W_LoadWadFile (char *filename);
70void W_CleanupName (char *in, char *out);
71lumpinfo_t *W_GetLumpinfo (char *name);
72void *W_GetLumpName (char *name);
73void *W_GetLumpNum (int num);
74
75void SwapPic (qpic_t *pic);
diff --git a/apps/plugins/sdl/progs/quake/winquake.h b/apps/plugins/sdl/progs/quake/winquake.h
new file mode 100644
index 0000000000..a956984fe6
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/winquake.h
@@ -0,0 +1,115 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// winquake.h: Win32-specific Quake header file
21
22#pragma warning( disable : 4229 ) // mgraph gets this
23
24#include <windows.h>
25#define WM_MOUSEWHEEL 0x020A
26
27#ifndef SERVERONLY
28#include <ddraw.h>
29#include <dsound.h>
30#ifndef GLQUAKE
31#include <mgraph.h>
32#endif
33#endif
34
35extern HINSTANCE global_hInstance;
36extern int global_nCmdShow;
37
38#ifndef SERVERONLY
39
40extern LPDIRECTDRAW lpDD;
41extern qboolean DDActive;
42extern LPDIRECTDRAWSURFACE lpPrimary;
43extern LPDIRECTDRAWSURFACE lpFrontBuffer;
44extern LPDIRECTDRAWSURFACE lpBackBuffer;
45extern LPDIRECTDRAWPALETTE lpDDPal;
46extern LPDIRECTSOUND pDS;
47extern LPDIRECTSOUNDBUFFER pDSBuf;
48
49extern DWORD gSndBufSize;
50//#define SNDBUFSIZE 65536
51
52void VID_LockBuffer (void);
53void VID_UnlockBuffer (void);
54
55#endif
56
57typedef int modestate_t;
58enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT};
59
60extern modestate_t modestate;
61
62extern HWND mainwindow;
63extern qboolean ActiveApp, Minimized;
64
65extern qboolean WinNT;
66
67int VID_ForceUnlockedAndReturnState (void);
68void VID_ForceLockState (int lk);
69
70void IN_ShowMouse (void);
71void IN_DeactivateMouse (void);
72void IN_HideMouse (void);
73void IN_ActivateMouse (void);
74void IN_RestoreOriginalMouseState (void);
75void IN_SetQuakeMouseState (void);
76void IN_MouseEvent (int mstate);
77
78extern qboolean winsock_lib_initialized;
79
80extern cvar_t _windowed_mouse;
81
82extern int window_center_x, window_center_y;
83extern RECT window_rect;
84
85extern qboolean mouseinitialized;
86extern HWND hwnd_dialog;
87
88extern HANDLE hinput, houtput;
89
90void IN_UpdateClipCursor (void);
91void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify);
92
93void S_BlockSound (void);
94void S_UnblockSound (void);
95
96void VID_SetDefaultMode (void);
97
98int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
99int (PASCAL FAR *pWSACleanup)(void);
100int (PASCAL FAR *pWSAGetLastError)(void);
101SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol);
102int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
103int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname,
104 const char FAR * optval, int optlen);
105int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags,
106 struct sockaddr FAR *from, int FAR * fromlen);
107int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags,
108 const struct sockaddr FAR *to, int tolen);
109int (PASCAL FAR *pclosesocket)(SOCKET s);
110int (PASCAL FAR *pgethostname)(char FAR * name, int namelen);
111struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name);
112struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr,
113 int len, int type);
114int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name,
115 int FAR * namelen);
diff --git a/apps/plugins/sdl/progs/quake/world.c b/apps/plugins/sdl/progs/quake/world.c
new file mode 100644
index 0000000000..e1acfea50c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/world.c
@@ -0,0 +1,962 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// world.c -- world query functions
21
22#include "quakedef.h"
23
24/*
25
26entities never clip against themselves, or their owner
27
28line of sight checks trace->crosscontent, but bullets don't
29
30*/
31
32
33typedef struct
34{
35 vec3_t boxmins, boxmaxs;// enclose the test object along entire move
36 float *mins, *maxs; // size of the moving object
37 vec3_t mins2, maxs2; // size when clipping against mosnters
38 float *start, *end;
39 trace_t trace;
40 int type;
41 edict_t *passedict;
42} moveclip_t;
43
44
45int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
46
47/*
48===============================================================================
49
50HULL BOXES
51
52===============================================================================
53*/
54
55
56static hull_t box_hull;
57static dclipnode_t box_clipnodes[6];
58static mplane_t box_planes[6];
59
60/*
61===================
62SV_InitBoxHull
63
64Set up the planes and clipnodes so that the six floats of a bounding box
65can just be stored out and get a proper hull_t structure.
66===================
67*/
68void SV_InitBoxHull (void)
69{
70 int i;
71 int side;
72
73 box_hull.clipnodes = box_clipnodes;
74 box_hull.planes = box_planes;
75 box_hull.firstclipnode = 0;
76 box_hull.lastclipnode = 5;
77
78 for (i=0 ; i<6 ; i++)
79 {
80 box_clipnodes[i].planenum = i;
81
82 side = i&1;
83
84 box_clipnodes[i].children[side] = CONTENTS_EMPTY;
85 if (i != 5)
86 box_clipnodes[i].children[side^1] = i + 1;
87 else
88 box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
89
90 box_planes[i].type = i>>1;
91 box_planes[i].normal[i>>1] = 1;
92 }
93
94}
95
96
97/*
98===================
99SV_HullForBox
100
101To keep everything totally uniform, bounding boxes are turned into small
102BSP trees instead of being compared directly.
103===================
104*/
105hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs)
106{
107 box_planes[0].dist = maxs[0];
108 box_planes[1].dist = mins[0];
109 box_planes[2].dist = maxs[1];
110 box_planes[3].dist = mins[1];
111 box_planes[4].dist = maxs[2];
112 box_planes[5].dist = mins[2];
113
114 return &box_hull;
115}
116
117
118
119/*
120================
121SV_HullForEntity
122
123Returns a hull that can be used for testing or clipping an object of mins/maxs
124size.
125Offset is filled in to contain the adjustment that must be added to the
126testing object's origin to get a point to use with the returned hull.
127================
128*/
129hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
130{
131 model_t *model;
132 vec3_t size;
133 vec3_t hullmins, hullmaxs;
134 hull_t *hull;
135
136// decide which clipping hull to use, based on the size
137 if (ent->v.solid == SOLID_BSP)
138 { // explicit hulls in the BSP model
139 if (ent->v.movetype != MOVETYPE_PUSH)
140 Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");
141
142 model = sv.models[ (int)ent->v.modelindex ];
143
144 if (!model || model->type != mod_brush)
145 Sys_Error ("MOVETYPE_PUSH with a non bsp model");
146
147 VectorSubtract (maxs, mins, size);
148 if (size[0] < 3)
149 hull = &model->hulls[0];
150 else if (size[0] <= 32)
151 hull = &model->hulls[1];
152 else
153 hull = &model->hulls[2];
154
155// calculate an offset value to center the origin
156 VectorSubtract (hull->clip_mins, mins, offset);
157 VectorAdd (offset, ent->v.origin, offset);
158 }
159 else
160 { // create a temp hull from bounding box sizes
161
162 VectorSubtract (ent->v.mins, maxs, hullmins);
163 VectorSubtract (ent->v.maxs, mins, hullmaxs);
164 hull = SV_HullForBox (hullmins, hullmaxs);
165
166 VectorCopy (ent->v.origin, offset);
167 }
168
169
170 return hull;
171}
172
173/*
174===============================================================================
175
176ENTITY AREA CHECKING
177
178===============================================================================
179*/
180
181typedef struct areanode_s
182{
183 int axis; // -1 = leaf node
184 float dist;
185 struct areanode_s *children[2];
186 link_t trigger_edicts;
187 link_t solid_edicts;
188} areanode_t;
189
190#define AREA_DEPTH 4
191#define AREA_NODES 32
192
193static areanode_t sv_areanodes[AREA_NODES];
194static int sv_numareanodes;
195
196/*
197===============
198SV_CreateAreaNode
199
200===============
201*/
202areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
203{
204 areanode_t *anode;
205 vec3_t size;
206 vec3_t mins1, maxs1, mins2, maxs2;
207
208 anode = &sv_areanodes[sv_numareanodes];
209 sv_numareanodes++;
210
211 ClearLink (&anode->trigger_edicts);
212 ClearLink (&anode->solid_edicts);
213
214 if (depth == AREA_DEPTH)
215 {
216 anode->axis = -1;
217 anode->children[0] = anode->children[1] = NULL;
218 return anode;
219 }
220
221 VectorSubtract (maxs, mins, size);
222 if (size[0] > size[1])
223 anode->axis = 0;
224 else
225 anode->axis = 1;
226
227 anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
228 VectorCopy (mins, mins1);
229 VectorCopy (mins, mins2);
230 VectorCopy (maxs, maxs1);
231 VectorCopy (maxs, maxs2);
232
233 maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
234
235 anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
236 anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
237
238 return anode;
239}
240
241/*
242===============
243SV_ClearWorld
244
245===============
246*/
247void SV_ClearWorld (void)
248{
249 SV_InitBoxHull ();
250
251 memset (sv_areanodes, 0, sizeof(sv_areanodes));
252 sv_numareanodes = 0;
253 SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
254}
255
256
257/*
258===============
259SV_UnlinkEdict
260
261===============
262*/
263void SV_UnlinkEdict (edict_t *ent)
264{
265 if (!ent->area.prev)
266 return; // not linked in anywhere
267 RemoveLink (&ent->area);
268 ent->area.prev = ent->area.next = NULL;
269}
270
271
272/*
273====================
274SV_TouchLinks
275====================
276*/
277void SV_TouchLinks ( edict_t *ent, areanode_t *node )
278{
279 link_t *l, *next;
280 edict_t *touch;
281 int old_self, old_other;
282
283// touch linked edicts
284 for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
285 {
286 next = l->next;
287 touch = EDICT_FROM_AREA(l);
288 if (touch == ent)
289 continue;
290 if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)
291 continue;
292 if (ent->v.absmin[0] > touch->v.absmax[0]
293 || ent->v.absmin[1] > touch->v.absmax[1]
294 || ent->v.absmin[2] > touch->v.absmax[2]
295 || ent->v.absmax[0] < touch->v.absmin[0]
296 || ent->v.absmax[1] < touch->v.absmin[1]
297 || ent->v.absmax[2] < touch->v.absmin[2] )
298 continue;
299 old_self = pr_global_struct->self;
300 old_other = pr_global_struct->other;
301
302 pr_global_struct->self = EDICT_TO_PROG(touch);
303 pr_global_struct->other = EDICT_TO_PROG(ent);
304 pr_global_struct->time = sv.time;
305 PR_ExecuteProgram (touch->v.touch);
306
307 pr_global_struct->self = old_self;
308 pr_global_struct->other = old_other;
309 }
310
311// recurse down both sides
312 if (node->axis == -1)
313 return;
314
315 if ( ent->v.absmax[node->axis] > node->dist )
316 SV_TouchLinks ( ent, node->children[0] );
317 if ( ent->v.absmin[node->axis] < node->dist )
318 SV_TouchLinks ( ent, node->children[1] );
319}
320
321
322/*
323===============
324SV_FindTouchedLeafs
325
326===============
327*/
328void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
329{
330 mplane_t *splitplane;
331 mleaf_t *leaf;
332 int sides;
333 int leafnum;
334
335 if (node->contents == CONTENTS_SOLID)
336 return;
337
338// add an efrag if the node is a leaf
339
340 if ( node->contents < 0)
341 {
342 if (ent->num_leafs == MAX_ENT_LEAFS)
343 return;
344
345 leaf = (mleaf_t *)node;
346 leafnum = leaf - sv.worldmodel->leafs - 1;
347
348 ent->leafnums[ent->num_leafs] = leafnum;
349 ent->num_leafs++;
350 return;
351 }
352
353// NODE_MIXED
354
355 splitplane = node->plane;
356 sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);
357
358// recurse down the contacted sides
359 if (sides & 1)
360 SV_FindTouchedLeafs (ent, node->children[0]);
361
362 if (sides & 2)
363 SV_FindTouchedLeafs (ent, node->children[1]);
364}
365
366/*
367===============
368SV_LinkEdict
369
370===============
371*/
372void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
373{
374 areanode_t *node;
375
376 if (ent->area.prev)
377 SV_UnlinkEdict (ent); // unlink from old position
378
379 if (ent == sv.edicts)
380 return; // don't add the world
381
382 if (ent->free)
383 return;
384
385// set the abs box
386
387#ifdef QUAKE2
388 if (ent->v.solid == SOLID_BSP &&
389 (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
390 { // expand for rotation
391 float max, v;
392 int i;
393
394 max = 0;
395 for (i=0 ; i<3 ; i++)
396 {
397 v =fabs( ent->v.mins[i]);
398 if (v > max)
399 max = v;
400 v =fabs( ent->v.maxs[i]);
401 if (v > max)
402 max = v;
403 }
404 for (i=0 ; i<3 ; i++)
405 {
406 ent->v.absmin[i] = ent->v.origin[i] - max;
407 ent->v.absmax[i] = ent->v.origin[i] + max;
408 }
409 }
410 else
411#endif
412 {
413 VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
414 VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
415 }
416
417//
418// to make items easier to pick up and allow them to be grabbed off
419// of shelves, the abs sizes are expanded
420//
421 if ((int)ent->v.flags & FL_ITEM)
422 {
423 ent->v.absmin[0] -= 15;
424 ent->v.absmin[1] -= 15;
425 ent->v.absmax[0] += 15;
426 ent->v.absmax[1] += 15;
427 }
428 else
429 { // because movement is clipped an epsilon away from an actual edge,
430 // we must fully check even when bounding boxes don't quite touch
431 ent->v.absmin[0] -= 1;
432 ent->v.absmin[1] -= 1;
433 ent->v.absmin[2] -= 1;
434 ent->v.absmax[0] += 1;
435 ent->v.absmax[1] += 1;
436 ent->v.absmax[2] += 1;
437 }
438
439// link to PVS leafs
440 ent->num_leafs = 0;
441 if (ent->v.modelindex)
442 SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
443
444 if (ent->v.solid == SOLID_NOT)
445 return;
446
447// find the first node that the ent's box crosses
448 node = sv_areanodes;
449 while (1)
450 {
451 if (node->axis == -1)
452 break;
453 if (ent->v.absmin[node->axis] > node->dist)
454 node = node->children[0];
455 else if (ent->v.absmax[node->axis] < node->dist)
456 node = node->children[1];
457 else
458 break; // crosses the node
459 }
460
461// link it in
462
463 if (ent->v.solid == SOLID_TRIGGER)
464 InsertLinkBefore (&ent->area, &node->trigger_edicts);
465 else
466 InsertLinkBefore (&ent->area, &node->solid_edicts);
467
468// if touch_triggers, touch all entities at this node and decend for more
469 if (touch_triggers)
470 SV_TouchLinks ( ent, sv_areanodes );
471}
472
473
474
475/*
476===============================================================================
477
478POINT TESTING IN HULLS
479
480===============================================================================
481*/
482
483#if !id386
484
485/*
486==================
487SV_HullPointContents
488
489==================
490*/
491int SV_HullPointContents (hull_t *hull, int num, vec3_t p)
492{
493 float d;
494 dclipnode_t *node;
495 mplane_t *plane;
496
497 while (num >= 0)
498 {
499 if (num < hull->firstclipnode || num > hull->lastclipnode)
500 Sys_Error ("SV_HullPointContents: bad node number");
501
502 node = hull->clipnodes + num;
503 plane = hull->planes + node->planenum;
504
505 if (plane->type < 3)
506 d = p[plane->type] - plane->dist;
507 else
508 d = DotProduct (plane->normal, p) - plane->dist;
509 if (d < 0)
510 num = node->children[1];
511 else
512 num = node->children[0];
513 }
514
515 return num;
516}
517
518#endif // !id386
519
520
521/*
522==================
523SV_PointContents
524
525==================
526*/
527int SV_PointContents (vec3_t p)
528{
529 int cont;
530
531 cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
532 if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
533 cont = CONTENTS_WATER;
534 return cont;
535}
536
537int SV_TruePointContents (vec3_t p)
538{
539 return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
540}
541
542//===========================================================================
543
544/*
545============
546SV_TestEntityPosition
547
548This could be a lot more efficient...
549============
550*/
551edict_t *SV_TestEntityPosition (edict_t *ent)
552{
553 trace_t trace;
554
555 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent);
556
557 if (trace.startsolid)
558 return sv.edicts;
559
560 return NULL;
561}
562
563
564/*
565===============================================================================
566
567LINE TESTING IN HULLS
568
569===============================================================================
570*/
571
572// 1/32 epsilon to keep floating point happy
573#define DIST_EPSILON (0.03125)
574
575/*
576==================
577SV_RecursiveHullCheck
578
579==================
580*/
581qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
582{
583 dclipnode_t *node;
584 mplane_t *plane;
585 float t1, t2;
586 float frac;
587 int i;
588 vec3_t mid;
589 int side;
590 float midf;
591
592// check for empty
593 if (num < 0)
594 {
595 if (num != CONTENTS_SOLID)
596 {
597 trace->allsolid = false;
598 if (num == CONTENTS_EMPTY)
599 trace->inopen = true;
600 else
601 trace->inwater = true;
602 }
603 else
604 trace->startsolid = true;
605 return true; // empty
606 }
607
608 if (num < hull->firstclipnode || num > hull->lastclipnode)
609 Sys_Error ("SV_RecursiveHullCheck: bad node number");
610
611//
612// find the point distances
613//
614 node = hull->clipnodes + num;
615 plane = hull->planes + node->planenum;
616
617 if (plane->type < 3)
618 {
619 t1 = p1[plane->type] - plane->dist;
620 t2 = p2[plane->type] - plane->dist;
621 }
622 else
623 {
624 t1 = DotProduct (plane->normal, p1) - plane->dist;
625 t2 = DotProduct (plane->normal, p2) - plane->dist;
626 }
627
628#if 1
629 if (t1 >= 0 && t2 >= 0)
630 return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
631 if (t1 < 0 && t2 < 0)
632 return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
633#else
634 if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
635 return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
636 if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
637 return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
638#endif
639
640// put the crosspoint DIST_EPSILON pixels on the near side
641 if (t1 < 0)
642 frac = (t1 + DIST_EPSILON)/(t1-t2);
643 else
644 frac = (t1 - DIST_EPSILON)/(t1-t2);
645 if (frac < 0)
646 frac = 0;
647 if (frac > 1)
648 frac = 1;
649
650 midf = p1f + (p2f - p1f)*frac;
651 for (i=0 ; i<3 ; i++)
652 mid[i] = p1[i] + frac*(p2[i] - p1[i]);
653
654 side = (t1 < 0);
655
656// move up to the node
657 if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
658 return false;
659
660#ifdef PARANOID
661 if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])
662 == CONTENTS_SOLID)
663 {
664 Con_Printf ("mid PointInHullSolid\n");
665 return false;
666 }
667#endif
668
669 if (SV_HullPointContents (hull, node->children[side^1], mid)
670 != CONTENTS_SOLID)
671// go past the node
672 return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
673
674 if (trace->allsolid)
675 return false; // never got out of the solid area
676
677//==================
678// the other side of the node is solid, this is the impact point
679//==================
680 if (!side)
681 {
682 VectorCopy (plane->normal, trace->plane.normal);
683 trace->plane.dist = plane->dist;
684 }
685 else
686 {
687 VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
688 trace->plane.dist = -plane->dist;
689 }
690
691 while (SV_HullPointContents (hull, hull->firstclipnode, mid)
692 == CONTENTS_SOLID)
693 { // shouldn't really happen, but does occasionally
694 frac -= 0.1;
695 if (frac < 0)
696 {
697 trace->fraction = midf;
698 VectorCopy (mid, trace->endpos);
699 Con_DPrintf ("backup past 0\n");
700 return false;
701 }
702 midf = p1f + (p2f - p1f)*frac;
703 for (i=0 ; i<3 ; i++)
704 mid[i] = p1[i] + frac*(p2[i] - p1[i]);
705 }
706
707 trace->fraction = midf;
708 VectorCopy (mid, trace->endpos);
709
710 return false;
711}
712
713
714/*
715==================
716SV_ClipMoveToEntity
717
718Handles selection or creation of a clipping hull, and offseting (and
719eventually rotation) of the end points
720==================
721*/
722trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
723{
724 trace_t trace;
725 vec3_t offset;
726 vec3_t start_l, end_l;
727 hull_t *hull;
728
729// fill in a default trace
730 memset (&trace, 0, sizeof(trace_t));
731 trace.fraction = 1;
732 trace.allsolid = true;
733 VectorCopy (end, trace.endpos);
734
735// get the clipping hull
736 hull = SV_HullForEntity (ent, mins, maxs, offset);
737
738 VectorSubtract (start, offset, start_l);
739 VectorSubtract (end, offset, end_l);
740
741#ifdef QUAKE2
742 // rotate start and end into the models frame of reference
743 if (ent->v.solid == SOLID_BSP &&
744 (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
745 {
746 vec3_t a;
747 vec3_t forward, right, up;
748 vec3_t temp;
749
750 AngleVectors (ent->v.angles, forward, right, up);
751
752 VectorCopy (start_l, temp);
753 start_l[0] = DotProduct (temp, forward);
754 start_l[1] = -DotProduct (temp, right);
755 start_l[2] = DotProduct (temp, up);
756
757 VectorCopy (end_l, temp);
758 end_l[0] = DotProduct (temp, forward);
759 end_l[1] = -DotProduct (temp, right);
760 end_l[2] = DotProduct (temp, up);
761 }
762#endif
763
764// trace a line through the apropriate clipping hull
765 SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
766
767#ifdef QUAKE2
768 // rotate endpos back to world frame of reference
769 if (ent->v.solid == SOLID_BSP &&
770 (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
771 {
772 vec3_t a;
773 vec3_t forward, right, up;
774 vec3_t temp;
775
776 if (trace.fraction != 1)
777 {
778 VectorSubtract (vec3_origin, ent->v.angles, a);
779 AngleVectors (a, forward, right, up);
780
781 VectorCopy (trace.endpos, temp);
782 trace.endpos[0] = DotProduct (temp, forward);
783 trace.endpos[1] = -DotProduct (temp, right);
784 trace.endpos[2] = DotProduct (temp, up);
785
786 VectorCopy (trace.plane.normal, temp);
787 trace.plane.normal[0] = DotProduct (temp, forward);
788 trace.plane.normal[1] = -DotProduct (temp, right);
789 trace.plane.normal[2] = DotProduct (temp, up);
790 }
791 }
792#endif
793
794// fix trace up by the offset
795 if (trace.fraction != 1)
796 VectorAdd (trace.endpos, offset, trace.endpos);
797
798// did we clip the move?
799 if (trace.fraction < 1 || trace.startsolid )
800 trace.ent = ent;
801
802 return trace;
803}
804
805//===========================================================================
806
807/*
808====================
809SV_ClipToLinks
810
811Mins and maxs enclose the entire area swept by the move
812====================
813*/
814void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
815{
816 link_t *l, *next;
817 edict_t *touch;
818 trace_t trace;
819
820// touch linked edicts
821 for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
822 {
823 next = l->next;
824 touch = EDICT_FROM_AREA(l);
825 if (touch->v.solid == SOLID_NOT)
826 continue;
827 if (touch == clip->passedict)
828 continue;
829 if (touch->v.solid == SOLID_TRIGGER)
830 Sys_Error ("Trigger in clipping list");
831
832 if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP)
833 continue;
834
835 if (clip->boxmins[0] > touch->v.absmax[0]
836 || clip->boxmins[1] > touch->v.absmax[1]
837 || clip->boxmins[2] > touch->v.absmax[2]
838 || clip->boxmaxs[0] < touch->v.absmin[0]
839 || clip->boxmaxs[1] < touch->v.absmin[1]
840 || clip->boxmaxs[2] < touch->v.absmin[2] )
841 continue;
842
843 if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
844 continue; // points never interact
845
846 // might intersect, so do an exact clip
847 if (clip->trace.allsolid)
848 return;
849 if (clip->passedict)
850 {
851 if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)
852 continue; // don't clip against own missiles
853 if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)
854 continue; // don't clip against owner
855 }
856
857 if ((int)touch->v.flags & FL_MONSTER)
858 trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
859 else
860 trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
861 if (trace.allsolid || trace.startsolid ||
862 trace.fraction < clip->trace.fraction)
863 {
864 trace.ent = touch;
865 if (clip->trace.startsolid)
866 {
867 clip->trace = trace;
868 clip->trace.startsolid = true;
869 }
870 else
871 clip->trace = trace;
872 }
873 else if (trace.startsolid)
874 clip->trace.startsolid = true;
875 }
876
877// recurse down both sides
878 if (node->axis == -1)
879 return;
880
881 if ( clip->boxmaxs[node->axis] > node->dist )
882 SV_ClipToLinks ( node->children[0], clip );
883 if ( clip->boxmins[node->axis] < node->dist )
884 SV_ClipToLinks ( node->children[1], clip );
885}
886
887
888/*
889==================
890SV_MoveBounds
891==================
892*/
893void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
894{
895#if 0
896// debug to test against everything
897boxmins[0] = boxmins[1] = boxmins[2] = -9999;
898boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
899#else
900 int i;
901
902 for (i=0 ; i<3 ; i++)
903 {
904 if (end[i] > start[i])
905 {
906 boxmins[i] = start[i] + mins[i] - 1;
907 boxmaxs[i] = end[i] + maxs[i] + 1;
908 }
909 else
910 {
911 boxmins[i] = end[i] + mins[i] - 1;
912 boxmaxs[i] = start[i] + maxs[i] + 1;
913 }
914 }
915#endif
916}
917
918/*
919==================
920SV_Move
921==================
922*/
923trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
924{
925 moveclip_t clip;
926 int i;
927
928 memset ( &clip, 0, sizeof ( moveclip_t ) );
929
930// clip to world
931 clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );
932
933 clip.start = start;
934 clip.end = end;
935 clip.mins = mins;
936 clip.maxs = maxs;
937 clip.type = type;
938 clip.passedict = passedict;
939
940 if (type == MOVE_MISSILE)
941 {
942 for (i=0 ; i<3 ; i++)
943 {
944 clip.mins2[i] = -15;
945 clip.maxs2[i] = 15;
946 }
947 }
948 else
949 {
950 VectorCopy (mins, clip.mins2);
951 VectorCopy (maxs, clip.maxs2);
952 }
953
954// create the bounding box of the entire move
955 SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
956
957// clip to entities
958 SV_ClipToLinks ( sv_areanodes, &clip );
959
960 return clip.trace;
961}
962
diff --git a/apps/plugins/sdl/progs/quake/world.h b/apps/plugins/sdl/progs/quake/world.h
new file mode 100644
index 0000000000..cddb94fca0
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/world.h
@@ -0,0 +1,78 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// world.h
21
22typedef struct
23{
24 vec3_t normal;
25 float dist;
26} plane_t;
27
28typedef struct
29{
30 qboolean allsolid; // if true, plane is not valid
31 qboolean startsolid; // if true, the initial point was in a solid area
32 qboolean inopen, inwater;
33 float fraction; // time completed, 1.0 = didn't hit anything
34 vec3_t endpos; // final position
35 plane_t plane; // surface normal at impact
36 edict_t *ent; // entity the surface is on
37} trace_t;
38
39
40#define MOVE_NORMAL 0
41#define MOVE_NOMONSTERS 1
42#define MOVE_MISSILE 2
43
44
45void SV_ClearWorld (void);
46// called after the world model has been loaded, before linking any entities
47
48void SV_UnlinkEdict (edict_t *ent);
49// call before removing an entity, and before trying to move one,
50// so it doesn't clip against itself
51// flags ent->v.modified
52
53void SV_LinkEdict (edict_t *ent, qboolean touch_triggers);
54// Needs to be called any time an entity changes origin, mins, maxs, or solid
55// flags ent->v.modified
56// sets ent->v.absmin and ent->v.absmax
57// if touchtriggers, calls prog functions for the intersected triggers
58
59int SV_PointContents (vec3_t p);
60int SV_TruePointContents (vec3_t p);
61// returns the CONTENTS_* value from the world at the given point.
62// does not check any entities at all
63// the non-true version remaps the water current contents to content_water
64
65edict_t *SV_TestEntityPosition (edict_t *ent);
66
67trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);
68// mins and maxs are reletive
69
70// if the entire move stays in a solid volume, trace.allsolid will be set
71
72// if the starting point is in a solid, it will be allowed to move out
73// to an open area
74
75// nomonsters is used for line of sight or edge testing, where mosnters
76// shouldn't be considered solid objects
77
78// passedict is explicitly excluded from clipping checks (normally NULL)
diff --git a/apps/plugins/sdl/progs/quake/zone.c b/apps/plugins/sdl/progs/quake/zone.c
new file mode 100644
index 0000000000..e30d7f847f
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/zone.c
@@ -0,0 +1,935 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// Z_zone.c
21
22#include "quakedef.h"
23
24#define DYNAMIC_SIZE 0xc000
25
26#define ZONEID 0x1d4a11
27#define MINFRAGMENT 64
28
29typedef struct memblock_s
30{
31 int size; // including the header and possibly tiny fragments
32 int tag; // a tag of 0 is a free block
33 int id; // should be ZONEID
34 struct memblock_s *next, *prev;
35 int pad; // pad to 64 bit boundary
36} memblock_t;
37
38typedef struct
39{
40 int size; // total bytes malloced, including header
41 memblock_t blocklist; // start / end cap for linked list
42 memblock_t *rover;
43} memzone_t;
44
45void Cache_FreeLow (int new_low_hunk);
46void Cache_FreeHigh (int new_high_hunk);
47
48
49/*
50==============================================================================
51
52 ZONE MEMORY ALLOCATION
53
54There is never any space between memblocks, and there will never be two
55contiguous free memblocks.
56
57The rover can be left pointing at a non-empty block
58
59The zone calls are pretty much only used for small strings and structures,
60all big things are allocated on the hunk.
61==============================================================================
62*/
63
64memzone_t *mainzone;
65
66void Z_ClearZone (memzone_t *zone, int size);
67
68
69/*
70========================
71Z_ClearZone
72========================
73*/
74void Z_ClearZone (memzone_t *zone, int size)
75{
76 memblock_t *block;
77
78// set the entire zone to one free block
79
80 zone->blocklist.next = zone->blocklist.prev = block =
81 (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
82 zone->blocklist.tag = 1; // in use block
83 zone->blocklist.id = 0;
84 zone->blocklist.size = 0;
85 zone->rover = block;
86
87 block->prev = block->next = &zone->blocklist;
88 block->tag = 0; // free block
89 block->id = ZONEID;
90 block->size = size - sizeof(memzone_t);
91}
92
93
94/*
95========================
96Z_Free
97========================
98*/
99void Z_Free (void *ptr)
100{
101 memblock_t *block, *other;
102
103 if (!ptr)
104 Sys_Error ("Z_Free: NULL pointer");
105
106 block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
107 if (block->id != ZONEID)
108 Sys_Error ("Z_Free: freed a pointer without ZONEID");
109 if (block->tag == 0)
110 Sys_Error ("Z_Free: freed a freed pointer");
111
112 block->tag = 0; // mark as free
113
114 other = block->prev;
115 if (!other->tag)
116 { // merge with previous free block
117 other->size += block->size;
118 other->next = block->next;
119 other->next->prev = other;
120 if (block == mainzone->rover)
121 mainzone->rover = other;
122 block = other;
123 }
124
125 other = block->next;
126 if (!other->tag)
127 { // merge the next free block onto the end
128 block->size += other->size;
129 block->next = other->next;
130 block->next->prev = block;
131 if (other == mainzone->rover)
132 mainzone->rover = block;
133 }
134}
135
136
137/*
138========================
139Z_Malloc
140========================
141*/
142void *Z_Malloc (int size)
143{
144 void *buf;
145
146Z_CheckHeap (); // DEBUG
147 buf = Z_TagMalloc (size, 1);
148 if (!buf)
149 Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size);
150 Q_memset (buf, 0, size);
151
152 return buf;
153}
154
155void *Z_TagMalloc (int size, int tag)
156{
157 int extra;
158 memblock_t *start, *rover, *new, *base;
159
160 if (!tag)
161 Sys_Error ("Z_TagMalloc: tried to use a 0 tag");
162
163//
164// scan through the block list looking for the first free block
165// of sufficient size
166//
167 size += sizeof(memblock_t); // account for size of block header
168 size += 4; // space for memory trash tester
169 size = (size + 7) & ~7; // align to 8-byte boundary
170
171 base = rover = mainzone->rover;
172 start = base->prev;
173
174 do
175 {
176 if (rover == start) // scaned all the way around the list
177 return NULL;
178 if (rover->tag)
179 base = rover = rover->next;
180 else
181 rover = rover->next;
182 } while (base->tag || base->size < size);
183
184//
185// found a block big enough
186//
187 extra = base->size - size;
188 if (extra > MINFRAGMENT)
189 { // there will be a free fragment after the allocated block
190 new = (memblock_t *) ((byte *)base + size );
191 new->size = extra;
192 new->tag = 0; // free block
193 new->prev = base;
194 new->id = ZONEID;
195 new->next = base->next;
196 new->next->prev = new;
197 base->next = new;
198 base->size = size;
199 }
200
201 base->tag = tag; // no longer a free block
202
203 mainzone->rover = base->next; // next allocation will start looking here
204
205 base->id = ZONEID;
206
207// marker for memory trash testing
208 *(int *)((byte *)base + base->size - 4) = ZONEID;
209
210 return (void *) ((byte *)base + sizeof(memblock_t));
211}
212
213
214/*
215========================
216Z_Print
217========================
218*/
219void Z_Print (memzone_t *zone)
220{
221 memblock_t *block;
222
223 Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
224
225 for (block = zone->blocklist.next ; ; block = block->next)
226 {
227 Con_Printf ("block:%p size:%7i tag:%3i\n",
228 block, block->size, block->tag);
229
230 if (block->next == &zone->blocklist)
231 break; // all blocks have been hit
232 if ( (byte *)block + block->size != (byte *)block->next)
233 Con_Printf ("ERROR: block size does not touch the next block\n");
234 if ( block->next->prev != block)
235 Con_Printf ("ERROR: next block doesn't have proper back link\n");
236 if (!block->tag && !block->next->tag)
237 Con_Printf ("ERROR: two consecutive free blocks\n");
238 }
239}
240
241
242/*
243========================
244Z_CheckHeap
245========================
246*/
247void Z_CheckHeap (void)
248{
249 memblock_t *block;
250
251 for (block = mainzone->blocklist.next ; ; block = block->next)
252 {
253 if (block->next == &mainzone->blocklist)
254 break; // all blocks have been hit
255 if ( (byte *)block + block->size != (byte *)block->next)
256 Sys_Error ("Z_CheckHeap: block size does not touch the next block\n");
257 if ( block->next->prev != block)
258 Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
259 if (!block->tag && !block->next->tag)
260 Sys_Error ("Z_CheckHeap: two consecutive free blocks\n");
261 }
262}
263
264//============================================================================
265
266#define HUNK_SENTINAL 0x1df001ed
267
268typedef struct
269{
270 int sentinal;
271 int size; // including sizeof(hunk_t), -1 = not allocated
272 char name[8];
273} hunk_t;
274
275byte *hunk_base;
276int hunk_size;
277
278int hunk_low_used;
279int hunk_high_used;
280
281qboolean hunk_tempactive;
282int hunk_tempmark;
283
284void R_FreeTextures (void);
285
286/*
287==============
288Hunk_Check
289
290Run consistancy and sentinal trahing checks
291==============
292*/
293void Hunk_Check (void)
294{
295 hunk_t *h;
296
297 for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; )
298 {
299 if (h->sentinal != HUNK_SENTINAL)
300 Sys_Error ("Hunk_Check: trahsed sentinal");
301 if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
302 Sys_Error ("Hunk_Check: bad size");
303 h = (hunk_t *)((byte *)h+h->size);
304 }
305}
306
307/*
308==============
309Hunk_Print
310
311If "all" is specified, every single allocation is printed.
312Otherwise, allocations with the same name will be totaled up before printing.
313==============
314*/
315void Hunk_Print (qboolean all)
316{
317 hunk_t *h, *next, *endlow, *starthigh, *endhigh;
318 int count, sum;
319 int totalblocks;
320 char name[9];
321
322 name[8] = 0;
323 count = 0;
324 sum = 0;
325 totalblocks = 0;
326
327 h = (hunk_t *)hunk_base;
328 endlow = (hunk_t *)(hunk_base + hunk_low_used);
329 starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
330 endhigh = (hunk_t *)(hunk_base + hunk_size);
331
332 Con_Printf (" :%8i total hunk size\n", hunk_size);
333 Con_Printf ("-------------------------\n");
334
335 while (1)
336 {
337 //
338 // skip to the high hunk if done with low hunk
339 //
340 if ( h == endlow )
341 {
342 Con_Printf ("-------------------------\n");
343 Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used);
344 Con_Printf ("-------------------------\n");
345 h = starthigh;
346 }
347
348 //
349 // if totally done, break
350 //
351 if ( h == endhigh )
352 break;
353
354 //
355 // run consistancy checks
356 //
357 if (h->sentinal != HUNK_SENTINAL)
358 Sys_Error ("Hunk_Check: trahsed sentinal");
359 if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)
360 Sys_Error ("Hunk_Check: bad size");
361
362 next = (hunk_t *)((byte *)h+h->size);
363 count++;
364 totalblocks++;
365 sum += h->size;
366
367 //
368 // print the single block
369 //
370 memcpy (name, h->name, 8);
371 if (all)
372 Con_Printf ("%8p :%8i %8s\n",h, h->size, name);
373
374 //
375 // print the total
376 //
377 if (next == endlow || next == endhigh ||
378 strncmp (h->name, next->name, 8) )
379 {
380 if (!all)
381 Con_Printf (" :%8i %8s (TOTAL)\n",sum, name);
382 count = 0;
383 sum = 0;
384 }
385
386 h = next;
387 }
388
389 Con_Printf ("-------------------------\n");
390 Con_Printf ("%8i total blocks\n", totalblocks);
391
392}
393
394/*
395===================
396Hunk_AllocName
397===================
398*/
399void *Hunk_AllocName (int size, char *name)
400{
401 hunk_t *h;
402
403#ifdef PARANOID
404 Hunk_Check ();
405#endif
406
407 if (size < 0)
408 Sys_Error ("Hunk_Alloc: bad size: %i", size);
409
410 size = sizeof(hunk_t) + ((size+15)&~15);
411
412 if (hunk_size - hunk_low_used - hunk_high_used < size)
413 Sys_Error ("Hunk_Alloc: failed on %i bytes",size);
414
415 h = (hunk_t *)(hunk_base + hunk_low_used);
416 hunk_low_used += size;
417
418 Cache_FreeLow (hunk_low_used);
419
420 memset (h, 0, size);
421
422 h->size = size;
423 h->sentinal = HUNK_SENTINAL;
424 Q_strncpy (h->name, name, 8);
425
426 return (void *)(h+1);
427}
428
429/*
430===================
431Hunk_Alloc
432===================
433*/
434void *Hunk_Alloc (int size)
435{
436 return Hunk_AllocName (size, "unknown");
437}
438
439int Hunk_LowMark (void)
440{
441 return hunk_low_used;
442}
443
444void Hunk_FreeToLowMark (int mark)
445{
446 if (mark < 0 || mark > hunk_low_used)
447 Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark);
448 memset (hunk_base + mark, 0, hunk_low_used - mark);
449 hunk_low_used = mark;
450}
451
452int Hunk_HighMark (void)
453{
454 if (hunk_tempactive)
455 {
456 hunk_tempactive = false;
457 Hunk_FreeToHighMark (hunk_tempmark);
458 }
459
460 return hunk_high_used;
461}
462
463void Hunk_FreeToHighMark (int mark)
464{
465 if (hunk_tempactive)
466 {
467 hunk_tempactive = false;
468 Hunk_FreeToHighMark (hunk_tempmark);
469 }
470 if (mark < 0 || mark > hunk_high_used)
471 Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark);
472 memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);
473 hunk_high_used = mark;
474}
475
476
477/*
478===================
479Hunk_HighAllocName
480===================
481*/
482void *Hunk_HighAllocName (int size, char *name)
483{
484 hunk_t *h;
485
486 if (size < 0)
487 Sys_Error ("Hunk_HighAllocName: bad size: %i", size);
488
489 if (hunk_tempactive)
490 {
491 Hunk_FreeToHighMark (hunk_tempmark);
492 hunk_tempactive = false;
493 }
494
495#ifdef PARANOID
496 Hunk_Check ();
497#endif
498
499 size = sizeof(hunk_t) + ((size+15)&~15);
500
501 if (hunk_size - hunk_low_used - hunk_high_used < size)
502 {
503 Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size);
504 return NULL;
505 }
506
507 hunk_high_used += size;
508 Cache_FreeHigh (hunk_high_used);
509
510 h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);
511
512 memset (h, 0, size);
513 h->size = size;
514 h->sentinal = HUNK_SENTINAL;
515 Q_strncpy (h->name, name, 8);
516
517 return (void *)(h+1);
518}
519
520
521/*
522=================
523Hunk_TempAlloc
524
525Return space from the top of the hunk
526=================
527*/
528void *Hunk_TempAlloc (int size)
529{
530 void *buf;
531
532 size = (size+15)&~15;
533
534 if (hunk_tempactive)
535 {
536 Hunk_FreeToHighMark (hunk_tempmark);
537 hunk_tempactive = false;
538 }
539
540 hunk_tempmark = Hunk_HighMark ();
541
542 buf = Hunk_HighAllocName (size, "temp");
543
544 hunk_tempactive = true;
545
546 return buf;
547}
548
549/*
550===============================================================================
551
552CACHE MEMORY
553
554===============================================================================
555*/
556
557typedef struct cache_system_s
558{
559 int size; // including this header
560 cache_user_t *user;
561 char name[16];
562 struct cache_system_s *prev, *next;
563 struct cache_system_s *lru_prev, *lru_next; // for LRU flushing
564} cache_system_t;
565
566cache_system_t *Cache_TryAlloc (int size, qboolean nobottom);
567
568cache_system_t cache_head;
569
570/*
571===========
572Cache_Move
573===========
574*/
575void Cache_Move ( cache_system_t *c)
576{
577 cache_system_t *new;
578
579// we are clearing up space at the bottom, so only allocate it late
580 new = Cache_TryAlloc (c->size, true);
581 if (new)
582 {
583// Con_Printf ("cache_move ok\n");
584
585 Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) );
586 new->user = c->user;
587 Q_memcpy (new->name, c->name, sizeof(new->name));
588 Cache_Free (c->user);
589 new->user->data = (void *)(new+1);
590 }
591 else
592 {
593// Con_Printf ("cache_move failed\n");
594
595 Cache_Free (c->user); // tough luck...
596 }
597}
598
599/*
600============
601Cache_FreeLow
602
603Throw things out until the hunk can be expanded to the given point
604============
605*/
606void Cache_FreeLow (int new_low_hunk)
607{
608 cache_system_t *c;
609
610 while (1)
611 {
612 c = cache_head.next;
613 if (c == &cache_head)
614 return; // nothing in cache at all
615 if ((byte *)c >= hunk_base + new_low_hunk)
616 return; // there is space to grow the hunk
617 Cache_Move ( c ); // reclaim the space
618 }
619}
620
621/*
622============
623Cache_FreeHigh
624
625Throw things out until the hunk can be expanded to the given point
626============
627*/
628void Cache_FreeHigh (int new_high_hunk)
629{
630 cache_system_t *c, *prev;
631
632 prev = NULL;
633 while (1)
634 {
635 c = cache_head.prev;
636 if (c == &cache_head)
637 return; // nothing in cache at all
638 if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)
639 return; // there is space to grow the hunk
640 if (c == prev)
641 Cache_Free (c->user); // didn't move out of the way
642 else
643 {
644 Cache_Move (c); // try to move it
645 prev = c;
646 }
647 }
648}
649
650void Cache_UnlinkLRU (cache_system_t *cs)
651{
652 if (!cs->lru_next || !cs->lru_prev)
653 Sys_Error ("Cache_UnlinkLRU: NULL link");
654
655 cs->lru_next->lru_prev = cs->lru_prev;
656 cs->lru_prev->lru_next = cs->lru_next;
657
658 cs->lru_prev = cs->lru_next = NULL;
659}
660
661void Cache_MakeLRU (cache_system_t *cs)
662{
663 if (cs->lru_next || cs->lru_prev)
664 Sys_Error ("Cache_MakeLRU: active link");
665
666 cache_head.lru_next->lru_prev = cs;
667 cs->lru_next = cache_head.lru_next;
668 cs->lru_prev = &cache_head;
669 cache_head.lru_next = cs;
670}
671
672/*
673============
674Cache_TryAlloc
675
676Looks for a free block of memory between the high and low hunk marks
677Size should already include the header and padding
678============
679*/
680cache_system_t *Cache_TryAlloc (int size, qboolean nobottom)
681{
682 cache_system_t *cs, *new;
683
684// is the cache completely empty?
685
686 if (!nobottom && cache_head.prev == &cache_head)
687 {
688 if (hunk_size - hunk_high_used - hunk_low_used < size)
689 Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size);
690
691 new = (cache_system_t *) (hunk_base + hunk_low_used);
692 memset (new, 0, sizeof(*new));
693 new->size = size;
694
695 cache_head.prev = cache_head.next = new;
696 new->prev = new->next = &cache_head;
697
698 Cache_MakeLRU (new);
699 return new;
700 }
701
702// search from the bottom up for space
703
704 new = (cache_system_t *) (hunk_base + hunk_low_used);
705 cs = cache_head.next;
706
707 do
708 {
709 if (!nobottom || cs != cache_head.next)
710 {
711 if ( (byte *)cs - (byte *)new >= size)
712 { // found space
713 memset (new, 0, sizeof(*new));
714 new->size = size;
715
716 new->next = cs;
717 new->prev = cs->prev;
718 cs->prev->next = new;
719 cs->prev = new;
720
721 Cache_MakeLRU (new);
722
723 return new;
724 }
725 }
726
727 // continue looking
728 new = (cache_system_t *)((byte *)cs + cs->size);
729 cs = cs->next;
730
731 } while (cs != &cache_head);
732
733// try to allocate one at the very end
734 if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size)
735 {
736 memset (new, 0, sizeof(*new));
737 new->size = size;
738
739 new->next = &cache_head;
740 new->prev = cache_head.prev;
741 cache_head.prev->next = new;
742 cache_head.prev = new;
743
744 Cache_MakeLRU (new);
745
746 return new;
747 }
748
749 return NULL; // couldn't allocate
750}
751
752/*
753============
754Cache_Flush
755
756Throw everything out, so new data will be demand cached
757============
758*/
759void Cache_Flush (void)
760{
761 while (cache_head.next != &cache_head)
762 Cache_Free ( cache_head.next->user ); // reclaim the space
763}
764
765
766/*
767============
768Cache_Print
769
770============
771*/
772void Cache_Print (void)
773{
774 cache_system_t *cd;
775
776 for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next)
777 {
778 Con_Printf ("%8i : %s\n", cd->size, cd->name);
779 }
780}
781
782/*
783============
784Cache_Report
785
786============
787*/
788void Cache_Report (void)
789{
790 Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) );
791}
792
793/*
794============
795Cache_Compact
796
797============
798*/
799void Cache_Compact (void)
800{
801}
802
803/*
804============
805Cache_Init
806
807============
808*/
809void Cache_Init (void)
810{
811 cache_head.next = cache_head.prev = &cache_head;
812 cache_head.lru_next = cache_head.lru_prev = &cache_head;
813
814 Cmd_AddCommand ("flush", Cache_Flush);
815}
816
817/*
818==============
819Cache_Free
820
821Frees the memory and removes it from the LRU list
822==============
823*/
824void Cache_Free (cache_user_t *c)
825{
826 cache_system_t *cs;
827
828 if (!c->data)
829 Sys_Error ("Cache_Free: not allocated");
830
831 cs = ((cache_system_t *)c->data) - 1;
832
833 cs->prev->next = cs->next;
834 cs->next->prev = cs->prev;
835 cs->next = cs->prev = NULL;
836
837 c->data = NULL;
838
839 Cache_UnlinkLRU (cs);
840}
841
842
843
844/*
845==============
846Cache_Check
847==============
848*/
849void *Cache_Check (cache_user_t *c)
850{
851 cache_system_t *cs;
852
853 if (!c->data)
854 return NULL;
855
856 cs = ((cache_system_t *)c->data) - 1;
857
858// move to head of LRU
859 Cache_UnlinkLRU (cs);
860 Cache_MakeLRU (cs);
861
862 return c->data;
863}
864
865
866/*
867==============
868Cache_Alloc
869==============
870*/
871void *Cache_Alloc (cache_user_t *c, int size, char *name)
872{
873 cache_system_t *cs;
874
875 if (c->data)
876 Sys_Error ("Cache_Alloc: allready allocated");
877
878 if (size <= 0)
879 Sys_Error ("Cache_Alloc: size %i", size);
880
881 size = (size + sizeof(cache_system_t) + 15) & ~15;
882
883// find memory for it
884 while (1)
885 {
886 cs = Cache_TryAlloc (size, false);
887 if (cs)
888 {
889 strncpy (cs->name, name, sizeof(cs->name)-1);
890 c->data = (void *)(cs+1);
891 cs->user = c;
892 break;
893 }
894
895 // free the least recently used cahedat
896 if (cache_head.lru_prev == &cache_head)
897 Sys_Error ("Cache_Alloc: out of memory");
898 // not enough memory at all
899 Cache_Free ( cache_head.lru_prev->user );
900 }
901
902 return Cache_Check (c);
903}
904
905//============================================================================
906
907
908/*
909========================
910Memory_Init
911========================
912*/
913void Memory_Init (void *buf, int size)
914{
915 int p;
916 int zonesize = DYNAMIC_SIZE;
917
918 hunk_base = buf;
919 hunk_size = size;
920 hunk_low_used = 0;
921 hunk_high_used = 0;
922
923 Cache_Init ();
924 p = COM_CheckParm ("-zone");
925 if (p)
926 {
927 if (p < com_argc-1)
928 zonesize = Q_atoi (com_argv[p+1]) * 1024;
929 else
930 Sys_Error ("Memory_Init: you must specify a size in KB after -zone");
931 }
932 mainzone = Hunk_AllocName (zonesize, "zone" );
933 Z_ClearZone (mainzone, zonesize);
934}
935
diff --git a/apps/plugins/sdl/progs/quake/zone.h b/apps/plugins/sdl/progs/quake/zone.h
new file mode 100644
index 0000000000..7655ad9c08
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/zone.h
@@ -0,0 +1,131 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20/*
21 memory allocation
22
23
24H_??? The hunk manages the entire memory block given to quake. It must be
25contiguous. Memory can be allocated from either the low or high end in a
26stack fashion. The only way memory is released is by resetting one of the
27pointers.
28
29Hunk allocations should be given a name, so the Hunk_Print () function
30can display usage.
31
32Hunk allocations are guaranteed to be 16 byte aligned.
33
34The video buffers are allocated high to avoid leaving a hole underneath
35server allocations when changing to a higher video mode.
36
37
38Z_??? Zone memory functions used for small, dynamic allocations like text
39strings from command input. There is only about 48K for it, allocated at
40the very bottom of the hunk.
41
42Cache_??? Cache memory is for objects that can be dynamically loaded and
43can usefully stay persistant between levels. The size of the cache
44fluctuates from level to level.
45
46To allocate a cachable object
47
48
49Temp_??? Temp memory is used for file loading and surface caching. The size
50of the cache memory is adjusted so that there is a minimum of 512k remaining
51for temp memory.
52
53
54------ Top of Memory -------
55
56high hunk allocations
57
58<--- high hunk reset point held by vid
59
60video buffer
61
62z buffer
63
64surface cache
65
66<--- high hunk used
67
68cachable memory
69
70<--- low hunk used
71
72client and server low hunk allocations
73
74<-- low hunk reset point held by host
75
76startup hunk allocations
77
78Zone block
79
80----- Bottom of Memory -----
81
82
83
84*/
85
86void Memory_Init (void *buf, int size);
87
88void Z_Free (void *ptr);
89void *Z_Malloc (int size); // returns 0 filled memory
90void *Z_TagMalloc (int size, int tag);
91
92void Z_DumpHeap (void);
93void Z_CheckHeap (void);
94int Z_FreeMemory (void);
95
96void *Hunk_Alloc (int size); // returns 0 filled memory
97void *Hunk_AllocName (int size, char *name);
98
99void *Hunk_HighAllocName (int size, char *name);
100
101int Hunk_LowMark (void);
102void Hunk_FreeToLowMark (int mark);
103
104int Hunk_HighMark (void);
105void Hunk_FreeToHighMark (int mark);
106
107void *Hunk_TempAlloc (int size);
108
109void Hunk_Check (void);
110
111typedef struct cache_user_s
112{
113 void *data;
114} cache_user_t;
115
116void Cache_Flush (void);
117
118void *Cache_Check (cache_user_t *c);
119// returns the cached data, and moves to the head of the LRU list
120// if present, otherwise returns NULL
121
122void Cache_Free (cache_user_t *c);
123
124void *Cache_Alloc (cache_user_t *c, int size, char *name);
125// Returns NULL if all purgable data was tossed and there still
126// wasn't enough room.
127
128void Cache_Report (void);
129
130
131
diff --git a/apps/plugins/sdl/sdl.make b/apps/plugins/sdl/sdl.make
index 492284e333..a00948da28 100644
--- a/apps/plugins/sdl/sdl.make
+++ b/apps/plugins/sdl/sdl.make
@@ -13,34 +13,46 @@ SDL_OBJDIR := $(BUILDDIR)/apps/plugins/sdl
13SDL_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES) 13SDL_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES)
14DUKE3D_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES.duke) 14DUKE3D_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES.duke)
15WOLF3D_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES.wolf) 15WOLF3D_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES.wolf)
16QUAKE_SRC := $(call preprocess, $(SDL_SRCDIR)/SOURCES.quake)
16 17
17SDL_OBJ := $(call c2obj, $(SDL_SRC)) 18SDL_OBJ := $(call c2obj, $(SDL_SRC))
18DUKE3D_OBJ = $(call c2obj, $(DUKE3D_SRC)) 19DUKE3D_OBJ = $(call c2obj, $(DUKE3D_SRC))
19WOLF3D_OBJ = $(call c2obj, $(WOLF3D_SRC)) 20WOLF3D_OBJ = $(call c2obj, $(WOLF3D_SRC))
21QUAKE_OBJ = $(call c2obj, $(QUAKE_SRC))
20 22
21# add source files to OTHER_SRC to get automatic dependencies 23# add source files to OTHER_SRC to get automatic dependencies
22OTHER_SRC += $(SDL_SRC) $(DUKE3D_SRC) $(WOLF3D_SRC) 24OTHER_SRC += $(SDL_SRC) $(DUKE3D_SRC) $(WOLF3D_SRC) $(QUAKE_SRC)
23OTHER_INC += -I$(SDL_SRCDIR)/include 25OTHER_INC += -I$(SDL_SRCDIR)/include
24 26
25# include comes first because of possible system SDL headers taking 27# include comes first because of possible system SDL headers taking
26# precedence 28# precedence
27SDLFLAGS = -I$(SDL_SRCDIR)/include $(filter-out -O%,$(PLUGINFLAGS)) \ 29# some of these are for Quake only
28-O3 -Wno-unused-parameter -Xpreprocessor -Wno-undef -Wcast-align -w 30SDLFLAGS = -I$(SDL_SRCDIR)/include $(filter-out -O%,$(PLUGINFLAGS)) \
31-O3 -Wno-unused-parameter -Xpreprocessor -Wno-undef -Wcast-align \
32-ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations \
33-D_GNU_SOURCE=1 -D_REENTRANT -DSDL -DELF -w # disable all warnings
29 34
35# use FPU on ARMv6
30ifeq ($(ARCH_VERSION),6) 36ifeq ($(ARCH_VERSION),6)
31 SDLFLAGS += -mfloat-abi=softfp 37 SDLFLAGS += -mfloat-abi=softfp
32endif 38endif
33 39
34ifndef APP_TYPE 40ifndef APP_TYPE
35 ### no target has a big enough plugin buffer 41 ### no target has a big enough plugin buffer
36 ROCKS += $(SDL_OBJDIR)/duke3d.ovl $(SDL_OBJDIR)/wolf3d.ovl 42 ROCKS += $(SDL_OBJDIR)/duke3d.ovl
43 ROCKS += $(SDL_OBJDIR)/wolf3d.ovl
44 ROCKS += $(SDL_OBJDIR)/quake.ovl
45
37 DUKE3D_OUTLDS = $(SDL_OBJDIR)/duke3d.link 46 DUKE3D_OUTLDS = $(SDL_OBJDIR)/duke3d.link
38 WOLF3D_OUTLDS = $(SDL_OBJDIR)/wolf3d.link 47 WOLF3D_OUTLDS = $(SDL_OBJDIR)/wolf3d.link
48 QUAKE_OUTLDS = $(SDL_OBJDIR)/quake.link
49
39 SDL_OVLFLAGS = -Wl,--gc-sections -Wl,-Map,$(basename $@).map 50 SDL_OVLFLAGS = -Wl,--gc-sections -Wl,-Map,$(basename $@).map
40else 51else
41 ### simulator 52 ### simulator
42 ROCKS += $(SDL_OBJDIR)/duke3d.rock 53 ROCKS += $(SDL_OBJDIR)/duke3d.rock
43 ROCKS += $(SDL_OBJDIR)/wolf3d.rock 54 ROCKS += $(SDL_OBJDIR)/wolf3d.rock
55 ROCKS += $(SDL_OBJDIR)/quake.rock
44endif 56endif
45 57
46# Duke3D 58# Duke3D
@@ -77,6 +89,26 @@ $(SDL_OBJDIR)/wolf3d.ovl: $(SDL_OBJ) $(WOLF3D_OBJ) $(TLSFLIB) $(WOLF3D_OUTLDS)
77 -lgcc -T$(WOLF3D_OUTLDS) $(SDL_OVLFLAGS) 89 -lgcc -T$(WOLF3D_OUTLDS) $(SDL_OVLFLAGS)
78 $(call PRINTS,LD $(@F))$(call objcopy,$(basename $@).elf,$@) 90 $(call PRINTS,LD $(@F))$(call objcopy,$(basename $@).elf,$@)
79 91
92# Quake
93###
94
95$(SDL_OBJDIR)/quake.rock: $(SDL_OBJ) $(QUAKE_OBJ) $(TLSFLIB)
96
97$(SDL_OBJDIR)/quake.refmap: $(SDL_OBJ) $(QUAKE_OBJ) $(TLSFLIB)
98
99$(QUAKE_OUTLDS): $(PLUGIN_LDS) $(SDL_OBJDIR)/quake.refmap
100 $(call PRINTS,PP $(@F))$(call preprocess2file,$<,$@,-DOVERLAY_OFFSET=$(shell \
101 $(TOOLSDIR)/ovl_offset.pl $(SDL_OBJDIR)/quake.refmap))
102
103$(SDL_OBJDIR)/quake.ovl: $(SDL_OBJ) $(QUAKE_OBJ) $(TLSFLIB) $(QUAKE_OUTLDS)
104 $(SILENT)$(CC) $(PLUGINFLAGS) -o $(basename $@).elf \
105 $(filter %.o, $^) \
106 $(filter %.a, $+) \
107 -lgcc -T$(QUAKE_OUTLDS) $(SDL_OVLFLAGS)
108 $(call PRINTS,LD $(@F))$(call objcopy,$(basename $@).elf,$@)
109
110###
111
80# common 112# common
81 113
82$(SDL_OBJDIR)/%.o: $(SDL_SRCDIR)/%.c $(SDL_SRCDIR)/sdl.make $(BUILDDIR)/sysfont.h 114$(SDL_OBJDIR)/%.o: $(SDL_SRCDIR)/%.c $(SDL_SRCDIR)/sdl.make $(BUILDDIR)/sysfont.h
diff --git a/apps/plugins/sdl/src/audio/SDL_audio.c b/apps/plugins/sdl/src/audio/SDL_audio.c
index 9c0feeddfc..f2a2e59323 100644
--- a/apps/plugins/sdl/src/audio/SDL_audio.c
+++ b/apps/plugins/sdl/src/audio/SDL_audio.c
@@ -204,6 +204,7 @@ int SDLCALL SDL_RunAudio(void *audiop)
204 204
205 /* Convert the audio if necessary */ 205 /* Convert the audio if necessary */
206 if ( audio->convert.needed ) { 206 if ( audio->convert.needed ) {
207 LOGF("RB AUDIO: converting audio. Will be slow!");
207 SDL_ConvertAudio(&audio->convert); 208 SDL_ConvertAudio(&audio->convert);
208 stream = audio->GetAudioBuf(audio); 209 stream = audio->GetAudioBuf(audio);
209 if ( stream == NULL ) { 210 if ( stream == NULL ) {
diff --git a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c
index 78334303af..cb72687d48 100644
--- a/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c
+++ b/apps/plugins/sdl/src/audio/rockbox/SDL_rockboxaudio.c
@@ -225,12 +225,29 @@ static void ROCKBOXAUD_CloseAudio(_THIS)
225 rb->pcm_set_frequency(HW_SAMPR_DEFAULT); 225 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
226} 226}
227 227
228static bool freq_ok(unsigned int freq)
229{
230 for(int i = 0; i < SAMPR_NUM_FREQ; i++)
231 {
232 if(rb->hw_freq_sampr[i] == freq)
233 return true;
234 }
235 return false;
236}
237
228static int ROCKBOXAUD_OpenAudio(_THIS, SDL_AudioSpec *spec) 238static int ROCKBOXAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
229{ 239{
230 /* change to our format */ 240 /* change to our format */
231 spec->format = AUDIO_S16SYS; 241 spec->format = AUDIO_S16SYS;
232 spec->channels = 2; 242 spec->channels = 2;
233 spec->freq = RB_SAMPR; 243
244 if(!freq_ok(spec->freq))
245 {
246 rb->splashf(HZ, "Warning: Unsupported audio rate. Defaulting to %d Hz", RB_SAMPR);
247
248 // switch to default
249 spec->freq = RB_SAMPR;
250 }
234 251
235 /* we've changed it */ 252 /* we've changed it */
236 SDL_CalculateAudioSpec(spec); 253 SDL_CalculateAudioSpec(spec);
diff --git a/apps/plugins/sdl/src/thread/rockbox/SDL_systhread.c b/apps/plugins/sdl/src/thread/rockbox/SDL_systhread.c
index f9dc877815..b9bd8735d3 100644
--- a/apps/plugins/sdl/src/thread/rockbox/SDL_systhread.c
+++ b/apps/plugins/sdl/src/thread/rockbox/SDL_systhread.c
@@ -51,13 +51,13 @@ int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
51 static int threadnum = 0; 51 static int threadnum = 0;
52 snprintf(names[threadnum], 16, "sdl_%d", threadnum); 52 snprintf(names[threadnum], 16, "sdl_%d", threadnum);
53 53
54 while(global_args) rb->yield(); /* busy wait */ 54 while(global_args) rb->yield(); /* busy wait, pray that this works */
55 55
56 global_args = args; 56 global_args = args;
57 57
58 thread->handle = rb->create_thread(rbsdl_runthread, stacks[threadnum], DEFAULT_STACK_SIZE, 58 thread->handle = rb->create_thread(rbsdl_runthread, stacks[threadnum], DEFAULT_STACK_SIZE,
59 0, names[threadnum] /* collisions allowed? */ 59 0, names[threadnum] /* collisions allowed? */
60 IF_PRIO(, PRIORITY_USER_INTERFACE) 60 IF_PRIO(, PRIORITY_BUFFERING) // this is used for sound mixing
61 IF_COP(, CPU)); 61 IF_COP(, CPU));
62 62
63 threadnum++; 63 threadnum++;
diff --git a/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c b/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c
index f4e886260c..8da84552c5 100644
--- a/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c
+++ b/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c
@@ -28,6 +28,7 @@
28 28
29#include "plugin.h" 29#include "plugin.h"
30 30
31/* color because greylib will use timer otherwise */
31#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) && !defined(RB_PROFILE) 32#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) && !defined(RB_PROFILE)
32#define USE_TIMER 33#define USE_TIMER
33#endif 34#endif
diff --git a/apps/plugins/sdl/src/video/rockbox/SDL_rockboxvideo.c b/apps/plugins/sdl/src/video/rockbox/SDL_rockboxvideo.c
index 58de15754d..3a12d984b8 100644
--- a/apps/plugins/sdl/src/video/rockbox/SDL_rockboxvideo.c
+++ b/apps/plugins/sdl/src/video/rockbox/SDL_rockboxvideo.c
@@ -769,8 +769,8 @@ static void ROCKBOX_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
769 /* FIXME: this won't work for rotated screen or overlapping rects */ 769 /* FIXME: this won't work for rotated screen or overlapping rects */
770 flip_pixels(rects[i].x, rects[i].y, rects[i].w, rects[i].h); 770 flip_pixels(rects[i].x, rects[i].y, rects[i].w, rects[i].h);
771#endif 771#endif
772 rb->lcd_update_rect(rects[i].x, rects[i].y, rects[i].w, rects[i].h);
772 } /* for */ 773 } /* for */
773 rb->lcd_update();
774 } /* if */ 774 } /* if */
775} 775}
776 776
diff --git a/apps/plugins/sdl/wrappers.c b/apps/plugins/sdl/wrappers.c
index ee512dd573..02e9db1992 100644
--- a/apps/plugins/sdl/wrappers.c
+++ b/apps/plugins/sdl/wrappers.c
@@ -165,9 +165,80 @@ static double rb_strtod(const char *str, char **endptr)
165 return number; 165 return number;
166} 166}
167 167
168double atof_wrapper(const char *str) 168// stolen from Quake
169float atof_wrapper (char *str)
169{ 170{
170 return rb_strtod(str, NULL); 171 double val;
172 int sign;
173 int c;
174 int decimal, total;
175
176 if (*str == '-')
177 {
178 sign = -1;
179 str++;
180 }
181 else
182 sign = 1;
183
184 val = 0;
185
186//
187// check for hex
188//
189 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
190 {
191 str += 2;
192 while (1)
193 {
194 c = *str++;
195 if (c >= '0' && c <= '9')
196 val = (val*16) + c - '0';
197 else if (c >= 'a' && c <= 'f')
198 val = (val*16) + c - 'a' + 10;
199 else if (c >= 'A' && c <= 'F')
200 val = (val*16) + c - 'A' + 10;
201 else
202 return val*sign;
203 }
204 }
205
206//
207// check for character
208//
209 if (str[0] == '\'')
210 {
211 return sign * str[1];
212 }
213
214//
215// assume decimal
216//
217 decimal = -1;
218 total = 0;
219 while (1)
220 {
221 c = *str++;
222 if (c == '.')
223 {
224 decimal = total;
225 continue;
226 }
227 if (c <'0' || c > '9')
228 break;
229 val = val*10 + c - '0';
230 total++;
231 }
232
233 if (decimal == -1)
234 return val*sign;
235 while (total > decimal)
236 {
237 val /= 10;
238 total--;
239 }
240
241 return val*sign;
171} 242}
172 243
173double sin_wrapper(double rads) 244double sin_wrapper(double rads)
@@ -217,6 +288,51 @@ float tan_wrapper(float f)
217 return sin_wrapper(f)/cos_wrapper(f); 288 return sin_wrapper(f)/cos_wrapper(f);
218} 289}
219 290
291// Total hack. Supports only format strings of the form %Cc, where C
292// is a format specifier and c is a delimiter. Surprisingly, most
293// format strings aren't that complicated to need a real fscanf. This
294// is just enough to make Quake run!
295int fscanf_wrapper(FILE *f, const char *fmt, ...)
296{
297 va_list ap;
298
299 va_start(ap, fmt);
300
301 if(strlen(fmt) != 3)
302 return 0; // not implemented
303
304 if(fmt[0] != '%')
305 return 0; // not implemented
306
307 char format = fmt[1];
308 char delim = fmt[2];
309
310 // extract argument
311 char buf[1024];
312 char *ptr = (format == 's' ? va_arg(ap, char*) : buf);
313 int c;
314 do {
315 c = fgetc(f);
316 *ptr++ = c;
317 } while(c != delim && c != EOF);
318
319 // overwrite delimiter
320 *(ptr-1) = 0;
321
322 //rb->splashf(HZ, "got argument %s, %s\n", fmt, buf);
323
324 switch(format)
325 {
326 case 'i':
327 *va_arg(ap, int*) = atoi(buf);
328 break;
329 case 'f':
330 *va_arg(ap, float*) = atof(buf);
331 break;
332 }
333 return 1;
334}
335
220/* stolen from doom */ 336/* stolen from doom */
221// Here is a hacked up printf command to get the output from the game. 337// Here is a hacked up printf command to get the output from the game.
222int printf_wrapper(const char *fmt, ...) 338int printf_wrapper(const char *fmt, ...)
@@ -272,7 +388,7 @@ int vsprintf_wrapper(char *str, const char *fmt, va_list ap)
272 388
273char *strcpy_wrapper(char *dest, const char *src) 389char *strcpy_wrapper(char *dest, const char *src)
274{ 390{
275 rb->strlcpy(dest, src, 999); 391 strlcpy(dest, src, 999);
276 return dest; 392 return dest;
277} 393}
278 394
diff --git a/docs/CREDITS b/docs/CREDITS
index 09be17090d..cef7a2ee40 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -711,3 +711,4 @@ The SDL team
711The Chocolate Duke Nukem 3D team 711The Chocolate Duke Nukem 3D team
712The Wolfenstein 3D team 712The Wolfenstein 3D team
713The MAME team 713The MAME team
714The Quake team
diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex
index 5b13829b65..c07d106024 100644
--- a/manual/plugins/main.tex
+++ b/manual/plugins/main.tex
@@ -76,6 +76,8 @@ text files%
76 76
77\opt{lcd_bitmap}{\input{plugins/pong.tex}} 77\opt{lcd_bitmap}{\input{plugins/pong.tex}}
78 78
79\opt{lcd_color}{\nopt{lowmem,iaudiox5,iriverh300}{\input{plugins/quake.tex}}}
80
79\opt{lcd_bitmap}{\input{plugins/reversi.tex}} 81\opt{lcd_bitmap}{\input{plugins/reversi.tex}}
80 82
81\opt{lcd_bitmap}{\input{plugins/robotfindskitten.tex}} 83\opt{lcd_bitmap}{\input{plugins/robotfindskitten.tex}}
diff --git a/manual/plugins/quake.tex b/manual/plugins/quake.tex
new file mode 100644
index 0000000000..e7a9367a6e
--- /dev/null
+++ b/manual/plugins/quake.tex
@@ -0,0 +1,15 @@
1\subsection{Quake}
2
3This is id Software's \emph{Quake}, first released in 1996. The game
4features a Gothic atmosphere and full 3D graphics.
5
6\subsubsection{Installation}
7Copy the game data files into \fname{/.rockbox/quake} on your
8device. There should be an \fname{id1/} directory with a {.pak}
9file. The shareware version is known to work.
10
11\subsubsection{Configuration}
12It is possible to customize the game controls through the
13\emph{Options > Customize Controls} menu. Currently a limitation
14exists which prevents one key from being bound to more than one
15function.