commit db613ab35d02bb2bbb30d0a9e2d27e69d9623712 Author: Ozkan Sezer Date: Mon Feb 15 23:26:55 2010 +0000 initial import of SDL port of Fitzquake-0.85 / 20090510 sources. git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@2 af15c1b1-3010-417e-b628-4374ebc0bcbd diff --git a/Linux/Fitzquake.cbp b/Linux/Fitzquake.cbp new file mode 100644 index 00000000..6ab12cb0 --- /dev/null +++ b/Linux/Fitzquake.cbp @@ -0,0 +1,285 @@ + + + + + + diff --git a/Linux/Fitzquake.depend b/Linux/Fitzquake.depend new file mode 100644 index 00000000..ed04cb68 --- /dev/null +++ b/Linux/Fitzquake.depend @@ -0,0 +1,1169 @@ +# depslib dependency file v1.0 +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cd_sdl.c + "quakedef.h" + +1199704471 h" + +1199750385 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\quakedef.h + + + + + + + "common.h" + "bspfile.h" + "vid.h" + "sys.h" + "zone.h" + "mathlib.h" + "SDL/SDL.h" + "SDL/SDL_opengl.h" + "wad.h" + "draw.h" + "cvar.h" + "screen.h" + "net.h" + "protocol.h" + "cmd.h" + "sbar.h" + "sound.h" + "render.h" + "client.h" + "progs.h" + "server.h" + "gl_model.h" + "input.h" + "world.h" + "keys.h" + "console.h" + "view.h" + "menu.h" + "crc.h" + "cdaudio.h" + "glquake.h" + "image.h" + "gl_texmgr.h" + +1199052373 .h" + +1199731904 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\common.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\bspfile.h + +1199704472 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\vid.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sys.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\zone.h + +1199733698 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\mathlib.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\wad.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\draw.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cvar.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\screen.h + +1199704472 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\protocol.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cmd.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sbar.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sound.h + +1199704472 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\render.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\client.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progs.h + "pr_comp.h" + "progdefs.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_comp.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progdefs.h + "progdefs.q1" + +1199704471 q1" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progdefs.q1 + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\server.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_model.h + "modelgen.h" + "spritegn.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\modelgen.h + + + + + "cmdlib.h" + "scriplib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1199704471 " + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\spritegn.h + + + + + "cmdlib.h" + "scriplib.h" + "dictlib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\input.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\world.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\keys.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\console.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\view.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\menu.h + +1199733161 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\crc.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cdaudio.h + +1200313846 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\glquake.h + +1093037525 c:\programme\sdl\include\sdl_opengl.h + + + + + + + + +1199704471 + +1199733161 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\image.h + +1199728779 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_texmgr.h + +1200313846 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\chase.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_demo.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_input.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_main.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_parse.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_tent.c + "quakedef.h" + +1200313846 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cmd.c + "quakedef.h" + +1199704472 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\common.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\conproc.c + + "conproc.h" + "quakedef.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\conproc.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\console.c + + + + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\crc.c + "quakedef.h" + "crc.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cvar.c + "quakedef.h" + +1199737988 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_draw.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_fog.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_mesh.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_model.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_refrag.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rlight.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rmain.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rmisc.c + "quakedef.h" + +1199734266 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_screen.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_sky.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_test.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_texmgr.c + "quakedef.h" + "imdebug-0.931b-bin/imdebug.h" + +1199704471 .931b-bin/imdebug.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_opengl.h + "SDL_config.h" + + + + + + + + + + +1199733161 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\platform.h + "SDL/SDL.h" + "SDL/SDL_opengl.h" + +1199733161 pengl.h" + +1199052373 c:\programme\sdl\include\sdl\sdl.h + "SDL_main.h" + "SDL_stdinc.h" + "SDL_audio.h" + "SDL_cdrom.h" + "SDL_cpuinfo.h" + "SDL_endian.h" + "SDL_error.h" + "SDL_events.h" + "SDL_loadso.h" + "SDL_mutex.h" + "SDL_rwops.h" + "SDL_thread.h" + "SDL_timer.h" + "SDL_video.h" + "SDL_version.h" + "begin_code.h" + "close_code.h" + +1199052373 e.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_main.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + "begin_code.h" + "close_code.h" + +1090382006 c:\programme\sdl\include\sdl\sdl_types.h + +1199052373 c:\programme\sdl\include\sdl\begin_code.h + +1199052373 c:\programme\sdl\include\sdl\close_code.h + +1018532113 c:\programme\sdl\include\sdl\sdl_getenv.h + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_error.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_rwops.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_timer.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_audio.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_endian.h" + "SDL_mutex.h" + "SDL_thread.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1100297357 c:\programme\sdl\include\sdl\sdl_byteorder.h + +1199052373 c:\programme\sdl\include\sdl\sdl_cdrom.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_joystick.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_events.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_active.h" + "SDL_keyboard.h" + "SDL_mouse.h" + "SDL_joystick.h" + "SDL_quit.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_active.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_keyboard.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_keysym.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_keysym.h + +1199052373 c:\programme\sdl\include\sdl\sdl_mouse.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_video.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_video.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_mutex.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_quit.h + "SDL_stdinc.h" + "SDL_error.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_version.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_stdinc.h + "SDL_config.h" + + + + + + + + + + + + + + + + + "begin_code.h" + + + + + + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_config.h + "SDL_platform.h" + + +1199052373 c:\programme\sdl\include\sdl\sdl_platform.h + +1199052373 c:\programme\sdl\include\sdl\sdl_endian.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_thread.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_mutex.h" + "begin_code.h" + + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_cpuinfo.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199052373 c:\programme\sdl\include\sdl\sdl_loadso.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1200313903 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_vidsdl.c + "quakedef.h" + "resource.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\resource.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_warp.c + "quakedef.h" + "gl_warp_sin.h" + +1199704471 in.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_warp_sin.h + +1199734266 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\host.c + "quakedef.h" + +1200313846 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\host_cmd.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\image.c + "quakedef.h" + +1199728353 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\in_sdl.c + "quakedef.h" + +1199734266 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\keys.c + "quakedef.h" + +1199704472 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\main.c + + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\mathlib.c + + "quakedef.h" + +1199750385 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\menu.c + "quakedef.h" + +1199750802 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_dgrm.c + + + + "quakedef.h" + "net_dgrm.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_dgrm.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_loop.c + "quakedef.h" + "net_loop.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_loop.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_main.c + "quakedef.h" + +1199704472 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_sdl.c + "quakedef.h" + "net_loop.h" + "net_dgrm.h" + "net_ser.h" + "net_wins.h" + "net_wipx.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_ser.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_wins.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_wipx.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_cmds.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_edict.c + "quakedef.h" + +1199704472 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_exec.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_alias.c + "quakedef.h" + "anorms.h" + "anorm_dots.h" + +1199704471 s.h" + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\anorms.h + +1199704471 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\anorm_dots.h + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_brush.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_part.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_sprite.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_world.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sbar.c + "quakedef.h" + +1199734266 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_dma.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_mem.c + "quakedef.h" + +1199734266 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_mix.c + "quakedef.h" + +1199728353 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_sdl.c + + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_main.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_move.c + "quakedef.h" + +1199704472 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_phys.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_user.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sys_sdl.c + "quakedef.h" + + "errno.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\test.c + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\view.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\wad.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\world.c + "quakedef.h" + +1199704471 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\zone.c + "quakedef.h" + +1199801563 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\windows\main.c + + "../Quake/quakedef.h" + +1199801563 quakedef.h" + +1200429830 source:/home/kristian/Desktop/Fitzquake/Linux/main.c + + "../Quake/quakedef.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/quakedef.h + + + + + + + "common.h" + "bspfile.h" + "vid.h" + "sys.h" + "zone.h" + "mathlib.h" + "platform.h" + "SDL/SDL.h" + "SDL/SDL_opengl.h" + "wad.h" + "draw.h" + "cvar.h" + "screen.h" + "net.h" + "protocol.h" + "cmd.h" + "sbar.h" + "sound.h" + "render.h" + "client.h" + "progs.h" + "server.h" + "gl_model.h" + "input.h" + "world.h" + "keys.h" + "console.h" + "view.h" + "menu.h" + "crc.h" + "cdaudio.h" + "glquake.h" + "image.h" + "gl_texmgr.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/common.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/bspfile.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/vid.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/sys.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/zone.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/mathlib.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/wad.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/draw.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/cvar.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/screen.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/protocol.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/cmd.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/sbar.h + +1204383897 /home/kristian/Desktop/Fitzquake/Quake/sound.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/render.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/client.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/progs.h + "pr_comp.h" + "progdefs.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/pr_comp.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/progdefs.h + "progdefs.q1" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/progdefs.q1 + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/server.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/gl_model.h + "modelgen.h" + "spritegn.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/modelgen.h + + + + + "cmdlib.h" + "scriplib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/spritegn.h + + + + + "cmdlib.h" + "scriplib.h" + "dictlib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/input.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/world.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/keys.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/console.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/view.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/menu.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/crc.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/cdaudio.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/glquake.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/image.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/gl_texmgr.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cd_sdl.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/chase.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cl_demo.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cl_input.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cl_main.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cl_parse.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cl_tent.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cmd.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/common.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/console.c + + + + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/crc.c + "quakedef.h" + "crc.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/cvar.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_draw.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/gl_fog.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_mesh.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_model.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_refrag.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_rlight.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_rmain.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_rmisc.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/gl_screen.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_sky.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_test.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_texmgr.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_vidsdl.c + "quakedef.h" + "resource.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/resource.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/gl_warp.c + "quakedef.h" + "gl_warp_sin.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/gl_warp_sin.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/host.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/host_cmd.c + + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/image.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/in_sdl.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/keys.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/mathlib.c + + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/menu.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/net_dgrm.c + + + + "quakedef.h" + "net_dgrm.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net_dgrm.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/net_loop.c + "quakedef.h" + "net_loop.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net_loop.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/net_main.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/net_sdl.c + "quakedef.h" + "net_loop.h" + "net_dgrm.h" + "net_sdlnet.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net_ser.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net_wins.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/net_wipx.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/pr_cmds.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/pr_edict.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/pr_exec.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/r_alias.c + "quakedef.h" + "anorms.h" + "anorm_dots.h" + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/anorms.h + +1204383782 /home/kristian/Desktop/Fitzquake/Quake/anorm_dots.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/r_brush.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/r_part.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/r_sprite.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/r_world.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/sbar.c + "quakedef.h" + +1204383897 source:/home/kristian/Desktop/Fitzquake/Quake/snd_dma.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/snd_mem.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/snd_mix.c + "quakedef.h" + +1204383897 source:/home/kristian/Desktop/Fitzquake/Quake/snd_sdl.c + + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/sv_main.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/sv_move.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/sv_phys.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/sv_user.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/sys_sdl.c + "quakedef.h" + "errno.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/test.c + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/view.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/wad.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/world.c + "quakedef.h" + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/zone.c + "quakedef.h" + +1215264371 source:/home/kristian/Desktop/Fitzquake/Quake/main.c + + "quakedef.h" + +1215264371 /home/kristian/Desktop/Fitzquake/Quake/platform.h + +1204383782 source:/home/kristian/Desktop/Fitzquake/Quake/pl_linux.c + "quakedef.h" + +1215264371 /home/kristian/Desktop/Fitzquake/Quake/net_sdlnet.h + +1215265607 source:/home/kristian/Desktop/Fitzquake/Quake/net_sdlnet.c + "quakedef.h" + + + + "net_sdlnet.h" + +1150927708 /usr/include/SDL/SDL_net.h + "SDL.h" + "SDL_endian.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL.h + "SDL_main.h" + "SDL_stdinc.h" + "SDL_audio.h" + "SDL_cdrom.h" + "SDL_cpuinfo.h" + "SDL_endian.h" + "SDL_error.h" + "SDL_events.h" + "SDL_loadso.h" + "SDL_mutex.h" + "SDL_rwops.h" + "SDL_thread.h" + "SDL_timer.h" + "SDL_video.h" + "SDL_version.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_main.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_stdinc.h + "SDL_config.h" + + + + + + + + + + + + + + + + + "begin_code.h" + + + + + "close_code.h" + +1186756365 /usr/include/SDL/SDL_config.h + "SDL_platform.h" + + +1186756365 /usr/include/SDL/SDL_platform.h + +1186756365 /usr/include/SDL/begin_code.h + +1186756365 /usr/include/SDL/close_code.h + +1186756365 /usr/include/SDL/SDL_audio.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_endian.h" + "SDL_mutex.h" + "SDL_thread.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_error.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_endian.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_mutex.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_thread.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_mutex.h" + "begin_code.h" + + "close_code.h" + +1186756365 /usr/include/SDL/SDL_rwops.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_cdrom.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_cpuinfo.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_events.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_active.h" + "SDL_keyboard.h" + "SDL_mouse.h" + "SDL_joystick.h" + "SDL_quit.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_active.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_keyboard.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_keysym.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_keysym.h + +1186756365 /usr/include/SDL/SDL_mouse.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_video.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_video.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_joystick.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_quit.h + "SDL_stdinc.h" + "SDL_error.h" + +1186756365 /usr/include/SDL/SDL_loadso.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_timer.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1186756365 /usr/include/SDL/SDL_version.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + diff --git a/Linux/Fitzquake.layout b/Linux/Fitzquake.layout new file mode 100644 index 00000000..7d7f07cf --- /dev/null +++ b/Linux/Fitzquake.layout @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Linux/Fitzquake.workspace b/Linux/Fitzquake.workspace new file mode 100644 index 00000000..5a4ed4a9 --- /dev/null +++ b/Linux/Fitzquake.workspace @@ -0,0 +1,6 @@ + + + + + + diff --git a/Linux/cb.bmp b/Linux/cb.bmp new file mode 100644 index 00000000..f912a9e6 Binary files /dev/null and b/Linux/cb.bmp differ diff --git a/Mac OS X/AppController.h b/Mac OS X/AppController.h new file mode 100644 index 00000000..6f45f9ca --- /dev/null +++ b/Mac OS X/AppController.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import +#import +#import "QuakeArguments.h"; + +extern NSString *FQPrefCommandLineKey; +extern NSString *FQPrefFullscreenKey; +extern NSString *FQPrefScreenModeKey; +extern NSString *FQPrefShowDialog; + +@interface AppController : NSObject { + IBOutlet NSWindow *launcherWindow; + IBOutlet NSTextField *paramTextField; + IBOutlet NSPopUpButton *screenModePopUp; + IBOutlet NSButton *fullscreenCheckBox; + IBOutlet NSButton *showDialogCheckBox; + + NSMutableArray *screenModes; + QuakeArguments *arguments; +} + +- (IBAction)changeScreenMode:(id)sender; +- (IBAction)launchQuake:(id)sender; +- (IBAction)cancel:(id)sender; + +- (NSArray *)screenModes; + +@end diff --git a/Mac OS X/AppController.m b/Mac OS X/AppController.m new file mode 100644 index 00000000..2b49f3c1 --- /dev/null +++ b/Mac OS X/AppController.m @@ -0,0 +1,193 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#import "AppController.h" +#import "ScreenInfo.h" +#import "SDL.h" +#import "SDLMain.h" + +NSString *FQPrefCommandLineKey = @"CommandLine"; +NSString *FQPrefFullscreenKey = @"Fullscreen"; +NSString *FQPrefScreenModeKey = @"ScreenMode"; +NSString *FQPrefShowDialog = @"ShowDialog"; + +@implementation AppController + ++(void) initialize { + + NSMutableDictionary *defaults = [NSMutableDictionary dictionary]; + + [defaults setObject:@"" forKey:FQPrefCommandLineKey]; + [defaults setObject:[NSNumber numberWithBool:YES] forKey:FQPrefFullscreenKey]; + [defaults setObject:[NSNumber numberWithInt:0] forKey:FQPrefScreenModeKey]; + [defaults setObject:[NSNumber numberWithBool:YES] forKey:FQPrefShowDialog]; + + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; +} + +- (id)init { + int i,j; + int flags; + int bpps[3] = {32, 24, 16}; + SDL_PixelFormat format; + SDL_Rect **modes; + ScreenInfo *info; + + self = [super init]; + if (!self) + return nil; + + screenModes = [[NSMutableArray alloc] init]; + [screenModes addObject:@"Default or command line arguments"]; + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) + return self; + + flags = SDL_OPENGL | SDL_FULLSCREEN; + format.palette = NULL; + + for (i = 0; i < 3; i++) { + format.BitsPerPixel = bpps[i]; + modes = SDL_ListModes(&format, flags); + + if (modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1) + continue; + + for (j = 0; modes[j]; j++) { + info = [[ScreenInfo alloc] initWithWidth:modes[j]->w height:modes[j]->h bpp:bpps[i]]; + [screenModes addObject:info]; + [info release]; + } + } + + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + arguments = [[QuakeArguments alloc] initWithArguments:gArgv + 1 count:gArgc - 1]; + return self; +} + +- (NSArray *)screenModes { + + return screenModes; +} + +- (void)awakeFromNib { + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL showDialog = [defaults boolForKey:FQPrefShowDialog]; + [showDialogCheckBox setState:showDialog ? NSOnState : NSOffState]; + + if ([arguments count] > 0) { + [paramTextField setStringValue:[arguments description]]; + if ([arguments argument:@"-window"] != nil) + [fullscreenCheckBox setState:NSOffState]; + } else { + [paramTextField setStringValue:[defaults stringForKey:FQPrefCommandLineKey]]; + + BOOL fullscreen = [defaults boolForKey:FQPrefFullscreenKey]; + [fullscreenCheckBox setState:fullscreen ? NSOnState : NSOffState]; + + int screenModeIndex = [defaults integerForKey:FQPrefScreenModeKey]; + [screenModePopUp selectItemAtIndex:screenModeIndex]; + } +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL showDialog = [defaults boolForKey:FQPrefShowDialog]; + + CGEventRef event = CGEventCreate(NULL /*default event source*/); + CGEventFlags mods = CGEventGetFlags(event); + + if (showDialog || (mods & kCGEventFlagMaskCommand)) + [launcherWindow makeKeyAndOrderFront:self]; + else + [self launchQuake:self]; +} + +- (IBAction)changeScreenMode:(id)sender { + + int index = [screenModePopUp indexOfSelectedItem]; + [fullscreenCheckBox setEnabled:index != 0]; +} + +- (IBAction)launchQuake:(id)sender { + + [arguments parseArguments:[paramTextField stringValue]]; + + int index = [screenModePopUp indexOfSelectedItem]; + if (index > 0) { + ScreenInfo *info = [screenModes objectAtIndex:index]; + + int width = [info width]; + int height = [info height]; + int bpp = [info bpp]; + BOOL fullscreen = [fullscreenCheckBox state] == NSOnState; + + [arguments addArgument:@"-width" withValue:[NSString stringWithFormat:@"%d", width]]; + [arguments addArgument:@"-height" withValue:[NSString stringWithFormat:@"%d", height]]; + [arguments addArgument:@"-bpp" withValue:[NSString stringWithFormat:@"%d", bpp]]; + + if (!fullscreen) + [arguments addArgument:@"-window"]; + } + + NSString *path = [NSString stringWithCString:gArgv[0] encoding:NSASCIIStringEncoding]; + + int i; + for (i = 0; i < 4; i++) + path = [path stringByDeletingLastPathComponent]; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager changeCurrentDirectoryPath:path]; + + int argc = [arguments count] + 1; + char *argv[argc]; + + argv[0] = gArgv[0]; + [arguments setArguments:argv + 1]; + + [launcherWindow close]; + + // update the defaults + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:[paramTextField stringValue] forKey:FQPrefCommandLineKey]; + [defaults setObject:[NSNumber numberWithBool:[fullscreenCheckBox state] == NSOnState] forKey:FQPrefFullscreenKey]; + [defaults setObject:[NSNumber numberWithInt:index] forKey:FQPrefScreenModeKey]; + [defaults setObject:[NSNumber numberWithBool:[showDialogCheckBox state] == NSOnState] forKey:FQPrefShowDialog]; + [defaults synchronize]; + + int status = SDL_main (argc, argv); + exit(status); +} + +- (IBAction)cancel:(id)sender { + + exit(0); +} + +- (void) dealloc +{ + [screenModes release]; + [super dealloc]; +} + + +@end diff --git a/Mac OS X/English.lproj/InfoPlist.strings b/Mac OS X/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..4300c59b Binary files /dev/null and b/Mac OS X/English.lproj/InfoPlist.strings differ diff --git a/Mac OS X/English.lproj/Launcher.nib/designable.nib b/Mac OS X/English.lproj/Launcher.nib/designable.nib new file mode 100644 index 00000000..4b04d874 --- /dev/null +++ b/Mac OS X/English.lproj/Launcher.nib/designable.nib @@ -0,0 +1,3291 @@ + + + + 1040 + 9C31 + 629 + 949.26 + 352.00 + + YES + + + + + YES + com.apple.InterfaceBuilderKit + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + SDLMain + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + NewApplication + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + + NSMenuMixedState + + submenuAction: + + + + YES + + + About NewApplication + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + UHJlZmVyZW5jZXPigKY + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide NewApplication + h + 1048576 + 2147483647 + + + + + + Hide Others + + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit NewApplication + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + New + n + 1048576 + 2147483647 + + + + + + T3BlbuKApg + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + U2F2ZSBBc+KApg + S + 1179648 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + UHJpbnTigKY + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + RmluZOKApg + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + U2hvdyBTcGVsbGluZ+KApg + : + 1048576 + 2147483647 + + + + + + Check Spelling + ; + 1048576 + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Smart Copy/Paste + + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + + 1048576 + 2147483647 + + + 2 + + + + Smart Links + + 1179648 + 2147483647 + + + 3 + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Show Colors + C + 1179648 + 2147483647 + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Show Toolbar + + 1572864 + 2147483647 + + + + + + Q3VzdG9taXplIFRvb2xiYXLigKY + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + NewApplication Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + 3 + 2 + {{772, 548}, {516, 280}} + 1954022400 + Fitzquake + NSWindow + + + + 256 + + YES + + + 268 + {{378, 41}, {124, 32}} + + + YES + + 67239424 + 134217728 + Start + + LucidaGrande + 1.300000e+01 + 1044 + + + -2038284033 + 129 + + + 200 + 25 + + + + + 12 + + YES + + + 256 + + YES + + + 268 + {{15, 127}, {172, 17}} + + + YES + + 67239488 + 272630784 + Command line parameters + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2OQA + + + + 6 + + controlTextColor + + 3 + MAA + + + + + + + 268 + {{18, 97}, {440, 22}} + + + YES + + -1804468671 + 272630784 + + + + YES + + 6 + + textBackgroundColor + + 3 + MQA + + + + 6 + + textColor + + + + + + + 268 + {{15, 54}, {175, 17}} + + + YES + + 67239488 + 272630784 + Resolution and color depth + + + + + + + + + 268 + {{15, 22}, {446, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + 400 + 75 + + + YES + Item 1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + Item 2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item 3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 1 + YES + YES + 2 + + + + + 268 + {{374, 52}, {86, 18}} + + + YES + + -2080244224 + 0 + Fullscreen + + + 1211912703 + 2 + + + NSSwitch + + + NSSwitch + + + + 200 + 25 + + + + {{1, 1}, {480, 159}} + + + + + {{17, 85}, {482, 175}} + + + {0, 0} + + 67239424 + 0 + Settings + + + 1.100000e+01 + 3100 + + + + 3 + MCAwLjgwMDAwMDAxAA + + + + 1 + 0 + 2 + NO + + + + 268 + {{254, 41}, {124, 32}} + + + YES + + 67239424 + 134217728 + Cancel + + + -2038284033 + 129 + + + 200 + 25 + + + + + 268 + {{18, 50}, {173, 18}} + + + YES + + -2080244224 + 0 + Always show this dialog + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 268 + {{17, 15}, {210, 29}} + + + YES + + 67239424 + 272629760 + Hold the Command key on startup to display this dialog again + + + 1.100000e+01 + 16 + + + + + 1 + MCAwIDAgMC42NDk5OTk5OAA + + + + + {516, 280} + + + + {{0, 0}, {1680, 1028}} + + + AppController + + + YES + + + + + YES + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + showHelp: + + + + 360 + + + + orderFrontColorPanel: + + + + 361 + + + + saveDocument: + + + + 362 + + + + saveDocumentAs: + + + + 363 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + terminate: + + + + 369 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + launchQuake: + + + + 378 + + + + paramTextField + + + + 412 + + + + launcherWindow + + + + 414 + + + + delegate + + + + 415 + + + + screenSettingsPopUp + + + + 417 + + + + cancel: + + + + 418 + + + + content: screenModes + + + + + + + content + screenModes + 2 + + + 449 + + + + screenModePopUp + + + + 452 + + + + fullscreenCheckBox + + + + 453 + + + + changeScreenMode: + + + + 455 + + + + showDialogCheckBox + + + + 463 + + + + + + + + 464 + + + + + YES + + 0 + + YES + + + + + + -2 + + + RmlsZSdzIE93bmVyA + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + + MainMenu + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 103 + + + YES + + + + 1 + + + 217 + + + YES + + + + + + 83 + + + YES + + + + + + 81 + + + YES + + + + + + + + + + + + + + + + 75 + + + 3 + + + 80 + + + 8 + + + 78 + + + 6 + + + 72 + + + + + 82 + + + 9 + + + 124 + + + YES + + + + + + 77 + + + 5 + + + 73 + + + + + + 79 + + + 7 + + + 112 + + + 10 + + + 74 + + + 2 + + + 125 + + + YES + + + + + + 126 + + + + + 205 + + + YES + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + YES + + + + + + 216 + + + YES + + + + + + 200 + + + YES + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + YES + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 106 + + + YES + + + + + + + 111 + + + + + 57 + + + YES + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + 1111 + + + 144 + + + + + 129 + + + 121 + + + 143 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + YES + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + YES + + + + + + 296 + + + YES + + + + + + + 297 + + + + + 298 + + + + + 299 + + + YES + + + + + + 300 + + + YES + + + + + + + 344 + + + + + 345 + + + + + 211 + + + YES + + + + + + 212 + + + YES + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + YES + + + + + + 349 + + + YES + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + YES + + + + + + 372 + + + YES + + + + + + + + + + 375 + + + + + 376 + + + YES + + + + + + 377 + + + + + 395 + + + YES + + + + + + + + + + 397 + + + YES + + + + + + 398 + + + YES + + + + + + 399 + + + YES + + + + + + 400 + + + YES + + + + + + 401 + + + YES + + + + + + 402 + + + YES + + + + + + + + 403 + + + + + 404 + + + + + 405 + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 410 + + + YES + + + + + + 411 + + + + + 419 + + + + + 450 + + + YES + + + + + + 451 + + + + + 459 + + + YES + + + + + + 460 + + + + + 461 + + + YES + + + + + + 462 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 103.IBPluginDependency + 103.ImportedFromIB2 + 106.IBPluginDependency + 106.ImportedFromIB2 + 106.editorWindowContentRectSynchronizationRect + 111.IBPluginDependency + 111.ImportedFromIB2 + 112.IBPluginDependency + 112.ImportedFromIB2 + 124.IBPluginDependency + 124.ImportedFromIB2 + 125.IBPluginDependency + 125.ImportedFromIB2 + 125.editorWindowContentRectSynchronizationRect + 126.IBPluginDependency + 126.ImportedFromIB2 + 129.IBPluginDependency + 129.ImportedFromIB2 + 130.IBPluginDependency + 130.ImportedFromIB2 + 130.editorWindowContentRectSynchronizationRect + 131.IBPluginDependency + 131.ImportedFromIB2 + 134.IBPluginDependency + 134.ImportedFromIB2 + 136.IBPluginDependency + 136.ImportedFromIB2 + 143.IBPluginDependency + 143.ImportedFromIB2 + 144.IBPluginDependency + 144.ImportedFromIB2 + 145.IBPluginDependency + 145.ImportedFromIB2 + 149.IBPluginDependency + 149.ImportedFromIB2 + 150.IBPluginDependency + 150.ImportedFromIB2 + 19.IBPluginDependency + 19.ImportedFromIB2 + 195.IBPluginDependency + 195.ImportedFromIB2 + 196.IBPluginDependency + 196.ImportedFromIB2 + 197.IBPluginDependency + 197.ImportedFromIB2 + 198.IBPluginDependency + 198.ImportedFromIB2 + 199.IBPluginDependency + 199.ImportedFromIB2 + 200.IBPluginDependency + 200.ImportedFromIB2 + 200.editorWindowContentRectSynchronizationRect + 201.IBPluginDependency + 201.ImportedFromIB2 + 202.IBPluginDependency + 202.ImportedFromIB2 + 203.IBPluginDependency + 203.ImportedFromIB2 + 204.IBPluginDependency + 204.ImportedFromIB2 + 205.IBPluginDependency + 205.ImportedFromIB2 + 205.editorWindowContentRectSynchronizationRect + 206.IBPluginDependency + 206.ImportedFromIB2 + 207.IBPluginDependency + 207.ImportedFromIB2 + 208.IBPluginDependency + 208.ImportedFromIB2 + 209.IBPluginDependency + 209.ImportedFromIB2 + 210.IBPluginDependency + 210.ImportedFromIB2 + 211.IBPluginDependency + 211.ImportedFromIB2 + 212.IBPluginDependency + 212.ImportedFromIB2 + 212.editorWindowContentRectSynchronizationRect + 213.IBPluginDependency + 213.ImportedFromIB2 + 214.IBPluginDependency + 214.ImportedFromIB2 + 215.IBPluginDependency + 215.ImportedFromIB2 + 216.IBPluginDependency + 216.ImportedFromIB2 + 217.IBPluginDependency + 217.ImportedFromIB2 + 218.IBPluginDependency + 218.ImportedFromIB2 + 219.IBPluginDependency + 219.ImportedFromIB2 + 220.IBPluginDependency + 220.ImportedFromIB2 + 220.editorWindowContentRectSynchronizationRect + 221.IBPluginDependency + 221.ImportedFromIB2 + 23.IBPluginDependency + 23.ImportedFromIB2 + 236.IBPluginDependency + 236.ImportedFromIB2 + 239.IBPluginDependency + 239.ImportedFromIB2 + 24.IBPluginDependency + 24.ImportedFromIB2 + 24.editorWindowContentRectSynchronizationRect + 29.IBPluginDependency + 29.ImportedFromIB2 + 29.WindowOrigin + 29.editorWindowContentRectSynchronizationRect + 295.IBPluginDependency + 296.IBPluginDependency + 296.editorWindowContentRectSynchronizationRect + 297.IBPluginDependency + 298.IBPluginDependency + 299.IBPluginDependency + 300.IBPluginDependency + 300.editorWindowContentRectSynchronizationRect + 344.IBPluginDependency + 345.IBPluginDependency + 346.IBPluginDependency + 346.ImportedFromIB2 + 348.IBPluginDependency + 348.ImportedFromIB2 + 349.IBPluginDependency + 349.ImportedFromIB2 + 349.editorWindowContentRectSynchronizationRect + 350.IBPluginDependency + 350.ImportedFromIB2 + 351.IBPluginDependency + 351.ImportedFromIB2 + 354.IBPluginDependency + 354.ImportedFromIB2 + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 371.editorWindowContentRectSynchronizationRect + 372.IBPluginDependency + 375.IBPluginDependency + 376.IBPluginDependency + 377.IBPluginDependency + 395.IBPluginDependency + 395.IBUserGuides + 397.IBPluginDependency + 398.IBPluginDependency + 399.IBPluginDependency + 400.IBPluginDependency + 401.IBPluginDependency + 402.IBPluginDependency + 402.editorWindowContentRectSynchronizationRect + 403.IBPluginDependency + 404.IBPluginDependency + 405.IBPluginDependency + 406.IBPluginDependency + 407.IBPluginDependency + 408.IBPluginDependency + 410.IBPluginDependency + 411.IBPluginDependency + 450.IBPluginDependency + 451.IBPluginDependency + 459.IBPluginDependency + 460.IBPluginDependency + 461.IBPluginDependency + 462.IBPluginDependency + 5.IBPluginDependency + 5.ImportedFromIB2 + 56.IBPluginDependency + 56.ImportedFromIB2 + 57.IBPluginDependency + 57.ImportedFromIB2 + 57.editorWindowContentRectSynchronizationRect + 58.IBPluginDependency + 58.ImportedFromIB2 + 72.IBPluginDependency + 72.ImportedFromIB2 + 73.IBPluginDependency + 73.ImportedFromIB2 + 74.IBPluginDependency + 74.ImportedFromIB2 + 75.IBPluginDependency + 75.ImportedFromIB2 + 77.IBPluginDependency + 77.ImportedFromIB2 + 78.IBPluginDependency + 78.ImportedFromIB2 + 79.IBPluginDependency + 79.ImportedFromIB2 + 80.IBPluginDependency + 80.ImportedFromIB2 + 81.IBPluginDependency + 81.ImportedFromIB2 + 81.editorWindowContentRectSynchronizationRect + 82.IBPluginDependency + 82.ImportedFromIB2 + 83.IBPluginDependency + 83.ImportedFromIB2 + 92.IBPluginDependency + 92.ImportedFromIB2 + + + YES + + + + + + + + {{596, 852}, {216, 23}} + + + + + + + + + {{522, 812}, {146, 23}} + + + + + + + {{436, 809}, {64, 6}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{608, 612}, {275, 83}} + + + + + + + + + + + {{187, 434}, {243, 243}} + + + + + + + + + + + + + + + {{608, 612}, {167, 43}} + + + + + + + + + + + + + + + + + {{608, 612}, {241, 103}} + + + + + + + + + + + {{525, 802}, {197, 73}} + + + {74, 862} + {{6, 686}, {478, 20}} + + + {{475, 832}, {234, 43}} + + + + + {{231, 634}, {176, 43}} + + + + + + + + + {{608, 612}, {215, 63}} + + + + + + + + {{412, 523}, {516, 280}} + + {{412, 523}, {516, 280}} + + + + + + + YES + + + + + + + + {{188, 248}, {446, 63}} + + + + + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + + {{23, 794}, {245, 183}} + + + + + + + + + + + + + + + + + + + + + {{145, 474}, {199, 203}} + + + + + + + + + + YES + + YES + + + YES + + + + + YES + + YES + + + YES + + + + 464 + + + + YES + + SDLMain + NSObject + + YES + + YES + + + YES + + + + YES + + YES + + + YES + + + + IBProjectSource + SDLMain.h + + + + AppController + + + YES + + YES + cancel: + changeScreenMode: + launchQuake: + + + YES + id + + + + + + YES + + YES + fullscreenCheckBox + launcherWindow + paramTextField + screenModePopUp + showDialogCheckBox + + + YES + NSButton + + NSTextField + NSPopUpButton + + + + + + AppController.h + + + + + + + YES + + YES + + + YES + + + + YES + + YES + + + YES + + + + IBUserSource + + + + + + 0 + ../../Fitzquake.xcodeproj + 3 + + YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA +AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxECxQALAAwAMQA1ADYAPAA9 +AEEARQB7AIMAhgCHAJcAoAALAKEAvQC+AMYAxwDKAM8A0ADRANQA0ADYANsA3ADgAOYA5wDrAO8A/wEE +AQUBCQEKAQ4BDwESARMBFgEaASEBJQEmAScBKAEsATMBNwE4ATkBOgE+AUUBSQFKAUsBTwFWAVcBWAFc +AWMBZAFlAWkBcwF0AXUBdgF6AYIBhwGIAYkBigGOAZUBlgGXAZgBnAGjAaQBpQGpAbEBtQG2AbcBuAG9 +AdAB0QCNAdIB2gHiAeoB6wH2AfcCCwIPAhcCHwIgAisCLAI2AjcCOAI8Aj4CQwJEAkcCSgJNAlUCVgJg +AmUCZgJpAm4CbwJ3AngCfwKAAogCiQKeAqwCsAKxArICswK5AsICsQLDAswCsQLNAtEC0wLXAtoC2wLd +At4C3wLlAuYC6wLuAvEC+QL6AwEDAgMKAwsDFAMVAx0DHgMmAycDKwMvAAsDMAMxAzQDNQM5A0ADQQNC +A0MDRwNOA08DUANRA1YDVwNbA2IDYwNkA2UDaQNwA3EDcgNzA3gDeQN+A4UDhgOHA4wDjQOSA5MDmAOZ +A50DpAOlA6YDqwOsA7ADtwO8A70DvgPCA8kDygPLA8wD0APXA9gD2QPaA94D5QPmA+cD6APsA/MD9AP1 +A/kEAAQEBAUEBgQKBBEEFQQWBBcEGwQiBCYEJwQoBCkELQQ0BDUENgQ3BDwEPQRBBEgESQRKBEsETwRW +BFcEWARZBF0EZARlBGYEZwRrBHIEdwR4BHkEfQSEBIUEhgSKBJEEkgSTBJQEmASfBKMEpASlBKYEqwSu +BK8EswS6BLsEvAS9BMEEyATJBMoEywTPBNYE1wTYBNkE3QTkBOUE5gTnBOsE8gTzBPQE9QT5BQAFAQUC +BQcFCAUSBRMFFAUVBRgFhwWRBZoFmwWiBawFrQWuBbQFuwW8Bb0FwgXDBc0F1gWtBdcF5QXuBfcGAAWt +BgEGBgYJBgoGEwYcBh0GJgWtBicGNQY+Ba0GPwZDBkQGTQZWBa0GVwZnBnAGeQaCBa0GgwaLBpIGkwaa +BpsGowakBqUFrQauBrcFrQa4Br0GxgWtBscGzAbTBtQG3QWtBt4G4wbsBa0G7Qb0BvUG/gWtBv8HAwcE +BwgHDAcOB30H7QhdCF4IXwhgCGEIYghjCGQIZQhmCGcIaAhpCGoIawhsCG0IbghvCHAIcQhyCHMIdAh1 +CHYIdwh4CHkIegh7CHwIfQh+CH8IgAiBCIIIgwiECIUIhgiHCIgIiQiKCIsIjAiNCI4IjwiQCJEIkgiT +CJQIlQiWCJcImAiZCJoImwicCJ0IngifCKAIoQiiCKMIpAilCKYIpwioCKkIqgirCKwIrQiuCK8IsAix +CLIIswi0CLUItgi3CLgIuQi6CLsIvAi9CL4IvwjACMEIwgjDCMQIxQjGCMcIyAjJCMoIzQjQCXMKFgoX +ChgKGQoaChsAugocCh0KHgofCiAKIQHvApoKIgojCiQKJQomCicKKAopCioKKwosCi0KLgovCjAKMQoy +CjMKNAo1CjYKNwo4CjkKOgo7CjwKPQo+Cj8KQApBCkIKQwpECkUKRgpHCkgKSQpKCksKTApNCk4KTwpQ +ClEKUgpTClQKVQpWClcKWApZCloKWwpcApIKXQpeCl8KYAphCmIKYwpkCmUKZgpnCmgKaQpqCmsKbApt +Cm4KbwpwCnEKcgpzCnQKdQp2CncKeAp5CnoKewp8Cn0Kfgp/CoAKgQqCCoMKhAqFCoYKhwqICokKigqL +CowKjQqOCo8KkAqRCpIKkwqUCpUKlgqXCpgKmQqaCpsKnAqdCp4KnwqgCqEKogqjCqQKpQqmCqcKqAqp +CqoKqwqsCq0KrgqvCrAKsQqyCrUKuAq7VSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkA +GgAbABwAHQAeAB8AIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYkY2xhc3Nd +TlNPYmplY3RzS2V5c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNWYWx1ZXNd +TlNDb25uZWN0aW9uc1tOU05hbWVzS2V5c1tOU0ZyYW1ld29ya11OU0NsYXNzZXNLZXlzWk5TT2lkc0tl +eXNdTlNOYW1lc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eUNvbm5lY3RvcnNdTlNGb250TWFuYWdlcl8Q +EE5TVmlzaWJsZVdpbmRvd3NfEA9OU09iamVjdHNWYWx1ZXNfEBdOU0FjY2Vzc2liaWxpdHlPaWRzS2V5 +c1lOU05leHRPaWRcTlNPaWRzVmFsdWVzgAKBAsSBAVeBAh6BAsOACIEBroAFgQIdgQIfgQGvgQLBgACA +BoEBrYECwhEB0oECINIADgAyADMANFtOU0NsYXNzTmFtZYAEgANXU0RMTWFpbtIANwA4ADkAOlgkY2xh +c3Nlc1okY2xhc3NuYW1logA6ADteTlNDdXN0b21PYmplY3RYTlNPYmplY3RfEBBJQkNvY29hRnJhbWV3 +b3Jr0gAOAD4APwBAWk5TLm9iamVjdHOAB6DSADcAOABCAEOjAEMARAA7XE5TTXV0YWJsZVNldFVOU1Nl +dNIADgA+AEYAR4CWrxAzAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0A +XgBfAGAAYQBiAGMAZABlAGYAZwBoAGkAagBrAGwAbQBuAG8AcABxAHIAcwB0AHUAdgB3AHgAeQB6gAmA +IYAsgDKAOIA9gEGARYBKgFCAVYBZgF+AtoC7gMCAwoDHgMyAzoDSgNSA1oDYgNyA3oDjgOiA7YDygPaA ++4EBAIEBBoEBC4EBDYEBEoEBF4EBHIEBIYEBJYEBKoEBMIEBM4EBOIEBPYEBQoEBR4EBTIEBUIEBUtQA +DgB8AH0AfgB/AIAAgQCCXU5TRGVzdGluYXRpb25YTlNTb3VyY2VXTlNMYWJlbIAggAyACoAf0gAOADIA +MwCFgASAC11BcHBDb250cm9sbGVy2ACIAA4AiQCKAIsAjACNAI4AjwCQAJEAkgCTAJQAlQCPXxAPTlNO +ZXh0UmVzcG9uZGVyV05TRnJhbWVWTlNDZWxsWE5TdkZsYWdzWU5TRW5hYmxlZFhOU1dpbmRvd1tOU1N1 +cGVydmlld4ANgB6ADoAQEQEMCYAPgA3XAIgADgCJAJgAiwCNAI4AmQCaAJsAnACdAJUAmVpOU1N1YnZp +ZXdzgGqAm4CagGwRAQCAD4BqXxAVe3szNzQsIDUyfSwgezg2LCAxOH193gCiAA4AowCkAKUApgCnAKgA +qQCqAKsArACtAK4ArwCwALEAsgCzALQAtQCxALcAuACAALoAuwC8W05TQ2VsbEZsYWdzXxATTlNBbHRl +cm5hdGVDb250ZW50c11OU05vcm1hbEltYWdlXxASTlNQZXJpb2RpY0ludGVydmFsXk5TQnV0dG9uRmxh +Z3MyXxAQTlNBbHRlcm5hdGVJbWFnZV8QD05TS2V5RXF1aXZhbGVudFpOU0NvbnRlbnRzWU5TU3VwcG9y +dF1OU0NvbnRyb2xWaWV3XxAPTlNQZXJpb2RpY0RlbGF5XE5TQ2VsbEZsYWdzMl1OU0J1dHRvbkZsYWdz +E/////+EAf4AgB2AHIAVEBkQAoAZgByAEYASgAwQyBAAEkg8Uf9aRnVsbHNjcmVlbtQADgC/AMAAwQDC +AMMAxADFVk5TU2l6ZVZOU05hbWVYTlNmRmxhZ3OAFCNAKgAAAAAAAIATEQQUXEx1Y2lkYUdyYW5kZdIA +NwA4AMgAyaIAyQA7Vk5TRm9udNMADgAyAMsAzADNAM5eTlNSZXNvdXJjZU5hbWWAGIAWgBdXTlNJbWFn +ZVhOU1N3aXRjaNIANwA4ANIA06IA0wA7XxAQTlNDdXN0b21SZXNvdXJjZdIADgDVANYA11tOU0ltYWdl +TmFtZYAbgBrSADcAOADZANqiANoAO18QE05TQnV0dG9uSW1hZ2VTb3VyY2VQ0gA3ADgA3QDepADeAN8A +igA7XE5TQnV0dG9uQ2VsbFxOU0FjdGlvbkNlbGzSADcAOADhAOKlAOIA4wDkAOUAO1hOU0J1dHRvbllO +U0NvbnRyb2xWTlNWaWV3W05TUmVzcG9uZGVyXxASZnVsbHNjcmVlbkNoZWNrQm940gA3ADgA6ADpowDp +AOoAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9yXk5TTmliQ29ubmVjdG9y0wAOAH0AfgDsAO0A7oArgCKA +KtgADgDwAPEA8gDzAPQA9QD2APcA+AD5ALEA+wD8AP0A/ldOU1RpdGxlXxARTlNLZXlFcXVpdk1vZE1h +c2taTlNLZXlFcXVpdl1OU01uZW1vbmljTG9jWU5TT25JbWFnZVxOU01peGVkSW1hZ2VWTlNNZW51gCmA +JBIAEAAAgBwSf////4AlgCeAI9MADgDwAQABAQECAQNbTlNNZW51SXRlbXOAl4EBk4EBlV1TdG9wIFNw +ZWFraW5n0wAOADIAywDMAM0BCIAYgBaAJl8QD05TTWVudUNoZWNrbWFya9MADgAyAMsAzADNAQ2AGIAW +gChfEBBOU01lbnVNaXhlZFN0YXRl0gA3ADgBEAERogERADtaTlNNZW51SXRlbV1zdG9wU3BlYWtpbmc6 +0gA3ADgBFAEVowEVAOoAO18QFU5TTmliQ29udHJvbENvbm5lY3RvctMADgB9AH4A7AEYARmAK4AtgDHY +AA4A8ADxAPIA8wD0APUA9gD3ARwA+QEdAPsA/AD9ASCAKYAvgDCAJYAngC7TAA4A8AEAAQEBIwEkgJeB +AYCBAYJaU2VsZWN0IEFsbFFhWnNlbGVjdEFsbDrTAA4AfQB+AOwBKgErgCuAM4A32AAOAPAA8QDyAPMA +9AD1APYA9wEuAPkBLwD7APwA/QEygCmANYA2gCWAJ4A00wAOAPABAAEBATUBNoCXgQFagQFbXkNoZWNr +IFNwZWxsaW5nUTteY2hlY2tTcGVsbGluZzrTAA4AfQB+AOwBPAE9gCuAOYA81wAOAPAA8gDzAPQA9QD2 +APcBQACxAPsA/AD9AUSAKYA7gByAJYAngDrTAA4A8AEAAQEBRwFIgJeBAXaBAXhfEA9SZXZlcnQgdG8g +U2F2ZWRfEBZyZXZlcnREb2N1bWVudFRvU2F2ZWQ60wAOAH0AfgDsAU0BToArgD6AQNgADgDwAPEA8gDz +APQA9QD2APcBUQD5ALEA+wD8AP0BMoApgD+AHIAlgCeANF8QG0NoZWNrIFNwZWxsaW5nIFdoaWxlIFR5 +cGluZ18QHnRvZ2dsZUNvbnRpbnVvdXNTcGVsbENoZWNraW5nOtMADgB9AH4A7AFaAVuAK4BCgETYAA4A +8ADxAPIA8wD0APUA9gD3AV4A+QCxAPsA/AD9AP6AKYBDgByAJYAngCNeU3RhcnQgU3BlYWtpbmdec3Rh +cnRTcGVha2luZzrTAA4AfQB+AOwBZwFogCuARoBJ2QAOAWoA8ADxAPIA8wD0APUA9gD3ALEBbQFuAW8A ++wD8AP0BRFlOU1Rvb2xUaXCAKYAcgEcSABIAAIBIgCWAJ4A6XVBhZ2UgU2V0dXAuLi5RUF5ydW5QYWdl +TGF5b3V0OtMADgB9AH4A7AF4AXmAK4BLgE/YAA4A8ADxAPIA8wD0APUA9gD3AXwBfQF+APsA/AD9AYGA +KYBNEgAYAACAToAlgCeATNQADgDwAMABAAEBAYQBhQGGgJeBAWeBAXSBAWlbSGlkZSBPdGhlcnNRaF8Q +FmhpZGVPdGhlckFwcGxpY2F0aW9uczrTAA4AfQB+AOwBjAGNgCuAUYBU2AAOAPAA8QDyAPMA9AD1APYA +9wGQAPkBkQD7APwA/QEggCmAUoBTgCWAJ4AuVENvcHlRY1Vjb3B5OtMADgB9AH4A7AGaAZuAK4BWgFjY +AA4A8ADxAPIA8wD0APUA9gD3AZ4A+QCxAPsA/AD9AYGAKYBXgByAJYAngExYU2hvdyBBbGxfEBZ1bmhp +ZGVBbGxBcHBsaWNhdGlvbnM60wAOAH0AfgDsAacBqIArgFqAXtkADgDwAPEA8gDzAPQA9QD2AaoA9wGs +APkBrQD7APwA/QGwALRVTlNUYWeAKYBcgF2AJYAngFvTAA4A8AEAAQEBswG0gJeBAV2BAV9cU21hcnQg +UXVvdGVzUWdfECF0b2dnbGVBdXRvbWF0aWNRdW90ZVN1YnN0aXR1dGlvbjrUAA4AfAB9AH4AfwG6AIEB +vIAggGCACoC12gG+AA4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcoBywHMAc0AtAHOACtcTlNXaW5kb3dW +aWV3XE5TU2NyZWVuUmVjdF1OU1dpbmRvd1RpdGxlWU5TV1RGbGFnc11OU1dpbmRvd0NsYXNzXE5TV2lu +ZG93UmVjdF8QD05TV2luZG93QmFja2luZ18QEU5TV2luZG93U3R5bGVNYXNrW05TVmlld0NsYXNzgGSA +tICzgGISdHgEAIBjgGEQA4AAXxAYe3s3NzIsIDU0OH0sIHs1MTYsIDI4MH19WUZpdHpxdWFrZdcAiAAO +AJgAiwHTAI0AjgCVAJoB1gCdAdcAlQHZW05TRnJhbWVTaXplgA+Am4BlgLGAD4Cy0gAOAD4ARgHcgJal +Ad0AmQHfAeAB4YBmgGqAo4CngKvYAIgADgCJAIoAiwCMAI0AjgHHAJAB5QHmAJMAlACVAceAZIAegGeA +aAmAD4BkXxAWe3szNzgsIDQxfSwgezEyNCwgMzJ9fdwAogAOAKMApQCmAKgAqQCqAKsArACtAK4B7ACw +ALEAswHvALEB8QC4Ad0AugH0AfUSBAH+AIAdgBwQgYAcgGmAEoBmEggAAAAT/////4aCQP9VU3RhcnTe +AIgB+AAOAfkAiQH6AJgAiwH7AI0B/AH9AI4B/gHHALsCAAIBAgICAwIEAgUCBgCVAggAtAHHAI9ZTlNC +b3hUeXBlW05TVGl0bGVDZWxsXU5TVHJhbnNwYXJlbnRcTlNCb3JkZXJUeXBlWU5TT2Zmc2V0c18QD05T +VGl0bGVQb3NpdGlvbl1OU0NvbnRlbnRWaWV3gGSAooCegJwIgGsQDBABgA+AnYBkgA3SAA4APgBGAg2A +lqEAj4AN0gAOAD4ARgIRgJalAhICEwIUAhUAgIBtgHuAg4CHgAzYAIgADgCJAIoAiwCMAI0AjgCPAhkC +GgIbAJMAlACVAI+ADYB6gG6AbwmAD4ANXxAWe3sxNSwgMTI3fSwgezE3MiwgMTd9fdgAogAOAiEAqQCq +AKsArQIiAiMCJAIlAiYAuAISAikCKl8QEU5TQmFja2dyb3VuZENvbG9yW05TVGV4dENvbG9yEgQB/kCA +eYBxgHCAEoBtEhBABACAdl8QF0NvbW1hbmQgbGluZSBwYXJhbWV0ZXJz1QAOAi0CLgIvAjACMQIyAjMC +NAI1V05TQ29sb3JcTlNDb2xvclNwYWNlW05TQ29sb3JOYW1lXU5TQ2F0YWxvZ05hbWWAdYB0EAaAc4By +VlN5c3RlbVxjb250cm9sQ29sb3LTAA4CLgI5AjEBzgI7V05TV2hpdGWAdUswLjY2NjY2NjY5ANIANwA4 +Aj0CLaICLQA71QAOAi0CLgIvAjACMQJAAjMCQQI1gHWAeIB3gHJfEBBjb250cm9sVGV4dENvbG9y0wAO +Ai4COQIxAc4CRoB1QjAA0gA3ADgCSAJJpAJJAN8AigA7XxAPTlNUZXh0RmllbGRDZWxs0gA3ADgCSwJM +pQJMAOMA5ADlADtbTlNUZXh0RmllbGTYAIgADgCJAIoAiwCMAI0AjgCPAhkCUAJRAJMAlACVAI+ADYB6 +gHyAfQmAD4ANXxAVe3sxOCwgOTd9LCB7NDQwLCAyMn192QCiAA4CIQCpAKoAqwCtAlcCIgJYAiQCWgCx +ALgCEwIpAJQCX18QEU5TRHJhd3NCYWNrZ3JvdW5kE/////+Ucf5BgHmAfoAcgBKAewmAgdUADgItAi4C +LwIwAjECYgIzAmMCNYB1gICAf4ByXxATdGV4dEJhY2tncm91bmRDb2xvctMADgIuAjkCMQHOAmiAdUIx +ANUADgItAi4CLwIwAjECQAIzAmwCNYB1gHiAgoByWXRleHRDb2xvctgAiAAOAIkAigCLAIwAjQCOAI8C +GQJyAnMAkwCUAJUAj4ANgHqAhICFCYAPgA1fEBV7ezE1LCA1NH0sIHsxNzUsIDE3fX3YAKIADgIhAKkA +qgCrAK0CIgIjAiQCJQJ7ALgCFAIpAiqAeYBxgIaAEoCDgHZfEBpSZXNvbHV0aW9uIGFuZCBjb2xvciBk +ZXB0aNgAiAAOAIkAigCLAIwAjQCOAI8CggKDAoQAkwCUAJUAj4ANgJmAiICJCYAPgA1fEBV7ezE1LCAy +Mn0sIHs0NDYsIDI2fX3fEBIAogKKAosAowClAA4ApgCoAKoBEQCrAowCjQKOAKwArQD2AK4CjwCUALQA +sQKSApMCBgCxALgClgIVAgYAlACUApoCmwKcAp1fEBpOU01lbnVJdGVtUmVzcGVjdEFsaWdubWVudF8Q +D05TQXJyb3dQb3NpdGlvbl8QD05TUHJlZmVycmVkRWRnZV8QEk5TVXNlc0l0ZW1Gcm9tTWVudV1OU0Fs +dGVyc1N0YXRlE/////+EQf5ACYAcEEuAmIAcgBKAioCHCQkRAZARCACAixIGgkD/3AKfAA4A8ADxAPIC +oADzAPQA9QD2AqECogKEAPcCpQD5ALEAlAD7APwA/QKcAqsCBlhOU1RhcmdldFxOU0lzRGlzYWJsZWRY +TlNBY3Rpb25XTlNTdGF0ZYCJgCmAjIAcCYAlgCeAi4CN0wAOAPABAAEBAq4Cr4CXgI6Aj1ZJdGVtIDFf +EBFfcG9wVXBJdGVtQWN0aW9uOlpPdGhlclZpZXdz0gAOAD4ARgK1gJajApYCtwK4gIqAkICT2gKfAA4A +8ADxAPIA8wD0APUA9gKhAoQA9wK8APkAsQD7APwA/QKcAsGAiYApgJGAHIAlgCeAi4CSVkl0ZW0gMtoC +nwAOAPAA8QDyAPMA9AD1APYCoQKEAPcCxgD5ALEA+wD8AP0CnALLgImAKYCUgByAJYAngIuAlVZJdGVt +IDPSADcAOALOAs+jAs8C0AA7Xk5TTXV0YWJsZUFycmF5V05TQXJyYXnSADcAOALSAPaiAPYAO9IANwA4 +AtQC1aYC1QLWAN4A3wCKADtfEBFOU1BvcFVwQnV0dG9uQ2VsbF5OU01lbnVJdGVtQ2VsbNIANwA4AtgC +2aYC2QDiAOMA5ADlADtdTlNQb3BVcEJ1dHRvbl8QFHt7MSwgMX0sIHs0ODAsIDE1OX190gA3ADgC3ADk +owDkAOUAO18QFnt7MTcsIDg1fSwgezQ4MiwgMTc1fX1WezAsIDB91wCiAA4CIQCpAKoArQIiAewCJAJa +AuIC4wC7AuSAeYB+gJ+AoIChWFNldHRpbmdz1AAOAL8AwADBAMIC6ADEAuqAFCNAJgAAAAAAAIATEQwc +0wAOAi4COQIxAc4C7YB1TTAgMC44MDAwMDAwMQDSADcAOALvAvCkAvAA5ADlADtVTlNCb3jYAIgADgCJ +AIoAiwCMAI0AjgHHAJAC9AL1AJMAlACVAceAZIAegKSApQmAD4BkXxAWe3syNTQsIDQxfSwgezEyNCwg +MzJ9fdwAogAOAKMApQCmAKgAqQCqAKsArACtAK4B7ACwALEAswHvALEC/gC4Ad8AugH0AfWAHYAcgByA +poASgKNWQ2FuY2Vs2ACIAA4AiQCKAIsAjACNAI4BxwCQAwUDBgCTAJQAlQHHgGSAHoCogKkJgA+AZF8Q +FXt7MTgsIDUwfSwgezE3MywgMTh9fd4AogAOAKMApAClAKYApwCoAKkAqgCrAKwArQCuAK8AsACxALIA +swC0ALUAsQMRALgB4AC6ALsAvIAdgByAFYAZgByAqoASgKdfEBdBbHdheXMgc2hvdyB0aGlzIGRpYWxv +Z9gAiAAOAIkAigCLAIwAjQCOAccCGQMYAxkAkwCUAJUBx4BkgHqArICtCYAPgGRfEBV7ezE3LCAxNX0s +IHsyMTAsIDI5fX3YAKIADgIhAKkAqgCrAK0CIgHsAiQCJQMhAyIB4QMkAyWAeYBxgK6Ar4CrEhBAAACA +sF8QPEhvbGQgdGhlIENvbW1hbmQga2V5IG9uIHN0YXJ0dXAgdG8gZGlzcGxheSB0aGlzIGRpYWxvZyBh +Z2FpbtQADgC/AMAAwQDCAugAxAMqgBSAExAQ0wAOAi4DLAIxAgYDLlVOU1JHQoB1TxARMCAwIDAgMC42 +NDk5OTk5OABaezUxNiwgMjgwfV8QFnt7MCwgMH0sIHsxNjgwLCAxMDI4fX3SADcAOAMyAzOiAzMAO18Q +EE5TV2luZG93VGVtcGxhdGVebGF1bmNoZXJXaW5kb3fTAA4AfQB+AOwDNwM4gCuAt4C62QAOAPAA8QDy +APMA9AD1APYBqgD3AzsA+QM8APsA/AD9AbACBoApgLiAuYAlgCeAW18QEFNtYXJ0IENvcHkvUGFzdGVR +Zl8QGHRvZ2dsZVNtYXJ0SW5zZXJ0RGVsZXRlOtMADgB9AH4A7ANFA0aAK4C8gL/ZAA4A8ADxAPIA8wD0 +APUA9gGqAPcDSQFuA0oA+wD8AP0BsAHOgCmAvYC+gCWAJ4BbW1NtYXJ0IExpbmtzUUdfEB10b2dnbGVB +dXRvbWF0aWNMaW5rRGV0ZWN0aW9uOtQADgB8AH0AfgB/AhUAgQNVgCCAh4AKgMFfEBNzY3JlZW5TZXR0 +aW5nc1BvcFVw0wAOAH0AfgDsA1kDWoArgMOAxtgADgDwAPEA8gDzAPQA9QD2APcDXQD5A14A+wD8AP0B +IIApgMSAxYAlgCeALlNDdXRReFRjdXQ60wAOAH0AfgDsA2cDaIArgMiAy9gADgDwAPEA8gDzAPQA9QD2 +APcDawD5A2wA+wD8AP0BRIApgMmAyoAlgCeAOlNOZXdRblxuZXdEb2N1bWVudDrUAA4AfAB9AH4AfwCB +AboDd4AggAqAYIDNWGRlbGVnYXRl1AAOAHwAfQB+AOwAHwN8A32AK4ACgM+A0dcADgDwAPIA8wD0APUA +9gD3A4AAsQD7APwA/QGBgCmA0IAcgCWAJ4BMXxAUQWJvdXQgTmV3QXBwbGljYXRpb25fEB1vcmRlckZy +b250U3RhbmRhcmRBYm91dFBhbmVsOtQADgB8AH0AfgDsAIEB3QOLgCuACoBmgNNcbGF1bmNoUXVha2U6 +1AAOAHwAfQB+AH8CFQCBA5GAIICHgAqA1V8QD3NjcmVlbk1vZGVQb3BVcNQADgB8AH0AfgDsAIEB3wOX +gCuACoCjgNdXY2FuY2VsOtMADgB9AH4A7AObA5yAK4DZgNvYAA4A8ADxAPIA8wD0APUA9gD3A58A+QF+ +APsA/AD9AYGAKYDagE6AJYAngExfEBNIaWRlIE5ld0FwcGxpY2F0aW9uVWhpZGU61AAOAHwAfQB+AOwA +gQIVA6qAK4AKgIeA3V8QEWNoYW5nZVNjcmVlbk1vZGU60wAOAH0AfgDsA64Dr4ArgN+A4tgADgDwAPEA +8gDzAPQA9QD2APcDsgD5ALEA+wD8AP0DtoApgOGAHIAlgCeA4NQADgDwAMABAAEBA7kDugO7gJeBAXqB +AX2BAXxaQ2xlYXIgTWVudV8QFWNsZWFyUmVjZW50RG9jdW1lbnRzOtMADgB9AH4A7APAA8GAK4DkgOfY +AA4A8ADxAPIA8wD0APUA9gD3A8QA+QPFAPsA/AD9AYGAKYDlgOaAJYAngExfEBNRdWl0IE5ld0FwcGxp +Y2F0aW9uUXFadGVybWluYXRlOtMADgB9AH4A7APOA8+AK4DpgOzYAA4A8ADxAPIA8wD0APUA9gD3A9IA ++QPTAPsA/AD9AUSAKYDqgOuAJYAngDplAE8AcABlAG4gJlFvXW9wZW5Eb2N1bWVudDrTAA4AfQB+AOwD +3APdgCuA7oDx2AAOAPAA8QDyAPMA9AD1APYA9wPgAPkD4QD7APwA/QFEgCmA74DwgCWAJ4A6VUNsb3Nl +UXddcGVyZm9ybUNsb3NlOtMADgB9AH4A7APqA+uAK4DzgPXYAA4A8ADxAPIA8wD0APUA9gD3A+4A+QCx +APsA/AD9ATKAKYD0gByAJYAngDRfEBtDaGVjayBHcmFtbWFyIFdpdGggU3BlbGxpbmdfEBZ0b2dnbGVH +cmFtbWFyQ2hlY2tpbmc60wAOAH0AfgDsA/cD+IArgPeA+tkADgDwAPEA8gDzAPQA9QD2AaoA9wP7APkD +PAD7APwA/QP/AgaAKYD5gLmAJYAngPjTAA4A8AEAAQEEAgQDgJeBAYaBAYhlAEYAaQBuAGQgJl8QF3Bl +cmZvcm1GaW5kUGFuZWxBY3Rpb2460wAOAH0AfgDsBAgECYArgPyA/9gADgDwAPEA8gDzAPQA9QD2APcE +DAD5ALEA+wD8AP0EEIApgP6AHIAlgCeA/dMADgDwAQABAQQTBBSAl4EBnYEBn28QEgBDAHUAcwB0AG8A +bQBpAHoAZQAgAFQAbwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrT +AA4AfQB+AOwEGQQagCuBAQGBAQXYAA4A8ADxAPIA8wD0APUA9gD3BB0BbgQeAPsA/AD9BCGAKYEBA4EB +BIAlgCeBAQLTAA4A8AEAAQEEJAQlgJeBAZeBAZlbU2hvdyBDb2xvcnNRQ18QFW9yZGVyRnJvbnRDb2xv +clBhbmVsOtMADgB9AH4A7AQrBCyAK4EBB4EBCtgADgDwAPEA8gDzAPQA9QD2APcELwF9BDAA+wD8AP0E +EIApgQEIgQEJgCWAJ4D9XFNob3cgVG9vbGJhclF0XxATdG9nZ2xlVG9vbGJhclNob3duOtQADgB8AH0A +fgB/AeAAgQQ7gCCAp4AKgQEMXxASc2hvd0RpYWxvZ0NoZWNrQm940wAOAH0AfgDsBD8EQIArgQEOgQER +2AAOAPAA8QDyAPMA9AD1APYA9wRDAPkERAD7APwA/QEggCmBAQ+BARCAJYAngC5VUGFzdGVRdlZwYXN0 +ZTrTAA4AfQB+AOwETQROgCuBAROBARbYAA4A8ADxAPIA8wD0APUA9gD3BFEBbgRSAPsA/AD9AUSAKYEB +FIEBFYAlgCeAOmgAUwBhAHYAZQAgAEEAcyAmUVNfEA9zYXZlRG9jdW1lbnRBczrTAA4AfQB+AOwEWwRc +gCuBARiBARvYAA4A8ADxAPIA8wD0APUA9gD3BF8BbgRgAPsA/AD9ASCAKYEBGYEBGoAlgCeALlRSZWRv +UVpVcmVkbzrTAA4AfQB+AOwEaQRqgCuBAR2BASDYAA4A8ADxAPIA8wD0APUA9gD3BG0A+QCxAPsA/AD9 +BHGAKYEBH4AcgCWAJ4EBHtQADgDwAMABAAEBBHQEdQR2gJeBAaGBAaSBAaNfEBJCcmluZyBBbGwgdG8g +RnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrTAA4AfQB+AOwEewR8gCuBASKBASTYAA4A8ADxAPIA8wD0APUA +9gD3BH8A+QCxAPsA/AD9BHGAKYEBI4AcgCWAJ4EBHlRab29tXHBlcmZvcm1ab29tOtMADgB9AH4A7ASI +BImAK4EBJoEBKdgADgDwAPEA8gDzAPQA9QD2APcEjAD5BI0A+wD8AP0D/4ApgQEngQEogCWAJ4D4XxAR +SnVtcCB0byBTZWxlY3Rpb25Ral8QHWNlbnRlclNlbGVjdGlvbkluVmlzaWJsZUFyZWE60wAOAH0AfgDs +BJYEl4ArgQErgQEv2AAOAPAA8QDyAPMA9AD1APYA9wSaAPkEmwD7APwA/QSegCmBAS2BAS6AJYAngQEs +0wAOAPABAAEBBKEEooCXgQGmgQGoXxATTmV3QXBwbGljYXRpb24gSGVscFE/WXNob3dIZWxwOtQADgB8 +AH0AfgB/AIEEqQN3gCCACoEBMYDN0gAOADIAMwStgASBATJdTlNBcHBsaWNhdGlvbtMADgB9AH4A7ASx +BLKAK4EBNIEBN9gADgDwAPEA8gDzAPQA9QD2APcEtQD5BLYA+wD8AP0BRIApgQE1gQE2gCWAJ4A6VFNh +dmVRc11zYXZlRG9jdW1lbnQ60wAOAH0AfgDsBL8EwIArgQE5gQE82AAOAPAA8QDyAPMA9AD1APYA9wTD +APkExAD7APwA/QEygCmBATqBATuAJYAngDRuAFMAaABvAHcAIABTAHAAZQBsAGwAaQBuAGcgJlE6XxAP +c2hvd0d1ZXNzUGFuZWw60wAOAH0AfgDsBM0EzoArgQE+gQFB2AAOAPAA8QDyAPMA9AD1APYA9wTRAPkE +0gD7APwA/QFEgCmBAT+BAUCAJYAngDpmAFAAcgBpAG4AdCAmUXBWcHJpbnQ60wAOAH0AfgDsBNsE3IAr +gQFDgQFG2AAOAPAA8QDyAPMA9AD1APYA9wTfAPkE4AD7APwA/QRxgCmBAUSBAUWAJYAngQEeWE1pbmlt +aXplUW1fEBNwZXJmb3JtTWluaWF0dXJpemU60wAOAH0AfgDsBOkE6oArgQFIgQFL2AAOAPAA8QDyAPMA +9AD1APYA9wTtAPkE7gD7APwA/QEggCmBAUmBAUqAJYAngC5UVW5kb1F6VXVuZG860wAOAH0AfgDsBPcE ++IArgQFNgQFP2AAOAPAA8QDyAPMA9AD1APYA9wT7APkAsQD7APwA/QEggCmBAU6AHIAlgCeALlZEZWxl +dGVXZGVsZXRlOtQADgB8AH0AfgB/AhMAgQUGgCCAe4AKgQFRXnBhcmFtVGV4dEZpZWxk1wAOAHwFCQUK +AH0AfgULBQwAgQUOBQ8CFQURALRZTlNLZXlQYXRoWU5TQmluZGluZ18QHE5TTmliQmluZGluZ0Nvbm5l +Y3RvclZlcnNpb26BAVaACoEBVYEBVICHgQFTXxAUY29udGVudDogc2NyZWVuTW9kZXNXY29udGVudFtz +Y3JlZW5Nb2Rlc9IANwA4BRYFF6MFFwDqADtfEBVOU05pYkJpbmRpbmdDb25uZWN0b3LSAA4APgUZBRqB +AayvEGwBmgEqBR0FHgEyBSABjAJRBFsFJAIVAeEBZwKEBSkA/gQhBBkB3QSpASAFMAITA1kDRQObA2cB +xwU3BTgD9wP/AbABgQT3BGkEiAQQBUEECAK3AacEngFNAnMBPAIbAIEFSwS/BU0B4ASxBVABugMZAXgF +VAVVAO0EcQKWAVoFWgEYArgFXQTpAUQB3wCAA+oE2wQ/BWUDrgKcBWgCFAVqA3wC9QVtBJYCEgTNBE0F +cgR7AzcB5gV2BXcFeAV5A8AFewCZAJIEKwPOBYAFgQO2AwYFhAWFA9yAVoAzgQFYgQFZgDSBAVyAUYB9 +gQEYgQFggIeAq4BGgImBAWOAI4EBAoEBAYBmgQExgC6BAXWAe4DDgLyA2YDIgGSBAZqBAaqA94D4gFuA +TIEBTYEBHYEBJoD9gQGJgPyAkIBagQEsgD6AhYA5gG+ACoEBf4EBOYEBkoCngQE0gQFsgGCArYBLgQFy +gQFzgCKBAR6AioBCgQGggC2Ak4EBa4EBSIA6gKOADIDzgQFDgQEOgQGNgN+Ai4EBkICDgQFqgM+ApYEB +eYEBK4BtgQE+gQETgQFmgQEigLeAaIEBpYEBb4EBnIEBloDkgQGLgGqAEIEBB4DpgQGDgQF+gOCAqYEB +hYEBhIDu2gAOAPAA8QWIAPICoADzAPQA9QD2APcAsQD5AJQAsQCUAPsA/AD9AURdTlNJc1NlcGFyYXRv +coApgBwJgBwJgCWAJ4A62gAOAPAA8QWIAPICoADzAPQA9QD2APcAsQD5AJQAsQCUAPsA/AD9BHGAKYAc +CYAcCYAlgCeBAR5fEBRTcGVsbGluZyBhbmQgR3JhbW1hctIADgA+AEYFnYCWpAS/ASoBTQPqgQE5gDOA +PoDz2gAOBaMA8ADxAPIA8wD0APUA9gKhAPcBsAGzAPkAsQD7APwA/QEgBatZTlNTdWJtZW51gCmAW4EB +XYAcgCWAJ4AugQFeXVN1YnN0aXR1dGlvbnNec3VibWVudUFjdGlvbjrSAA4APgBGBbCAlqMDNwGnA0WA +t4BagLzYAA4A8ADxAPIA8wD0APUA9gD3BbYA+QW3APsA/AD9AYGAKYEBYYEBYoAlgCeATGwAUAByAGUA +ZgBlAHIAZQBuAGMAZQBzICZRLNQADgDwAMABAAEBBb8FwAXBgJeBAWSBAamBAWVZQU1haW5NZW510gAO +AD4ARgXFgJanBXIFMAVLBXkFeAVaBXaBAWaBAXWBAX+BAZaBAZyBAaCBAaXaAA4FowDwAPEA8gDzAPQA +9QD2AqEA9wGBAYQA+QCxAPsA/AD9BSkF1YApgEyBAWeAHIAlgCeBAWOBAWheTmV3QXBwbGljYXRpb27S +AA4APgBGBdmAlqsDfAVqBSQFXQVQBVQDmwF4AZoFVQPAgM+BAWqBAWCBAWuBAWyBAXKA2YBLgFaBAXOA +5NoADgDwAPEFiADyAqAA8wD0APUA9gD3ALEA+QCUALEAlAD7APwA/QGBgCmAHAmAHAmAJYAngEzaAA4A +8ADxBYgA8gKgAPMA9AD1APYA9wCxAPkAlACxAJQA+wD8AP0BgYApgBwJgBwJgCWAJ4BM2gAOBaMA8ADx +APIA8wD0APUA9gKhAPcFdwX6APkAsQD7APwA/QGBBf+AKYEBb4EBbYAcgCWAJ4BMgQFuWFNlcnZpY2Vz +1AAOAPAAwAEAAQEF+gYEBgWAl4EBbYEBcYEBcNIADgA+AEYGCICWoF8QD19OU1NlcnZpY2VzTWVuddoA +DgDwAPEFiADyAqAA8wD0APUA9gD3ALEA+QCUALEAlAD7APwA/QGBgCmAHAmAHAmAJYAngEzaAA4A8ADx +BYgA8gKgAPMA9AD1APYA9wCxAPkAlACxAJQA+wD8AP0BgYApgBwJgBwJgCWAJ4BMXF9OU0FwcGxlTWVu +ddoADgWjAPAA8QDyAPMA9AD1APYCoQD3AUQBRwD5ALEA+wD8AP0FKQYlgCmAOoEBdoAcgCWAJ4EBY4EB +d1RGaWxl0gAOAD4ARgYpgJarA2cDzgVtBR0D3ASxBE0BPAWBAWcEzYDIgOmBAXmBAViA7oEBNIEBE4A5 +gQF+gEaBAT7aAA4FowDwAPEA8gDzAPQA9QD2AqEA9wO2A7kA+QCxAPsA/AD9AUQGPYApgOCBAXqAHIAl +gCeAOoEBe1tPcGVuIFJlY2VudNIADgA+AEYGQYCWoQOugN9fEBZfTlNSZWNlbnREb2N1bWVudHNNZW51 +2gAOAPAA8QWIAPICoADzAPQA9QD2APcAsQD5AJQAsQCUAPsA/AD9AUSAKYAcCYAcCYAlgCeAOtoADgWj +APAA8QDyAPMA9AD1APYCoQD3ASABIwD5ALEA+wD8AP0FKQZVgCmALoEBgIAcgCWAJ4EBY4EBgVRFZGl0 +0gAOAD4ARgZZgJatBOkEWwWAA1kBjAQ/BPcBGAWFBYQFaAUgBU2BAUiBARiBAYOAw4BRgQEOgQFNgC2B +AYSBAYWBAZCBAVyBAZLaAA4A8ADxBYgA8gKgAPMA9AD1APYA9wCxAPkAlACxAJQA+wD8AP0BIIApgBwJ +gBwJgCWAJ4Au2gAOAPAA8QWIAPICoADzAPQA9QD2APcAsQD5AJQAsQCUAPsA/AD9ASCAKYAcCYAcCYAl +gCeALtoADgWjAPAA8QDyAPMA9AD1APYCoQD3A/8EAgD5ALEA+wD8AP0BIAaBgCmA+IEBhoAcgCWAJ4Au +gQGHVEZpbmTSAA4APgBGBoWAlqUD9wVBBXsFZQSIgPeBAYmBAYuBAY2BASbZAA4A8ADxAPIA8wD0APUA +9gGqAPcGjQD5Aa0A+wD8AP0D/wC0gCmBAYqAXYAlgCeA+FlGaW5kIE5leHTZAA4A8ADxAPIA8wD0APUA +9gGqAPcGlQFuA0oA+wD8AP0D/wHOgCmBAYyAvoAlgCeA+F1GaW5kIFByZXZpb3Vz2QAOAPAA8QDyAPMA +9AD1APYBqgD3Bp0A+QaeAPsA/AD9A/8GooApgQGOgQGPgCWAJ4D4EAdfEBZVc2UgU2VsZWN0aW9uIGZv +ciBGaW5kUWXaAA4FowDwAPEA8gDzAPQA9QD2AqEA9wEyATUA+QCxAPsA/AD9ASAGrYApgDSBAVqAHIAl +gCeALoEBkdoADgWjAPAA8QDyAPMA9AD1APYCoQD3AP4BAgD5ALEA+wD8AP0BIAa2gCmAI4EBk4AcgCWA +J4AugQGUVlNwZWVjaNIADgA+AEYGuoCWogFaAO2AQoAi2gAOBaMA8ADxAPIA8wD0APUA9gKhAPcEIQQk +APkAsQD7APwA/QUpBsWAKYEBAoEBl4AcgCWAJ4EBY4EBmFZGb3JtYXTSAA4APgBGBsmAlqIFNwQZgQGa +gQEB2AAOAPAA8QDyAPMA9AD1APYA9wbOAPkEMAD7APwA/QQhgCmBAZuBAQmAJYAngQECWlNob3cgRm9u +dHPaAA4FowDwAPEA8gDzAPQA9QD2AqEA9wQQBBMA+QCxAPsA/AD9BSkG3IApgP2BAZ2AHIAlgCeBAWOB +AZ5UVmlld9IADgA+AEYG4ICWogQrBAiBAQeA/NoADgWjAPAA8QDyAPMA9AD1APYCoQD3BHEEdAD5ALEA ++wD8AP0FKQbrgCmBAR6BAaGAHIAlgCeBAWOBAaJWV2luZG930gAOAD4ARgbvgJakBNsEewUeBGmBAUOB +ASKBAVmBAR1eX05TV2luZG93c01lbnXaAA4FowDwAPEA8gDzAPQA9QD2AqEA9wSeBKEA+QCxAPsA/AD9 +BSkG/YApgQEsgQGmgByAJYAngQFjgQGnVEhlbHDSAA4APgBGBwGAlqEEloEBK1tfTlNNYWluTWVuddIA +DgcFBwYAlF8QEE5TU2hhcmVkSW5zdGFuY2WBAasJ0gA3ADgHCQcKowcKBwsAO18QGE5TVXNlckRlZmF1 +bHRzQ29udHJvbGxlclxOU0NvbnRyb2xsZXLSADcAOAcNAtCiAtAAO9IADgA+BRkHEIEBrK8QbAGBATIB +RARxBWgBIAEgAhMBIAGBAJkBxwFEAhUAHwVNBXkEIQHHAB8FSwUpAJkBIAGwAYEBRAG6BCEAHwP/BYQF +IAVyASAEcQP/BXgD/wQQApwBsAV2ATICFAFEAhIAHwUpATIBIAHHAUQBgQAfAeEBgQGBAYEA/gVaApwA +/gUpASACnAGBASAFMAHHAJkBMgRxASAD/wO2AoQBIACZAYEBgQHfAUQEngCZAUQBRAUpBHEBsAHdBSkF +UAUpBSkBgQP/AccAgAQQAUQBIAFEBW0B4AEgASABRIBMgDSAOoEBHoEBkIAugC6Ae4AugEyAaoBkgDqA +h4ACgQGSgQGWgQECgGSAAoEBf4EBY4BqgC6AW4BMgDqAYIEBAoACgPiBAYWBAVyBAWaALoEBHoD4gQGc +gPiA/YCLgFuBAaWANICDgDqAbYACgQFjgDSALoBkgDqATIACgKuATIBMgEyAI4EBoICLgCOBAWOALoCL +gEyALoEBdYBkgGqANIEBHoAugPiA4ICJgC6AaoBMgEyAo4A6gQEsgGqAOoA6gQFjgQEegFuAZoEBY4EB +bIEBY4EBY4BMgPiAZIAMgP2AOoAugDqBAXmAp4AugC6AOtIADgA+BRkHf4EBrK8QbQGaASoFHQUeATIF +IAGMAlEEWwUkAeECFQFnAoQFKQD+BCEEGQHdBKkFMAEgAhMDZwNZA5sDRQHHBTcFOAP3AbAD/wGBBPcE +aQQQBAgEiAVBArcBpwSeAU0CcwE8AhsAgQVLBL8FTQHgBLEFUAG6AxkBeAVUBVUA7QRxApYBWgVaARgC +uAFEAd8E6QVdAIAD6gAfBNsEPwOuBWUCnAVoAhQFagN8AvUFbQSWAhIEzQRNBXIEewHmAzcFdgV4BXkF +dwPABXsAmQCSBCsDzgWBBYADtgMGBYQFhQPcgFaAM4EBWIEBWYA0gQFcgFGAfYEBGIEBYICrgIeARoCJ +gQFjgCOBAQKBAQGAZoEBMYEBdYAugHuAyIDDgNmAvIBkgQGagQGqgPeAW4D4gEyBAU2BAR2A/YD8gQEm +gQGJgJCAWoEBLIA+gIWAOYBvgAqBAX+BATmBAZKAp4EBNIEBbIBggK2AS4EBcoEBc4AigQEegIqAQoEB +oIAtgJOAOoCjgQFIgQFrgAyA84ACgQFDgQEOgN+BAY2Ai4EBkICDgQFqgM+ApYEBeYEBK4BtgQE+gQET +gQFmgQEigGiAt4EBpYEBnIEBloEBb4DkgQGLgGqAEIEBB4DpgQF+gQGDgOCAqYEBhYEBhIDu0gAOAD4F +GQfvgQGsrxBtB/AH8QfyB/MH9Af1B/YH9wf4B/kH+gf7B/wH/Qf+B/8IAAgBCAIIAwgECAUIBggHCAgI +CQgKCAsIDAgNCA4IDwgQCBEIEggTCBQIFQgWCBcIGAgZCBoIGwgcCB0IHggfCCAIIQgiCCMIJAglCCYI +JwgoCCkIKggrCCwILQguCC8IMAgxCDIIMwg0CDUINgg3CDgIOQg6CDsIPAg9CD4IPwhACEEIQghDCEQI +RQhGCEcISAhJCEoISwhMCE0ITghPCFAIUQhSCFMIVAhVCFYIVwhYCFkIWghbCFyBAbCBAbGBAbKBAbOB +AbSBAbWBAbaBAbeBAbiBAbmBAbqBAbuBAbyBAb2BAb6BAb+BAcCBAcGBAcKBAcOBAcSBAcWBAcaBAceB +AciBAcmBAcqBAcuBAcyBAc2BAc6BAc+BAdCBAdGBAdKBAdOBAdSBAdWBAdaBAdeBAdiBAdmBAdqBAduB +AdyBAd2BAd6BAd+BAeCBAeGBAeKBAeOBAeSBAeWBAeaBAeeBAeiBAemBAeqBAeuBAeyBAe2BAe6BAe+B +AfCBAfGBAfKBAfOBAfSBAfWBAfaBAfeBAfiBAfmBAfqBAfuBAfyBAf2BAf6BAf+BAgCBAgGBAgKBAgOB +AgSBAgWBAgaBAgeBAgiBAgmBAgqBAguBAgyBAg2BAg6BAg+BAhCBAhGBAhKBAhOBAhSBAhWBAhaBAheB +AhiBAhmBAhqBAhuBAhxfEBRNZW51IEl0ZW0gKFNob3cgQWxsKV8QGk1lbnUgSXRlbSAoQ2hlY2sgU3Bl +bGxpbmcpUTdbU2VwYXJhdG9yLTJfEBtNZW51IChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBlNZW51IEl0 +ZW0gKFN1YnN0aXR1dGlvbnMpXxAQTWVudSBJdGVtIChDb3B5KV8QD1RleHQgRmllbGQgQ2VsbF8QEE1l +bnUgSXRlbSAoUmVkbylTMTIxXxBKU3RhdGljIFRleHQgKEhvbGQgdGhlIENvbW1hbmQga2V5IG9uIHN0 +YXJ0dXAgdG8gZGlzcGxheSB0aGlzIGRpYWxvZyBhZ2FpbilfEBVQb3B1cCBCdXR0b24gKEl0ZW0gMSlR +NV8QG1BvcCBVcCBCdXR0b24gQ2VsbCAoSXRlbSAxKVhNYWluTWVudV1NZW51IChTcGVlY2gpXU1lbnUg +KEZvcm1hdClfEBdNZW51IEl0ZW0gKFNob3cgQ29sb3JzKV8QE1B1c2ggQnV0dG9uIChTdGFydClbQXBw +bGljYXRpb25fEBBNZW51IEl0ZW0gKEZpbGUpW01lbnUgKEVkaXQpWlRleHQgRmllbGRROV8QD01lbnUg +SXRlbSAoQ3V0KV8QH01lbnUgSXRlbSAoSGlkZSBOZXdBcHBsaWNhdGlvbilfEBdNZW51IEl0ZW0gKFNt +YXJ0IExpbmtzKVxDb250ZW50IFZpZXdfEBZNZW51IEl0ZW0gKFNob3cgRm9udHMpXxAfU2hhcmVkIFVz +ZXIgRGVmYXVsdHMgQ29udHJvbGxlcm8QEQBNAGUAbgB1ACAASQB0AGUAbQAgACgARgBpAG4AZCAmAClf +EBRNZW51IChTdWJzdGl0dXRpb25zKVtNZW51IChGaW5kKV8QFU1lbnUgKE5ld0FwcGxpY2F0aW9uKV8Q +Ek1lbnUgSXRlbSAoRGVsZXRlKV8QHk1lbnUgSXRlbSAoQnJpbmcgQWxsIHRvIEZyb250KVtNZW51IChW +aWV3KW8QHgBNAGUAbgB1ACAASQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIA +YQByICYAKV8QHU1lbnUgSXRlbSAoSnVtcCB0byBTZWxlY3Rpb24pXxAVTWVudSBJdGVtIChGaW5kIE5l +eHQpXxASTWVudSBJdGVtIChJdGVtIDIpXxAYTWVudSBJdGVtIChTbWFydCBRdW90ZXMpUTJfECdNZW51 +IEl0ZW0gKENoZWNrIFNwZWxsaW5nIFdoaWxlIFR5cGluZylfECxUZXh0IEZpZWxkIENlbGwgKFJlc29s +dXRpb24gYW5kIGNvbG9yIGRlcHRoKVIxMF8QKVRleHQgRmllbGQgQ2VsbCAoQ29tbWFuZCBsaW5lIHBh +cmFtZXRlcnMpXkFwcCBDb250cm9sbGVyXxAQTWVudSBJdGVtIChFZGl0KW8QGgBNAGUAbgB1ACAASQB0 +AGUAbQAgACgAUwBoAG8AdwAgAFMAcABlAGwAbABpAG4AZyAmAClfEBJNZW51IEl0ZW0gKFNwZWVjaClf +ECNDaGVjayBCb3ggKEFsd2F5cyBzaG93IHRoaXMgZGlhbG9nKVEzXxAUTWVudSBJdGVtIChTZXJ2aWNl +cylfEBJXaW5kb3cgKEZpdHpxdWFrZSlfEE5UZXh0IEZpZWxkIENlbGwgKEhvbGQgdGhlIENvbW1hbmQg +a2V5IG9uIHN0YXJ0dXAgdG8gZGlzcGxheSB0aGlzIGRpYWxvZyBhZ2FpbilfEBdNZW51IEl0ZW0gKEhp +ZGUgT3RoZXJzKVtTZXBhcmF0b3ItM1tTZXBhcmF0b3ItNF8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2lu +ZyldTWVudSAoV2luZG93KV8QEk1lbnUgSXRlbSAoSXRlbSAxKV8QGk1lbnUgSXRlbSAoU3RhcnQgU3Bl +YWtpbmcpXxASTWVudSBJdGVtIChXaW5kb3cpXxAWTWVudSBJdGVtIChTZWxlY3QgQWxsKV8QEk1lbnUg +SXRlbSAoSXRlbSAzKVtNZW51IChGaWxlKV8QFFB1c2ggQnV0dG9uIChDYW5jZWwpXxAQTWVudSBJdGVt +IChVbmRvKVtTZXBhcmF0b3ItNV8QFkNoZWNrIEJveCAoRnVsbHNjcmVlbilfECdNZW51IEl0ZW0gKENo +ZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGluZylcRmlsZSdzIE93bmVyXxAUTWVudSBJdGVtIChNaW5pbWl6 +ZSlfEBFNZW51IEl0ZW0gKFBhc3RlKV8QFk1lbnUgSXRlbSAoQ2xlYXIgTWVudSlfECJNZW51IEl0ZW0g +KFVzZSBTZWxlY3Rpb24gZm9yIEZpbmQpXxARTWVudSAoT3RoZXJWaWV3cylfECBNZW51IEl0ZW0gKFNw +ZWxsaW5nIGFuZCBHcmFtbWFyKV8QKFN0YXRpYyBUZXh0IChSZXNvbHV0aW9uIGFuZCBjb2xvciBkZXB0 +aClbU2VwYXJhdG9yLTZfECBNZW51IEl0ZW0gKEFib3V0IE5ld0FwcGxpY2F0aW9uKV8QFEJ1dHRvbiBD +ZWxsIChDYW5jZWwpXxAXTWVudSBJdGVtIChPcGVuIFJlY2VudClfEB9NZW51IEl0ZW0gKE5ld0FwcGxp +Y2F0aW9uIEhlbHApXxAlU3RhdGljIFRleHQgKENvbW1hbmQgbGluZSBwYXJhbWV0ZXJzKVE2UThfEBpN +ZW51IEl0ZW0gKE5ld0FwcGxpY2F0aW9uKV8QEE1lbnUgSXRlbSAoWm9vbSlfEBNCdXR0b24gQ2VsbCAo +U3RhcnQpXxAcTWVudSBJdGVtIChTbWFydCBDb3B5L1Bhc3RlKVExXxAQTWVudSBJdGVtIChWaWV3KV8Q +Ek1lbnUgSXRlbSAoRm9ybWF0KV8QD01lbnUgKFNlcnZpY2VzKVQxMTExXxAZTWVudSBJdGVtIChGaW5k +IFByZXZpb3VzKV5Cb3ggKFNldHRpbmdzKV8QGEJ1dHRvbiBDZWxsIChGdWxsc2NyZWVuKV8QGE1lbnUg +SXRlbSAoU2hvdyBUb29sYmFyKW8QEQBNAGUAbgB1ACAASQB0AGUAbQAgACgATwBwAGUAbiAmAClTMi0x +WVNlcGFyYXRvcl8QEk1lbnUgKE9wZW4gUmVjZW50KV8QJUJ1dHRvbiBDZWxsIChBbHdheXMgc2hvdyB0 +aGlzIGRpYWxvZylfEBBNZW51IEl0ZW0gKEZpbmQpW1NlcGFyYXRvci0xUzEtMdIADgA+BRkIzIEBrKDS +AA4APgUZCM+BAayg0gAOAD4FGQjSgQGsrxCgAZoBKgUdAGAAUwUeATIFIABJAGgBjAJRBFsFJAIVAeEA +WQBeAWcChAB0BSkA/gQhBBkAYgHdAHcEqQEgBTACEwNZA0UDmwNnAE8BxwU3AFAFOABUAFUAYwBqAGwA +cAP3AHkD/wGwAYEE9wRpBIgEEAVBBAgCtwGnBJ4BTQB2AnMASAE8AhsAgQBmBUsEvwBSBU0B4ASxAFYA +cwVQAboDGQBrAEoBeABXAG4FVAVVAF8AeADtBHEClgFaAE4ATQVaAFoBGAK4AEwFXQTpAUQB3wCAAG0D +6gAfBNsEPwVlA64AZAKcBWgCFABdAGcFagN8AFwC9QVtBJYASwISAHUEzQRNAGkFcgR7AzcB5gBRBXYF +dwV4BXkAWwPABXsAWACZAJIAZQBhBCsAegByAHEDzgWABYEDtgBvAwYFhAWFA9yAVoAzgQFYgNyAWYEB +WYA0gQFcgCGBAQCAUYB9gQEYgQFggIeAq4DHgNaARoCJgQE4gQFjgCOBAQKBAQGA44BmgQFHgQExgC6B +AXWAe4DDgLyA2YDIgEWAZIEBmoBKgQGqgF+AtoDogQELgQESgQElgPeBAVCA+IBbgEyBAU2BAR2BASaA +/YEBiYD8gJCAWoEBLIA+gQFCgIWACYA5gG+ACoD2gQF/gQE5gFWBAZKAp4EBNIC7gQEzgQFsgGCArYEB +DYAsgEuAwIEBHIEBcoEBc4DYgQFMgCKBAR6AioBCgEGAPYEBoIDMgC2Ak4A4gQFrgQFIgDqAo4AMgQEX +gPOAAoEBQ4EBDoEBjYDfgO2Ai4EBkICDgNSA+4EBaoDPgNKApYEBeYEBK4AygG2BAT2BAT6BAROBAQaB +AWaBASKAt4BogFCBAaWBAW+BAZyBAZaAzoDkgQGLgMKAaoAQgPKA3oEBB4EBUoEBMIEBKoDpgQGDgQF+ +gOCBASGAqYEBhYEBhIDu0gAOAD4FGQl1gQGsrxCgCXYJdwl4CXkJegl7CXwJfQl+CX8JgAmBCYIJgwmE +CYUJhgmHCYgJiQmKCYsJjAmNCY4JjwmQCZEJkgmTCZQJlQmWCZcJmAmZCZoJmwmcCZ0JngmfCaAJoQmi +CaMJpAmlCaYJpwmoCakJqgmrCawJrQmuCa8JsAmxCbIJswm0CbUJtgm3CbgJuQm6CbsJvAm9Cb4JvwnA +CcEJwgnDCcQJxQnGCccJyAnJCcoJywnMCc0JzgnPCdAJ0QnSCdMJ1AnVCdYJ1wnYCdkJ2gnbCdwJ3Qne +Cd8J4AnhCeIJ4wnkCeUJ5gnnCegJ6QnqCesJ7AntCe4J7wnwCfEJ8gnzCfQJ9Qn2CfcJ+An5CfoJ+wn8 +Cf0J/gn/CgAKAQoCCgMKBAoFCgYKBwoICgkKCgoLCgwKDQoOCg8KEAoRChIKEwoUChWBAiGBAiKBAiOB +AiSBAiWBAiaBAieBAiiBAimBAiqBAiuBAiyBAi2BAi6BAi+BAjCBAjGBAjKBAjOBAjSBAjWBAjaBAjeB +AjiBAjmBAjqBAjuBAjyBAj2BAj6BAj+BAkCBAkGBAkKBAkOBAkSBAkWBAkaBAkeBAkiBAkmBAkqBAkuB +AkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAlaBAleBAliBAlmBAlqBAluBAlyBAl2BAl6BAl+B +AmCBAmGBAmKBAmOBAmSBAmWBAmaBAmeBAmiBAmmBAmqBAmuBAmyBAm2BAm6BAm+BAnCBAnGBAnKBAnOB +AnSBAnWBAnaBAneBAniBAnmBAnqBAnuBAnyBAn2BAn6BAn+BAoCBAoGBAoKBAoOBAoSBAoWBAoaBAoeB +AoiBAomBAoqBAouBAoyBAo2BAo6BAo+BApCBApGBApKBApOBApSBApWBApaBApeBApiBApmBApqBApuB +ApyBAp2BAp6BAp+BAqCBAqGBAqKBAqOBAqSBAqWBAqaBAqeBAqiBAqmBAqqBAquBAqyBAq2BAq6BAq+B +ArCBArGBArKBArOBArSBArWBAraBAreBAriBArmBArqBAruBAryBAr2BAr6BAr+BAsAQlhDJEE8RAccR +AWQQXBEBXBDjEQFpEMURAZcQ1xEBzREBdREBohBNEQGREOYQHRDUEQEsEQFZEQFxEQF4EN8T//////// +//0QzRBTEQGOEMcRAWIQhhBSEFcRAXQRAVgRAXARAaMRAZ4RAWMRAXYRAc8RAWsQ9RDREQGcENwRAV0Q +ORDKEAUQ0hEBKBDQEQEqEQGUEQFfEGoQ2xAlEQGWEQHFEHARAZgRAXcQ8RDZEMwRAXIQ0xEByxEBZREB +ahCDEQFzEQHOEOIQ6BCREQGhECcQkBCVEQFvEOsQwxAYEQGVEMQQ6RDeEBMRAZ8QxhEBkxEBbBCPEM8Q +UREBmhEBwhDnEQFaEQHREBcQyxDdEH4QwREBkhDYEQGPEQHEEQFtEOwQOhEBehEBmxB8EG8Q4REBjRBW +EE4QUBEBbhA4EO8RAV4RAXkQ4BBnEIIRAScRASsQjhCIENUQ5BEBixEBwxEBWxB/EQEpEQHBEQHQEQFo +EEgQzhBKEH0Q8BEBzBDaENYQSdIADgA+AEYKtICWoNIADgA+BRkKt4EBrKDSAA4APgUZCrqBAayg0gA3 +ADgKvAq9ogq9ADteTlNJQk9iamVjdERhdGEACAAZACIAJwAxADoAPwBEAFIAVABmBfQF+gZFBkwGUwZh +BnMGjwadBqkGtQbDBs4G3Ab4BwYHGQcrB0UHTwdcB14HYQdkB2cHagdsB28HcQd0B3cHegd9B38HgQeE +B4cHigeNB5YHogekB6YHrge3B8AHywfQB98H6Af7CAQIDwgRCBIIGwgiCC8INQg+CEAIqQirCK0Irwix +CLMItQi3CLkIuwi9CL8IwQjDCMUIxwjJCMsIzQjPCNEI0wjVCNcI2QjbCN0I3wjhCOMI5QjnCOkI7Ajv +CPII9Qj4CPsI/gkBCQQJBwkKCQ0JEAkTCRYJGQkcCR8JIgkzCUEJSglSCVQJVglYCVoJYwllCWcJdQmW +CagJsAm3CcAJygnTCd8J4QnjCeUJ5wnqCesJ7QnvCgwKFwoZChsKHQofCiIKJAomCj4KdwqDCpkKpwq8 +CssK3grwCvsLBQsTCyULMgtAC0kLSwtNC08LUQtTC1ULVwtZC1sLXQtfC2ELZgtxC4ILiQuQC5kLmwuk +C6YLqQu2C78LxAvLC9gL5wvpC+sL7Qv1C/4MBwwMDB8MKAw0DDYMOAxBDEYMXAxdDGYMbwx8DIkMkgyd +DKYMsAy3DMMM2AzhDOgM/w0ODRsNHQ0fDSENQg1KDV4NaQ13DYENjg2VDZcNmQ2eDaANpQ2nDakNqw24 +DcQNxg3JDcwN2g3nDekN6w3tDf8ODA4ODhAOEg4lDi4OMw4+DkwOVQ5cDnQOgQ6DDoUOhw6oDqoOrA6u +DrAOsg60DsEOww7GDskO1A7WDuEO7g7wDvIO9A8VDxcPGQ8bDx0PHw8hDy4PMA8zDzYPRQ9HD1YPYw9l +D2cPaQ+GD4gPig+MD44PkA+SD58PoQ+kD6cPuQ/SD98P4Q/jD+UQBhAIEAoQDBAOEBAQEhAwEFEQXhBg +EGIQZBCFEIcQiRCLEI0QjxCREKAQrxC8EL4QwBDCEOcQ8RDzEPUQ9xD8EP4RABECEQQREhEUESMRMBEy +ETQRNhFXEVkRWxFgEWIRZBFmEWgReRF7EX4RgRGEEZARkhGrEbgRuhG8Eb4R3xHhEeMR5RHnEekR6xHw +EfIR+BIFEgcSCRILEiwSLhIwEjISNBI2EjgSQRJaEmcSaRJrEm0SkhKYEpoSnBKeEqASohKkErESsxK2 +ErkSxhLIEuwS/RL/EwETAxMFEy4TOxNIE1YTYBNuE3sTjROhE60TrxOxE7MTtRO6E7wTvhPAE8IT3RPn +FAQUEBQSFBQUFhQYFBoUHBQlFCcUMhQ0FDYUOBQ6FDwUXRRfFGEUYxRlFGYUaBRqFIMUtBS5FLsUvRS/ +FMEUwxTFFMcUzBTVFNsVFBUeFSoVOBVFFU8VYRVvFXEVcxV1FXcVeBV6FXwVfhWAFYIVhBWGFY8VkRWU +FZYVnxWhFawVrhWwFbIVtBW2FdcV2RXbFd0V3xXgFeIV5BX9Fh4WMhY+FkMWRRZHFkkWSxZNFlIWVBZu +FoMWixaYFqQWsha0FrYWuBa6FrwWwxbQFt0W5RbnFvMW/BcBFxYXGBcaFxwXHhcxFz4XQBdDF0wXVRdn +F3AXexeHF6gXqhesF64XsBexF7MXtRfNF/IYBhgPGBEYExgVGBcYGRgaGBwYMRgzGDUYNxg5GE8YXBhe +GGEYdhh4GHoYfBh+GIgYqRirGK0YrxixGLIYtBi2GM4Y7xjxGPMY9Rj3GPkY+xkYGTkZOxk9GT8ZQRlC +GUQZRhleGakZxhnYGeoZ/xoNGhYaFxoZGhsaHRofGiEaIxolGiYaJxoqGi0aLxo0GmUabhp7GoQajBqO +GpAakhqUGpUalxqZGpsanRqqGqwarhqwGrcayxrWGt8a4RroGuoa7BruGxcbGRsbGx0bHxshGyMbJRsn +Gy4bVxtZG1sbXRtfG2EbYxtlG2cbbht3G34bjRuVG54boxusG7kbzRvcG+Ub8hwAHBccIBwnHEAcRxxk +HGYcaBxqHGwcbhx3HIgcihyTHJUcmBylHKcctRy+HMcczRzuHPAc8hz0HPYc9xz5HPsdFB1FHUcdSR1L +HU0dTx1RHVgdeR17HX0dfx2BHYIdhB2GHZ4d1x3ZHdsd3R3fHeEd4x3lHeceAR4iHiQeJh4oHioeKx4t +Hi8eRx5oHmoebB5uHnAech53HnkeuB7JHssezR7PHtwe4h7kHvgfAx8cHyUfKh89H0wfWR9bH10fXx+E +H4YfiB+KH4wfjh+QH6MfpR/AH80fzx/RH9Mf+B/6H/wf/iAAIAIgBCAQIBIgMiBDIEUgRyBJIEsgYSBu +IHAgciB0IJUglyCZIJsgnSCfIKEgpSCnIKwguSC7IL0gvyDgIOIg5CDmIOgg6iDsIPAg8iD/IRAhEiEU +IRYhGCEhITIhNCE2ITghOiFXIVkhWyFdIV8hYSFjIXohmiGrIa0hryGxIbMhwCHRIdMh1SHXIdkh6yH8 +If4iACICIgQiDCIZIhsiHSIfIkAiQiJEIkYiSCJKIkwiYiJoInkieyJ9In8igSKVIqIipCKmIqgiySLL +Is0izyLRItMi1SLmIugi6yLuIvEi/CMUIyEjIyMlIycjSCNKI0wjTiNQI1IjVCNqI2wjdyOEI4YjiCOK +I6sjrSOvI7EjsyO1I7cjwiPEI9Ij3yPhI+Mj5SQGJAgkCiQMJA4kECQSJBgkGiQoJDUkNyQ5JDskXCRe +JGAkYiRkJGYkaCSGJJ8krCSuJLAksiTXJNkk2yTdJN8k4STjJPAk8iT1JPglAyUdJSolLCUuJTAlUSVT +JVUlVyVZJVslXSVqJWwlbyVyJZkluyXIJcolzSXQJfEl8yX2Jfkl+yX9JgAmDSYPJhImFSYhJiMmOyZI +JkomTSZQJnEmcyZ2JnkmeyZ9Jn8mjCaOJqQmtSa3Jrkmuya+JtMm4CbiJuUm6CcJJwsnDicRJxMnFScX +Jx0nHycmJzMnNSc4JzsnXCdeJ2EnZCdmJ2gnaid7J30njyecJ54noSekJ8UnxyfKJ80nzyfRJ9Mn2Cfa +J+An7SfvJ/In9SgWKBgoGygdKB8oISgkKDUoNyg6KD0oQChVKGcodCh2KHkofCidKJ8ooiikKKYoqCir +KLAovSjKKMwozyjSKPMo9Sj4KPso/Sj/KQEpFSkXKTcpRClGKUkpTCltKW8pcil1KXcpeSl8KYkpiymO +KZEppympKbMpxCnGKcgpyynNKdYp2CnbKekp9in4Kfsp/iofKiEqJConKikqKyotKjIqNCpCKk8qUSpU +KlcqeCp6Kn0qgCqCKoQqhiqjKqUqtyrEKsYqySrMKu0q7yryKvUq9yr5KvsrCCsKKxErHisgKyMrJitH +K0krTCtPK1ErUytWK18rYSt3K4QrhiuJK4wrrSuvK7IrtSu3K7kruyvAK8IryCvVK9cr2ivdK/4sACwD +LAUsBywJLAssEiwaLCssLSwvLDEsNCxDLGAsaix0LJMsliyYLJssniygLKMsuizCLM4s1yzeLPYs/y0C +Ld0t3y3hLeQt5y3pLewt7i3wLfMt9i34Lfot/C3+LgEuAy4GLgkuCy4OLhAuEy4VLhcuGS4bLh0uHy4i +LiUuJy4pLisuLS4wLjMuNi44LjsuPS4/LkEuRC5GLkguSi5MLk4uUS5ULlcuWS5cLl8uYS5jLmUuaC5r +Lm0ucC5yLnQudy55Lnsufi6BLoMuhS6HLokujC6PLpIulC6WLpkumy6eLqAuoi6lLqguqi6tLrAusy62 +Lrguui69LsAuwy7GLsguyy7NLs8u0i7ULtcu2i7cLt4u4S7kLuYvDy8dLx8vIS8iLyQvJS8nLykvKy9U +L1YvWC9ZL1svXC9eL2AvYy96L4MvhS+OL5Evky+VL5cvwC/KL8wvzi/RL9Mv1S/XL9kv3C/qL/kwAjAE +MAswDTAPMBEwMjA0MDcwOjA8MD4wQDBZMFswbDBuMHEwdDB3MIEwijCMMJswnjChMKQwpzCqMK0wsDDZ +MNsw3TDgMOIw5DDmMOkw7DD7MQQxBjEdMR8xIjElMSgxKzEuMTAxMjE0MTcxOTFiMWQxZjFnMWkxajFs +MW4xcDGZMZsxnTGeMaAxoTGjMaUxpzHQMdIx1THYMdox3DHeMeAx4zHsMf0x/zICMgUyCDIRMhMyFDIm +Mk8yUTJTMlQyVjJXMlkyWzJdMoYyiDKKMosyjTKOMpAykjKUMqEyyjLMMs4y0TLTMtUy1zLaMt0y4jLr +Mu0zBDMGMwgzCzMOMxAzEzMWMxgzGzMdMyAzSTNLM00zUDNSM1QzVjNYM1szZzNwM3IzdTN3M5AzuTO7 +M70zvjPAM8EzwzPFM8cz8DPyM/Qz9zP5M/sz/TQANAM0CDQRNBM0LjQxNDQ0NzQ5NDs0PjRBNEM0RjRJ +NEw0TzRSNHs0fTR/NIA0gjSDNIU0hzSJNLI0tDS2NLc0uTS6NLw0vjTANOk06zTtNPA08jT0NPY0+DT7 +NQA1CTULNRY1GDUbNR41ITUkNUk1SzVONVA1UjVUNVY1YDWFNYc1ijWMNY41kDWSNaA1xTXHNco1zTXP +NdE10zXVNe418DYZNhs2HTYgNiI2JDYmNig2KzZUNlY2WDZbNl02XzZhNmM2ZjZtNnY2eDZ9Nn82gTaq +Nqw2rzayNrQ2tja4Nrs2vjbFNs420DbVNtg22zb8Nv43ATcENwY3CDcLNxY3PzdBN0M3RjdIN0o3TDdP +N1I3VzdgN2I3ZzdqN2w3lTeXN5o3nTefN6E3ozemN6k3sDe5N7s3xDfHN8o3zTfQN984CDgKOA04EDgS +OBQ4FjgZOBw4ITgqOCw4LzgyOD44RzhaOF04XjhnOG44iTiWOJ84pDitOLA5izmNOY85kTmUOZc5mTmb +OZ05nzmhOaM5pTmnOak5qzmuObE5tDm2Obg5uzm+OcA5wjnEOcY5yDnKOc05zznROdQ51znaOdw53znh +OeQ55jnoOeo57DnvOfE58zn1Ofc5+Tn8Of46ADoCOgQ6BjoIOgo6DDoOOhA6EjoVOhc6GTocOh46IDoi +OiQ6JzopOis6LTowOjI6NDo2Ojg6Ojo8Oj46QDpCOkQ6RzpJOks6TTpQOlM6VTpXOlo6XTpgOmM6ZTpn +Omk6azptOm86cTpzOnY6eDp6Onw6fjqHOoo7ZztpO2s7bjtxO3M7djt4O3o7fTuAO4I7hDuGO4g7izuN +O5A7kzuVO5g7mzudO587oTujO6U7pzupO6w7rzuxO7M7tTu3O7o7vTu/O8E7xDvHO8k7yzvOO9A70jvU +O9Y72DvbO9474TvjO+Y76TvrO+077zvyO/U79zv6O/w7/jwBPAM8BTwHPAk8DDwPPBE8EzwVPBg8Gzwd +PCA8IjwlPCc8KjwsPC48MTw0PDY8OTw8PD88QjxEPEY8STxMPE88UjxUPFc8WTxbPF48YDxjPGY8aDxq +PG08cDxyPHs8fj1bPV49YT1kPWc9aj1tPXA9cz12PXk9fD1/PYI9hT2IPYs9jj2RPZQ9lz2aPZ09oD2j +PaY9qT2sPa89sj21Pbg9uz2+PcE9xD3HPco9zT3QPdM91j3ZPdw93z3iPeU96D3rPe498T30Pfc9+j39 +PgA+Az4GPgk+DD4PPhI+FT4YPhs+Hj4hPiQ+Jz4qPi0+MD4zPjY+OT48Pj8+Qj5FPkg+Sz5OPlE+VD5X +Plo+XT5gPmM+Zj5pPmw+bz5yPnU+eD57Pn4+gT6EPoc+ij6NPpA+kz6WPpk+nD6fPqI+uT7WPtg+5D8C +Px4/MT9DP1Y/Wj+nP78/wT/fP+g/9kAEQB5ANEBAQFNAX0BqQGxAfkCgQLpAx0DgQQJBJ0E+QUpBYkF3 +QZhBpEHjQgNCG0IwQktCTUJ3QqZCqULVQuRC90MuQ0NDaUNrQ4JDl0PoRAJEDkQaRDZERERZRHZEi0Sk +RLlExUTcRO9E+0UURT5FS0ViRXZFj0W0RchF60YWRiJGRUZcRnZGmEbARsJGxEbhRvRHCkcpRytHPkdT +R2VHakeGR5VHsEfLR/BH9Ef+SBNIO0hOSFpIXkhnSGpIa0h0SHdIeEiBSIRJx0nJSctJzknQSdJJ1UnX +SdpJ3EnfSeFJ40nmSelJ60ntSe9J8UnzSfVJ+En7Sf1KAEoDSgVKB0oKSg1KD0oSShRKFkoYShpKHEoe +SiBKI0olSihKKkosSi5KMUo0SjdKOUo8Sj5KQEpCSkVKSEpLSk1KUEpSSlRKVkpZSltKXkpgSmJKZEpm +SmhKakptSnBKckp1SndKekp8Sn9KgkqESoZKiUqLSo1Kj0qSSpVKmEqaSp1Kn0qiSqRKpkqoSqpKrUqv +SrFKs0q1SrhKu0q9Sr9KwUrESsZKyErLSs5K0UrTStVK10raStxK3krgSuNK5UrnSulK7ErvSvFK80r2 +SvlK/Er/SwJLBUsHSwlLC0sOSxFLFEsXSxlLG0seSyBLIkskSyZLKEsrSy5LMUs0SzZLOUs8Sz5LQUtD +S0ZLSUtLS1RLV0yaTJ1MoEyjTKZMqUysTK9Msky1TLhMu0y+TMFMxEzHTMpMzUzQTNNM1kzZTNxM30zi +TOVM6EzrTO5M8Uz0TPdM+kz9TQBNA00GTQlNDE0PTRJNFU0YTRtNHk0hTSRNJ00qTS1NME0zTTZNOU08 +TT9NQk1FTUhNS01OTVFNVE1XTVpNXU1gTWNNZk1pTWxNb01yTXVNeE17TX5NgU2ETYdNik2NTZBNk02W +TZlNnE2fTaJNpU2oTatNrk2xTbRNt026Tb1NwE3DTcZNyU3MTc9N0k3VTdhN203eTeFN5E3nTepN7U3w +TfNN9k35TfxN/04CTgVOCE4LTg5OEU4UThdOGk4dTiBOI04mTilOLE4vTjJONU44TjtOPk5BTkROR05K +Tk1OUE5TTlZOWU5cTl9OYk5lTmhOa05uTnFOdE53TnpOfE5+ToBOg06GTohOi06NTpBOkk6VTpdOmk6d +TqBOok6lTqdOqU6rTq5OsU60TrdOuU7CTsROxk7JTstOzk7QTtJO1E7XTtpO3U7gTuNO5k7pTuxO707x +TvNO9k74TvtO/U7/TwFPA08GTwhPC08OTxFPE08VTxdPGk8dTx9PIk8lTydPKU8rTy5PME8zTzZPOU87 +Tz5PQU9DT0VPR09KT0xPTk9QT1NPVU9XT1lPXE9eT2BPYk9kT2dPaU9sT29PcU9zT3VPeE97T31PgE+D +T4VPh0+JT4tPjU+QT5JPlU+YT5tPnU+fT6JPpU+nT6lPq0+uT7BPsk+0T7dPuU+7T75PwU/DT8VPx0/K +T81Pz0/RT9NP1U/YT9tP3k/gT+NP5k/pT+xP7k/wT/JP9E/2T/lP+0/9T/9QCFAKUAtQFFAXUBhQIVAk +UCVQLlAzAAAAAAAAAgIAAAAAAAAKvgAAAAAAAAAAAAAAAAAAUEI + + + diff --git a/Mac OS X/English.lproj/Launcher.nib/keyedobjects.nib b/Mac OS X/English.lproj/Launcher.nib/keyedobjects.nib new file mode 100644 index 00000000..92d0d4bc Binary files /dev/null and b/Mac OS X/English.lproj/Launcher.nib/keyedobjects.nib differ diff --git a/Mac OS X/Fitzquake.icns b/Mac OS X/Fitzquake.icns new file mode 100644 index 00000000..0806582b Binary files /dev/null and b/Mac OS X/Fitzquake.icns differ diff --git a/Mac OS X/Fitzquake.xcodeproj/kristian.pbxuser b/Mac OS X/Fitzquake.xcodeproj/kristian.pbxuser new file mode 100644 index 00000000..1b159e0d --- /dev/null +++ b/Mac OS X/Fitzquake.xcodeproj/kristian.pbxuser @@ -0,0 +1,1389 @@ +// !$*UTF8*$! +{ + 002F3A2B09D0888800EBEB88 /* SDLMain.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 569}}"; + sepNavSelRange = "{0, 245}"; + sepNavVisRange = "{0, 414}"; + sepNavWindowFrame = "{{-1402, -252}, {642, 847}}"; + }; + }; + 002F3A2C09D0888800EBEB88 /* SDLMain.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1190}}"; + sepNavSelRange = "{2287, 0}"; + sepNavVisRange = "{1232, 1097}"; + sepNavWindowFrame = "{{-1306, -196}, {1115, 796}}"; + }; + }; + 089C165DFE840E0CC02AAC07 /* English */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 553}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 275}"; + }; + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeArchitecture = i386; + activeBuildConfigurationName = Release; + activeExecutable = 4802D72D0D2EE86A00DD8D4F /* Fitzquake */; + activeTarget = 8D1107260486CEB800E47090 /* Fitzquake */; + addToTargets = ( + 8D1107260486CEB800E47090 /* Fitzquake */, + ); + breakpoints = ( + ); + codeSenseManager = 4802D7440D2EE86D00DD8D4F /* Code sense */; + executables = ( + 4802D72D0D2EE86A00DD8D4F /* Fitzquake */, + ); + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 198, + 20, + 99, + 99, + 29, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA23EDF0692099D00951B8B" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 316, + 20, + 245, + 245, + 245, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 300, + 1071, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXErrorsWarningsDataSource_TypeID, + PBXErrorsWarningsDataSource_MessageID, + PBXErrorsWarningsDataSource_LocationID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 22, + 300, + 1069, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXExecutablesDataSource_ActiveFlagID, + PBXExecutablesDataSource_NameID, + PBXExecutablesDataSource_CommentsID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 1181, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 1141, + 60, + 20, + 48, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 236951725; + PBXWorkspaceStateSaveDate = 236951725; + }; + perUserProjectItems = { + 4817E0830E1F9DA600928DE3 /* PBXTextBookmark */ = 4817E0830E1F9DA600928DE3 /* PBXTextBookmark */; + 4817E0B80E1FA20300928DE3 /* PBXTextBookmark */ = 4817E0B80E1FA20300928DE3 /* PBXTextBookmark */; + 4817E0B90E1FA20300928DE3 /* PBXTextBookmark */ = 4817E0B90E1FA20300928DE3 /* PBXTextBookmark */; + 4817E0BB0E1FA20300928DE3 /* PBXTextBookmark */ = 4817E0BB0E1FA20300928DE3 /* PBXTextBookmark */; + 4817E0BC0E1FA20300928DE3 /* PBXTextBookmark */ = 4817E0BC0E1FA20300928DE3 /* PBXTextBookmark */; + 4817E0C90E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0C90E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CA0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CA0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CB0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CB0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CC0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CC0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CD0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CD0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CE0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CE0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0CF0E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0CF0E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D00E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D00E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D10E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D10E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D20E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D20E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D30E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D30E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D40E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D40E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D50E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D50E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D60E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D60E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D70E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D70E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0D80E1FA71D00928DE3 /* PBXTextBookmark */ = 4817E0D80E1FA71D00928DE3 /* PBXTextBookmark */; + 4817E0DC0E1FB8A700928DE3 /* PBXTextBookmark */ = 4817E0DC0E1FB8A700928DE3 /* PBXTextBookmark */; + }; + sourceControlManager = 4802D7430D2EE86D00DD8D4F /* Source Control */; + userBookmarkGroup = 4876DA540D8A77F1007D2413 /* PBXBookmarkGroup */; + userBuildSettings = { + }; + }; + 32CA4F630368D1EE00C91783 /* Fitzquake_Prefix.pch */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 795}"; + sepNavWindowFrame = "{{-1402, -252}, {642, 847}}"; + }; + }; + 4802D72D0D2EE86A00DD8D4F /* Fitzquake */ = { + isa = PBXExecutable; + activeArgIndices = ( + YES, + NO, + YES, + YES, + ); + argumentStrings = ( + "-window", + "-nosound", + "-basedir /Applications/Quake", + "+connect 192.168.178.37", + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Fitzquake; + savedGlobals = { + }; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + 4802D7430D2EE86D00DD8D4F /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + 4802D7440D2EE86D00DD8D4F /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 4817E0830E1F9DA600928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; + name = "net_sdlnet.c: 527"; + rLen = 0; + rLoc = 12169; + rType = 0; + vrLen = 885; + vrLoc = 5582; + }; + 4817E0B80E1FA20300928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A783F0D2EEAAB00CB2E4C /* net_main.c */; + name = "net_main.c: 362"; + rLen = 24; + rLoc = 8375; + rType = 0; + vrLen = 621; + vrLoc = 8155; + }; + 4817E0B90E1FA20300928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48728D280D3004A70004D61B /* net_dgrm.c */; + name = "net_dgrm.c: 1262"; + rLen = 0; + rLoc = 30659; + rType = 0; + vrLen = 1138; + vrLoc = 29391; + }; + 4817E0BB0E1FA20300928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A783F0D2EEAAB00CB2E4C /* net_main.c */; + name = "net_main.c: 362"; + rLen = 24; + rLoc = 8375; + rType = 0; + vrLen = 621; + vrLoc = 8155; + }; + 4817E0BC0E1FA20300928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48728D280D3004A70004D61B /* net_dgrm.c */; + name = "net_dgrm.c: 1262"; + rLen = 0; + rLoc = 30659; + rType = 0; + vrLen = 1138; + vrLoc = 29391; + }; + 4817E0C90E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A77EE0D2EE97700CB2E4C /* progdefs.h */; + name = "progdefs.h: 21"; + rLen = 0; + rLoc = 838; + rType = 0; + vrLen = 864; + vrLoc = 0; + }; + 4817E0CA0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 4846EB500D329BEB00A108DE /* platform.h */; + name = "platform.h: 31"; + rLen = 0; + rLoc = 1016; + rType = 0; + vrLen = 1016; + vrLoc = 0; + }; + 4817E0CB0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48895DB80D4914A000849ABF /* pl_osx.m */; + name = "pl_osx.m: 40"; + rLen = 0; + rLoc = 1131; + rType = 0; + vrLen = 1128; + vrLoc = 3; + }; + 4817E0CC0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A77FA0D2EE9A900CB2E4C /* net.h */; + name = "net.h: 24"; + rLen = 68; + rLoc = 874; + rType = 0; + vrLen = 1199; + vrLoc = 0; + }; + 4817E0CD0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; + name = "net_sdlnet.c: 110"; + rLen = 0; + rLoc = 2681; + rType = 0; + vrLen = 921; + vrLoc = 2404; + }; + 4817E0CE0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; + name = "net_sdlnet.c: 110"; + rLen = 0; + rLoc = 2681; + rType = 0; + vrLen = 921; + vrLoc = 2404; + }; + 4817E0CF0E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48895DB80D4914A000849ABF /* pl_osx.m */; + name = "pl_osx.m: 41"; + rLen = 0; + rLoc = 1133; + rType = 0; + vrLen = 1108; + vrLoc = 45; + }; + 4817E0D00E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; + name = "net_sdlnet.c: 110"; + rLen = 0; + rLoc = 2681; + rType = 0; + vrLen = 921; + vrLoc = 2404; + }; + 4817E0D10E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 4846EB500D329BEB00A108DE /* platform.h */; + name = "platform.h: 32"; + rLen = 0; + rLoc = 1016; + rType = 0; + vrLen = 1058; + vrLoc = 0; + }; + 4817E0D20E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48895DB80D4914A000849ABF /* pl_osx.m */; + name = "pl_osx.m: 41"; + rLen = 0; + rLoc = 1131; + rType = 0; + vrLen = 1105; + vrLoc = 45; + }; + 4817E0D30E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A77EE0D2EE97700CB2E4C /* progdefs.h */; + name = "progdefs.h: 21"; + rLen = 0; + rLoc = 838; + rType = 0; + vrLen = 864; + vrLoc = 0; + }; + 4817E0D40E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 4846EB500D329BEB00A108DE /* platform.h */; + name = "platform.h: 32"; + rLen = 0; + rLoc = 1016; + rType = 0; + vrLen = 1057; + vrLoc = 0; + }; + 4817E0D50E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48895DB80D4914A000849ABF /* pl_osx.m */; + name = "pl_osx.m: 40"; + rLen = 0; + rLoc = 1131; + rType = 0; + vrLen = 1128; + vrLoc = 3; + }; + 4817E0D60E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 4846EB500D329BEB00A108DE /* platform.h */; + name = "platform.h: 31"; + rLen = 0; + rLoc = 1016; + rType = 0; + vrLen = 1016; + vrLoc = 0; + }; + 4817E0D70E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 48895DB80D4914A000849ABF /* pl_osx.m */; + name = "pl_osx.m: 40"; + rLen = 0; + rLoc = 1131; + rType = 0; + vrLen = 1128; + vrLoc = 3; + }; + 4817E0D80E1FA71D00928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A77FA0D2EE9A900CB2E4C /* net.h */; + name = "net.h: 24"; + rLen = 68; + rLoc = 874; + rType = 0; + vrLen = 1199; + vrLoc = 0; + }; + 4817E0DC0E1FB8A700928DE3 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; + name = "net_sdlnet.c: 13"; + rLen = 0; + rLoc = 520; + rType = 0; + vrLen = 1061; + vrLoc = 168; + }; + 48243B130D33F01A00C29F8F /* main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2030}}"; + sepNavSelRange = "{3951, 0}"; + sepNavVisRange = "{2592, 1936}"; + sepNavWindowFrame = "{{193, 140}, {642, 797}}"; + }; + }; + 48305B530D8AF8EC00A29C24 /* net_udp.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 714}}"; + sepNavSelRange = "{742, 920}"; + sepNavVisRange = "{0, 1662}"; + }; + }; + 48305B540D8AF90600A29C24 /* net_udp.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 6510}}"; + sepNavSelRange = "{4277, 2}"; + sepNavVisRange = "{3656, 1107}"; + sepNavWindowFrame = "{{235, 154}, {1115, 874}}"; + }; + }; + 4830B79D0D464CAE00EF4498 /* Changelog.txt */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 677}}"; + sepNavSelRange = "{1181, 0}"; + sepNavVisRange = "{0, 1523}"; + sepNavWindowFrame = "{{-1425, -119}, {959, 896}}"; + }; + }; + 4830B79E0D464CAE00EF4498 /* Todo.txt */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1142, 583}}"; + sepNavSelRange = "{461, 0}"; + sepNavVisRange = "{0, 980}"; + sepNavWindowFrame = "{{-1008, -116}, {959, 896}}"; + }; + }; + 483A77E60D2EE97700CB2E4C /* cmd.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1750}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1286}"; + }; + }; + 483A77E70D2EE97700CB2E4C /* common.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2604}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1121}"; + }; + }; + 483A77E80D2EE97700CB2E4C /* console.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 686}}"; + sepNavSelRange = "{1097, 0}"; + sepNavVisRange = "{627, 978}"; + }; + }; + 483A77E90D2EE97700CB2E4C /* crc.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1086}"; + }; + }; + 483A77EA0D2EE97700CB2E4C /* cvar.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1484, 1428}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 1367}"; + }; + }; + 483A77EB0D2EE97700CB2E4C /* mathlib.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {900, 1680}}"; + sepNavSelRange = "{1232, 88}"; + sepNavVisRange = "{136, 1522}"; + sepNavWindowFrame = "{{316, 73}, {959, 805}}"; + }; + }; + 483A77EC0D2EE97700CB2E4C /* menu.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 560}}"; + sepNavSelRange = "{612, 0}"; + sepNavVisRange = "{165, 979}"; + }; + }; + 483A77ED0D2EE97700CB2E4C /* pr_comp.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2156}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1180}"; + }; + }; + 483A77EE0D2EE97700CB2E4C /* progdefs.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 533}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 864}"; + }; + }; + 483A77EF0D2EE97700CB2E4C /* progs.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1918}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1094}"; + }; + }; + 483A77F00D2EE97700CB2E4C /* quakedef.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1119, 4494}}"; + sepNavSelRange = "{5768, 28}"; + sepNavVisRange = "{5551, 389}"; + sepNavWindowFrame = "{{15, 77}, {1115, 796}}"; + }; + }; + 483A77F10D2EE97700CB2E4C /* sbar.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 560}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1234}"; + }; + }; + 483A77F20D2EE97700CB2E4C /* sys.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1036}}"; + sepNavSelRange = "{1591, 10}"; + sepNavVisRange = "{856, 1172}"; + }; + }; + 483A77F30D2EE97700CB2E4C /* view.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1055}"; + }; + }; + 483A77F40D2EE97700CB2E4C /* wad.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1036}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1047}"; + }; + }; + 483A77F50D2EE97700CB2E4C /* world.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1190}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1090}"; + }; + }; + 483A77F60D2EE97700CB2E4C /* zone.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1848}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 1191}"; + sepNavWindowFrame = "{{-1402, -291}, {642, 847}}"; + }; + }; + 483A77F70D2EE98D00CB2E4C /* input.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 630}}"; + sepNavSelRange = "{1377, 20}"; + sepNavVisRange = "{136, 1264}"; + }; + }; + 483A77F80D2EE98D00CB2E4C /* keys.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2044}}"; + sepNavSelRange = "{892, 0}"; + sepNavVisRange = "{0, 1403}"; + sepNavWindowFrame = "{{-826, -175}, {642, 847}}"; + }; + }; + 483A77F90D2EE9A900CB2E4C /* client.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5096}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{2598, 1627}"; + }; + }; + 483A77FA0D2EE9A900CB2E4C /* net.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4690}}"; + sepNavSelRange = "{874, 68}"; + sepNavVisRange = "{0, 1199}"; + sepNavWindowFrame = "{{195, 68}, {1115, 810}}"; + }; + }; + 483A77FB0D2EE9A900CB2E4C /* protocol.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2408}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1701}"; + }; + }; + 483A77FC0D2EE9A900CB2E4C /* server.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3080}}"; + sepNavSelRange = "{1866, 0}"; + sepNavVisRange = "{855, 1486}"; + }; + }; + 483A77FD0D2EE9BD00CB2E4C /* cdaudio.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 569}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1054}"; + }; + }; + 483A77FE0D2EE9BD00CB2E4C /* sound.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2506}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{4079, 920}"; + sepNavWindowFrame = "{{-1425, -270}, {642, 847}}"; + }; + }; + 483A77FF0D2EE9F300CB2E4C /* anorm_dots.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {7700, 560}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 16251}"; + }; + }; + 483A78000D2EE9F300CB2E4C /* anorms.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2548}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1275}"; + }; + }; + 483A78010D2EE9F300CB2E4C /* bspfile.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4382}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1126}"; + }; + }; + 483A78020D2EE9F300CB2E4C /* d_ifacea.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1372}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{0, 1093}"; + }; + }; + 483A78030D2EE9F300CB2E4C /* draw.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 602}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1358}"; + }; + }; + 483A78040D2EE9F300CB2E4C /* gl_model.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 6132}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1018}"; + }; + }; + 483A78050D2EE9F300CB2E4C /* gl_texmgr.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1358}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 1378}"; + sepNavWindowFrame = "{{355, 73}, {959, 805}}"; + }; + }; + 483A78060D2EE9F300CB2E4C /* gl_warp_sin.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 798}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{0, 1756}"; + }; + }; + 483A78070D2EE9F300CB2E4C /* glquake.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3276}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{377, 935}"; + sepNavWindowFrame = "{{-1425, -280}, {959, 896}}"; + }; + }; + 483A78080D2EE9F300CB2E4C /* image.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1101}"; + }; + }; + 483A78090D2EE9F300CB2E4C /* modelgen.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1680}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1262}"; + }; + }; + 483A780A0D2EE9F300CB2E4C /* render.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2212}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{322, 946}"; + }; + }; + 483A780B0D2EE9F300CB2E4C /* screen.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 952}}"; + sepNavSelRange = "{949, 8}"; + sepNavVisRange = "{453, 1287}"; + }; + }; + 483A780C0D2EE9F300CB2E4C /* spritegn.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1302}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1381}"; + }; + }; + 483A780D0D2EE9F300CB2E4C /* vid.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1162}}"; + sepNavSelRange = "{948, 81}"; + sepNavVisRange = "{849, 1205}"; + sepNavWindowFrame = "{{298, 73}, {959, 805}}"; + }; + }; + 483A780E0D2EEA0F00CB2E4C /* progdefs.q1 */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2016}}"; + sepNavSelRange = "{465, 0}"; + sepNavVisRange = "{314, 954}"; + sepNavWindowFrame = "{{-1379, -273}, {642, 847}}"; + }; + }; + 483A78100D2EEA5400CB2E4C /* chase.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1610}}"; + sepNavSelRange = "{0, 785}"; + sepNavVisRange = "{0, 1123}"; + }; + }; + 483A78110D2EEA5400CB2E4C /* cmd.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 11088}}"; + sepNavSelRange = "{10212, 0}"; + sepNavVisRange = "{9585, 821}"; + sepNavWindowFrame = "{{-1425, -121}, {959, 896}}"; + }; + }; + 483A78120D2EEA5400CB2E4C /* common.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 25690}}"; + sepNavSelRange = "{22738, 0}"; + sepNavVisRange = "{22175, 952}"; + sepNavWindowFrame = "{{-1425, -127}, {959, 896}}"; + }; + }; + 483A78130D2EEA5400CB2E4C /* console.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {900, 14868}}"; + sepNavSelRange = "{2591, 32}"; + sepNavVisRange = "{2237, 990}"; + sepNavWindowFrame = "{{436, 154}, {959, 874}}"; + }; + }; + 483A78140D2EEA5400CB2E4C /* crc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1358}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1185}"; + }; + }; + 483A78150D2EEA5400CB2E4C /* cvar.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 6594}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 899}"; + sepNavWindowFrame = "{{-1427, -279}, {959, 896}}"; + }; + }; + 483A78160D2EEA5400CB2E4C /* host_cmd.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 30744}}"; + sepNavSelRange = "{8690, 0}"; + sepNavVisRange = "{8007, 1260}"; + }; + }; + 483A78170D2EEA5400CB2E4C /* host.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 12068}}"; + sepNavSelRange = "{17391, 0}"; + sepNavVisRange = "{16738, 1269}"; + sepNavWindowFrame = "{{61, 232}, {1115, 796}}"; + }; + }; + 483A78180D2EEA5400CB2E4C /* mathlib.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 7868}}"; + sepNavSelRange = "{1306, 0}"; + sepNavVisRange = "{893, 900}"; + sepNavWindowFrame = "{{15, 149}, {1115, 874}}"; + }; + }; + 483A78190D2EEA5400CB2E4C /* menu.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {704, 43918}}"; + sepNavSelRange = "{5490, 27}"; + sepNavVisRange = "{5260, 752}"; + sepNavWindowFrame = "{{453, 31}, {642, 847}}"; + }; + }; + 483A781A0D2EEA5400CB2E4C /* pr_cmds.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 22204}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1149}"; + }; + }; + 483A781B0D2EEA5400CB2E4C /* pr_edict.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 15540}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1388}"; + }; + }; + 483A781C0D2EEA5400CB2E4C /* pr_exec.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 9394}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1100}"; + }; + }; + 483A781D0D2EEA5400CB2E4C /* sbar.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 17416}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{0, 1511}"; + }; + }; + 483A781E0D2EEA5400CB2E4C /* sys_sdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3710}}"; + sepNavSelRange = "{4210, 0}"; + sepNavVisRange = "{3935, 721}"; + sepNavWindowFrame = "{{407, 219}, {1115, 796}}"; + }; + }; + 483A781F0D2EEA5400CB2E4C /* view.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 12474}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{378, 1136}"; + }; + }; + 483A78200D2EEA5400CB2E4C /* wad.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2142}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1336}"; + sepNavWindowFrame = "{{236, 80}, {959, 896}}"; + }; + }; + 483A78210D2EEA5400CB2E4C /* world.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 12432}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1286}"; + }; + }; + 483A78220D2EEA5400CB2E4C /* zone.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1619, 12908}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 853}"; + }; + }; + 483A78360D2EEA6D00CB2E4C /* in_sdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2366}}"; + sepNavSelRange = "{1185, 0}"; + sepNavVisRange = "{3223, 1187}"; + sepNavWindowFrame = "{{15, 227}, {1115, 796}}"; + }; + }; + 483A78370D2EEA6D00CB2E4C /* keys.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 15022}}"; + sepNavSelRange = "{9256, 7}"; + sepNavVisRange = "{9019, 1121}"; + sepNavWindowFrame = "{{217, 68}, {1115, 810}}"; + }; + }; + 483A783A0D2EEAAB00CB2E4C /* cl_demo.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4900}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1492}"; + }; + }; + 483A783B0D2EEAAB00CB2E4C /* cl_input.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5866}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1266}"; + sepNavWindowFrame = "{{61, 185}, {1115, 796}}"; + }; + }; + 483A783C0D2EEAAB00CB2E4C /* cl_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 10080}}"; + sepNavSelRange = "{6053, 22}"; + sepNavVisRange = "{5433, 999}"; + sepNavWindowFrame = "{{38, 206}, {1115, 796}}"; + }; + }; + 483A783D0D2EEAAB00CB2E4C /* cl_parse.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 13832}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{377, 1128}"; + }; + }; + 483A783E0D2EEAAB00CB2E4C /* cl_tent.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4816}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1143}"; + }; + }; + 483A783F0D2EEAAB00CB2E4C /* net_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 11956}}"; + sepNavSelRange = "{8375, 24}"; + sepNavVisRange = "{8155, 621}"; + sepNavWindowFrame = "{{84, 164}, {1115, 796}}"; + }; + }; + 483A78400D2EEAAB00CB2E4C /* net_sdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1442}}"; + sepNavSelRange = "{0, 818}"; + sepNavVisRange = "{816, 809}"; + }; + }; + 483A78410D2EEAAB00CB2E4C /* sv_main.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 16660}}"; + sepNavSelRange = "{25475, 0}"; + sepNavVisRange = "{27550, 1323}"; + }; + }; + 483A78420D2EEAAB00CB2E4C /* sv_move.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5796}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1477}"; + }; + }; + 483A78430D2EEAAB00CB2E4C /* sv_phys.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 16324}}"; + sepNavSelRange = "{1912, 22}"; + sepNavVisRange = "{627, 1504}"; + sepNavWindowFrame = "{{303, 132}, {959, 896}}"; + }; + }; + 483A78440D2EEAAB00CB2E4C /* sv_user.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 9002}}"; + sepNavSelRange = "{10790, 14}"; + sepNavVisRange = "{10589, 878}"; + sepNavWindowFrame = "{{616, 132}, {959, 896}}"; + }; + }; + 483A78500D2EEAC300CB2E4C /* cd_sdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 770}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{559, 566}"; + }; + }; + 483A78540D2EEAC300CB2E4C /* snd_sdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 1624}}"; + sepNavSelRange = "{0, 818}"; + sepNavVisRange = "{1107, 979}"; + sepNavWindowFrame = "{{38, 82}, {1115, 796}}"; + }; + }; + 483A785A0D2EEAF000CB2E4C /* gl_draw.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 10696}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 994}"; + }; + }; + 483A785B0D2EEAF000CB2E4C /* gl_fog.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5096}}"; + sepNavSelRange = "{1463, 3}"; + sepNavVisRange = "{1239, 1041}"; + sepNavWindowFrame = "{{38, 128}, {1115, 874}}"; + }; + }; + 483A785C0D2EEAF000CB2E4C /* gl_mesh.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5334}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{505, 809}"; + }; + }; + 483A785D0D2EEAF000CB2E4C /* gl_model.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 31276}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{378, 1160}"; + }; + }; + 483A785E0D2EEAF000CB2E4C /* gl_refrag.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2912}}"; + sepNavSelRange = "{3960, 0}"; + sepNavVisRange = "{2112, 571}"; + }; + }; + 483A785F0D2EEAF000CB2E4C /* gl_rlight.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 5600}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 832}"; + sepNavWindowFrame = "{{-1425, -280}, {959, 896}}"; + }; + }; + 483A78600D2EEAF000CB2E4C /* gl_rmain.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 10850}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{142, 1301}"; + }; + }; + 483A78610D2EEAF000CB2E4C /* gl_rmisc.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4774}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1104}"; + }; + }; + 483A78620D2EEAF000CB2E4C /* gl_screen.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 13636}}"; + sepNavSelRange = "{6403, 0}"; + sepNavVisRange = "{5804, 1236}"; + sepNavWindowFrame = "{{-1425, -280}, {959, 896}}"; + }; + }; + 483A78630D2EEAF000CB2E4C /* gl_sky.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 12054}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{442, 960}"; + }; + }; + 483A78640D2EEAF000CB2E4C /* gl_test.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2394}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1002}"; + }; + }; + 483A78650D2EEAF000CB2E4C /* gl_texmgr.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 19222}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{322, 1110}"; + }; + }; + 483A78660D2EEAF000CB2E4C /* gl_vidsdl.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 25830}}"; + sepNavSelRange = "{22069, 9}"; + sepNavVisRange = "{21468, 899}"; + sepNavWindowFrame = "{{494, 31}, {642, 847}}"; + }; + }; + 483A78670D2EEAF000CB2E4C /* gl_warp.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3528}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1203}"; + }; + }; + 483A78680D2EEAF000CB2E4C /* image.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4774}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1479}"; + sepNavWindowFrame = "{{219, 223}, {959, 805}}"; + }; + }; + 483A78690D2EEAF000CB2E4C /* r_alias.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 8204}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{378, 1079}"; + }; + }; + 483A786A0D2EEAF000CB2E4C /* r_brush.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 15722}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{199, 1391}"; + sepNavWindowFrame = "{{-1425, -280}, {959, 896}}"; + }; + }; + 483A786B0D2EEAF000CB2E4C /* r_part.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 14252}}"; + sepNavSelRange = "{6421, 4}"; + sepNavVisRange = "{6044, 642}"; + }; + }; + 483A786C0D2EEAF000CB2E4C /* r_sprite.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2632}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 956}"; + }; + }; + 483A786D0D2EEAF000CB2E4C /* r_world.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 9954}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{386, 1121}"; + }; + }; + 4846EB500D329BEB00A108DE /* platform.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 533}}"; + sepNavSelRange = "{1016, 0}"; + sepNavVisRange = "{0, 1016}"; + }; + }; + 486577C80D31A22A00E7920A /* snd_dma.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 13412}}"; + sepNavSelRange = "{5230, 0}"; + sepNavVisRange = "{4960, 938}"; + sepNavWindowFrame = "{{389, 4}, {959, 874}}"; + }; + }; + 486577C90D31A22A00E7920A /* snd_mem.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 4522}}"; + sepNavSelRange = "{1503, 10}"; + sepNavVisRange = "{1080, 874}"; + }; + }; + 486577CA0D31A22A00E7920A /* snd_mix.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3906}}"; + sepNavSelRange = "{818, 0}"; + sepNavVisRange = "{0, 1245}"; + sepNavWindowFrame = "{{-1402, -252}, {642, 847}}"; + }; + }; + 48728D280D3004A70004D61B /* net_dgrm.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 19110}}"; + sepNavSelRange = "{30659, 0}"; + sepNavVisRange = "{29391, 1138}"; + }; + }; + 48728D290D3004A80004D61B /* net_dgrm.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 714}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1444}"; + }; + }; + 48728D2A0D3004A80004D61B /* net_loop.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3402}}"; + sepNavSelRange = "{1684, 0}"; + sepNavVisRange = "{1975, 1081}"; + }; + }; + 48728D2B0D3004A80004D61B /* net_loop.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 504}}"; + sepNavSelRange = "{838, 0}"; + sepNavVisRange = "{0, 1366}"; + }; + }; + 4876DA540D8A77F1007D2413 /* PBXBookmarkGroup */ = { + isa = PBXBookmarkGroup; + children = ( + 4876DB340D8A972F007D2413 /* PBXTextBookmark */, + ); + name = Root; + }; + 4876DB340D8A972F007D2413 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 483A78160D2EEA5400CB2E4C /* host_cmd.c */; + name = "host_cmd.c: 403"; + rLen = 0; + rLoc = 9417; + rType = 0; + vrLen = 635; + vrLoc = 8960; + }; + 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1619, 7868}}"; + sepNavSelRange = "{12315, 0}"; + sepNavVisRange = "{4532, 711}"; + sepNavWindowFrame = "{{-1319, -43}, {1115, 810}}"; + }; + }; + 487C0A5C0DA94A0700A49FF5 /* net_sdlnet.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 714}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1667}"; + sepNavWindowFrame = "{{-1425, -136}, {1115, 900}}"; + }; + }; + 48895DB80D4914A000849ABF /* pl_osx.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 560}}"; + sepNavSelRange = "{1131, 0}"; + sepNavVisRange = "{3, 1128}"; + }; + }; + 489D8D2D0D3A630D00AA4471 /* ScreenInfo.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 546}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 940}"; + }; + }; + 489D8D2E0D3A630D00AA4471 /* ScreenInfo.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 714}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 943}"; + }; + }; + 48B9E7A50D340BEA0001CACF /* AppController.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 714}}"; + sepNavSelRange = "{1113, 0}"; + sepNavVisRange = "{0, 1419}"; + }; + }; + 48B9E7A60D340BEA0001CACF /* AppController.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 2646}}"; + sepNavSelRange = "{4081, 0}"; + sepNavVisRange = "{2845, 1847}"; + sepNavWindowFrame = "{{-1425, -231}, {642, 847}}"; + }; + }; + 48B9E7BE0D340EA80001CACF /* SDLApplication.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 805}"; + }; + }; + 48B9E7BF0D340EA80001CACF /* SDLApplication.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 490}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 981}"; + }; + }; + 48C85E390D3AD10E00797678 /* QuakeArgument.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 518}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 976}"; + }; + }; + 48C85E3A0D3AD10E00797678 /* QuakeArgument.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 980}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{0, 992}"; + }; + }; + 48FE58590D3A82C8006BB491 /* QuakeArguments.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 560}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{165, 988}"; + sepNavWindowFrame = "{{-1425, -280}, {959, 896}}"; + }; + }; + 48FE585A0D3A82C8006BB491 /* QuakeArguments.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 3178}}"; + sepNavSelRange = "{724, 0}"; + sepNavVisRange = "{1018, 979}"; + sepNavWindowFrame = "{{328, 73}, {642, 805}}"; + }; + }; + 8D1107260486CEB800E47090 /* Fitzquake */ = { + activeExec = 0; + executables = ( + 4802D72D0D2EE86A00DD8D4F /* Fitzquake */, + ); + }; + 8D1107310486CEB800E47090 /* Info.plist */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1359, 471}}"; + sepNavSelRange = "{749, 0}"; + sepNavVisRange = "{0, 845}"; + }; + }; +} diff --git a/Mac OS X/Fitzquake.xcodeproj/kristian.perspectivev3 b/Mac OS X/Fitzquake.xcodeproj/kristian.perspectivev3 new file mode 100644 index 00000000..a8218914 --- /dev/null +++ b/Mac OS X/Fitzquake.xcodeproj/kristian.perspectivev3 @@ -0,0 +1,1567 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + AIODescriptionKey + DockingSystemVisible + + Extension + perspectivev3 + FavBarConfig + + PBXProjectModuleGUID + 4802D7420D2EE86D00DD8D4F + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.defaultV3 + MajorVersion + 34 + MinorVersion + 0 + Name + All-In-One + Notifications + + OpenEditors + + PerspectiveWidths + + 1680 + 1680 + + Perspectives + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + active-target-popup + active-buildstyle-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-goOrGo + com.apple.ide.PBXToolbarStopButton + get-info + toggle-editor + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CA23ED40692098700951B8B + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 238 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 48243B060D33ED0A00C29F8F + 483A77D80D2EE8C500CB2E4C + 483A77D90D2EE8D400CB2E4C + 483A77DE0D2EE8FB00CB2E4C + 483A77DA0D2EE8DA00CB2E4C + 483A77DF0D2EE90500CB2E4C + 483A77DD0D2EE8F100CB2E4C + 483A77E00D2EE90B00CB2E4C + 29B97317FDCFA39411CA2CEA + 29B97323FDCFA39411CA2CEA + 1058C7A0FEA54F0111CA2CBB + 002F39F909D0881F00EBEB88 + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 83 + 64 + 15 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 552}, {238, 910}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {255, 928}} + GroupTreeTableConfiguration + + MainColumn + 238 + + RubberWindowFrame + 0 59 1680 969 0 0 1680 1028 + + Module + PBXSmartGroupTreeModule + Proportion + 255pt + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 4802D73D0D2EE86D00DD8D4F + PBXProjectModuleLabel + net_sdlnet.c + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 4802D73E0D2EE86D00DD8D4F + PBXProjectModuleLabel + net_sdlnet.c + _historyCapacity + 0 + bookmark + 4817E0DC0E1FB8A700928DE3 + history + + 4817E0B80E1FA20300928DE3 + 4817E0B90E1FA20300928DE3 + 4817E0C90E1FA71D00928DE3 + 4817E0CA0E1FA71D00928DE3 + 4817E0CB0E1FA71D00928DE3 + 4817E0CC0E1FA71D00928DE3 + 4817E0CD0E1FA71D00928DE3 + + prevStack + + 4817E0830E1F9DA600928DE3 + 4817E0BB0E1FA20300928DE3 + 4817E0BC0E1FA20300928DE3 + 4817E0CE0E1FA71D00928DE3 + 4817E0CF0E1FA71D00928DE3 + 4817E0D00E1FA71D00928DE3 + 4817E0D10E1FA71D00928DE3 + 4817E0D20E1FA71D00928DE3 + 4817E0D30E1FA71D00928DE3 + 4817E0D40E1FA71D00928DE3 + 4817E0D50E1FA71D00928DE3 + 4817E0D60E1FA71D00928DE3 + 4817E0D70E1FA71D00928DE3 + 4817E0D80E1FA71D00928DE3 + + + SplitCount + 1 + + StatusBarVisibility + + XCSharingToken + com.apple.Xcode.CommonNavigatorGroupSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {1420, 565}} + RubberWindowFrame + 0 59 1680 969 0 0 1680 1028 + + Module + PBXNavigatorGroup + Proportion + 565pt + + + Proportion + 358pt + Tabs + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EDF0692099D00951B8B + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{10, 27}, {1420, 331}} + + Module + XCDetailModule + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA23EE00692099D00951B8B + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{10, 27}, {1420, 331}} + + Module + PBXProjectFindModule + + + ContentConfiguration + + PBXCVSModuleFilterTypeKey + 1032 + PBXProjectModuleGUID + 1CA23EE10692099D00951B8B + PBXProjectModuleLabel + SCM Results + + GeometryConfiguration + + Frame + {{10, 27}, {1180, 131}} + + Module + PBXCVSModule + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{10, 27}, {1420, 331}} + RubberWindowFrame + 0 59 1680 969 0 0 1680 1028 + + Module + PBXBuildResultsModule + + + + + Proportion + 1420pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDockableTabModule + XCDetailModule + PBXProjectFindModule + PBXCVSModule + PBXBuildResultsModule + + TableOfContents + + 4817E0740E1F9B4400928DE3 + 1CA23ED40692098700951B8B + 4817E0750E1F9B4400928DE3 + 4802D73D0D2EE86D00DD8D4F + 4817E0760E1F9B4400928DE3 + 1CA23EDF0692099D00951B8B + 1CA23EE00692099D00951B8B + 1CA23EE10692099D00951B8B + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ChosenToolbarItems + + XCToolbarPerspectiveControl + NSToolbarSeparatorItem + build-and-go + go + NSToolbarFlexibleSpaceItem + debugger-fix-and-continue + debugger-restart-executable + debugger-pause + debugger-step-over + debugger-step-into + debugger-step-out + debugger-step-instruction + NSToolbarFlexibleSpaceItem + + ControllerClassBaseName + PBXDebugSessionModule + IconName + DebugTabIcon + Identifier + perspective.debug + IsVertical + + Layout + + + ContentConfiguration + + PBXProjectModuleGUID + 1CCC7628064C1048000F2A68 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {1680, 258}} + + Module + PBXDebugCLIModule + Proportion + 258pt + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {851, 211}} + {{851, 0}, {829, 211}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {1680, 211}} + {{0, 211}, {1680, 454}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1CCC7629064C1048000F2A68 + PBXProjectModuleLabel + Debug + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 263}, {1680, 665}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 217 + Value + 85 + Summary + 502 + + Frame + {{851, 0}, {829, 211}} + + + Module + PBXDebugSessionModule + Proportion + 665pt + + + Name + Debug + ServiceClasses + + XCModuleDock + PBXDebugCLIModule + PBXDebugSessionModule + PBXDebugProcessAndThreadModule + PBXDebugProcessViewModule + PBXDebugThreadViewModule + PBXDebugStackFrameViewModule + PBXNavigatorGroup + + TableOfContents + + 4817E0770E1F9B4400928DE3 + 1CCC7628064C1048000F2A68 + 1CCC7629064C1048000F2A68 + 4817E0780E1F9B4400928DE3 + 4817E0790E1F9B4400928DE3 + 4817E07A0E1F9B4400928DE3 + 4817E07B0E1F9B4400928DE3 + 4817E07C0E1F9B4400928DE3 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + + WindowJustification + 5 + WindowOrderList + + 4817E0AF0E1FA02000928DE3 + 4817E0B00E1FA02000928DE3 + 4817E0B10E1FA02000928DE3 + /Users/kristian/Documents/Code/XCode Workspace/Fitzquake/Mac OS X/Fitzquake.xcodeproj + + WindowString + 0 59 1680 969 0 0 1680 1028 + WindowToolsV3 + + + Identifier + windowTool.debugger + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {317, 164}} + {{317, 0}, {377, 164}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 164}} + {{0, 164}, {694, 216}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleDrawerSize + {100, 120} + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 380}} + RubberWindowFrame + 321 238 694 422 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 100% + + + Proportion + 100% + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1C0AD2AB069F1E9B00FABCE6 + 1C162984064C10D400B95A72 + 1C0AD2AC069F1E9B00FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 321 238 694 422 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + 0 + + + Identifier + windowTool.build + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD052900623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {500, 215}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + + GeometryConfiguration + + Frame + {{0, 222}, {500, 236}} + RubberWindowFrame + 192 257 500 500 0 0 1280 1002 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 458pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAA5065D492600B07095 + 1C78EAA6065D492600B07095 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 192 257 500 500 0 0 1280 1002 + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {440, 358}} + RubberWindowFrame + 522 364 440 400 0 0 1440 878 + + Module + PBXDebugCLIModule + Proportion + 358pt + + + Proportion + 359pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C530D5B069F1CE1000CFCEE + 484585940D2F244600F70AA9 + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 522 364 440 400 0 0 1440 878 + WindowToolGUID + 1C530D5B069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.09500122070312 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scmV3 + WindowString + 743 379 452 308 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 21 596 744 409 0 0 1680 1028 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 21 596 744 409 0 0 1680 1028 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + 48AE002A0D342D20003FCE13 + 48AE002B0D342D20003FCE13 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 21 596 744 409 0 0 1680 1028 + WindowToolGUID + 48AE002A0D342D20003FCE13 + WindowToolIsVisible + + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.bookmarks + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 4876DB3A0D8A973B007D2413 + PBXProjectModuleLabel + Bookmarks + + GeometryConfiguration + + Frame + {{0, 0}, {401, 166}} + RubberWindowFrame + 21 782 401 222 0 0 1680 1028 + + Module + PBXBookmarksModule + Proportion + 166pt + + + Proportion + 202pt + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + + TableOfContents + + 4876DB3B0D8A973B007D2413 + 4876DB3C0D8A973B007D2413 + 4876DB3A0D8A973B007D2413 + + WindowString + 21 782 401 222 0 0 1680 1028 + WindowToolGUID + 4876DB3B0D8A973B007D2413 + WindowToolIsVisible + + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {369, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {616, 353}} + MembersFrame + {{0, 105}, {369, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 94 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 597 125 616 374 0 0 1280 1002 + + Module + PBXClassBrowserModule + Proportion + 354pt + + + Proportion + 354pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C78EABA065D492600B07095 + 1C78EABB065D492600B07095 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 597 125 616 374 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 48C85DD30D3ACFA800797678 + + GeometryConfiguration + + Frame + {{0, 0}, {766, 559}} + RubberWindowFrame + 91 215 766 600 0 0 1440 878 + XCRefactoringSplitViewLowerHeight + 235 + XCRefactoringSplitViewTotalHeight + 476 + + Module + XCRefactoringModule + Proportion + 559pt + + + Proportion + 559pt + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + StatusbarIsVisible + + TableOfContents + + 48C85DD40D3ACFA800797678 + 48C85DD50D3ACFA800797678 + 48C85DD30D3ACFA800797678 + + WindowString + 91 215 766 600 0 0 1440 878 + WindowToolGUID + 48C85DD40D3ACFA800797678 + WindowToolIsVisible + + + + + diff --git a/Mac OS X/Fitzquake.xcodeproj/macmini.mode1v3 b/Mac OS X/Fitzquake.xcodeproj/macmini.mode1v3 new file mode 100644 index 00000000..a966ec65 --- /dev/null +++ b/Mac OS X/Fitzquake.xcodeproj/macmini.mode1v3 @@ -0,0 +1,1380 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + 9ABC4BF70FB733E500F2D53C + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-target-popup + active-buildstyle-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-goOrGo + com.apple.ide.PBXToolbarStopButton + get-info + toggle-editor + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 10 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 451}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 469}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 432 185 1052 510 0 0 1600 878 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {844, 0}} + RubberWindowFrame + 432 185 1052 510 0 0 1600 878 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 5}, {844, 464}} + RubberWindowFrame + 432 185 1052 510 0 0 1600 878 + + Module + XCDetailModule + Proportion + 464pt + + + Proportion + 844pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 9A48FC5A0FB73D4B0005CCF1 + 1CE0B1FE06471DED0097A5F4 + 9A48FC5B0FB73D4B0005CCF1 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + PinnedNavigatorIdentifier + 9ABC4BD80FB72FDF00F2D53C + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 9ABC4BF80FB733E500F2D53C + /Users/macmini/Desktop/MacEngine/fitzquake_sdl_20090510_src_beta_1/fitzquake_sdl_20090510/Mac OS X/Fitzquake.xcodeproj + + WindowString + 432 185 1052 510 0 0 1600 878 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {500, 218}} + RubberWindowFrame + 143 272 500 500 0 0 1600 878 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 223}, {500, 236}} + RubberWindowFrame + 143 272 500 500 0 0 1600 878 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 459pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 9ABC4BF80FB733E500F2D53C + 9A48FC5C0FB73D4B0005CCF1 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowString + 143 272 500 500 0 0 1600 878 + WindowToolGUID + 9ABC4BF80FB733E500F2D53C + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {316, 185}} + {{316, 0}, {378, 185}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 185}} + {{0, 185}, {694, 196}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 148 + + Frame + {{316, 0}, {378, 185}} + RubberWindowFrame + 453 250 694 422 0 0 1600 878 + + RubberWindowFrame + 453 250 694 422 0 0 1600 878 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + 9ABC4BFA0FB733E500F2D53C + 1C162984064C10D400B95A72 + 9ABC4BFB0FB733E500F2D53C + 9ABC4BFC0FB733E500F2D53C + 9ABC4BFD0FB733E500F2D53C + 9ABC4BFE0FB733E500F2D53C + 9ABC4BFF0FB733E500F2D53C + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 453 250 694 422 0 0 1600 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {650, 209}} + RubberWindowFrame + 453 422 650 250 0 0 1600 878 + + Module + PBXDebugCLIModule + Proportion + 209pt + + + Proportion + 209pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + 9ABC4C000FB733E500F2D53C + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 453 422 650 250 0 0 1600 878 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.09500122070312 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + Identifier + windowTool.breakpoints + IsVertical + 0 + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 0 + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 315 424 744 409 0 0 1440 878 + WindowToolGUID + 1CDDB66807F98D9800BB5817 + WindowToolIsVisible + 1 + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/Mac OS X/Fitzquake.xcodeproj/macmini.pbxuser b/Mac OS X/Fitzquake.xcodeproj/macmini.pbxuser new file mode 100644 index 00000000..e1f7be56 --- /dev/null +++ b/Mac OS X/Fitzquake.xcodeproj/macmini.pbxuser @@ -0,0 +1,149 @@ +// !$*UTF8*$! +{ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeArchitecture = i386; + activeBuildConfigurationName = Release; + activeExecutable = 9ABC4B480FB729A900F2D53C /* Fitzquake */; + activeTarget = 8D1107260486CEB800E47090 /* Fitzquake */; + codeSenseManager = 9ABC4B5A0FB729C800F2D53C /* Code sense */; + executables = ( + 9ABC4B480FB729A900F2D53C /* Fitzquake */, + ); + perUserDictionary = { + PBXConfiguration.PBXFileTableDataSource3.PBXErrorsWarningsDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXErrorsWarningsDataSource_LocationID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 380, + 415.20849609375, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXErrorsWarningsDataSource_TypeID, + PBXErrorsWarningsDataSource_MessageID, + PBXErrorsWarningsDataSource_LocationID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXExecutablesDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXExecutablesDataSource_NameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 22, + 300, + 493, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXExecutablesDataSource_ActiveFlagID, + PBXExecutablesDataSource_NameID, + PBXExecutablesDataSource_CommentsID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 605, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 565, + 60, + 20, + 48.16259765625, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 263667008; + PBXWorkspaceStateSaveDate = 263667008; + }; + sourceControlManager = 9ABC4B590FB729C800F2D53C /* Source Control */; + userBuildSettings = { + }; + }; + 483A77F00D2EE97700CB2E4C /* quakedef.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {691, 4648}}"; + sepNavSelRange = "{6952, 0}"; + sepNavVisRange = "{6466, 510}"; + sepNavWindowFrame = "{{84, 252}, {750, 558}}"; + }; + }; + 483A78050D2EE9F300CB2E4C /* gl_texmgr.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {691, 1386}}"; + sepNavSelRange = "{2686, 16}"; + sepNavVisRange = "{0, 1341}"; + sepNavWindowFrame = "{{61, 273}, {750, 558}}"; + }; + }; + 8D1107260486CEB800E47090 /* Fitzquake */ = { + activeExec = 0; + executables = ( + 9ABC4B480FB729A900F2D53C /* Fitzquake */, + ); + }; + 9ABC4B480FB729A900F2D53C /* Fitzquake */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Fitzquake; + sourceDirectories = ( + ); + }; + 9ABC4B590FB729C800F2D53C /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + }; + }; + 9ABC4B5A0FB729C800F2D53C /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; +} diff --git a/Mac OS X/Fitzquake.xcodeproj/project.pbxproj b/Mac OS X/Fitzquake.xcodeproj/project.pbxproj new file mode 100644 index 00000000..99c59627 --- /dev/null +++ b/Mac OS X/Fitzquake.xcodeproj/project.pbxproj @@ -0,0 +1,793 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; }; + 002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; }; + 002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A2C09D0888800EBEB88 /* SDLMain.m */; }; + 002F3C0109D093BD00EBEB88 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F3C0009D093BD00EBEB88 /* OpenGL.framework */; }; + 002F3C6109D0951E00EBEB88 /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F3C6009D0951E00EBEB88 /* GLUT.framework */; }; + 48243B140D33F01A00C29F8F /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 48243B130D33F01A00C29F8F /* main.c */; }; + 4824B3360DF5542E0001ED2C /* SDL_net.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 48DA393E0D998BC9007C2A77 /* SDL_net.framework */; }; + 48305B550D8AF90600A29C24 /* net_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 48305B540D8AF90600A29C24 /* net_udp.c */; }; + 4830B79F0D464CAE00EF4498 /* Changelog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4830B79D0D464CAE00EF4498 /* Changelog.txt */; }; + 4830B7A00D464CAE00EF4498 /* Todo.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4830B79E0D464CAE00EF4498 /* Todo.txt */; }; + 483A780F0D2EEA0F00CB2E4C /* progdefs.q1 in Resources */ = {isa = PBXBuildFile; fileRef = 483A780E0D2EEA0F00CB2E4C /* progdefs.q1 */; }; + 483A78230D2EEA5400CB2E4C /* chase.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78100D2EEA5400CB2E4C /* chase.c */; }; + 483A78240D2EEA5400CB2E4C /* cmd.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78110D2EEA5400CB2E4C /* cmd.c */; }; + 483A78250D2EEA5400CB2E4C /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78120D2EEA5400CB2E4C /* common.c */; }; + 483A78260D2EEA5400CB2E4C /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78130D2EEA5400CB2E4C /* console.c */; }; + 483A78270D2EEA5400CB2E4C /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78140D2EEA5400CB2E4C /* crc.c */; }; + 483A78280D2EEA5400CB2E4C /* cvar.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78150D2EEA5400CB2E4C /* cvar.c */; }; + 483A78290D2EEA5400CB2E4C /* host_cmd.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78160D2EEA5400CB2E4C /* host_cmd.c */; }; + 483A782A0D2EEA5400CB2E4C /* host.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78170D2EEA5400CB2E4C /* host.c */; }; + 483A782B0D2EEA5400CB2E4C /* mathlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78180D2EEA5400CB2E4C /* mathlib.c */; }; + 483A782C0D2EEA5400CB2E4C /* menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78190D2EEA5400CB2E4C /* menu.c */; }; + 483A782D0D2EEA5400CB2E4C /* pr_cmds.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781A0D2EEA5400CB2E4C /* pr_cmds.c */; }; + 483A782E0D2EEA5400CB2E4C /* pr_edict.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781B0D2EEA5400CB2E4C /* pr_edict.c */; }; + 483A782F0D2EEA5400CB2E4C /* pr_exec.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781C0D2EEA5400CB2E4C /* pr_exec.c */; }; + 483A78300D2EEA5400CB2E4C /* sbar.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781D0D2EEA5400CB2E4C /* sbar.c */; }; + 483A78310D2EEA5400CB2E4C /* sys_sdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781E0D2EEA5400CB2E4C /* sys_sdl.c */; }; + 483A78320D2EEA5400CB2E4C /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A781F0D2EEA5400CB2E4C /* view.c */; }; + 483A78330D2EEA5400CB2E4C /* wad.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78200D2EEA5400CB2E4C /* wad.c */; }; + 483A78340D2EEA5400CB2E4C /* world.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78210D2EEA5400CB2E4C /* world.c */; }; + 483A78350D2EEA5400CB2E4C /* zone.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78220D2EEA5400CB2E4C /* zone.c */; }; + 483A78380D2EEA6D00CB2E4C /* in_sdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78360D2EEA6D00CB2E4C /* in_sdl.c */; }; + 483A78390D2EEA6D00CB2E4C /* keys.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78370D2EEA6D00CB2E4C /* keys.c */; }; + 483A78450D2EEAAB00CB2E4C /* cl_demo.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783A0D2EEAAB00CB2E4C /* cl_demo.c */; }; + 483A78460D2EEAAB00CB2E4C /* cl_input.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783B0D2EEAAB00CB2E4C /* cl_input.c */; }; + 483A78470D2EEAAB00CB2E4C /* cl_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783C0D2EEAAB00CB2E4C /* cl_main.c */; }; + 483A78480D2EEAAB00CB2E4C /* cl_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783D0D2EEAAB00CB2E4C /* cl_parse.c */; }; + 483A78490D2EEAAB00CB2E4C /* cl_tent.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783E0D2EEAAB00CB2E4C /* cl_tent.c */; }; + 483A784A0D2EEAAB00CB2E4C /* net_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A783F0D2EEAAB00CB2E4C /* net_main.c */; }; + 483A784B0D2EEAAB00CB2E4C /* net_sdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78400D2EEAAB00CB2E4C /* net_sdl.c */; }; + 483A784C0D2EEAAB00CB2E4C /* sv_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78410D2EEAAB00CB2E4C /* sv_main.c */; }; + 483A784D0D2EEAAB00CB2E4C /* sv_move.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78420D2EEAAB00CB2E4C /* sv_move.c */; }; + 483A784E0D2EEAAB00CB2E4C /* sv_phys.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78430D2EEAAB00CB2E4C /* sv_phys.c */; }; + 483A784F0D2EEAAB00CB2E4C /* sv_user.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78440D2EEAAB00CB2E4C /* sv_user.c */; }; + 483A78550D2EEAC300CB2E4C /* cd_sdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78500D2EEAC300CB2E4C /* cd_sdl.c */; }; + 483A78590D2EEAC300CB2E4C /* snd_sdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78540D2EEAC300CB2E4C /* snd_sdl.c */; }; + 483A786E0D2EEAF000CB2E4C /* gl_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785A0D2EEAF000CB2E4C /* gl_draw.c */; }; + 483A786F0D2EEAF000CB2E4C /* gl_fog.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785B0D2EEAF000CB2E4C /* gl_fog.c */; }; + 483A78700D2EEAF000CB2E4C /* gl_mesh.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785C0D2EEAF000CB2E4C /* gl_mesh.c */; }; + 483A78710D2EEAF000CB2E4C /* gl_model.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785D0D2EEAF000CB2E4C /* gl_model.c */; }; + 483A78720D2EEAF000CB2E4C /* gl_refrag.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785E0D2EEAF000CB2E4C /* gl_refrag.c */; }; + 483A78730D2EEAF000CB2E4C /* gl_rlight.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A785F0D2EEAF000CB2E4C /* gl_rlight.c */; }; + 483A78740D2EEAF000CB2E4C /* gl_rmain.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78600D2EEAF000CB2E4C /* gl_rmain.c */; }; + 483A78750D2EEAF000CB2E4C /* gl_rmisc.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78610D2EEAF000CB2E4C /* gl_rmisc.c */; }; + 483A78760D2EEAF000CB2E4C /* gl_screen.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78620D2EEAF000CB2E4C /* gl_screen.c */; }; + 483A78770D2EEAF000CB2E4C /* gl_sky.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78630D2EEAF000CB2E4C /* gl_sky.c */; }; + 483A78780D2EEAF000CB2E4C /* gl_test.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78640D2EEAF000CB2E4C /* gl_test.c */; }; + 483A78790D2EEAF000CB2E4C /* gl_texmgr.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78650D2EEAF000CB2E4C /* gl_texmgr.c */; }; + 483A787A0D2EEAF000CB2E4C /* gl_vidsdl.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78660D2EEAF000CB2E4C /* gl_vidsdl.c */; }; + 483A787B0D2EEAF000CB2E4C /* gl_warp.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78670D2EEAF000CB2E4C /* gl_warp.c */; }; + 483A787C0D2EEAF000CB2E4C /* image.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78680D2EEAF000CB2E4C /* image.c */; }; + 483A787D0D2EEAF000CB2E4C /* r_alias.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A78690D2EEAF000CB2E4C /* r_alias.c */; }; + 483A787E0D2EEAF000CB2E4C /* r_brush.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A786A0D2EEAF000CB2E4C /* r_brush.c */; }; + 483A787F0D2EEAF000CB2E4C /* r_part.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A786B0D2EEAF000CB2E4C /* r_part.c */; }; + 483A78800D2EEAF000CB2E4C /* r_sprite.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A786C0D2EEAF000CB2E4C /* r_sprite.c */; }; + 483A78810D2EEAF000CB2E4C /* r_world.c in Sources */ = {isa = PBXBuildFile; fileRef = 483A786D0D2EEAF000CB2E4C /* r_world.c */; }; + 484AA4B40D3FF6C0005D917A /* Fitzquake.icns in Resources */ = {isa = PBXBuildFile; fileRef = 484AA4B30D3FF6C0005D917A /* Fitzquake.icns */; }; + 486577CB0D31A22A00E7920A /* snd_dma.c in Sources */ = {isa = PBXBuildFile; fileRef = 486577C80D31A22A00E7920A /* snd_dma.c */; }; + 486577CC0D31A22A00E7920A /* snd_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 486577C90D31A22A00E7920A /* snd_mem.c */; }; + 486577CD0D31A22A00E7920A /* snd_mix.c in Sources */ = {isa = PBXBuildFile; fileRef = 486577CA0D31A22A00E7920A /* snd_mix.c */; }; + 48728D2D0D3004A80004D61B /* net_dgrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 48728D280D3004A70004D61B /* net_dgrm.c */; }; + 48728D2E0D3004A80004D61B /* net_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 48728D2A0D3004A80004D61B /* net_loop.c */; }; + 487C0A5D0DA94A0700A49FF5 /* net_sdlnet.c in Sources */ = {isa = PBXBuildFile; fileRef = 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */; }; + 48895DB90D4914A000849ABF /* pl_osx.m in Sources */ = {isa = PBXBuildFile; fileRef = 48895DB80D4914A000849ABF /* pl_osx.m */; }; + 489D8D2F0D3A630D00AA4471 /* ScreenInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 489D8D2E0D3A630D00AA4471 /* ScreenInfo.m */; }; + 48B9E7880D340B1E0001CACF /* Launcher.nib in Resources */ = {isa = PBXBuildFile; fileRef = 48B9E7860D340B1E0001CACF /* Launcher.nib */; }; + 48B9E7A70D340BEA0001CACF /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 48B9E7A60D340BEA0001CACF /* AppController.m */; }; + 48B9E7C00D340EA80001CACF /* SDLApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 48B9E7BF0D340EA80001CACF /* SDLApplication.m */; }; + 48C85E3B0D3AD10E00797678 /* QuakeArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 48C85E3A0D3AD10E00797678 /* QuakeArgument.m */; }; + 48DA393F0D998BC9007C2A77 /* SDL_net.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48DA393E0D998BC9007C2A77 /* SDL_net.framework */; }; + 48FE585B0D3A82C8006BB491 /* QuakeArguments.m in Sources */ = {isa = PBXBuildFile; fileRef = 48FE585A0D3A82C8006BB491 /* QuakeArguments.m */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */, + 4824B3360DF5542E0001ED2C /* SDL_net.framework in Copy Frameworks into .app bundle */, + ); + name = "Copy Frameworks into .app bundle"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 002F39F909D0881F00EBEB88 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = ""; }; + 002F3A2B09D0888800EBEB88 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = ""; }; + 002F3A2C09D0888800EBEB88 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = ""; }; + 002F3C0009D093BD00EBEB88 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; + 002F3C6009D0951E00EBEB88 /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = ../../../../../../../../../../System/Library/Frameworks/GLUT.framework; sourceTree = SOURCE_ROOT; }; + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* Fitzquake_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fitzquake_Prefix.pch; sourceTree = ""; }; + 48243B130D33F01A00C29F8F /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../Quake/main.c; sourceTree = SOURCE_ROOT; }; + 48305B530D8AF8EC00A29C24 /* net_udp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net_udp.h; path = ../Quake/net_udp.h; sourceTree = SOURCE_ROOT; }; + 48305B540D8AF90600A29C24 /* net_udp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_udp.c; path = ../Quake/net_udp.c; sourceTree = SOURCE_ROOT; }; + 4830B79D0D464CAE00EF4498 /* Changelog.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Changelog.txt; path = ../Misc/Changelog.txt; sourceTree = SOURCE_ROOT; }; + 4830B79E0D464CAE00EF4498 /* Todo.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Todo.txt; path = ../Misc/Todo.txt; sourceTree = SOURCE_ROOT; }; + 483A77E60D2EE97700CB2E4C /* cmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmd.h; path = ../Quake/cmd.h; sourceTree = SOURCE_ROOT; }; + 483A77E70D2EE97700CB2E4C /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = common.h; path = ../Quake/common.h; sourceTree = SOURCE_ROOT; }; + 483A77E80D2EE97700CB2E4C /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = console.h; path = ../Quake/console.h; sourceTree = SOURCE_ROOT; }; + 483A77E90D2EE97700CB2E4C /* crc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc.h; path = ../Quake/crc.h; sourceTree = SOURCE_ROOT; }; + 483A77EA0D2EE97700CB2E4C /* cvar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cvar.h; path = ../Quake/cvar.h; sourceTree = SOURCE_ROOT; }; + 483A77EB0D2EE97700CB2E4C /* mathlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mathlib.h; path = ../Quake/mathlib.h; sourceTree = SOURCE_ROOT; }; + 483A77EC0D2EE97700CB2E4C /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = menu.h; path = ../Quake/menu.h; sourceTree = SOURCE_ROOT; }; + 483A77ED0D2EE97700CB2E4C /* pr_comp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pr_comp.h; path = ../Quake/pr_comp.h; sourceTree = SOURCE_ROOT; }; + 483A77EE0D2EE97700CB2E4C /* progdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = progdefs.h; path = ../Quake/progdefs.h; sourceTree = SOURCE_ROOT; }; + 483A77EF0D2EE97700CB2E4C /* progs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = progs.h; path = ../Quake/progs.h; sourceTree = SOURCE_ROOT; }; + 483A77F00D2EE97700CB2E4C /* quakedef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quakedef.h; path = ../Quake/quakedef.h; sourceTree = SOURCE_ROOT; }; + 483A77F10D2EE97700CB2E4C /* sbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sbar.h; path = ../Quake/sbar.h; sourceTree = SOURCE_ROOT; }; + 483A77F20D2EE97700CB2E4C /* sys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys.h; path = ../Quake/sys.h; sourceTree = SOURCE_ROOT; }; + 483A77F30D2EE97700CB2E4C /* view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = view.h; path = ../Quake/view.h; sourceTree = SOURCE_ROOT; }; + 483A77F40D2EE97700CB2E4C /* wad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wad.h; path = ../Quake/wad.h; sourceTree = SOURCE_ROOT; }; + 483A77F50D2EE97700CB2E4C /* world.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = world.h; path = ../Quake/world.h; sourceTree = SOURCE_ROOT; }; + 483A77F60D2EE97700CB2E4C /* zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zone.h; path = ../Quake/zone.h; sourceTree = SOURCE_ROOT; }; + 483A77F70D2EE98D00CB2E4C /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = input.h; path = ../Quake/input.h; sourceTree = SOURCE_ROOT; }; + 483A77F80D2EE98D00CB2E4C /* keys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = keys.h; path = ../Quake/keys.h; sourceTree = SOURCE_ROOT; }; + 483A77F90D2EE9A900CB2E4C /* client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = client.h; path = ../Quake/client.h; sourceTree = SOURCE_ROOT; }; + 483A77FA0D2EE9A900CB2E4C /* net.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net.h; path = ../Quake/net.h; sourceTree = SOURCE_ROOT; }; + 483A77FB0D2EE9A900CB2E4C /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = protocol.h; path = ../Quake/protocol.h; sourceTree = SOURCE_ROOT; }; + 483A77FC0D2EE9A900CB2E4C /* server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = server.h; path = ../Quake/server.h; sourceTree = SOURCE_ROOT; }; + 483A77FD0D2EE9BD00CB2E4C /* cdaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cdaudio.h; path = ../Quake/cdaudio.h; sourceTree = SOURCE_ROOT; }; + 483A77FE0D2EE9BD00CB2E4C /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sound.h; path = ../Quake/sound.h; sourceTree = SOURCE_ROOT; }; + 483A77FF0D2EE9F300CB2E4C /* anorm_dots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anorm_dots.h; path = ../Quake/anorm_dots.h; sourceTree = SOURCE_ROOT; }; + 483A78000D2EE9F300CB2E4C /* anorms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anorms.h; path = ../Quake/anorms.h; sourceTree = SOURCE_ROOT; }; + 483A78010D2EE9F300CB2E4C /* bspfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bspfile.h; path = ../Quake/bspfile.h; sourceTree = SOURCE_ROOT; }; + 483A78020D2EE9F300CB2E4C /* d_ifacea.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = d_ifacea.h; path = ../Quake/d_ifacea.h; sourceTree = SOURCE_ROOT; }; + 483A78030D2EE9F300CB2E4C /* draw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = draw.h; path = ../Quake/draw.h; sourceTree = SOURCE_ROOT; }; + 483A78040D2EE9F300CB2E4C /* gl_model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_model.h; path = ../Quake/gl_model.h; sourceTree = SOURCE_ROOT; }; + 483A78050D2EE9F300CB2E4C /* gl_texmgr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_texmgr.h; path = ../Quake/gl_texmgr.h; sourceTree = SOURCE_ROOT; }; + 483A78060D2EE9F300CB2E4C /* gl_warp_sin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gl_warp_sin.h; path = ../Quake/gl_warp_sin.h; sourceTree = SOURCE_ROOT; }; + 483A78070D2EE9F300CB2E4C /* glquake.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glquake.h; path = ../Quake/glquake.h; sourceTree = SOURCE_ROOT; }; + 483A78080D2EE9F300CB2E4C /* image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = image.h; path = ../Quake/image.h; sourceTree = SOURCE_ROOT; }; + 483A78090D2EE9F300CB2E4C /* modelgen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = modelgen.h; path = ../Quake/modelgen.h; sourceTree = SOURCE_ROOT; }; + 483A780A0D2EE9F300CB2E4C /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = render.h; path = ../Quake/render.h; sourceTree = SOURCE_ROOT; }; + 483A780B0D2EE9F300CB2E4C /* screen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = screen.h; path = ../Quake/screen.h; sourceTree = SOURCE_ROOT; }; + 483A780C0D2EE9F300CB2E4C /* spritegn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spritegn.h; path = ../Quake/spritegn.h; sourceTree = SOURCE_ROOT; }; + 483A780D0D2EE9F300CB2E4C /* vid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vid.h; path = ../Quake/vid.h; sourceTree = SOURCE_ROOT; }; + 483A780E0D2EEA0F00CB2E4C /* progdefs.q1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = progdefs.q1; path = ../Quake/progdefs.q1; sourceTree = SOURCE_ROOT; }; + 483A78100D2EEA5400CB2E4C /* chase.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = chase.c; path = ../Quake/chase.c; sourceTree = SOURCE_ROOT; }; + 483A78110D2EEA5400CB2E4C /* cmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cmd.c; path = ../Quake/cmd.c; sourceTree = SOURCE_ROOT; }; + 483A78120D2EEA5400CB2E4C /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common.c; path = ../Quake/common.c; sourceTree = SOURCE_ROOT; }; + 483A78130D2EEA5400CB2E4C /* console.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = console.c; path = ../Quake/console.c; sourceTree = SOURCE_ROOT; }; + 483A78140D2EEA5400CB2E4C /* crc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crc.c; path = ../Quake/crc.c; sourceTree = SOURCE_ROOT; }; + 483A78150D2EEA5400CB2E4C /* cvar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cvar.c; path = ../Quake/cvar.c; sourceTree = SOURCE_ROOT; }; + 483A78160D2EEA5400CB2E4C /* host_cmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = host_cmd.c; path = ../Quake/host_cmd.c; sourceTree = SOURCE_ROOT; }; + 483A78170D2EEA5400CB2E4C /* host.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = host.c; path = ../Quake/host.c; sourceTree = SOURCE_ROOT; }; + 483A78180D2EEA5400CB2E4C /* mathlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mathlib.c; path = ../Quake/mathlib.c; sourceTree = SOURCE_ROOT; }; + 483A78190D2EEA5400CB2E4C /* menu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = menu.c; path = ../Quake/menu.c; sourceTree = SOURCE_ROOT; }; + 483A781A0D2EEA5400CB2E4C /* pr_cmds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pr_cmds.c; path = ../Quake/pr_cmds.c; sourceTree = SOURCE_ROOT; }; + 483A781B0D2EEA5400CB2E4C /* pr_edict.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pr_edict.c; path = ../Quake/pr_edict.c; sourceTree = SOURCE_ROOT; }; + 483A781C0D2EEA5400CB2E4C /* pr_exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pr_exec.c; path = ../Quake/pr_exec.c; sourceTree = SOURCE_ROOT; }; + 483A781D0D2EEA5400CB2E4C /* sbar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sbar.c; path = ../Quake/sbar.c; sourceTree = SOURCE_ROOT; }; + 483A781E0D2EEA5400CB2E4C /* sys_sdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sys_sdl.c; path = ../Quake/sys_sdl.c; sourceTree = SOURCE_ROOT; }; + 483A781F0D2EEA5400CB2E4C /* view.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = view.c; path = ../Quake/view.c; sourceTree = SOURCE_ROOT; }; + 483A78200D2EEA5400CB2E4C /* wad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wad.c; path = ../Quake/wad.c; sourceTree = SOURCE_ROOT; }; + 483A78210D2EEA5400CB2E4C /* world.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = world.c; path = ../Quake/world.c; sourceTree = SOURCE_ROOT; }; + 483A78220D2EEA5400CB2E4C /* zone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zone.c; path = ../Quake/zone.c; sourceTree = SOURCE_ROOT; }; + 483A78360D2EEA6D00CB2E4C /* in_sdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = in_sdl.c; path = ../Quake/in_sdl.c; sourceTree = SOURCE_ROOT; }; + 483A78370D2EEA6D00CB2E4C /* keys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = keys.c; path = ../Quake/keys.c; sourceTree = SOURCE_ROOT; }; + 483A783A0D2EEAAB00CB2E4C /* cl_demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cl_demo.c; path = ../Quake/cl_demo.c; sourceTree = SOURCE_ROOT; }; + 483A783B0D2EEAAB00CB2E4C /* cl_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cl_input.c; path = ../Quake/cl_input.c; sourceTree = SOURCE_ROOT; }; + 483A783C0D2EEAAB00CB2E4C /* cl_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cl_main.c; path = ../Quake/cl_main.c; sourceTree = SOURCE_ROOT; }; + 483A783D0D2EEAAB00CB2E4C /* cl_parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cl_parse.c; path = ../Quake/cl_parse.c; sourceTree = SOURCE_ROOT; }; + 483A783E0D2EEAAB00CB2E4C /* cl_tent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cl_tent.c; path = ../Quake/cl_tent.c; sourceTree = SOURCE_ROOT; }; + 483A783F0D2EEAAB00CB2E4C /* net_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_main.c; path = ../Quake/net_main.c; sourceTree = SOURCE_ROOT; }; + 483A78400D2EEAAB00CB2E4C /* net_sdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_sdl.c; path = ../Quake/net_sdl.c; sourceTree = SOURCE_ROOT; }; + 483A78410D2EEAAB00CB2E4C /* sv_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sv_main.c; path = ../Quake/sv_main.c; sourceTree = SOURCE_ROOT; }; + 483A78420D2EEAAB00CB2E4C /* sv_move.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sv_move.c; path = ../Quake/sv_move.c; sourceTree = SOURCE_ROOT; }; + 483A78430D2EEAAB00CB2E4C /* sv_phys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sv_phys.c; path = ../Quake/sv_phys.c; sourceTree = SOURCE_ROOT; }; + 483A78440D2EEAAB00CB2E4C /* sv_user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sv_user.c; path = ../Quake/sv_user.c; sourceTree = SOURCE_ROOT; }; + 483A78500D2EEAC300CB2E4C /* cd_sdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cd_sdl.c; path = ../Quake/cd_sdl.c; sourceTree = SOURCE_ROOT; }; + 483A78540D2EEAC300CB2E4C /* snd_sdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snd_sdl.c; path = ../Quake/snd_sdl.c; sourceTree = SOURCE_ROOT; }; + 483A785A0D2EEAF000CB2E4C /* gl_draw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_draw.c; path = ../Quake/gl_draw.c; sourceTree = SOURCE_ROOT; }; + 483A785B0D2EEAF000CB2E4C /* gl_fog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_fog.c; path = ../Quake/gl_fog.c; sourceTree = SOURCE_ROOT; }; + 483A785C0D2EEAF000CB2E4C /* gl_mesh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_mesh.c; path = ../Quake/gl_mesh.c; sourceTree = SOURCE_ROOT; }; + 483A785D0D2EEAF000CB2E4C /* gl_model.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_model.c; path = ../Quake/gl_model.c; sourceTree = SOURCE_ROOT; }; + 483A785E0D2EEAF000CB2E4C /* gl_refrag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_refrag.c; path = ../Quake/gl_refrag.c; sourceTree = SOURCE_ROOT; }; + 483A785F0D2EEAF000CB2E4C /* gl_rlight.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_rlight.c; path = ../Quake/gl_rlight.c; sourceTree = SOURCE_ROOT; }; + 483A78600D2EEAF000CB2E4C /* gl_rmain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_rmain.c; path = ../Quake/gl_rmain.c; sourceTree = SOURCE_ROOT; }; + 483A78610D2EEAF000CB2E4C /* gl_rmisc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_rmisc.c; path = ../Quake/gl_rmisc.c; sourceTree = SOURCE_ROOT; }; + 483A78620D2EEAF000CB2E4C /* gl_screen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_screen.c; path = ../Quake/gl_screen.c; sourceTree = SOURCE_ROOT; }; + 483A78630D2EEAF000CB2E4C /* gl_sky.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_sky.c; path = ../Quake/gl_sky.c; sourceTree = SOURCE_ROOT; }; + 483A78640D2EEAF000CB2E4C /* gl_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_test.c; path = ../Quake/gl_test.c; sourceTree = SOURCE_ROOT; }; + 483A78650D2EEAF000CB2E4C /* gl_texmgr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_texmgr.c; path = ../Quake/gl_texmgr.c; sourceTree = SOURCE_ROOT; }; + 483A78660D2EEAF000CB2E4C /* gl_vidsdl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_vidsdl.c; path = ../Quake/gl_vidsdl.c; sourceTree = SOURCE_ROOT; }; + 483A78670D2EEAF000CB2E4C /* gl_warp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gl_warp.c; path = ../Quake/gl_warp.c; sourceTree = SOURCE_ROOT; }; + 483A78680D2EEAF000CB2E4C /* image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = image.c; path = ../Quake/image.c; sourceTree = SOURCE_ROOT; }; + 483A78690D2EEAF000CB2E4C /* r_alias.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_alias.c; path = ../Quake/r_alias.c; sourceTree = SOURCE_ROOT; }; + 483A786A0D2EEAF000CB2E4C /* r_brush.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_brush.c; path = ../Quake/r_brush.c; sourceTree = SOURCE_ROOT; }; + 483A786B0D2EEAF000CB2E4C /* r_part.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_part.c; path = ../Quake/r_part.c; sourceTree = SOURCE_ROOT; }; + 483A786C0D2EEAF000CB2E4C /* r_sprite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_sprite.c; path = ../Quake/r_sprite.c; sourceTree = SOURCE_ROOT; }; + 483A786D0D2EEAF000CB2E4C /* r_world.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = r_world.c; path = ../Quake/r_world.c; sourceTree = SOURCE_ROOT; }; + 4846EB500D329BEB00A108DE /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = ../Quake/platform.h; sourceTree = SOURCE_ROOT; }; + 484AA4B30D3FF6C0005D917A /* Fitzquake.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Fitzquake.icns; sourceTree = ""; }; + 486577C80D31A22A00E7920A /* snd_dma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snd_dma.c; path = ../Quake/snd_dma.c; sourceTree = SOURCE_ROOT; }; + 486577C90D31A22A00E7920A /* snd_mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snd_mem.c; path = ../Quake/snd_mem.c; sourceTree = SOURCE_ROOT; }; + 486577CA0D31A22A00E7920A /* snd_mix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snd_mix.c; path = ../Quake/snd_mix.c; sourceTree = SOURCE_ROOT; }; + 48728D280D3004A70004D61B /* net_dgrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_dgrm.c; path = ../Quake/net_dgrm.c; sourceTree = SOURCE_ROOT; }; + 48728D290D3004A80004D61B /* net_dgrm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net_dgrm.h; path = ../Quake/net_dgrm.h; sourceTree = SOURCE_ROOT; }; + 48728D2A0D3004A80004D61B /* net_loop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_loop.c; path = ../Quake/net_loop.c; sourceTree = SOURCE_ROOT; }; + 48728D2B0D3004A80004D61B /* net_loop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net_loop.h; path = ../Quake/net_loop.h; sourceTree = SOURCE_ROOT; }; + 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = net_sdlnet.c; path = ../Quake/net_sdlnet.c; sourceTree = SOURCE_ROOT; }; + 487C0A5C0DA94A0700A49FF5 /* net_sdlnet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = net_sdlnet.h; path = ../Quake/net_sdlnet.h; sourceTree = SOURCE_ROOT; }; + 48895DB80D4914A000849ABF /* pl_osx.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = pl_osx.m; path = ../Quake/pl_osx.m; sourceTree = SOURCE_ROOT; }; + 489D8D2D0D3A630D00AA4471 /* ScreenInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenInfo.h; sourceTree = ""; }; + 489D8D2E0D3A630D00AA4471 /* ScreenInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ScreenInfo.m; sourceTree = ""; }; + 48B9E7870D340B1E0001CACF /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Launcher.nib; sourceTree = ""; }; + 48B9E7A50D340BEA0001CACF /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; + 48B9E7A60D340BEA0001CACF /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = ""; }; + 48B9E7BE0D340EA80001CACF /* SDLApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLApplication.h; sourceTree = ""; }; + 48B9E7BF0D340EA80001CACF /* SDLApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLApplication.m; sourceTree = ""; }; + 48C85E390D3AD10E00797678 /* QuakeArgument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuakeArgument.h; sourceTree = ""; }; + 48C85E3A0D3AD10E00797678 /* QuakeArgument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuakeArgument.m; sourceTree = ""; }; + 48DA393E0D998BC9007C2A77 /* SDL_net.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_net.framework; path = /Library/Frameworks/SDL_net.framework; sourceTree = ""; }; + 48FE58590D3A82C8006BB491 /* QuakeArguments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuakeArguments.h; sourceTree = ""; }; + 48FE585A0D3A82C8006BB491 /* QuakeArguments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuakeArguments.m; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* Fitzquake.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Fitzquake.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */, + 002F3C6109D0951E00EBEB88 /* GLUT.framework in Frameworks */, + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + 002F3C0109D093BD00EBEB88 /* OpenGL.framework in Frameworks */, + 48DA393F0D998BC9007C2A77 /* SDL_net.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 002F39F909D0881F00EBEB88 /* SDL.framework */, + 48DA393E0D998BC9007C2A77 /* SDL_net.framework */, + 002F3C6009D0951E00EBEB88 /* GLUT.framework */, + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + 002F3C0009D093BD00EBEB88 /* OpenGL.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* Fitzquake.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* Fitzquake */ = { + isa = PBXGroup; + children = ( + 48243B060D33ED0A00C29F8F /* Mac OS X */, + 483A77D80D2EE8C500CB2E4C /* Quake */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 4830B79D0D464CAE00EF4498 /* Changelog.txt */, + 4830B79E0D464CAE00EF4498 /* Todo.txt */, + ); + name = Fitzquake; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 484AA4B30D3FF6C0005D917A /* Fitzquake.icns */, + 48B9E7860D340B1E0001CACF /* Launcher.nib */, + 8D1107310486CEB800E47090 /* Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + 48243B060D33ED0A00C29F8F /* Mac OS X */ = { + isa = PBXGroup; + children = ( + 48B9E7A50D340BEA0001CACF /* AppController.h */, + 48B9E7A60D340BEA0001CACF /* AppController.m */, + 32CA4F630368D1EE00C91783 /* Fitzquake_Prefix.pch */, + 48FE58590D3A82C8006BB491 /* QuakeArguments.h */, + 48FE585A0D3A82C8006BB491 /* QuakeArguments.m */, + 489D8D2D0D3A630D00AA4471 /* ScreenInfo.h */, + 489D8D2E0D3A630D00AA4471 /* ScreenInfo.m */, + 48B9E7BE0D340EA80001CACF /* SDLApplication.h */, + 48B9E7BF0D340EA80001CACF /* SDLApplication.m */, + 002F3A2B09D0888800EBEB88 /* SDLMain.h */, + 002F3A2C09D0888800EBEB88 /* SDLMain.m */, + 48C85E390D3AD10E00797678 /* QuakeArgument.h */, + 48C85E3A0D3AD10E00797678 /* QuakeArgument.m */, + ); + name = "Mac OS X"; + sourceTree = ""; + }; + 483A77D80D2EE8C500CB2E4C /* Quake */ = { + isa = PBXGroup; + children = ( + 483A77D90D2EE8D400CB2E4C /* Generic */, + 483A77DA0D2EE8DA00CB2E4C /* Input */, + 483A77DD0D2EE8F100CB2E4C /* Network */, + 483A77DC0D2EE8ED00CB2E4C /* Sound */, + 483A77DB0D2EE8E600CB2E4C /* Video */, + ); + name = Quake; + sourceTree = ""; + }; + 483A77D90D2EE8D400CB2E4C /* Generic */ = { + isa = PBXGroup; + children = ( + 483A77DE0D2EE8FB00CB2E4C /* Headers */, + 483A78100D2EEA5400CB2E4C /* chase.c */, + 483A78110D2EEA5400CB2E4C /* cmd.c */, + 483A78120D2EEA5400CB2E4C /* common.c */, + 483A78130D2EEA5400CB2E4C /* console.c */, + 483A78140D2EEA5400CB2E4C /* crc.c */, + 483A78150D2EEA5400CB2E4C /* cvar.c */, + 483A78170D2EEA5400CB2E4C /* host.c */, + 483A78160D2EEA5400CB2E4C /* host_cmd.c */, + 48243B130D33F01A00C29F8F /* main.c */, + 483A78180D2EEA5400CB2E4C /* mathlib.c */, + 483A78190D2EEA5400CB2E4C /* menu.c */, + 48895DB80D4914A000849ABF /* pl_osx.m */, + 483A781A0D2EEA5400CB2E4C /* pr_cmds.c */, + 483A781B0D2EEA5400CB2E4C /* pr_edict.c */, + 483A781C0D2EEA5400CB2E4C /* pr_exec.c */, + 483A780E0D2EEA0F00CB2E4C /* progdefs.q1 */, + 483A781D0D2EEA5400CB2E4C /* sbar.c */, + 483A781E0D2EEA5400CB2E4C /* sys_sdl.c */, + 483A781F0D2EEA5400CB2E4C /* view.c */, + 483A78200D2EEA5400CB2E4C /* wad.c */, + 483A78210D2EEA5400CB2E4C /* world.c */, + 483A78220D2EEA5400CB2E4C /* zone.c */, + ); + name = Generic; + sourceTree = ""; + }; + 483A77DA0D2EE8DA00CB2E4C /* Input */ = { + isa = PBXGroup; + children = ( + 483A77DF0D2EE90500CB2E4C /* Headers */, + 483A78360D2EEA6D00CB2E4C /* in_sdl.c */, + 483A78370D2EEA6D00CB2E4C /* keys.c */, + ); + name = Input; + sourceTree = ""; + }; + 483A77DB0D2EE8E600CB2E4C /* Video */ = { + isa = PBXGroup; + children = ( + 483A77E20D2EE91500CB2E4C /* Headers */, + 483A785A0D2EEAF000CB2E4C /* gl_draw.c */, + 483A785B0D2EEAF000CB2E4C /* gl_fog.c */, + 483A785C0D2EEAF000CB2E4C /* gl_mesh.c */, + 483A785D0D2EEAF000CB2E4C /* gl_model.c */, + 483A785E0D2EEAF000CB2E4C /* gl_refrag.c */, + 483A785F0D2EEAF000CB2E4C /* gl_rlight.c */, + 483A78600D2EEAF000CB2E4C /* gl_rmain.c */, + 483A78610D2EEAF000CB2E4C /* gl_rmisc.c */, + 483A78620D2EEAF000CB2E4C /* gl_screen.c */, + 483A78630D2EEAF000CB2E4C /* gl_sky.c */, + 483A78640D2EEAF000CB2E4C /* gl_test.c */, + 483A78650D2EEAF000CB2E4C /* gl_texmgr.c */, + 483A78660D2EEAF000CB2E4C /* gl_vidsdl.c */, + 483A78670D2EEAF000CB2E4C /* gl_warp.c */, + 483A78680D2EEAF000CB2E4C /* image.c */, + 483A78690D2EEAF000CB2E4C /* r_alias.c */, + 483A786A0D2EEAF000CB2E4C /* r_brush.c */, + 483A786B0D2EEAF000CB2E4C /* r_part.c */, + 483A786C0D2EEAF000CB2E4C /* r_sprite.c */, + 483A786D0D2EEAF000CB2E4C /* r_world.c */, + ); + name = Video; + sourceTree = ""; + }; + 483A77DC0D2EE8ED00CB2E4C /* Sound */ = { + isa = PBXGroup; + children = ( + 483A77E10D2EE91000CB2E4C /* Headers */, + 483A78500D2EEAC300CB2E4C /* cd_sdl.c */, + 486577C80D31A22A00E7920A /* snd_dma.c */, + 486577C90D31A22A00E7920A /* snd_mem.c */, + 486577CA0D31A22A00E7920A /* snd_mix.c */, + 483A78540D2EEAC300CB2E4C /* snd_sdl.c */, + ); + name = Sound; + sourceTree = ""; + }; + 483A77DD0D2EE8F100CB2E4C /* Network */ = { + isa = PBXGroup; + children = ( + 483A77E00D2EE90B00CB2E4C /* Headers */, + 483A783A0D2EEAAB00CB2E4C /* cl_demo.c */, + 483A783B0D2EEAAB00CB2E4C /* cl_input.c */, + 483A783C0D2EEAAB00CB2E4C /* cl_main.c */, + 483A783D0D2EEAAB00CB2E4C /* cl_parse.c */, + 483A783E0D2EEAAB00CB2E4C /* cl_tent.c */, + 48728D280D3004A70004D61B /* net_dgrm.c */, + 48728D2A0D3004A80004D61B /* net_loop.c */, + 483A783F0D2EEAAB00CB2E4C /* net_main.c */, + 483A78400D2EEAAB00CB2E4C /* net_sdl.c */, + 487C0A5B0DA94A0700A49FF5 /* net_sdlnet.c */, + 48305B540D8AF90600A29C24 /* net_udp.c */, + 483A78410D2EEAAB00CB2E4C /* sv_main.c */, + 483A78420D2EEAAB00CB2E4C /* sv_move.c */, + 483A78430D2EEAAB00CB2E4C /* sv_phys.c */, + 483A78440D2EEAAB00CB2E4C /* sv_user.c */, + ); + name = Network; + sourceTree = ""; + }; + 483A77DE0D2EE8FB00CB2E4C /* Headers */ = { + isa = PBXGroup; + children = ( + 483A77E60D2EE97700CB2E4C /* cmd.h */, + 483A77E70D2EE97700CB2E4C /* common.h */, + 483A77E80D2EE97700CB2E4C /* console.h */, + 483A77E90D2EE97700CB2E4C /* crc.h */, + 483A77EA0D2EE97700CB2E4C /* cvar.h */, + 483A77EB0D2EE97700CB2E4C /* mathlib.h */, + 483A77EC0D2EE97700CB2E4C /* menu.h */, + 4846EB500D329BEB00A108DE /* platform.h */, + 483A77ED0D2EE97700CB2E4C /* pr_comp.h */, + 483A77EE0D2EE97700CB2E4C /* progdefs.h */, + 483A77EF0D2EE97700CB2E4C /* progs.h */, + 483A77F00D2EE97700CB2E4C /* quakedef.h */, + 483A77F10D2EE97700CB2E4C /* sbar.h */, + 483A77F20D2EE97700CB2E4C /* sys.h */, + 483A77F30D2EE97700CB2E4C /* view.h */, + 483A77F40D2EE97700CB2E4C /* wad.h */, + 483A77F50D2EE97700CB2E4C /* world.h */, + 483A77F60D2EE97700CB2E4C /* zone.h */, + ); + name = Headers; + sourceTree = ""; + }; + 483A77DF0D2EE90500CB2E4C /* Headers */ = { + isa = PBXGroup; + children = ( + 483A77F70D2EE98D00CB2E4C /* input.h */, + 483A77F80D2EE98D00CB2E4C /* keys.h */, + ); + name = Headers; + sourceTree = ""; + }; + 483A77E00D2EE90B00CB2E4C /* Headers */ = { + isa = PBXGroup; + children = ( + 483A77F90D2EE9A900CB2E4C /* client.h */, + 483A77FA0D2EE9A900CB2E4C /* net.h */, + 48728D290D3004A80004D61B /* net_dgrm.h */, + 48728D2B0D3004A80004D61B /* net_loop.h */, + 487C0A5C0DA94A0700A49FF5 /* net_sdlnet.h */, + 48305B530D8AF8EC00A29C24 /* net_udp.h */, + 483A77FB0D2EE9A900CB2E4C /* protocol.h */, + 483A77FC0D2EE9A900CB2E4C /* server.h */, + ); + name = Headers; + sourceTree = ""; + }; + 483A77E10D2EE91000CB2E4C /* Headers */ = { + isa = PBXGroup; + children = ( + 483A77FD0D2EE9BD00CB2E4C /* cdaudio.h */, + 483A77FE0D2EE9BD00CB2E4C /* sound.h */, + ); + name = Headers; + sourceTree = ""; + }; + 483A77E20D2EE91500CB2E4C /* Headers */ = { + isa = PBXGroup; + children = ( + 483A77FF0D2EE9F300CB2E4C /* anorm_dots.h */, + 483A78000D2EE9F300CB2E4C /* anorms.h */, + 483A78010D2EE9F300CB2E4C /* bspfile.h */, + 483A78020D2EE9F300CB2E4C /* d_ifacea.h */, + 483A78030D2EE9F300CB2E4C /* draw.h */, + 483A78040D2EE9F300CB2E4C /* gl_model.h */, + 483A78050D2EE9F300CB2E4C /* gl_texmgr.h */, + 483A78060D2EE9F300CB2E4C /* gl_warp_sin.h */, + 483A78070D2EE9F300CB2E4C /* glquake.h */, + 483A78080D2EE9F300CB2E4C /* image.h */, + 483A78090D2EE9F300CB2E4C /* modelgen.h */, + 483A780A0D2EE9F300CB2E4C /* render.h */, + 483A780B0D2EE9F300CB2E4C /* screen.h */, + 483A780C0D2EE9F300CB2E4C /* spritegn.h */, + 483A780D0D2EE9F300CB2E4C /* vid.h */, + ); + name = Headers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* Fitzquake */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Fitzquake" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Fitzquake; + productInstallPath = "$(HOME)/Applications"; + productName = Fitzquake; + productReference = 8D1107320486CEB800E47090 /* Fitzquake.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Fitzquake" */; + compatibilityVersion = "Xcode 2.4"; + hasScannedForEncodings = 1; + mainGroup = 29B97314FDCFA39411CA2CEA /* Fitzquake */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* Fitzquake */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 483A780F0D2EEA0F00CB2E4C /* progdefs.q1 in Resources */, + 48B9E7880D340B1E0001CACF /* Launcher.nib in Resources */, + 484AA4B40D3FF6C0005D917A /* Fitzquake.icns in Resources */, + 4830B79F0D464CAE00EF4498 /* Changelog.txt in Resources */, + 4830B7A00D464CAE00EF4498 /* Todo.txt in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */, + 483A78230D2EEA5400CB2E4C /* chase.c in Sources */, + 483A78240D2EEA5400CB2E4C /* cmd.c in Sources */, + 483A78250D2EEA5400CB2E4C /* common.c in Sources */, + 483A78260D2EEA5400CB2E4C /* console.c in Sources */, + 483A78270D2EEA5400CB2E4C /* crc.c in Sources */, + 483A78280D2EEA5400CB2E4C /* cvar.c in Sources */, + 483A78290D2EEA5400CB2E4C /* host_cmd.c in Sources */, + 483A782A0D2EEA5400CB2E4C /* host.c in Sources */, + 483A782B0D2EEA5400CB2E4C /* mathlib.c in Sources */, + 483A782C0D2EEA5400CB2E4C /* menu.c in Sources */, + 483A782D0D2EEA5400CB2E4C /* pr_cmds.c in Sources */, + 483A782E0D2EEA5400CB2E4C /* pr_edict.c in Sources */, + 483A782F0D2EEA5400CB2E4C /* pr_exec.c in Sources */, + 483A78300D2EEA5400CB2E4C /* sbar.c in Sources */, + 483A78310D2EEA5400CB2E4C /* sys_sdl.c in Sources */, + 483A78320D2EEA5400CB2E4C /* view.c in Sources */, + 483A78330D2EEA5400CB2E4C /* wad.c in Sources */, + 483A78340D2EEA5400CB2E4C /* world.c in Sources */, + 483A78350D2EEA5400CB2E4C /* zone.c in Sources */, + 483A78380D2EEA6D00CB2E4C /* in_sdl.c in Sources */, + 483A78390D2EEA6D00CB2E4C /* keys.c in Sources */, + 483A78450D2EEAAB00CB2E4C /* cl_demo.c in Sources */, + 483A78460D2EEAAB00CB2E4C /* cl_input.c in Sources */, + 483A78470D2EEAAB00CB2E4C /* cl_main.c in Sources */, + 483A78480D2EEAAB00CB2E4C /* cl_parse.c in Sources */, + 483A78490D2EEAAB00CB2E4C /* cl_tent.c in Sources */, + 483A784A0D2EEAAB00CB2E4C /* net_main.c in Sources */, + 483A784B0D2EEAAB00CB2E4C /* net_sdl.c in Sources */, + 483A784C0D2EEAAB00CB2E4C /* sv_main.c in Sources */, + 483A784D0D2EEAAB00CB2E4C /* sv_move.c in Sources */, + 483A784E0D2EEAAB00CB2E4C /* sv_phys.c in Sources */, + 483A784F0D2EEAAB00CB2E4C /* sv_user.c in Sources */, + 483A78550D2EEAC300CB2E4C /* cd_sdl.c in Sources */, + 483A78590D2EEAC300CB2E4C /* snd_sdl.c in Sources */, + 483A786E0D2EEAF000CB2E4C /* gl_draw.c in Sources */, + 483A786F0D2EEAF000CB2E4C /* gl_fog.c in Sources */, + 483A78700D2EEAF000CB2E4C /* gl_mesh.c in Sources */, + 483A78710D2EEAF000CB2E4C /* gl_model.c in Sources */, + 483A78720D2EEAF000CB2E4C /* gl_refrag.c in Sources */, + 483A78730D2EEAF000CB2E4C /* gl_rlight.c in Sources */, + 483A78740D2EEAF000CB2E4C /* gl_rmain.c in Sources */, + 483A78750D2EEAF000CB2E4C /* gl_rmisc.c in Sources */, + 483A78760D2EEAF000CB2E4C /* gl_screen.c in Sources */, + 483A78770D2EEAF000CB2E4C /* gl_sky.c in Sources */, + 483A78780D2EEAF000CB2E4C /* gl_test.c in Sources */, + 483A78790D2EEAF000CB2E4C /* gl_texmgr.c in Sources */, + 483A787A0D2EEAF000CB2E4C /* gl_vidsdl.c in Sources */, + 483A787B0D2EEAF000CB2E4C /* gl_warp.c in Sources */, + 483A787C0D2EEAF000CB2E4C /* image.c in Sources */, + 483A787D0D2EEAF000CB2E4C /* r_alias.c in Sources */, + 483A787E0D2EEAF000CB2E4C /* r_brush.c in Sources */, + 483A787F0D2EEAF000CB2E4C /* r_part.c in Sources */, + 483A78800D2EEAF000CB2E4C /* r_sprite.c in Sources */, + 483A78810D2EEAF000CB2E4C /* r_world.c in Sources */, + 48728D2D0D3004A80004D61B /* net_dgrm.c in Sources */, + 48728D2E0D3004A80004D61B /* net_loop.c in Sources */, + 486577CB0D31A22A00E7920A /* snd_dma.c in Sources */, + 486577CC0D31A22A00E7920A /* snd_mem.c in Sources */, + 486577CD0D31A22A00E7920A /* snd_mix.c in Sources */, + 48243B140D33F01A00C29F8F /* main.c in Sources */, + 48B9E7A70D340BEA0001CACF /* AppController.m in Sources */, + 48B9E7C00D340EA80001CACF /* SDLApplication.m in Sources */, + 489D8D2F0D3A630D00AA4471 /* ScreenInfo.m in Sources */, + 48FE585B0D3A82C8006BB491 /* QuakeArguments.m in Sources */, + 48C85E3B0D3AD10E00797678 /* QuakeArgument.m in Sources */, + 48895DB90D4914A000849ABF /* pl_osx.m in Sources */, + 48305B550D8AF90600A29C24 /* net_udp.c in Sources */, + 487C0A5D0DA94A0700A49FF5 /* net_sdlnet.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 48B9E7860D340B1E0001CACF /* Launcher.nib */ = { + isa = PBXVariantGroup; + children = ( + 48B9E7870D340B1E0001CACF /* English */, + ); + name = Launcher.nib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = Fitzquake; + WRAPPER_EXTENSION = app; + ZERO_LINK = YES; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = Fitzquake; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(HOME)/Library/Frameworks", + /Library/Frameworks, + "$(FRAMEWORK_SEARCH_PATHS)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(HOME)/Library/Frameworks/SDL.framework/Headers", + /Library/Frameworks/SDL.framework/Headers, + "$(HEADER_SEARCH_PATHS)", + ); + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ( + "$(HOME)/Library/Frameworks", + /Library/Frameworks, + "$(FRAMEWORK_SEARCH_PATHS)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(HOME)/Library/Frameworks/SDL.framework/Headers", + /Library/Frameworks/SDL.framework/Headers, + "$(HEADER_SEARCH_PATHS)", + ); + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Fitzquake" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Fitzquake" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Mac OS X/Fitzquake_Prefix.pch b/Mac OS X/Fitzquake_Prefix.pch new file mode 100644 index 00000000..d4f4148e --- /dev/null +++ b/Mac OS X/Fitzquake_Prefix.pch @@ -0,0 +1,25 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL.h" + +#ifdef __OBJC__ + #import +#endif diff --git a/Mac OS X/Info.plist b/Mac OS X/Info.plist new file mode 100644 index 00000000..7f76fd1b --- /dev/null +++ b/Mac OS X/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + Fitzquake + CFBundleIdentifier + net.celephais.Fitzquake + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + Launcher + NSPrincipalClass + NSApplication + + diff --git a/Mac OS X/Launcher-Info.plist b/Mac OS X/Launcher-Info.plist new file mode 100644 index 00000000..7b944358 --- /dev/null +++ b/Mac OS X/Launcher-Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.yourcompany.Launcher + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/Mac OS X/QuakeArgument.h b/Mac OS X/QuakeArgument.h new file mode 100644 index 00000000..604daa26 --- /dev/null +++ b/Mac OS X/QuakeArgument.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import + + +@interface QuakeArgument : NSObject { + NSString *name; + NSString *value; +} + +- (id)initWithArgument:(NSString *)n; +- (id)initWithArgument:(NSString *)n andValue:(NSString *)v; + +- (NSString *)name; +- (NSString *)value; + +- (BOOL)hasValue; +@end diff --git a/Mac OS X/QuakeArgument.m b/Mac OS X/QuakeArgument.m new file mode 100644 index 00000000..cdf3d162 --- /dev/null +++ b/Mac OS X/QuakeArgument.m @@ -0,0 +1,80 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import "QuakeArgument.h" + + +@implementation QuakeArgument + +- (id)initWithArgument:(NSString *)n { + + return [self initWithArgument:n andValue:nil]; +} + +- (id)initWithArgument:(NSString *)n andValue:(NSString *)v { + + self = [super init]; + if (self == nil) + return nil; + + name = [n retain]; + if (v != nil) + value = [v retain]; + + return self; +} + +- (NSString *)name { + + return name; +} + +- (NSString *)value { + + return value; +} + +- (BOOL)hasValue { + + return value != nil; +} + +- (NSString *)description { + + NSMutableString *buffer = [[NSMutableString alloc] init]; + + [buffer appendString:name]; + if ([self hasValue]) { + [buffer appendString:@" "]; + [buffer appendString:value]; + } + + return buffer; +} + +- (void) dealloc +{ + [name release]; + [value release]; + + [super dealloc]; +} + +@end diff --git a/Mac OS X/QuakeArguments.h b/Mac OS X/QuakeArguments.h new file mode 100644 index 00000000..999243ed --- /dev/null +++ b/Mac OS X/QuakeArguments.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import +#import "QuakeArgument.h" + + +@interface QuakeArguments : NSObject { + NSMutableArray *quakeArgs; +} + +- (id)initWithArguments:(char **)argv count:(int)argc; +- (void)parseArguments:(NSString *)args; + +- (void)addArgument:(NSString *)arg; +- (void)addArgument:(NSString *)arg withValue:(NSString *)value; + +- (QuakeArgument *)argument:(NSString *)name; + +- (int)count; +- (void)setArguments:(char **)args; +@end diff --git a/Mac OS X/QuakeArguments.m b/Mac OS X/QuakeArguments.m new file mode 100644 index 00000000..ee21dd68 --- /dev/null +++ b/Mac OS X/QuakeArguments.m @@ -0,0 +1,231 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import "QuakeArguments.h" +#import "QuakeArgument.h" + +@implementation QuakeArguments + +- (id)init { + + self = [super init]; + if (!self) + return nil; + + quakeArgs = [[NSMutableArray alloc] init]; + return self; +} + +- (id)initWithArguments:(char **)argv count:(int)argc { + + int i; + NSString *next; + NSString *current; + QuakeArgument *argument; + + self = [self init]; + if (!self) + return nil; + + if (argc > 0) { + for (i = 0; argv[i]; i++) { + current = [NSString stringWithCString:argv[i] encoding:NSASCIIStringEncoding]; + if (i < argc-1) { + next = [NSString stringWithCString:argv[i+1] encoding:NSASCIIStringEncoding]; + } else { + next = nil; + } + + if (next != nil && [next characterAtIndex:0] != '-' && [next characterAtIndex:0] != '+') { + argument = [[QuakeArgument alloc] initWithArgument:current andValue:next]; + i++; + } else { + argument = [[QuakeArgument alloc] initWithArgument:current]; + } + [quakeArgs addObject:argument]; + [argument release]; + } + } + + return self; +} + +- (void)parseArguments:(NSString *)args { + + int i; + unichar c; + unichar p = ' '; + NSMutableString *word = nil; + NSMutableArray *words = [[NSMutableArray alloc] init]; + BOOL quoted = FALSE; + + [quakeArgs removeAllObjects]; + + for (i = 0; i < [args length]; i++) { + + c = [args characterAtIndex:i]; + switch (c) { + case ' ': + if (!quoted) { + // ignore whitespace + if (p == ' ') + break; + + if (word != nil) { + [words addObject:word]; + [word release]; + + word = nil; + } + } + break; + case '"': + quoted = !quoted; + break; + default: + if (p == ' ') { + word = [[NSMutableString alloc] init]; + } + [word appendFormat:@"%C", c]; + break; + } + p = c; + } + + if (word != nil) { + [words addObject:word]; + [word release]; + } + + NSString *current; + NSString *next; + QuakeArgument *argument = nil; + + for (i = 0; i < [words count];) { + current = [words objectAtIndex:i++]; + if (i < [words count]) { + next = [words objectAtIndex:i++]; + unichar c = [next characterAtIndex:0]; + if (c != '-' && c != '+') + argument = [[QuakeArgument alloc] initWithArgument:current andValue:next]; + else + i--; + + } + + if (argument == nil) { + argument = [[QuakeArgument alloc] initWithArgument:current]; + } + + [quakeArgs addObject:argument]; + [argument release]; + argument = nil; + } +} + +- (void)addArgument:(NSString *)name { + + QuakeArgument *argument = [[QuakeArgument alloc] initWithArgument:name]; + [quakeArgs addObject:argument]; + + [argument release]; +} + +- (void)addArgument:(NSString *)name withValue:(NSString *)value { + + QuakeArgument *argument = [[QuakeArgument alloc] initWithArgument:name andValue:value]; + [quakeArgs addObject:argument]; + + [argument release]; +} + +- (QuakeArgument *)argument:(NSString *)name { + + NSEnumerator *enumerator = [quakeArgs objectEnumerator]; + QuakeArgument *argument; + + while ((argument = [enumerator nextObject])) { + if ([name isEqualToString:[argument name]]) + return argument; + } + + return nil; +} + +- (int)count { + + int c = 0; + + NSEnumerator *enumerator = [quakeArgs objectEnumerator]; + QuakeArgument *argument; + + while ((argument = [enumerator nextObject])) { + c++; + if ([argument hasValue]) + c++; + } + + return c; +} + +- (void)setArguments:(char **)args { + + int i = 0; + + NSEnumerator *enumerator = [quakeArgs objectEnumerator]; + QuakeArgument *argument; + + while ((argument = [enumerator nextObject])) { + args[i++] = (char *)[[argument name] cStringUsingEncoding:NSASCIIStringEncoding]; + + if ([argument hasValue]) + args[i++] = (char *)[[argument value] cStringUsingEncoding:NSASCIIStringEncoding]; + } +} + +- (NSString *)description { + + int i; + NSMutableString *buffer = [[NSMutableString alloc] init]; + + for (i = 0; i < [quakeArgs count]; i++) { + if (i > 0) + [buffer appendString:@" "]; + + QuakeArgument *argument = [quakeArgs objectAtIndex:i]; + [buffer appendString:[argument name]]; + + if ([argument hasValue]) { + [buffer appendString:@" "]; + [buffer appendString:[argument value]]; + } + } + + return buffer; +} + +- (void) dealloc +{ + [quakeArgs release]; + [super dealloc]; +} + + +@end diff --git a/Mac OS X/SDLApplication.h b/Mac OS X/SDLApplication.h new file mode 100644 index 00000000..abc4b4ed --- /dev/null +++ b/Mac OS X/SDLApplication.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import + + +@interface SDLApplication : NSApplication { + +} + +@end diff --git a/Mac OS X/SDLApplication.m b/Mac OS X/SDLApplication.m new file mode 100644 index 00000000..0f9f34db --- /dev/null +++ b/Mac OS X/SDLApplication.m @@ -0,0 +1,34 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import "SDLApplication.h" +#import "SDL.h" + +@implementation SDLApplication +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); + + [super terminate:sender]; +} +@end diff --git a/Mac OS X/SDLMain.h b/Mac OS X/SDLMain.h new file mode 100644 index 00000000..7493210e --- /dev/null +++ b/Mac OS X/SDLMain.h @@ -0,0 +1,16 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import + +extern int gArgc; +extern char **gArgv; +extern BOOL gFinderLaunch; +extern BOOL gCalledAppMainline; + +@interface SDLMain : NSObject +@end diff --git a/Mac OS X/SDLMain.m b/Mac OS X/SDLMain.m new file mode 100644 index 00000000..741f3c50 --- /dev/null +++ b/Mac OS X/SDLMain.m @@ -0,0 +1,84 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import "SDL.h" +#import "SDLMain.h" +#import /* for MAXPATHLEN */ +#import +#import "SDLApplication.h" + +int gArgc; +char **gArgv; +BOOL gFinderLaunch; +BOOL gCalledAppMainline = FALSE; + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + if (shouldChdir) + { + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } + +} + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +#ifdef main +# undef main +#endif + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); + return 0; +} diff --git a/Mac OS X/ScreenInfo.h b/Mac OS X/ScreenInfo.h new file mode 100644 index 00000000..fdb2abbd --- /dev/null +++ b/Mac OS X/ScreenInfo.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import + + +@interface ScreenInfo : NSObject { + int width; + int height; + int bpp; + NSString *description; +} + +- (id)initWithWidth:(int)w height:(int)h bpp:(int)b; + +- (int)width; +- (int)height; +- (int)bpp; +- (NSString *)description; + +@end diff --git a/Mac OS X/ScreenInfo.m b/Mac OS X/ScreenInfo.m new file mode 100644 index 00000000..783e8a8f --- /dev/null +++ b/Mac OS X/ScreenInfo.m @@ -0,0 +1,61 @@ +/* +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#import "ScreenInfo.h" + + +@implementation ScreenInfo + +- (id)initWithWidth:(int)w height:(int)h bpp:(int)b { + + self = [super init]; + if (!self) + return nil; + + width = w; + height = h; + bpp = b; + + description = [NSString stringWithFormat:@"%d x %d %d Bit", width, height, bpp]; + + return self; +} + +- (int)width { + + return width; +} + +- (int)height { + + return height; +} + +- (int)bpp { + + return bpp; +} + +- (NSString *)description { + + return description; +} + +@end diff --git a/Misc/Changelog.txt b/Misc/Changelog.txt new file mode 100644 index 00000000..c6a6c563 --- /dev/null +++ b/Misc/Changelog.txt @@ -0,0 +1,41 @@ +01/22/2008 +- release mouse pointer when console is active. +- enable key repeats (doesn't work on OS X, test in Win32).c + +01/23/2008 +- implement Sys_SendKeyEvents +- disable mouse input when console is inactive using SDL_SetEventFilter +- move mouse input processing to main event loop +- add vid.mode to determine window mode +- fixed Sys_printf() +- enable key repeats when console is active only +- return 0 if any of the cl_bob vars is 0 in V_CalcBob + +01/24/2008 +- changed in_deactivate so that it does not always release the mouse cursor +- adapted all calls to in_activate and in_deactive, because they need to be called regardless of the current mode +- added platform dependent messagebox code for fatal errors on OS X and Windows + +02/06/2008 +- fixed numlock acting as caps lock issue +- fixed: input is not activated on map command (hopefull got them all this time) +- center window in windowed modes + +2008/03/14 +- discard mouse movement while input is deactivated +- implement maps and mods commands using POSIX functions and added a POSIX wrapper for Win32 +- activate mouse input when binding a key, otherwise mouse keys cannot be bound through the menu +- fixed shift key behaviour + +2008/06/3 +- fixed numerous bugs in sdl_net.c + +2008/06/4 +- fixed fog command (use fmax instead of max in Fog_FogCommand_f) +- fixed bug that lead to the screen being set to minimum size when the sizedown command is issued multiple times + +2008/07/4 +- LSHIFT + ESC and circomflex always opens the console + +2008/07/5 +- print everything to stdout diff --git a/Misc/Icon.psd b/Misc/Icon.psd new file mode 100644 index 00000000..c720c2e3 Binary files /dev/null and b/Misc/Icon.psd differ diff --git a/Misc/Todo.txt b/Misc/Todo.txt new file mode 100644 index 00000000..988de3db --- /dev/null +++ b/Misc/Todo.txt @@ -0,0 +1,14 @@ +- Implement TCP networking. +- Clean up in vidsdl: remove windowed and determine window state from modestate ? +- Fix Sys_Error behaviour (what is quake double error?) +- Open Console with Circomflex or Shift-Escape + +- Change SDL cursor to resemble the OS cursor (John) +- Sensitivity is off (SDL related? Or can I try and replicate the original behaviour?) (John) +- Paste doesn't work (needs to be implemented in platform.h) (John) +- Keybindings are not loaded correctly upon first start? (spirit) +- Log everything to the shell as well as to the console (spirit) +- make esc work after a map tried changeleveling to a non-existant map (like e1m2quoth) +- Launch Fitzquake, switch to other game via game (I tried Quoth and Marcher), load any map (I tried quoth's startmap and marcher): segfault + +- My "toggle r_showtris" bind causes the screen to be filled with the brown hud/viewsize texture. The only way to make the screen visible again was to delete the config. (works fine for me) diff --git a/Misc/fitzquake080.txt b/Misc/fitzquake080.txt new file mode 100644 index 00000000..0e94cbc4 --- /dev/null +++ b/Misc/fitzquake080.txt @@ -0,0 +1,462 @@ +================================================================================ + +Beta release of an SDL port of Fitzquake version 0.80, July 5, 2008 + +Author : Kristian Duske +Email Address : deceive.inveigle.obfuscate@gmail.com +Author's Homepage : http://www.kristianduske.com/fitzquake +Minimum SDL version : 1.2.10 + +This is a port of the Fitzquake engine to SDL. The main goal of this port is to +allow fitzquake to run on all major platforms. Currently there are builds for +Windows, Linux and Mac OS X. + +To run this engine, you need to install the SDL and SDL_net library binaries. For +Linux, you should probably use the packages for your distribution which should be +available through your package manager of choice. The minimum SDL version you +need to run this is 1.2.10. On Windows, you can download the SDL and SDL_net dlls +from http://www.libsdl.org/. On Mac, the SDL framework is included in the +application bundle. + +The Mac OS X version includes a simple launcher program. + +Known issues: +- Mouse sensitivity is different than in the original Fitzquake (or vanilla Quake, + for that matter). +- Pasting from the clipboard does not work. +- It is not possible to switch the screen refresh rates from within the engine. +- On Linux, there are problems with the default sound sampling rate of 11025Hz. + This can be fixed by supplying -sndspeed 48000 on the commandline. + +Changes since the March 7 beta: +- discard mouse movement while input is deactivated +- implement maps and mods commands using POSIX functions and added a POSIX wrapper + for Win32 +- activate mouse input when binding a key, otherwise mouse keys cannot be bound + through the menu +- fixed shift key behaviour +- implemented TCP networking +- fixed fog command (use fmax instead of max in Fog_FogCommand_f) +- fixed bug that lead to the screen being set to minimum size when the sizedown + command is issued multiple times +- LSHIFT + ESC and circomflex always opens the console +- print everything to stdout +- and more... + +Below, you can find the original fitzquake readme. + +================================================================================ + +Fitzquake version 0.80, May 26, 2005 + +Filename : fitzquake080.exe +Author : John Fitzgibbons +Email Address : johnfitz@u.washington.edu +Author's Homepage : http://www.celephais.net/ +Fitzquake Homepage : http://www.celephais.net/fitzquake + +Fitzquake is a modified glquake based on the source code released by id +Software. My primary focus is fixing a lot of the rendering bugs which made +glquake inferior to the software renderer. My secondary focus is adding +conveniences for mappers and general users. I am also slowly adding support for +new modding or mapping features such as skyboxes, fog, and colored light. + +While I have made extensive changes to the code, I pretty much use the same +OpenGL features that the original glquake uses. Therefore, if you can run +glquake, you can probably run Fitzquake. + +I am not finished working on this project, so bug reports and feature requests +are welcome. + +Acknowlegements +-------------------------------------------------------------------------------- + +id Software (quake and quake2 code) +LordHavoc (code and assistance) +Bengt Jardrup (feedback, assistance, testing) + +additional thanks to: Aardappel, SmallPileOfGibs, FrikaC, Vondur, Topaz, Tomaz, +Tonik, Radix, EvilTypeGuy, NightBringer, MH, Maddes, Fett, Craig Wills, Heffo, +Riot, Gleeb, people in #flipcode, and others for their tutorials, code, testing, +and assistance. + +Copyright / Permissions +-------------------------------------------------------------------------------- + +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place - Suite 330, Boston, MA 02111-1307, USA. + +History +================================================================================ + +changes in 0.80 +--------------- + + - map loading is about four times faster. This is due to some optimizations in the texture loading code. + - video mode can now be changed in-game. You can change resolution, color depth, refresh rate, and switch between windowed and fullscreen modes. This can be accomplished easily using the video options menu, and is also available at the console using cvars. Note: if you launch fitzquake with -width, -height, -window, or -bpp in the command line, Fitzquake will use the command line settings and ignore whatever it reads from the config files at startup. However, you will still be able to change the video mode from the menu or the console as you like. Also note: to change video modes by execing a config file, the config file must include "vid_restart" after the other vid_ cvars have been set. (see cvars "vid_width," "vid_height," "vid_fullscreen," "vid_bpp," "vid_refreshrate," and commands "vid_restart," "vid_test") + - added control of entity count limits (MAX_EDICTS.) The default maximum has been increased from 600 to 1024. It can be raised even higher (up to 8192 -- this is a limit set by the network protocol) using a cvar. (see cvar "max_edicts") + - added control of vertical sync. (see cvar "vid_vsync") + - added control of anistropic filtering. Anisotropic filtering is a method to improve texture clarity on surfaces when viewed at steep angles. (see cvar "gl_texture_anisotropy") + - console buffer size can now be set. The command line option "-consize" allows you to specify the buffer size in kilobytes. For reference, fitzquake's default buffer size is 64k, and glquake's is 16k. 16k is also the smallest size fitzquake will allow you to set. Note: this buffer lives in the heap, so if you want to have a HUGE buffer, you might need to increase -heapsize also. + - increased max surface extents from 256 (the software quake maximum) to 2000. For reference, the glquake maximum is 512. This should eliminate the "bad surface extents" crash when running some maps that could be played in glquake, but not fitzquake or winquake. + - increased max vertices in an alias model from 1024 (the glquake maximum) to 2000 (the software quake maximum.) + - increased MAX_CHANNELS from 128 to 512 and MAX_DYNAMIC_CHANNELS from 8 to 128 + - screenshot filenames are now in the format "fitz0000.tga", increasing the maximum number of screenshots per folder from one hundred to ten thousand. + - vid_describemodes output cleaned up; now displays a list of valid refresh rates for each mode + - added a more intuitive cvar control of slow motion/fast-forward for demos and live gameplay. (see cvar "host_timescale") + - "reset to defaults" option in the menu now executes the "resetall" command before loading default.cfg + - game command now writes config.cfg to current gamedir before switching + - +mlook is now saved to config.cfg + - changed smallest allowed window size from 320x240 to 320x200 + - console cursor images are now hard-coded, and the insert mode cursor is now a vertical bar instead of an underscore. This was prompted by several popular mods (OUM, Xmen TC) using nonstandard cursors, which are incompatible the fitzquake console enhancements. + - gl_farclip now defaults to 16384. This should be high enough to handle even the largest open areas without unwanted clipping. The only reason you'd want to lower this number is if you see z-fighting. + - added cvar r_drawworld (see below) + - added cvar r_showtris (see below) + - added cvar r_showbboxes (see below) + - added a command to cycle a cvar through a list of values. (see command "cycle") + - mapname command now works on dedicated server. + - added a hack to fix those white edges on the bottom of the large box of shells. I feel dirty, but they look better, now. + - changed stuffcmds behavior to allow hyphenated map names, config file names, etc. in the command line. (example: "fitzquake.exe +exec my-config.cfg +map my-map") However, you still can't load a map or config file when the first character in the filename is a hyphen. + - skybox loader now reverts to scrolling sky if all 6 skybox faces failed to load. + - tweaked circular particles to match the apparent size of the square particles. + - fixed crash when loading mods with large player skins (like the chainsaw mod, and PerQuake.) Colormapping can now handle any size player texture (limited to the heapsize, of course.) + - fixed bug where a replacement model in a mod is messed up becuase a matching .ms2 file in id1/glquake is present. The fix is simply to disable all mesh caching, which slows down model loading a little. + - fixed freeze when gl_overbright is 1 and either texture_env_combine or multitexture is disabled or not supported. + - fixed "numgltextures == MAX_GLTEXTURES" crash when viewing multiplayer->setup menu. + - fixed "numgltextures == MAX_GLTEXTURES" crash when playing large maps (nesp09,) due to frequent model recaches. + - fixed bug where entities and water were not being drawn any frame in which a model had to be recached. + - fixed skybox texture showing up in the place of other textures/skins/lightmaps, when the previous loaded map had a skybox. + - fixed missing polygons on edges of screen when underwater and r_waterwarp is 1. + - fixed missing polygons on edges of screen when r_stereo is enabled. + - fixed long mapnames that scroll are truncated to be shorter than what appears in the console. Well, sort of. What I did was increase the maximum length from 39 to 127. A mapname longer than 127 will still be truncated, but these are pretty rare. + - fixed rogue's teamplay skin showing up as an all-white texture. + - fixed checkerboard texture shows up sometimes when an animated texture has fullbright pixels on some frames, but not others (reactor core in junk.bsp) + - fixed color 255 is not fullbright + - fixed fuscia dots appearing in corners of resampled textures + - fixed mapname command crashes when client is disconnected. + - fixed cl_nolerp 1 screws up speed of demo playback + - fixed annoying client-side step-up smoothing when in noclip mode (except on nonlocal servers.) + - fixed scr_clock 2 displays hour twelve as "0" instead of "12" + - fixed skip textured surfaces still drawn even after running tyrann's skip utility + - fixed crash when loading a map with a sky texture where the "sky" in the texturename is not lowercase + - fixed hang in e2m2 on easy skill, where you can shoot one of the buttons at the beginning and then trick-jump through the open gate. Now it prints a warning message ("SV_TouchLinks: null link") and lets you keep playing. + - fixed bug when viewsize < 100, and r_oldwater is 0, where you can see the water textures overlaying part of the brown frame around the viewport. + - fixed bug where imagelist and r_speeds2 would report the same megabyte counts in both 16bpp and 32bpp mode, even though texture bpp should match (and does match) framebuffer bpp. The numbers are now different and accurate for each bit depth. + - removed cvars "vid_config_x," "vid_config_y," "vid_wait," "vid_nopageflip," "_vid_wait_override," "_vid_default_mode," "_vid_default_mode_win," and "vid_stretch_by_2," none of which glquake ever used. + - removed cvar "vid_mode" and commands "vid_describemode" and "vid_nummodes," because of the new video mode handling. + +cvars: + + - gl_texture_anisotropy. Controls the amount of anisotropy in texture filtering. If 1 or less than 1, texture filtering is normal (isotropic.) If greater than 1, increasing degrees of anisotropic filtering are used, up to the hardware maximum. Set value to 2 for 2x anisotropic, 4 for 4x, etc. Default 1. + + - host_timescale. Scales the passage of time on client and server. Set to 0 or 1 for normal speed, less than 1 for slow motion, and greater than 1 for fast-forward. If greater than 0, overrides host_framerate. Default 0. + + - max_edicts. Sets the maximum number of entites on both the client and server. Default 1024. Acceptable values range from 256 to 8192. Set to 600 to mimic standard quake. Changes won't take effect until the next time a map is loaded. Note: if a client connects to a server, and the client's maximum is lower than the server's, the client will probably crash if it ever sees an entnum higher than its local max_edicts. Warning: you may need to increase -heapsize if you want a high max_edicts value. + + - r_drawworld. If 1, draw world as usual. If 0, don't draw the world. Default 1. (compare r_drawentities) + + - r_showbboxes. If 1, draw a wireframe bounding box around each entity. Note that these are the server-side per-edict physics bounding boxes, not the client-side per-model rendering bboxes. If 0, disable this feature. Default 0. + + - r_showtris. If 1, draw wireframe outlines for every triangle in the scene. Like in Quake 3, the lines will be visible even through solid geometry. If 2, draw the outlines only on visible surfaces (like r_showtris 2 in Medal of Honor.) If 0, disable wireframe overlay. Default 0. + + - vid_bpp. Sets the color depth of the screen in fullscreen mode. Windowed mode ignores this setting. Can be 16 or 32. Default 16. (Changes won't take effect until the next call to vid_restart.) + + - vid_fullscreen. If 1, fitzquake will run fullscreen. If 0, fitzquake will run in a window. Default 1. (Changes won't take effect until the next call to vid_restart.) + + - vid_height. Sets the vertical screen/window resolution. Default 480. In windowed mode, cannot be less than 200. (Changes won't take effect until the next call to vid_restart.) + + - vid_refreshrate. Sets the refresh rate of the screen in fullscreen mode. Windowed mode ignores this setting. Possible values include 60, 70, 72, 75, 85, etc. Default 60. (Changes won't take effect until the next call to vid_restart.) + + - vid_width. Sets the horizontal screen/window resolution. Default 640. In windowed mode, cannot be less than 320. (Changes won't take effect until the next call to vid_restart.) + + - vid_vsync. Set to 1 to enable vertical sync, which eliminates tearing, but caps your framerate at the monitor refreshrate. Set to 0 to disable vertical sync, which allows tearing but doesn't cap your framerate. Default 0. Note: If fitzquake detects that your driver settings have forced vsync to be disabled, it will post a message to the console saying so, and this cvar will have no effect. + +commands: + + - "cycle [ [ ...]]" to cycle a cvar through a list of values.. Note: this command will get stuck on a list that contains the same value more than once, such as "cycle blah 1 2 1 3". If you're doing anything that complex you can just use aliases. + + - vid_restart. Tries to set a video mode that matches the values of vid_width, vid_height, vid_fullscreen, and, if vid_fullscreen is 1, vid_bpp and vid_refreshrate. + + - vid_test. Like vid_restart, except that after switching to the new mode pops up a confirmation dialogue. This is useful if you are not sure what modes your monitor can handle, so you don't get stuck with a blank screen. The dialogue has a time limit so that if you don't press a key within 5 seconds, it will revert to the previous mode. + +changes in 0.75 +--------------- + + - totally rewritten bsp drawing code. The new code combines the advantages of the gl_texsort 1 and gl_texsort 0 codepaths from glquake into one codepath that uses texture sorting and multitexture. In my tests, i've found that it's about the same speed as glquake in low poly scenes (like the original quake levels,) but as you get into the thousands of wpolys, it's faster and faster. + - 2x overbright lighting. Lighting now looks like software quake. Just like overbright lighting on models, overbright on world polys requires GL_EXT_texture_env_combine (TNT and later, voodoo4 and later.) Without it, FitzQuake will be use two passes to render overbright world polys. So if you don't have that extension, you might disable it for performance reasons. (see cvar "gl_overbright") + - colored lighting support using .lit files. + - totally new water surface animation. The new method requires no surface subdivision, isn't plagued by tearing and sparklies caused by tjunctions, and looks almost identical to software quake's water, and doesn't slow down on very large sheets of water. (see cvars "r_waterquality" and "r_oldwater") + - old water aninmation fixed so that it doesn't look bad when gl_subdivide_size is 32 or lower. + - can load external textures (currently targa and pcx) if they match the texture name in the bsp and are located in the id1/textures, or /textures directory. At the moment no other images (skins, menu, etc.) can be replaced. + - gamma correction now goes back to normal when Fitzquake loses focus. + - tab completion now adds a space after the completed command/cvar if the cursor is at the end of the editline. + - increased the max length of the video mode list from 30 to 80. This should alleviate the problems people with newer cards were having trying to use some 32-bit modes -- there were so many 16-bit modes that they filled up the list before all 32-bit modes could be detected. The video menu will still only list a certain number of modes due to space constraints, but you can see the complete list by using the console command "vid_describemodes" + - number of listed video modes in the "video options" menu increased from 27 to 36. + - added alpha control for the front sky layer. (see cvar "r_skyalpha") + - clock can now display time in 24-hour or "military" time. + - added an "mtex" counter to the r_speeds 2 readout. This measures the number of megabytes of texture memory used each frame to draw the scene. Note: this doesn't count textures used to draw the console, menu, or statusbar. + - added optional drawing of surfaces inside sky leaves, for compiler/map testing purposes. (see cvar "r_oldskyleaf") + - sky surfaces on bmodels are now visible, though drawn incorrectly. + - fixed multiple textures in bsp with same name or no name get overwritten/not loaded. (example: rd1m3) + - fixed some nasty texture loading bugs that were especially hounding 3dfx users (wrong texture, no texture, or unnecessarily low-res textures displayed on models and world.) These bugs would also occur in conjunction with nonzero values of gl_max_size or gl_picmip. + - fixed bug where changing gl_max_size or gl_picmip in-game would screw up alias model texture coordinates. + - fixed bug where if -gamma is specified at the command line, the "gamma" cvar would be ignored. + - fixed model more than 2048 units above floor us unlit by static lighting. + - fixed crash with con_logcenterprint when centerprint message was too long. + - fixed crash when changing to a nonexistant gamedir and then trying to write a file (screenshot, etc.) Fitzquake now creates the directory as needed. + - fixed "bad surface extents" error when sky or water surface is missing from bsp file. + - fixed alias model shadows write to z-buffer. + - fixed underwater intermission camera has warp, but no screenblend. + - fixed console buffer still scrolled back after using the "clear" command. + - fixed console command history (the list of previous commands) not being rewound after toggling the console. + - removed cvar gl_texsort. New bsp drawing code always sorts by texture. + - removed cvar gl_ztrick. The depth buffer is now cleared every frame. + - removed cvar gl_keeptjunctions. Extra verts created by qbsp to eliminate tjunctions are now always kept. + - removed "sliding on monsters' heads" fix, becuase I decided I don't like the idea of changing gameplay, even if the original behaviour is clearly a bug. Since this bug can be fixed in quakec also, I feel safer leaving it as it was. + +cvars: + + - gl_overbright. default 1. This variable controls overbright lighting on the world polygons. (For lighting on models, use gl_overbright_models.) If 1, overbright will be enabled and lighting will resemble software Quake. If 0, overbright will be disabled and lighting will resemble GLQuake. + + - r_oldskyleaf. default 0. If 0, surfaces inside sky leaves will be skipped by the renderer. If 1, they will be drawn whenever they are in your PVS, just like any other surface. + + - r_oldwater. default 1. If 1, use the old GLQuake method of subdividing the water surface to enable a warping animation. If 0, use the new render-to-texture method. Note: in general, r_oldwater 0 looks better and runs slower. So experiment to see if the performance hit is acceptable to you. + + - r_skyalpha. default 1. Sets the alpha of the front sky layer. Note that if sky alpha is less than 1.0, the sky will be drawn in two passes even if you have multitexture. + + - r_waterquality. default 8. Sets the quality of the water when r_oldwater is 0. Can be anywhere from 1 to 64. Lower values give better performance, higher values look better. A value of 4 will provide water that looks at least as good as glquake can get, and 32 is close enough to software quake for all but the most picky. To control the quality of water when r_oldwater is 1, use gl_subdivide_size instead. + + - scr_clock. default 0. If 1, game time is displayed. If 2, system time is displayed in 12-hour format. If 3, system time will be displayed in 24-hour or "military" time. + +Changes in 0.70 +--------------- + + - added anaglyph stereo rendering. Note that this will cut your framerate in half, as it is rendering the scene once for each eye. You might want to turn off r_drawviewmodel as it is hard to focus on becuase it is so close. (see cvars "r_stereo", "r_stereodepth") + - now uses ARB_multitexture if present, otherwise tries to use SGIS_multitexture. This should fix various blending bugs on some cards, such as weird cloud layers, all-black models, and inverted torches. (only ARB guarantees that GL_DECAL blending will work) + - overbright models now uses GL_EXT_texture_env_combine if supported (TNT and later, voodoo4 and later,) which saves one or two passes on model rendering when gl_overbright_models is 1. The command line option -nocombine will disable this. + - gl_overbright_models now defaults to 1 + - custom palettes are now correctly loaded when you use the "game" command. + - RecursiveLightPoint is now lerped for smoother lighting of slow-moving models. Check out the ogre in e3m3 for an example. + - dynamic lighting (rockets, etc) has been moderately sped up. (some lightmaps were being uploaded even though they weren't actually touched by a dynamic light.) + - overhauled 2d drawing to allow independent scaling of console, menu, and sbar (see cvars "scr_conwdith," "scr_menuscale," and "scr_sbarscale") command line switches "-conwidth" and "-conheight" removed. cvar "scr_stretch_menus" removed. + - user control of max framerate. (see cvar "host_maxfps") + - improved the accuracy of the FPS counter a bit, but it still seems suspect. + - particles can now be drawn as quads or triangles. (see cvar "r_quadparticles") + - opengl information (vendor, renderer, version, extensions) is no longer printed during initialization. (see command "gl_info") + - rewrote texture management. Now instead of quake's memory usage going up and up forever (becuase textures were uploaded to the opengl.dll and never freed,) all textures will get flushed when you switch games, bringing you back down to where you were when fitzquake first launched. + - gl_texturemode command will now accept a number (1 through 6) as well as the name (gl_linear_mipmap_nearest, etc.) + - gl_describetexturemodes will list all texturemodes. + - the inside of sky leaves are no longer rendered -- so when noclipping inside them, it will look the same as noclipping inside a solid wall. This does not affect gameplay. + - cleaned up intermission display in singleplayer -- no more overlapping numbers + - r_speeds readout modified a bit. (see cvar "r_speeds") + - r_sky_quality now defaults to 12 instead of 8, since skies are now drawn in 1 pass (with multitexture at least) + - gl_texsort now always defaults to 0. (it used to be forced to 1 when multitexture was unavailable) + - fixed bug where models would actually darken when dlights got bright enough + - fixed deathmatch, coop cvars not reset to zero when starting a new game from the single player menu + - fixed r_lightmap doesn't work when gl_texsort = 0. + - fixed inverted lightmaps / no textures / no dynamic light bug when multitexture is disabled and gl_texsort = 0 + - fixed scrolling map title in wrong place when width does not equal conwidth + - fixed a few color borking problems in 16-bit mode. The front sky layer, sprites, and pics with transparency will still look a bit off (as in glquake,) but at least the console image and statusbar background look better. Though it isn't perfect, it should once again look like what you expect from glquake in 16bit. + - fixed pixel gap on both sides of the console in 1024x768 + - fixed wpoly count being slightly lower when gl_texsort = 0 (the count was correct when gl_texsort = 1) + - fixed lmap count always zero when gl_texsort = 1 + - dlight fans are now drawn after water, so that it looks right at least when wateralpha is 1. + - fixed a possible bug with older 3dfx cards (voodoo 1/2/rush) where the gamma cvar might not work (untested) + - fixed old commands showing up in the console prompt after hitting 'enter' + - increased MAX_HANDLES so that you should never see the "out of handles" error message. + - removed cvar "chase_alpha." the transparent player model was buggy and didn't work well in a lot of conditions. + - removed cvar "gl_doubleeys" (yes, that is the correct misspelling) With overbright models, eyes can be seen as easily as in software mode. + - removed cvars "cl_crossx," "cl_crossy," "lcd_x," "lcd_yaw," and "gl_reporttjunctions" which didn't do anything (in glquake, at least). + - removed support for GL_EXT_shared_texture_palette (special 8-bit texture format) + - removed VCR code. command line switches "-record" and "-playback" no longer supported. + - removed support for command line switch "-gamma" -- just use the gamma cvar, or idgamma or something. + +cvars: + + - r_stereo. default 0. If nonzero, the scene will be rendered once in red, and again in cyan, with the two views shifted slightly. If you have 3D glasses you can appreciate this (assumes that the left eye is red and the right eye is cyan.) The value of r_stereo sets the eye separation. If your glasses have red on the right eye, use a negative value to flip the views. + + - r_stereodepth. default 128. Sets the distance at which the two views will converge when stereo rendering is active. + + - scr_conwdith. default 0. Sets the virtual console width, where smaller numbers means larger text. Values larger than window width, or smaller than 320, will be clamped to that range, and all values will be rounded to a multiple of 8. If 0, the window width will be used. Note that values that divide evenly into the window width will make the text look nicest. + + - scr_menuscale. default 1. Sets the scale factor for menus and other centered overlays. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. Menus will never be drawn smaller than 1:1, and never larger than the size of the window. Note that integer values will make the text look nicest. + + - scr_sbarscale. default 1. Sets the scale factor for the statusbar. If 1, images will be drawn at 1:1 scale. If 2, images will be double size. The statusbar will never be drawn smaller than 1:1, and never larger than the width of the window. Note that integer values will make the text look nicest. + + - host_maxfps. default 72. sets the maximum frames per second fitzquake will render (also the maximum number of server frames per second.) Clamped to the range 10 - 1000. Set to 72 to mimic standard quake. + + - r_quadparticles. default 1. If 1, particles are drawn as GL_QUADS instead of GL_TRIANGLES. Quads use 4 verts instead of 3, but the fillrate cost is 1/2 that of triangles. Depending on your card, either one may be faster. This cvar has no effect on the appearance of particles. + + - r_speeds. default 0. Values of 1 and 2 will give you increasing amounts of information. When you see two numbers separated by a slash, the first number is polys, and the second number is passes. + +commands: + + - gl_info. Displays opengl info which was previously displayed during initialization: vendor, renderer, version, and extensions + + - imagelist. Displays a list of loaded textures, and their dimentions. + + - gl_texturemode. Now accepts a number (1 through 6) as well as the name (gl_nearest, etc.) + + - gl_describetexturemodes. Lists all texturemodes. + +Changes in 0.65 +--------------- + + - gamma cvar now supported. (see cvar "gamma") + - fullbrights on models now supported. + - odd-sized world textures are now bilinearly resampled (instead of glquake's nearest pixel resample) + - removed all fixed-size buffers for loading textures; now the only limit is the size of your memory heap (textures will still be downsampled if they are bigger than the hardware can handle) + - styled lights (torch flicker, etc.) can now be disabled (see cvar "r_flatlightstyles") + - sky now uses multitexture if available. + - centerprints are now optionally logged to the console (see cvar "con_logcenterprint") + - number of savegame slots increased to 20 (from 12) + - if a map title is longer than 22 characters, it scrolls marquee-style in the statusbar. + - gl_flashblend defaults to 1 again. (consistency with glquake) + - gl_ztrick defaults to 1 again. (consistency with glquake) + - command line gamma now defaults to 1.0 for all cards. (consistency with glquake, plus hardware gamma is better) + - now checks hardware for maximum texture size. Users of later voodoo cards should be able to see large textures now. (see cvar "gl_max_size") + - now shows AM/PM when scr_clock is 2 + - fixed crash when starting dedicated server + - fixed crash when loading too many textures. (now it throws a sys_error and quits) + - fixed fitzquake-specific crash when player goes near water in a demo playback. + - scr_conalpha now actually works. + - keypad enter in the console works again. + - optional 2x overbrightening on models. (see cvar "gl_overbright_models") + - optional quake2-style noclip. (see cvar "sv_altnoclip") + - new icon + +cvars: + + - con_logcenterprint: If 1, centerprint messages will be logged to the console in sp/coop. If 2, they will also be logged in deathmatch. Default 1. + + - gamma: Brighten or darken the screen to compensate for differences between monitors. This is now supported by using your video card's gamma support. Just like in winquake, values less than 1 are brighter and values greater than one are darker. Default 1. Notes: I have added special code so that this will work on 3dfx cards too, but i have no way to check that it works. If fitzquake crashes, your hardware gamma may be stuck at the wrong value. You can use the "display settings" control panel fix this, or you could try lordhavoc's useful "setgamma" utility (available on this page.) Also note that if texture-brightening gamma has been requested at the command line (fitzquake.exe -gamma ), harware gamma will not be used and the gamma cvar will have no effect. + + - gl_max_size: Now defaults to 0. If 0, textures will be as large as the hardware allows. Positive values can be used to impose a limit smaller than the hardware's reported maximum. + + - gl_overbright_models: If 1, models will be rendered using 2x overbrightening and will appear at roughly the same brightness as they do in software quake, which is noticably brighter than the default fitzquake / glquake appearance. I disabled this cvar by default becuase this is still a poorly supported feature -- it currently takes 2 or 3 passes to render a model when this feature is enabled, compared to only 1 pass when it is disabled. Default 0. + + - r_flatlightstyles: If 1, styled lights (torch flicker, etc.) will be displayed as a steady light. If 2, the peak intensity will be used instead of the average intensity. Default 0. + + - sv_altnoclip: If 1, enable the alternative noclip movement which resembles quake2 and is not constrained to the horizontal plane. Set to 0 to retain quake's original noclip behavior. Default 1. + +Changes in 0.60 +--------------- + + - graphics: + - better sky projection, configurable for performance + - menus and other overlays are now centered on the screen, and can optionally stretch to fit resolution. + - all 2d graphics now obey gl_texturemode and all texturemode changes take effect immediately + - underwater warping now resembles quake3's perspective munging, and obeys r_waterwarp + - fixed frustum culling b0rked (giving HOM at certain FOV / vidsize / screensize combinations) + - fixed lack of support for VP_PARALLEL_ORIENTED, VP_PARALLEL_UPRIGHT, and FACING_UPRIGHT sprites + - fixed fullbrights not displayed on world/bmodels + - fixed texture cache mismatch error + - fixed pink edges on sprites, menu items, etc + - fixed particle z-buffer bug (apparent when a particle is in front of a water surface) + - fixed ugly resampling of non-power of two gfx, skins, sprites + - fixed large models (shamblers, shub) dissapearing near edge of screen + - fixed statusbar not visible when gl_clear = 1 + - fixed r_fullbright change not immedate when gl_texsort = 0 + - fixed alias models still dark when r_fullbright = 1 + - fixed HOM when screen is partially underwater + - fixed gunshot decals not showing up on some walls + - sky and water warp now freeze when you pause, as well as lightning bolts + - r_novis changes now take effect immediately, rather than when you cross a leaf boundary + - removed mirror code + - two particle styles, circle and square (cvar controlled) + - console: + - improved tab completion: + - hitting tab once will display a list of possible matches and complete the line using the first match + - hitting tab or shift-tab will cycle through the matches + - autocomplete will now match against aliases as well as commands and cvars. + - autocomplete will now complete later in the string (e.g. "bind mouse1 +att" + tab will complete '+attack') + - autocomplete will even complete inside the string (e.g. "bind m +attack" + tab will complete 'mouse1' if the cursor is right after the 'm') + - new key functionality: + - tab -- autocomplete, cycle through multiple matches + - shift-tab -- cycle backwards through multiple matches + - ins -- toggle insertmode + - del -- delete current character + - backspace -- delete previous character + - ctrl-v -- paste from windows clippboard + - leftarrow -- move cursor one character left in line + - rightarrow -- move cursor one character right in line. or, get one character from the previous command. + - home -- move cursor to beginning of line + - end -- move cursor to end of line + - ctrl-pgup -- scroll up a screen at a time + - ctrl-pgdn -- scroll down a screen at a time + - ctrl-home -- scroll to top of console history + - ctrl-end -- scroll to bottom of console history + - carets indicate that you are scrolled back, like in quakeworld/quake2 + - left arrow, right arrow, pgup, pgdn keys now auto-repeat + - quadrupled the length of the console history + - commands: + - "game " to load a mod. + - "reset " to reset a cvar to default. Note that this is the engine default, not the default.cfg value + - resetall. resets all cvars. + - mods. lists all child folders of quake directory which contain either a progs.dat or a pak file + - maps. lists all addon levels available (i.e. all levels that are not in id1/*.pak) + - mapname. outputs the short name of the current level (e.g. "e1m5") + - cmdlist. alphabetized. 'cmdlist blah' will list only cmds that start with 'blah' + - cvarlist. alphabetized. 'cvarlist blah' will list only cvars that start with 'blah' + - "inc [amount]" to increment a cvar by amount. amount defaults to 1. + - "toggle " to invert the value of a cvar (nonzero -> 0 and 0 -> 1) + - god, noclip, notarget, and fly can now be explicitly set. example: "god 0" will disable god mode + - viewpos. outputs (X,Y,Z) pitch yaw roll + - "give a " now gives you armour. type depends on value + - bindlist. lists all key bindings + - "alias " now outputs the current command string + - "unalias " to delete an alias + - unaliasall. delete all aliases. + - condump. dumps console to condump.txt + - fog. set global fog. syntax is "fog ", "fog ", or "fog " See section on modding for details. Set density to 0 to disable fog. + - "sky " to load a skybox. if skyname is "", this will turn off skybox rendering. + - stuffcmds now parses the "cmdline" cvar rather than the args actually passed to the program. This is useful for loading mods dynamically, so you can edit the cmdline before execing quake.rc (which calls "stuffcmds") + - cvars: + - scr_stretch_menus. default 1. if 1, menus and other overlays are stretched to fill the screen + - scr_conalpha. default 1. This is the opacity when the console is halfscreen. 0.6 will mimic glquake + - scr_clock. default 0. if 1, game time is displayed. If 2, system time is displayed. + - scr_showfps. default 0. if 1, FPS are displayed. + - r_waterwarp recognized. default 1. if zero, no underwater warping will take place + - r_drawflat recognized. default 0. if 1, polygons will be drawn as a solid color with no lightmap or texture + - r_particles. default 1. 0 = no particles, 1 = circular particles, 2 = square particles + - r_fastsky. default 0. if 1, sky will be rendered as solid color, for added performance + - r_sky_quality. default 8. Higher number divides the sky more, for a smoother effect and slower performance. + - r_clearcolor now supported. default 2. specify a palette index from 0 to 255. + - gl_fullbrights. default 1. set to 0 to disable fullbrights + - gl_farclip. default 8192. set to 4096 to mimic glquake. note that the skybox will be drawn somewhat closer than this value. + - cl_maxpitch. default 90 (straight down.) set to 80 to mimic normal quake + - cl_minpitch. default -90 (straight up.) set to -70 to mimic normal quake + - cl_keypad. default 1. if 0, keypad keys will respond as in quake.exe (for example, pushing 'KP_END' will be the same as pushing '1') + - gl_flashblend now defaults to 0. + - gl_ztrick now defaults to 0. + - gl_keeptjunctions now defaults to 1. (note, contrary to the name of this cvar, what is being kept is the extra polygon verts which *eliminate* tjunctions. This is a good thing, so i made it default to 1) + - chase_alpha. default 1. lower values make the chasecam player model translucent. Buggy. + - keyboard + - keypad keys are now bindable: + KP_NUMLOCK, KP_SLASH, KP_STAR, KP_MINUS, KP_HOME, KP_UPARROW, KP_PGUP, KP_PLUS, KP_LEFTARROW, KP_5, KP_RIGHTARROW, KP_END, KP_DOWNARROW, KP_PGDN, KP_ENTER, KP_INS, KP_DEL + - command line: + - running with -gamma at the command line will set the gamma. There is still no way to change this value in game. Default is 1.0 for 3dfx cards, 0.7 for all others + - if unspecified, -conwidth now defaults to -width + - modding extensions: + - skyboxes (worldspawn and qc settable), currently only targa and pcx formats accepted + - global fog (worldspawn and qc settable) + - physics + - fixed sliding around while standing on solid entities' bounding boxes (monsters, players, etc) + - misc + - default heapsize is now 32mb (was 16mb) + - default zonesize is now 256k (was 48k) \ No newline at end of file diff --git a/Misc/fitzquake512.tga b/Misc/fitzquake512.tga new file mode 100644 index 00000000..6d4b4a8b Binary files /dev/null and b/Misc/fitzquake512.tga differ diff --git a/Quake/anorm_dots.h b/Quake/anorm_dots.h new file mode 100644 index 00000000..0a7ca8b4 --- /dev/null +++ b/Quake/anorm_dots.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +{ +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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}, +{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} +} diff --git a/Quake/anorms.h b/Quake/anorms.h new file mode 100644 index 00000000..1d2ff367 --- /dev/null +++ b/Quake/anorms.h @@ -0,0 +1,182 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/Quake/bspfile.h b/Quake/bspfile.h new file mode 100644 index 00000000..41eb7830 --- /dev/null +++ b/Quake/bspfile.h @@ -0,0 +1,326 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + +// upper design bounds + +#define MAX_MAP_HULLS 4 + +#define MAX_MAP_MODELS 256 +#define MAX_MAP_BRUSHES 4096 +#define MAX_MAP_ENTITIES 1024 +#define MAX_MAP_ENTSTRING 65536 + +#define MAX_MAP_PLANES 32767 +#define MAX_MAP_NODES 32767 // because negative shorts are contents +#define MAX_MAP_CLIPNODES 32767 +#define MAX_MAP_LEAFS 32767 //johnfitz -- was 8192 +#define MAX_MAP_VERTS 65535 +#define MAX_MAP_FACES 65535 +#define MAX_MAP_MARKSURFACES 65535 +#define MAX_MAP_TEXINFO 4096 +#define MAX_MAP_EDGES 256000 +#define MAX_MAP_SURFEDGES 512000 +#define MAX_MAP_TEXTURES 512 +#define MAX_MAP_MIPTEX 0x200000 +#define MAX_MAP_LIGHTING 0x100000 +#define MAX_MAP_VISIBILITY 0x100000 + +#define MAX_MAP_PORTALS 65536 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + + +#define BSPVERSION 29 +#define TOOLVERSION 2 + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 + +#define HEADER_LUMPS 15 + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +typedef struct +{ + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[16]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored +} miptex_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + + +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid + +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int miptex; + int flags; +} texinfo_t; +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision +#define TEX_MISSING 2 // johnfitz -- this texinfo does not have a texture + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + + + +#define AMBIENT_WATER 0 +#define AMBIENT_SKY 1 +#define AMBIENT_SLIME 2 +#define AMBIENT_LAVA 3 + +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + + byte ambient_level[NUM_AMBIENTS]; +} dleaf_t; + + +//============================================================================ + +#ifndef QUAKE_GAME + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the utilities get to be lazy and just use large static arrays + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int texdatasize; +extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numclipnodes; +extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int nummarksurfaces; +extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +#endif diff --git a/Quake/cd_sdl.c b/Quake/cd_sdl.c new file mode 100644 index 00000000..52245840 --- /dev/null +++ b/Quake/cd_sdl.c @@ -0,0 +1,54 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +extern cvar_t bgmvolume; + +int CDAudio_Init (void) +{ + return -1; +} + +void CDAudio_Play (byte track, qboolean looping) +{ +} + +void CDAudio_Stop (void) +{ +} + +void CDAudio_Pause (void) +{ +} + +void CDAudio_Resume (void) +{ +} + +void CDAudio_Shutdown (void) +{ +} + +void CDAudio_Update (void) +{ +} diff --git a/Quake/cdaudio.h b/Quake/cdaudio.h new file mode 100644 index 00000000..5b55af5b --- /dev/null +++ b/Quake/cdaudio.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +int CDAudio_Init(void); +void CDAudio_Play(byte track, qboolean looping); +void CDAudio_Stop(void); +void CDAudio_Pause(void); +void CDAudio_Resume(void); +void CDAudio_Shutdown(void); +void CDAudio_Update(void); diff --git a/Quake/chase.c b/Quake/chase.c new file mode 100644 index 00000000..526b4c96 --- /dev/null +++ b/Quake/chase.c @@ -0,0 +1,118 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// chase.c -- chase camera code + +#include "quakedef.h" + +cvar_t chase_back = {"chase_back", "100"}; +cvar_t chase_up = {"chase_up", "16"}; +cvar_t chase_right = {"chase_right", "0"}; +cvar_t chase_active = {"chase_active", "0"}; + +/* +============== +Chase_Init +============== +*/ +void Chase_Init (void) +{ + Cvar_RegisterVariable (&chase_back, NULL); + Cvar_RegisterVariable (&chase_up, NULL); + Cvar_RegisterVariable (&chase_right, NULL); + Cvar_RegisterVariable (&chase_active, NULL); +} + +/* +============== +TraceLine + +TODO: impact on bmodels, monsters +============== +*/ +void TraceLine (vec3_t start, vec3_t end, vec3_t impact) +{ + trace_t trace; + + memset (&trace, 0, sizeof(trace)); + SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); + + VectorCopy (trace.endpos, impact); +} + +/* +============== +Chase_UpdateForClient -- johnfitz -- orient client based on camera. called after input +============== +*/ +void Chase_UpdateForClient (void) +{ + //place camera + + //assign client angles to camera + + //see where camera points + + //adjust client angles to point at the same place +} + +/* +============== +Chase_UpdateForDrawing -- johnfitz -- orient camera based on client. called before drawing + +TODO: stay at least 8 units away from all walls in this leaf +============== +*/ +void Chase_UpdateForDrawing (void) +{ + int i; + //float dist; + vec3_t forward, up, right; + vec3_t ideal, crosshair, temp; + + AngleVectors (cl.viewangles, forward, right, up); + + // calc ideal camera location before checking for walls + for (i=0 ; i<3 ; i++) + ideal[i] = cl.viewent.origin[i] + - forward[i]*chase_back.value + + right[i]*chase_right.value; + //+ up[i]*chase_up.value; + ideal[2] = cl.viewent.origin[2] + chase_up.value; + + // make sure camera is not in or behind a wall + TraceLine(r_refdef.vieworg, ideal, temp); + if (Length(temp) != 0) + VectorCopy(temp, ideal); + + // place camera + VectorCopy (ideal, r_refdef.vieworg); + + // find the spot the player is looking at + VectorMA (cl.viewent.origin, 4096, forward, temp); + TraceLine (cl.viewent.origin, temp, crosshair); + + // calculate camera angles to look at the same spot + VectorSubtract (crosshair, r_refdef.vieworg, temp); + VectorAngles (temp, r_refdef.viewangles); + if (r_refdef.viewangles[PITCH] == 90 || r_refdef.viewangles[PITCH] == -90) + r_refdef.viewangles[YAW] = cl.viewangles[YAW]; +} + diff --git a/Quake/cl_demo.c b/Quake/cl_demo.c new file mode 100644 index 00000000..adff353d --- /dev/null +++ b/Quake/cl_demo.c @@ -0,0 +1,368 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +void CL_FinishTimeDemo (void); + +/* +============================================================================== + +DEMO CODE + +When a demo is playing back, all NET_SendMessages are skipped, and +NET_GetMessages are read from the demo file. + +Whenever cl.time gets past the last received message, another message is +read from the demo file. +============================================================================== +*/ + +/* +============== +CL_StopPlayback + +Called when a demo file runs out, or the user starts a game +============== +*/ +void CL_StopPlayback (void) +{ + if (!cls.demoplayback) + return; + + fclose (cls.demofile); + cls.demoplayback = false; + cls.demofile = NULL; + cls.state = ca_disconnected; + + if (cls.timedemo) + CL_FinishTimeDemo (); +} + +/* +==================== +CL_WriteDemoMessage + +Dumps the current net message, prefixed by the length and view angles +==================== +*/ +void CL_WriteDemoMessage (void) +{ + int len; + int i; + float f; + + len = LittleLong (net_message.cursize); + fwrite (&len, 4, 1, cls.demofile); + for (i=0 ; i<3 ; i++) + { + f = LittleFloat (cl.viewangles[i]); + fwrite (&f, 4, 1, cls.demofile); + } + fwrite (net_message.data, net_message.cursize, 1, cls.demofile); + fflush (cls.demofile); +} + +/* +==================== +CL_GetMessage + +Handles recording and playback of demos, on top of NET_ code +==================== +*/ +int CL_GetMessage (void) +{ + int r, i; + float f; + + if (cls.demoplayback) + { + // decide if it is time to grab the next message + if (cls.signon == SIGNONS) // allways grab until fully connected + { + if (cls.timedemo) + { + if (host_framecount == cls.td_lastframe) + return 0; // allready read this frame's message + cls.td_lastframe = host_framecount; + // if this is the second frame, grab the real td_starttime + // so the bogus time on the first frame doesn't count + if (host_framecount == cls.td_startframe + 1) + cls.td_starttime = realtime; + } + else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) + { + return 0; // don't need another message yet + } + } + + // get the next message + fread (&net_message.cursize, 4, 1, cls.demofile); + VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); + for (i=0 ; i<3 ; i++) + { + r = fread (&f, 4, 1, cls.demofile); + cl.mviewangles[0][i] = LittleFloat (f); + } + + net_message.cursize = LittleLong (net_message.cursize); + if (net_message.cursize > MAX_MSGLEN) + Sys_Error ("Demo message > MAX_MSGLEN"); + r = fread (net_message.data, net_message.cursize, 1, cls.demofile); + if (r != 1) + { + CL_StopPlayback (); + return 0; + } + + return 1; + } + + while (1) + { + r = NET_GetMessage (cls.netcon); + + if (r != 1 && r != 2) + return r; + + // discard nop keepalive message + if (net_message.cursize == 1 && net_message.data[0] == svc_nop) + Con_Printf ("<-- server to client keepalive\n"); + else + break; + } + + if (cls.demorecording) + CL_WriteDemoMessage (); + + return r; +} + + +/* +==================== +CL_Stop_f + +stop recording a demo +==================== +*/ +void CL_Stop_f (void) +{ + if (cmd_source != src_command) + return; + + if (!cls.demorecording) + { + Con_Printf ("Not recording a demo.\n"); + return; + } + +// write a disconnect message to the demo file + SZ_Clear (&net_message); + MSG_WriteByte (&net_message, svc_disconnect); + CL_WriteDemoMessage (); + +// finish up + fclose (cls.demofile); + cls.demofile = NULL; + cls.demorecording = false; + Con_Printf ("Completed demo\n"); +} + +/* +==================== +CL_Record_f + +record [cd track] +==================== +*/ +void CL_Record_f (void) +{ + int c; + char name[MAX_OSPATH]; + int track; + + if (cmd_source != src_command) + return; + + c = Cmd_Argc(); + if (c != 2 && c != 3 && c != 4) + { + Con_Printf ("record [ [cd track]]\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + if (c == 2 && cls.state == ca_connected) + { + Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); + return; + } + +// write the forced cd track number, or -1 + if (c == 4) + { + track = atoi(Cmd_Argv(3)); + Con_Printf ("Forcing CD track to %i\n", cls.forcetrack); + } + else + track = -1; + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + +// +// start the map up +// + if (c > 2) + Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command); + +// +// open the demo file +// + COM_DefaultExtension (name, ".dem"); + + Con_Printf ("recording to %s.\n", name); + cls.demofile = fopen (name, "wb"); + if (!cls.demofile) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + cls.forcetrack = track; + fprintf (cls.demofile, "%i\n", cls.forcetrack); + + cls.demorecording = true; +} + + +/* +==================== +CL_PlayDemo_f + +play [demoname] +==================== +*/ +void CL_PlayDemo_f (void) +{ + char name[256]; + int c; + qboolean neg = false; + + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("play : plays a demo\n"); + return; + } + +// +// disconnect from server +// + CL_Disconnect (); + +// +// open the demo file +// + strcpy (name, Cmd_Argv(1)); + COM_DefaultExtension (name, ".dem"); + + Con_Printf ("Playing demo from %s.\n", name); + COM_FOpenFile (name, &cls.demofile); + if (!cls.demofile) + { + Con_Printf ("ERROR: couldn't open.\n"); + cls.demonum = -1; // stop demo loop + return; + } + + cls.demoplayback = true; + cls.state = ca_connected; + cls.forcetrack = 0; + + while ((c = getc(cls.demofile)) != '\n') + if (c == '-') + neg = true; + else + cls.forcetrack = cls.forcetrack * 10 + (c - '0'); + + if (neg) + cls.forcetrack = -cls.forcetrack; +// ZOID, fscanf is evil +// fscanf (cls.demofile, "%i\n", &cls.forcetrack); +} + +/* +==================== +CL_FinishTimeDemo + +==================== +*/ +void CL_FinishTimeDemo (void) +{ + int frames; + float time; + + cls.timedemo = false; + +// the first frame didn't count + frames = (host_framecount - cls.td_startframe) - 1; + time = realtime - cls.td_starttime; + if (!time) + time = 1; + Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time); +} + +/* +==================== +CL_TimeDemo_f + +timedemo [demoname] +==================== +*/ +void CL_TimeDemo_f (void) +{ + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("timedemo : gets demo speeds\n"); + return; + } + + CL_PlayDemo_f (); + +// cls.td_starttime will be grabbed at the second frame of the demo, so +// all the loading time doesn't get counted + + cls.timedemo = true; + cls.td_startframe = host_framecount; + cls.td_lastframe = -1; // get a new message this frame +} + diff --git a/Quake/cl_input.c b/Quake/cl_input.c new file mode 100644 index 00000000..e3a2be66 --- /dev/null +++ b/Quake/cl_input.c @@ -0,0 +1,448 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl.input.c -- builds an intended movement command to send to the server + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. + +#include "quakedef.h" + +extern cvar_t cl_maxpitch; //johnfitz -- variable pitch clamping +extern cvar_t cl_minpitch; //johnfitz -- variable pitch clamping + +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook, in_klook; +kbutton_t in_left, in_right, in_forward, in_back; +kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; +kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack; +kbutton_t in_up, in_down; + +int in_impulse; + + +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + Con_Printf ("Three keys down for a button!\n"); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + return; // some other key is still holding it down + + if (!(b->state & 1)) + return; // still up (this should not happen) + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_MLookUp (void) { +KeyUp(&in_mlook); +if ( !(in_mlook.state&1) && lookspring.value) + V_StartPitchDrift(); +} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} +void IN_ForwardDown(void) {KeyDown(&in_forward);} +void IN_ForwardUp(void) {KeyUp(&in_forward);} +void IN_BackDown(void) {KeyDown(&in_back);} +void IN_BackUp(void) {KeyUp(&in_back);} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} +void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} +void IN_MoverightDown(void) {KeyDown(&in_moveright);} +void IN_MoverightUp(void) {KeyUp(&in_moveright);} + +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +void IN_AttackDown(void) {KeyDown(&in_attack);} +void IN_AttackUp(void) {KeyUp(&in_attack);} + +void IN_UseDown (void) {KeyDown(&in_use);} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) {KeyDown(&in_jump);} +void IN_JumpUp (void) {KeyUp(&in_jump);} + +void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val; + qboolean impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + val = 0; + + if (impulsedown && !impulseup) + if (down) + val = 0.5; // pressed and held this frame + else + val = 0; // I_Error (); + if (impulseup && !impulsedown) + if (down) + val = 0; // I_Error (); + else + val = 0; // released this frame + if (!impulsedown && !impulseup) + if (down) + val = 1.0; // held the entire frame + else + val = 0; // up the entire frame + if (impulsedown && impulseup) + if (down) + val = 0.75; // released and re-pressed this frame + else + val = 0.25; // pressed and released this frame + + key->state &= 1; // clear impulses + + return val; +} + + + + +//========================================================================== + +cvar_t cl_upspeed = {"cl_upspeed","200"}; +cvar_t cl_forwardspeed = {"cl_forwardspeed","200", true}; +cvar_t cl_backspeed = {"cl_backspeed","200", true}; +cvar_t cl_sidespeed = {"cl_sidespeed","350"}; + +cvar_t cl_movespeedkey = {"cl_movespeedkey","2.0"}; + +cvar_t cl_yawspeed = {"cl_yawspeed","140"}; +cvar_t cl_pitchspeed = {"cl_pitchspeed","150"}; + +cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5"}; + + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles (void) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + speed = host_frametime * cl_anglespeedkey.value; + else + speed = host_frametime; + + if (!(in_strafe.state & 1)) + { + cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); + cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); + cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDrift (); + cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward); + cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up; + cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down; + + if (up || down) + V_StopPitchDrift (); + + //johnfitz -- variable pitch clamping + if (cl.viewangles[PITCH] > cl_maxpitch.value) + cl.viewangles[PITCH] = cl_maxpitch.value; + if (cl.viewangles[PITCH] < cl_minpitch.value) + cl.viewangles[PITCH] = cl_minpitch.value; + //johnfitz + + if (cl.viewangles[ROLL] > 50) + cl.viewangles[ROLL] = 50; + if (cl.viewangles[ROLL] < -50) + cl.viewangles[ROLL] = -50; + +} + +/* +================ +CL_BaseMove + +Send the intended movement message to the server +================ +*/ +void CL_BaseMove (usercmd_t *cmd) +{ + if (cls.signon != SIGNONS) + return; + + CL_AdjustAngles (); + + Q_memset (cmd, 0, sizeof(*cmd)); + + if (in_strafe.state & 1) + { + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); + + if (! (in_klook.state & 1) ) + { + cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + } + +// +// adjust for speed key +// + if (in_speed.state & 1) + { + cmd->forwardmove *= cl_movespeedkey.value; + cmd->sidemove *= cl_movespeedkey.value; + cmd->upmove *= cl_movespeedkey.value; + } +} + + + +/* +============== +CL_SendMove +============== +*/ +void CL_SendMove (usercmd_t *cmd) +{ + int i; + int bits; + sizebuf_t buf; + byte data[128]; + + buf.maxsize = 128; + buf.cursize = 0; + buf.data = data; + + cl.cmd = *cmd; + +// +// send the movement message +// + MSG_WriteByte (&buf, clc_move); + + MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times + + for (i=0 ; i<3 ; i++) + //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE + if (cl.protocol == PROTOCOL_NETQUAKE) + MSG_WriteAngle (&buf, cl.viewangles[i]); + else + MSG_WriteAngle16 (&buf, cl.viewangles[i]); + //johnfitz + + MSG_WriteShort (&buf, cmd->forwardmove); + MSG_WriteShort (&buf, cmd->sidemove); + MSG_WriteShort (&buf, cmd->upmove); + +// +// send button bits +// + bits = 0; + + if ( in_attack.state & 3 ) + bits |= 1; + in_attack.state &= ~2; + + if (in_jump.state & 3) + bits |= 2; + in_jump.state &= ~2; + + MSG_WriteByte (&buf, bits); + + MSG_WriteByte (&buf, in_impulse); + in_impulse = 0; + +// +// deliver the message +// + if (cls.demoplayback) + return; + +// +// allways dump the first two message, because it may contain leftover inputs +// from the last level +// + if (++cl.movemessages <= 2) + return; + + if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) + { + Con_Printf ("CL_SendMove: lost server connection\n"); + CL_Disconnect (); + } +} + +/* +============ +CL_InitInput +============ +*/ +void CL_InitInput (void) +{ + Cmd_AddCommand ("+moveup",IN_UpDown); + Cmd_AddCommand ("-moveup",IN_UpUp); + Cmd_AddCommand ("+movedown",IN_DownDown); + Cmd_AddCommand ("-movedown",IN_DownUp); + Cmd_AddCommand ("+left",IN_LeftDown); + Cmd_AddCommand ("-left",IN_LeftUp); + Cmd_AddCommand ("+right",IN_RightDown); + Cmd_AddCommand ("-right",IN_RightUp); + Cmd_AddCommand ("+forward",IN_ForwardDown); + Cmd_AddCommand ("-forward",IN_ForwardUp); + Cmd_AddCommand ("+back",IN_BackDown); + Cmd_AddCommand ("-back",IN_BackUp); + Cmd_AddCommand ("+lookup", IN_LookupDown); + Cmd_AddCommand ("-lookup", IN_LookupUp); + Cmd_AddCommand ("+lookdown", IN_LookdownDown); + Cmd_AddCommand ("-lookdown", IN_LookdownUp); + Cmd_AddCommand ("+strafe", IN_StrafeDown); + Cmd_AddCommand ("-strafe", IN_StrafeUp); + Cmd_AddCommand ("+moveleft", IN_MoveleftDown); + Cmd_AddCommand ("-moveleft", IN_MoveleftUp); + Cmd_AddCommand ("+moveright", IN_MoverightDown); + Cmd_AddCommand ("-moveright", IN_MoverightUp); + Cmd_AddCommand ("+speed", IN_SpeedDown); + Cmd_AddCommand ("-speed", IN_SpeedUp); + Cmd_AddCommand ("+attack", IN_AttackDown); + Cmd_AddCommand ("-attack", IN_AttackUp); + Cmd_AddCommand ("+use", IN_UseDown); + Cmd_AddCommand ("-use", IN_UseUp); + Cmd_AddCommand ("+jump", IN_JumpDown); + Cmd_AddCommand ("-jump", IN_JumpUp); + Cmd_AddCommand ("impulse", IN_Impulse); + Cmd_AddCommand ("+klook", IN_KLookDown); + Cmd_AddCommand ("-klook", IN_KLookUp); + Cmd_AddCommand ("+mlook", IN_MLookDown); + Cmd_AddCommand ("-mlook", IN_MLookUp); + +} + diff --git a/Quake/cl_main.c b/Quake/cl_main.c new file mode 100644 index 00000000..3ee9772c --- /dev/null +++ b/Quake/cl_main.c @@ -0,0 +1,807 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_main.c -- client main loop + +#include "quakedef.h" + +// we need to declare some mouse variables here, because the menu system +// references them even when on a unix system. + +// these two are not intended to be set directly +cvar_t cl_name = {"_cl_name", "player", true}; +cvar_t cl_color = {"_cl_color", "0", true}; + +cvar_t cl_shownet = {"cl_shownet","0"}; // can be 0, 1, or 2 +cvar_t cl_nolerp = {"cl_nolerp","0"}; + +cvar_t lookspring = {"lookspring","0", true}; +cvar_t lookstrafe = {"lookstrafe","0", true}; +cvar_t sensitivity = {"sensitivity","3", true}; + +cvar_t m_pitch = {"m_pitch","0.022", true}; +cvar_t m_yaw = {"m_yaw","0.022", true}; +cvar_t m_forward = {"m_forward","1", true}; +cvar_t m_side = {"m_side","0.8", true}; + +cvar_t cl_maxpitch = {"cl_maxpitch", "90", true}; //johnfitz -- variable pitch clamping +cvar_t cl_minpitch = {"cl_minpitch", "-90", true}; //johnfitz -- variable pitch clamping + +client_static_t cls; +client_state_t cl; +// FIXME: put these on hunk? +efrag_t cl_efrags[MAX_EFRAGS]; +entity_t cl_static_entities[MAX_STATIC_ENTITIES]; +lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +dlight_t cl_dlights[MAX_DLIGHTS]; + +entity_t *cl_entities; //johnfitz -- was a static array, now on hunk +int cl_max_edicts; //johnfitz -- only changes when new map loads + +int cl_numvisedicts; +entity_t *cl_visedicts[MAX_VISEDICTS]; + +extern cvar_t r_lerpmodels, r_lerpmove; //johnfitz + +/* +===================== +CL_ClearState + +===================== +*/ +void CL_ClearState (void) +{ + int i; + + if (!sv.active) + Host_ClearMemory (); + +// wipe the entire cl structure + memset (&cl, 0, sizeof(cl)); + + SZ_Clear (&cls.message); + +// clear other arrays + memset (cl_efrags, 0, sizeof(cl_efrags)); + memset (cl_dlights, 0, sizeof(cl_dlights)); + memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); + memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); + memset (cl_beams, 0, sizeof(cl_beams)); + + //johnfitz -- cl_entities is now dynamically allocated + cl_max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); + cl_entities = Hunk_AllocName (cl_max_edicts*sizeof(entity_t), "cl_entities"); + //johnfitz + +// +// allocate the efrags and chain together into a free list +// + cl.free_efrags = cl_efrags; + for (i=0 ; i>4, ((int)cl_color.value)&15)); + + MSG_WriteByte (&cls.message, clc_stringcmd); + sprintf (str, "spawn %s", cls.spawnparms); + MSG_WriteString (&cls.message, str); + break; + + case 3: + MSG_WriteByte (&cls.message, clc_stringcmd); + MSG_WriteString (&cls.message, "begin"); + Cache_Report (); // print remaining memory + break; + + case 4: + SCR_EndLoadingPlaque (); // allow normal screen updates + break; + } +} + +/* +===================== +CL_NextDemo + +Called to play the next demo in the demo loop +===================== +*/ +void CL_NextDemo (void) +{ + char str[1024]; + + if (cls.demonum == -1) + return; // don't play demos + + SCR_BeginLoadingPlaque (); + + if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) + { + cls.demonum = 0; + if (!cls.demos[cls.demonum][0]) + { + Con_Printf ("No demos listed with startdemos\n"); + cls.demonum = -1; + return; + } + } + + sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); + Cbuf_InsertText (str); + cls.demonum++; +} + +/* +============== +CL_PrintEntities_f +============== +*/ +void CL_PrintEntities_f (void) +{ + entity_t *ent; + int i; + + for (i=0,ent=cl_entities ; imodel) + { + Con_Printf ("EMPTY\n"); + continue; + } + Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n" + ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); + } +} + +//johnfitz -- deleted SetPal() + +/* +=============== +CL_AllocDlight + +=============== +*/ +dlight_t *CL_AllocDlight (int key) +{ + int i; + dlight_t *dl; + +// first look for an exact key match + if (key) + { + dl = cl_dlights; + for (i=0 ; ikey == key) + { + memset (dl, 0, sizeof(*dl)); + dl->key = key; + dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc + return dl; + } + } + } + +// then look for anything else + dl = cl_dlights; + for (i=0 ; idie < cl.time) + { + memset (dl, 0, sizeof(*dl)); + dl->key = key; + dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc + return dl; + } + } + + dl = &cl_dlights[0]; + memset (dl, 0, sizeof(*dl)); + dl->key = key; + dl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc + return dl; +} + + +/* +=============== +CL_DecayLights + +=============== +*/ +void CL_DecayLights (void) +{ + int i; + dlight_t *dl; + float time; + + time = cl.time - cl.oldtime; + + dl = cl_dlights; + for (i=0 ; idie < cl.time || !dl->radius) + continue; + + dl->radius -= time*dl->decay; + if (dl->radius < 0) + dl->radius = 0; + } +} + + +/* +=============== +CL_LerpPoint + +Determines the fraction between the last two messages that the objects +should be put at. +=============== +*/ +float CL_LerpPoint (void) +{ + float f, frac; + + f = cl.mtime[0] - cl.mtime[1]; + + if (!f || cls.timedemo || sv.active) + { + cl.time = cl.mtime[0]; + return 1; + } + + if (f > 0.1) // dropped packet, or start of demo + { + cl.mtime[1] = cl.mtime[0] - 0.1; + f = 0.1; + } + + frac = (cl.time - cl.mtime[1]) / f; + + if (frac < 0) + { + if (frac < -0.01) + cl.time = cl.mtime[1]; + frac = 0; + } + else if (frac > 1) + { + if (frac > 1.01) + cl.time = cl.mtime[0]; + frac = 1; + } + + //johnfitz -- better nolerp behavior + if (cl_nolerp.value) + return 1; + //johnfitz + + return frac; +} + +/* +=============== +CL_RelinkEntities +=============== +*/ +void CL_RelinkEntities (void) +{ + entity_t *ent; + int i, j; + float frac, f, d; + vec3_t delta; + float bobjrotate; + vec3_t oldorg; + dlight_t *dl; + +// determine partial update time + frac = CL_LerpPoint (); + + cl_numvisedicts = 0; + +// +// interpolate player info +// + for (i=0 ; i<3 ; i++) + cl.velocity[i] = cl.mvelocity[1][i] + + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + + if (cls.demoplayback) + { + // interpolate the angles + for (j=0 ; j<3 ; j++) + { + d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + cl.viewangles[j] = cl.mviewangles[1][j] + frac*d; + } + } + + bobjrotate = anglemod(100*cl.time); + +// start on the entity after the world + for (i=1,ent=cl_entities+1 ; imodel) + { // empty slot + if (ent->forcelink) + R_RemoveEfrags (ent); // just became empty + continue; + } + +// if the object wasn't included in the last packet, remove it + if (ent->msgtime != cl.mtime[0]) + { + ent->model = NULL; + ent->lerpflags |= LERP_RESETMOVE|LERP_RESETANIM; //johnfitz -- next time this entity slot is reused, the lerp will need to be reset + continue; + } + + VectorCopy (ent->origin, oldorg); + + if (ent->forcelink) + { // the entity was not updated in the last message + // so move to the final spot + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->angles); + } + else + { // if the delta is large, assume a teleport and don't lerp + f = frac; + for (j=0 ; j<3 ; j++) + { + delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; + if (delta[j] > 100 || delta[j] < -100) + { + f = 1; // assume a teleportation, not a motion + ent->lerpflags |= LERP_RESETMOVE; //johnfitz -- don't lerp teleports + } + } + + //johnfitz -- don't cl_lerp entities that will be r_lerped + if (r_lerpmove.value && (ent->lerpflags & LERP_MOVESTEP)) + f = 1; + //johnfitz + + // interpolate the origin and angles + for (j=0 ; j<3 ; j++) + { + ent->origin[j] = ent->msg_origins[1][j] + f*delta[j]; + + d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + ent->angles[j] = ent->msg_angles[1][j] + f*d; + } + + } + +// rotate binary objects locally + if (ent->model->flags & EF_ROTATE) + ent->angles[1] = bobjrotate; + + if (ent->effects & EF_BRIGHTFIELD) + R_EntityParticles (ent); + + if (ent->effects & EF_MUZZLEFLASH) + { + vec3_t fv, rv, uv; + + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] += 16; + AngleVectors (ent->angles, fv, rv, uv); + + VectorMA (dl->origin, 18, fv, dl->origin); + dl->radius = 200 + (rand()&31); + dl->minlight = 32; + dl->die = cl.time + 0.1; + + //johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped + if (r_lerpmodels.value != 2) + { + if (ent == &cl_entities[cl.viewentity]) + cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames + else + ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames + } + //johnfitz + } + if (ent->effects & EF_BRIGHTLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] += 16; + dl->radius = 400 + (rand()&31); + dl->die = cl.time + 0.001; + } + if (ent->effects & EF_DIMLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200 + (rand()&31); + dl->die = cl.time + 0.001; + } + + if (ent->model->flags & EF_GIB) + R_RocketTrail (oldorg, ent->origin, 2); + else if (ent->model->flags & EF_ZOMGIB) + R_RocketTrail (oldorg, ent->origin, 4); + else if (ent->model->flags & EF_TRACER) + R_RocketTrail (oldorg, ent->origin, 3); + else if (ent->model->flags & EF_TRACER2) + R_RocketTrail (oldorg, ent->origin, 5); + else if (ent->model->flags & EF_ROCKET) + { + R_RocketTrail (oldorg, ent->origin, 0); + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200; + dl->die = cl.time + 0.01; + } + else if (ent->model->flags & EF_GRENADE) + R_RocketTrail (oldorg, ent->origin, 1); + else if (ent->model->flags & EF_TRACER3) + R_RocketTrail (oldorg, ent->origin, 6); + + ent->forcelink = false; + + if (i == cl.viewentity && !chase_active.value) + continue; + + if (cl_numvisedicts < MAX_VISEDICTS) + { + cl_visedicts[cl_numvisedicts] = ent; + cl_numvisedicts++; + } + } +} + + +/* +=============== +CL_ReadFromServer + +Read all incoming data from the server +=============== +*/ +int CL_ReadFromServer (void) +{ + int ret; + extern int num_temp_entities; //johnfitz + int num_beams = 0; //johnfitz + int num_dlights = 0; //johnfitz + beam_t *b; //johnfitz + dlight_t *l; //johnfitz + int i; //johnfitz + + + cl.oldtime = cl.time; + cl.time += host_frametime; + + do + { + ret = CL_GetMessage (); + if (ret == -1) + Host_Error ("CL_ReadFromServer: lost server connection"); + if (!ret) + break; + + cl.last_received_message = realtime; + CL_ParseServerMessage (); + } while (ret && cls.state == ca_connected); + + if (cl_shownet.value) + Con_Printf ("\n"); + + CL_RelinkEntities (); + CL_UpdateTEnts (); + +//johnfitz -- devstats + + //visedicts + if (cl_numvisedicts > 256 && dev_peakstats.visedicts <= 256) + Con_Warning ("%i visedicts exceeds standard limit of 256.\n", cl_numvisedicts); + dev_stats.visedicts = cl_numvisedicts; + dev_peakstats.visedicts = max(cl_numvisedicts, dev_peakstats.visedicts); + + //temp entities + if (num_temp_entities > 64 && dev_peakstats.tempents <= 64) + Con_Warning ("%i tempentities exceeds standard limit of 64.\n", num_temp_entities); + dev_stats.tempents = num_temp_entities; + dev_peakstats.tempents = max(num_temp_entities, dev_peakstats.tempents); + + //beams + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->model && b->endtime >= cl.time) + num_beams++; + if (num_beams > 24 && dev_peakstats.beams <= 24) + Con_Warning ("%i beams exceeded standard limit of 24.\n", num_beams); + dev_stats.beams = num_beams; + dev_peakstats.beams = max(num_beams, dev_peakstats.beams); + + //dlights + for (i=0, l=cl_dlights ; idie >= cl.time && l->radius) + num_dlights++; + if (num_dlights > 32 && dev_peakstats.dlights <= 32) + Con_Warning ("%i dlights exceeded standard limit of 32.\n", num_dlights); + dev_stats.dlights = num_dlights; + dev_peakstats.dlights = max(num_dlights, dev_peakstats.dlights); + +//johnfitz + +// +// bring the links up to date +// + return 0; +} + +/* +================= +CL_SendCmd +================= +*/ +void CL_SendCmd (void) +{ + usercmd_t cmd; + + if (cls.state != ca_connected) + return; + + if (cls.signon == SIGNONS) + { + // get basic movement from keyboard + CL_BaseMove (&cmd); + + // allow mice or other external controllers to add to the move + IN_Move (&cmd); + + // send the unreliable message + CL_SendMove (&cmd); + + } + + if (cls.demoplayback) + { + SZ_Clear (&cls.message); + return; + } + +// send the reliable message + if (!cls.message.cursize) + return; // no message at all + + if (!NET_CanSendMessage (cls.netcon)) + { + Con_DPrintf ("CL_WriteToServer: can't send\n"); + return; + } + + if (NET_SendMessage (cls.netcon, &cls.message) == -1) + Host_Error ("CL_WriteToServer: lost server connection"); + + SZ_Clear (&cls.message); +} + +/* +============= +CL_Tracepos_f -- johnfitz + +display impact point of trace along VPN +============= +*/ +void CL_Tracepos_f (void) +{ + vec3_t v, w; + + VectorScale(vpn, 8192.0, v); + TraceLine(r_refdef.vieworg, v, w); + + if (Length(w) == 0) + Con_Printf ("Tracepos: trace didn't hit anything\n"); + else + Con_Printf ("Tracepos: (%i %i %i)\n", (int)w[0], (int)w[1], (int)w[2]); +} + +/* +============= +CL_Viewpos_f -- johnfitz + +display client's position and angles +============= +*/ +void CL_Viewpos_f (void) +{ +#if 0 + //camera position + Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n", + (int)r_refdef.vieworg[0], + (int)r_refdef.vieworg[1], + (int)r_refdef.vieworg[2], + (int)r_refdef.viewangles[PITCH], + (int)r_refdef.viewangles[YAW], + (int)r_refdef.viewangles[ROLL]); +#else + //player position + Con_Printf ("Viewpos: (%i %i %i) %i %i %i\n", + (int)cl_entities[cl.viewentity].origin[0], + (int)cl_entities[cl.viewentity].origin[1], + (int)cl_entities[cl.viewentity].origin[2], + (int)cl.viewangles[PITCH], + (int)cl.viewangles[YAW], + (int)cl.viewangles[ROLL]); +#endif +} + +/* +================= +CL_Init +================= +*/ +void CL_Init (void) +{ + SZ_Alloc (&cls.message, 1024); + + CL_InitInput (); + CL_InitTEnts (); + + Cvar_RegisterVariable (&cl_name, NULL); + Cvar_RegisterVariable (&cl_color, NULL); + Cvar_RegisterVariable (&cl_upspeed, NULL); + Cvar_RegisterVariable (&cl_forwardspeed, NULL); + Cvar_RegisterVariable (&cl_backspeed, NULL); + Cvar_RegisterVariable (&cl_sidespeed, NULL); + Cvar_RegisterVariable (&cl_movespeedkey, NULL); + Cvar_RegisterVariable (&cl_yawspeed, NULL); + Cvar_RegisterVariable (&cl_pitchspeed, NULL); + Cvar_RegisterVariable (&cl_anglespeedkey, NULL); + Cvar_RegisterVariable (&cl_shownet, NULL); + Cvar_RegisterVariable (&cl_nolerp, NULL); + Cvar_RegisterVariable (&lookspring, NULL); + Cvar_RegisterVariable (&lookstrafe, NULL); + Cvar_RegisterVariable (&sensitivity, NULL); + + Cvar_RegisterVariable (&m_pitch, NULL); + Cvar_RegisterVariable (&m_yaw, NULL); + Cvar_RegisterVariable (&m_forward, NULL); + Cvar_RegisterVariable (&m_side, NULL); + + Cvar_RegisterVariable (&cl_maxpitch, NULL); //johnfitz -- variable pitch clamping + Cvar_RegisterVariable (&cl_minpitch, NULL); //johnfitz -- variable pitch clamping + + Cmd_AddCommand ("entities", CL_PrintEntities_f); + Cmd_AddCommand ("disconnect", CL_Disconnect_f); + Cmd_AddCommand ("record", CL_Record_f); + Cmd_AddCommand ("stop", CL_Stop_f); + Cmd_AddCommand ("playdemo", CL_PlayDemo_f); + Cmd_AddCommand ("timedemo", CL_TimeDemo_f); + + Cmd_AddCommand ("tracepos", CL_Tracepos_f); //johnfitz + Cmd_AddCommand ("viewpos", CL_Viewpos_f); //johnfitz +} + diff --git a/Quake/cl_parse.c b/Quake/cl_parse.c new file mode 100644 index 00000000..bfd95cd8 --- /dev/null +++ b/Quake/cl_parse.c @@ -0,0 +1,1218 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_parse.c -- parse a message received from the server + +#include "quakedef.h" + +char *svc_strings[] = +{ + "svc_bad", + "svc_nop", + "svc_disconnect", + "svc_updatestat", + "svc_version", // [long] server version + "svc_setview", // [short] entity number + "svc_sound", // + "svc_time", // [float] server time + "svc_print", // [string] null terminated string + "svc_stufftext", // [string] stuffed into client's console buffer + // the string should be \n terminated + "svc_setangle", // [vec3] set the view angle to this absolute value + + "svc_serverinfo", // [long] version + // [string] signon string + // [string]..[0]model cache [string]...[0]sounds cache + // [string]..[0]item cache + "svc_lightstyle", // [byte] [string] + "svc_updatename", // [byte] [string] + "svc_updatefrags", // [byte] [short] + "svc_clientdata", // + "svc_stopsound", // + "svc_updatecolors", // [byte] [byte] + "svc_particle", // [vec3] + "svc_damage", // [byte] impact [byte] blood [vec3] from + + "svc_spawnstatic", + "OBSOLETE svc_spawnbinary", + "svc_spawnbaseline", + + "svc_temp_entity", // + "svc_setpause", + "svc_signonnum", + "svc_centerprint", + "svc_killedmonster", + "svc_foundsecret", + "svc_spawnstaticsound", + "svc_intermission", + "svc_finale", // [string] music [string] text + "svc_cdtrack", // [byte] track [byte] looptrack + "svc_sellscreen", + "svc_cutscene", +//johnfitz -- new server messages + "", // 35 + "", // 36 + "svc_skybox", // 37 // [string] skyname + "", // 38 + "", // 39 + "svc_bf", // 40 // no data + "svc_fog", // 41 // [byte] density [byte] red [byte] green [byte] blue [float] time + "svc_spawnbaseline2", //42 // support for large modelindex, large framenum, alpha, using flags + "svc_spawnstatic2", // 43 // support for large modelindex, large framenum, alpha, using flags + "svc_spawnstaticsound2", // 44 // [coord3] [short] samp [byte] vol [byte] aten + "", // 44 + "", // 45 + "", // 46 + "", // 47 + "", // 48 + "", // 49 +//johnfitz +}; + +qboolean warn_about_nehahra_protocol; //johnfitz + +extern vec3_t v_punchangles[2]; //johnfitz + +//============================================================================= + +/* +=============== +CL_EntityNum + +This error checks and tracks the total number of entities +=============== +*/ +entity_t *CL_EntityNum (int num) +{ + //johnfitz -- check minimum number too + if (num < 0) + Host_Error ("CL_EntityNum: %i is an invalid number",num); + //john + + if (num >= cl.num_entities) + { + if (num >= cl_max_edicts) //johnfitz -- no more MAX_EDICTS + Host_Error ("CL_EntityNum: %i is an invalid number",num); + while (cl.num_entities<=num) + { + cl_entities[cl.num_entities].colormap = vid.colormap; + cl_entities[cl.num_entities].lerpflags |= LERP_RESETMOVE|LERP_RESETANIM; //johnfitz + cl.num_entities++; + } + } + + return &cl_entities[num]; +} + + +/* +================== +CL_ParseStartSoundPacket +================== +*/ +void CL_ParseStartSoundPacket(void) +{ + vec3_t pos; + int channel, ent; + int sound_num; + int volume; + int field_mask; + float attenuation; + int i; + + field_mask = MSG_ReadByte(); + + if (field_mask & SND_VOLUME) + volume = MSG_ReadByte (); + else + volume = DEFAULT_SOUND_PACKET_VOLUME; + + if (field_mask & SND_ATTENUATION) + attenuation = MSG_ReadByte () / 64.0; + else + attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + + //johnfitz -- PROTOCOL_FITZQUAKE + if (field_mask & SND_LARGEENTITY) + { + ent = (unsigned short) MSG_ReadShort (); + channel = MSG_ReadByte (); + } + else + { + channel = (unsigned short) MSG_ReadShort (); + ent = channel >> 3; + channel &= 7; + } + + if (field_mask & SND_LARGESOUND) + sound_num = (unsigned short) MSG_ReadShort (); + else + sound_num = MSG_ReadByte (); + //johnfitz + + //johnfitz -- check soundnum + if (sound_num >= MAX_SOUNDS) + Host_Error ("CL_ParseStartSoundPacket: %i > MAX_SOUNDS", sound_num); + //johnfitz + + if (ent > cl_max_edicts) //johnfitz -- no more MAX_EDICTS + Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); + + for (i=0 ; i<3 ; i++) + pos[i] = MSG_ReadCoord (); + + S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); +} + +/* +================== +CL_KeepaliveMessage + +When the client is taking a long time to load stuff, send keepalive messages +so the server doesn't disconnect. +================== +*/ +void CL_KeepaliveMessage (void) +{ + float time; + static float lastmsg; + int ret; + sizebuf_t old; + byte olddata[8192]; + + if (sv.active) + return; // no need if server is local + if (cls.demoplayback) + return; + +// read messages from server, should just be nops + old = net_message; + memcpy (olddata, net_message.data, net_message.cursize); + + do + { + ret = CL_GetMessage (); + switch (ret) + { + default: + Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); + case 0: + break; // nothing waiting + case 1: + Host_Error ("CL_KeepaliveMessage: received a message"); + break; + case 2: + if (MSG_ReadByte() != svc_nop) + Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); + break; + } + } while (ret); + + net_message = old; + memcpy (net_message.data, olddata, net_message.cursize); + +// check time + time = Sys_FloatTime (); + if (time - lastmsg < 5) + return; + lastmsg = time; + +// write out a nop + Con_Printf ("--> client to server keepalive\n"); + + MSG_WriteByte (&cls.message, clc_nop); + NET_SendMessage (cls.netcon, &cls.message); + SZ_Clear (&cls.message); +} + +/* +================== +CL_ParseServerInfo +================== +*/ +void CL_ParseServerInfo (void) +{ + char *str; + int i; + int nummodels, numsounds; + char model_precache[MAX_MODELS][MAX_QPATH]; + char sound_precache[MAX_SOUNDS][MAX_QPATH]; + + Con_DPrintf ("Serverinfo packet received.\n"); +// +// wipe the client_state_t struct +// + CL_ClearState (); + +// parse protocol version number + i = MSG_ReadLong (); + //johnfitz -- support multiple protocols + if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) { + Con_Printf ("\n"); //becuase there's no newline after serverinfo print + Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); + } + cl.protocol = i; + //johnfitz + +// parse maxclients + cl.maxclients = MSG_ReadByte (); + if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) + { + Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); + return; + } + cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); + +// parse gametype + cl.gametype = MSG_ReadByte (); + +// parse signon message + str = MSG_ReadString (); + strncpy (cl.levelname, str, sizeof(cl.levelname)-1); + +// seperate the printfs so the server message can have a color + Con_Printf ("\n%s\n", Con_Quakebar(40)); //johnfitz + Con_Printf ("%c%s\n", 2, str); + +//johnfitz -- tell user which protocol this is + Con_Printf ("Using protocol %i\n", i); + +// first we go through and touch all of the precache data that still +// happens to be in the cache, so precaching something else doesn't +// needlessly purge it + +// precache models + memset (cl.model_precache, 0, sizeof(cl.model_precache)); + for (nummodels=1 ; ; nummodels++) + { + str = MSG_ReadString (); + if (!str[0]) + break; + if (nummodels==MAX_MODELS) + { + Con_Printf ("Server sent too many model precaches\n"); + return; + } + strcpy (model_precache[nummodels], str); + Mod_TouchModel (str); + } + + //johnfitz -- check for excessive models + if (nummodels >= 256) + Con_Warning ("%i models exceeds standard limit of 256.\n", nummodels); + //johnfitz + +// precache sounds + memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); + for (numsounds=1 ; ; numsounds++) + { + str = MSG_ReadString (); + if (!str[0]) + break; + if (numsounds==MAX_SOUNDS) + { + Con_Printf ("Server sent too many sound precaches\n"); + return; + } + strcpy (sound_precache[numsounds], str); + S_TouchSound (str); + } + + //johnfitz -- check for excessive sounds + if (numsounds >= 256) + Con_Warning ("%i sounds exceeds standard limit of 256.\n", numsounds); + //johnfitz + +// +// now we try to load everything else until a cache allocation fails +// + + for (i=1 ; imsgtime != cl.mtime[1]) + forcelink = true; // no previous frame to lerp from + else + forcelink = false; + + //johnfitz -- lerping + if (ent->msgtime + 0.2 < cl.mtime[0]) //more than 0.2 seconds since the last message (most entities think every 0.1 sec) + ent->lerpflags |= LERP_RESETANIM; //if we missed a think, we'd be lerping from the wrong frame + //johnfitz + + ent->msgtime = cl.mtime[0]; + + if (bits & U_MODEL) + { + modnum = MSG_ReadByte (); + if (modnum >= MAX_MODELS) + Host_Error ("CL_ParseModel: bad modnum"); + } + else + modnum = ent->baseline.modelindex; + + if (bits & U_FRAME) + ent->frame = MSG_ReadByte (); + else + ent->frame = ent->baseline.frame; + + if (bits & U_COLORMAP) + i = MSG_ReadByte(); + else + i = ent->baseline.colormap; + if (!i) + ent->colormap = vid.colormap; + else + { + if (i > cl.maxclients) + Sys_Error ("i >= cl.maxclients"); + ent->colormap = cl.scores[i-1].translations; + } + if (bits & U_SKIN) + skin = MSG_ReadByte(); + else + skin = ent->baseline.skin; + if (skin != ent->skinnum) { + ent->skinnum = skin; + if (num > 0 && num <= cl.maxclients) + R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin + } + if (bits & U_EFFECTS) + ent->effects = MSG_ReadByte(); + else + ent->effects = ent->baseline.effects; + +// shift the known values for interpolation + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + + if (bits & U_ORIGIN1) + ent->msg_origins[0][0] = MSG_ReadCoord (); + else + ent->msg_origins[0][0] = ent->baseline.origin[0]; + if (bits & U_ANGLE1) + ent->msg_angles[0][0] = MSG_ReadAngle(); + else + ent->msg_angles[0][0] = ent->baseline.angles[0]; + + if (bits & U_ORIGIN2) + ent->msg_origins[0][1] = MSG_ReadCoord (); + else + ent->msg_origins[0][1] = ent->baseline.origin[1]; + if (bits & U_ANGLE2) + ent->msg_angles[0][1] = MSG_ReadAngle(); + else + ent->msg_angles[0][1] = ent->baseline.angles[1]; + + if (bits & U_ORIGIN3) + ent->msg_origins[0][2] = MSG_ReadCoord (); + else + ent->msg_origins[0][2] = ent->baseline.origin[2]; + if (bits & U_ANGLE3) + ent->msg_angles[0][2] = MSG_ReadAngle(); + else + ent->msg_angles[0][2] = ent->baseline.angles[2]; + + //johnfitz -- lerping for movetype_step entities + if ( bits & U_STEP ) + { + ent->lerpflags |= LERP_MOVESTEP; + ent->forcelink = true; + } + else + ent->lerpflags &= ~LERP_MOVESTEP; + //johnfitz + + //johnfitz -- PROTOCOL_FITZQUAKE and PROTOCOL_NEHAHRA + if (cl.protocol == PROTOCOL_FITZQUAKE) + { + if (bits & U_ALPHA) + ent->alpha = MSG_ReadByte(); + else + ent->alpha = ent->baseline.alpha; + if (bits & U_FRAME2) + ent->frame = (ent->frame & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_MODEL2) + modnum = (modnum & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_LERPFINISH) + { + ent->lerpfinish = ent->msgtime + ((float)(MSG_ReadByte()) / 255); + ent->lerpflags |= LERP_FINISH; + } + else + ent->lerpflags &= ~LERP_FINISH; + } + else if (cl.protocol == PROTOCOL_NETQUAKE) + { + //HACK: if this bit is set, assume this is PROTOCOL_NEHAHRA + if (bits & U_TRANS) + { + float a,b; + + if (warn_about_nehahra_protocol) { + Con_Warning ("nonstandard update bit, assuming Nehahra protocol\n"); + warn_about_nehahra_protocol = false; + } + + a = MSG_ReadFloat(); + b = MSG_ReadFloat(); //alpha + if (a == 2) + MSG_ReadFloat(); //fullbright (not using this yet) + ent->alpha = ENTALPHA_ENCODE(b); + } + else + ent->alpha = ent->baseline.alpha; + } + //johnfitz + + //johnfitz -- moved here from above + model = cl.model_precache[modnum]; + if (model != ent->model) + { + ent->model = model; + // automatic animation (torches, etc) can be either all together + // or randomized + if (model) + { + if (model->synctype == ST_RAND) + ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; + else + ent->syncbase = 0.0; + } + else + forcelink = true; // hack to make null model players work + if (num > 0 && num <= cl.maxclients) + R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin + + ent->lerpflags |= LERP_RESETANIM; //johnfitz -- don't lerp animation across model changes + } + //johnfitz + + if ( forcelink ) + { // didn't have an update last message + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + VectorCopy (ent->msg_angles[0], ent->angles); + ent->forcelink = true; + } +} + +/* +================== +CL_ParseBaseline +================== +*/ +void CL_ParseBaseline (entity_t *ent, int version) //johnfitz -- added argument +{ + int i; + int bits; //johnfitz + + //johnfitz -- PROTOCOL_FITZQUAKE + bits = (version == 2) ? MSG_ReadByte() : 0; + ent->baseline.modelindex = (bits & B_LARGEMODEL) ? MSG_ReadShort() : MSG_ReadByte(); + ent->baseline.frame = (bits & B_LARGEFRAME) ? MSG_ReadShort() : MSG_ReadByte(); + //johnfitz + + ent->baseline.colormap = MSG_ReadByte(); + ent->baseline.skin = MSG_ReadByte(); + for (i=0 ; i<3 ; i++) + { + ent->baseline.origin[i] = MSG_ReadCoord (); + ent->baseline.angles[i] = MSG_ReadAngle (); + } + + ent->baseline.alpha = (bits & B_ALPHA) ? MSG_ReadByte() : ENTALPHA_DEFAULT; //johnfitz -- PROTOCOL_FITZQUAKE +} + + +/* +================== +CL_ParseClientdata + +Server information pertaining to this client only +================== +*/ +void CL_ParseClientdata (void) +{ + int i, j; + int bits; //johnfitz + + bits = (unsigned short)MSG_ReadShort (); //johnfitz -- read bits here isntead of in CL_ParseServerMessage() + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & SU_EXTEND1) + bits |= (MSG_ReadByte() << 16); + if (bits & SU_EXTEND2) + bits |= (MSG_ReadByte() << 24); + //johnfitz + + if (bits & SU_VIEWHEIGHT) + cl.viewheight = MSG_ReadChar (); + else + cl.viewheight = DEFAULT_VIEWHEIGHT; + + if (bits & SU_IDEALPITCH) + cl.idealpitch = MSG_ReadChar (); + else + cl.idealpitch = 0; + + VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1< cl.maxclients) + Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); + dest = cl.scores[slot].translations; + source = vid.colormap; + memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations)); + top = cl.scores[slot].colors & 0xf0; + bottom = (cl.scores[slot].colors &15)<<4; + R_TranslatePlayerSkin (slot); + + for (i=0 ; i= MAX_STATIC_ENTITIES) + Host_Error ("Too many static entities"); + + ent = &cl_static_entities[i]; + cl.num_statics++; + CL_ParseBaseline (ent, version); //johnfitz -- added second parameter + +// copy it to the current state + + ent->model = cl.model_precache[ent->baseline.modelindex]; + ent->lerpflags |= LERP_RESETANIM; //johnfitz -- lerping + ent->frame = ent->baseline.frame; + + ent->colormap = vid.colormap; + ent->skinnum = ent->baseline.skin; + ent->effects = ent->baseline.effects; + ent->alpha = ent->baseline.alpha; //johnfitz -- alpha + + VectorCopy (ent->baseline.origin, ent->origin); + VectorCopy (ent->baseline.angles, ent->angles); + R_AddEfrags (ent); +} + +/* +=================== +CL_ParseStaticSound +=================== +*/ +void CL_ParseStaticSound (int version) //johnfitz -- added argument +{ + vec3_t org; + int sound_num, vol, atten; + int i; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (version == 2) + sound_num = MSG_ReadShort (); + else + sound_num = MSG_ReadByte (); + //johnfitz + + vol = MSG_ReadByte (); + atten = MSG_ReadByte (); + + S_StaticSound (cl.sound_precache[sound_num], org, vol, atten); +} + + +#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); + +/* +===================== +CL_ParseServerMessage +===================== +*/ +void CL_ParseServerMessage (void) +{ + int cmd; + int i; + char *str; //johnfitz + int total, j, lastcmd; //johnfitz + +// +// if recording demos, copy the message out +// + if (cl_shownet.value == 1) + Con_Printf ("%i ",net_message.cursize); + else if (cl_shownet.value == 2) + Con_Printf ("------------------\n"); + + cl.onground = false; // unless the server says otherwise +// +// parse the message +// + MSG_BeginReading (); + + while (1) + { + if (msg_badread) + Host_Error ("CL_ParseServerMessage: Bad server message"); + + cmd = MSG_ReadByte (); + + if (cmd == -1) + { + SHOWNET("END OF MESSAGE"); + return; // end of message + } + + // if the high bit of the command byte is set, it is a fast update + if (cmd & U_SIGNAL) //johnfitz -- was 128, changed for clarity + { + SHOWNET("fast update"); + CL_ParseUpdate (cmd&127); + continue; + } + + SHOWNET(svc_strings[cmd]); + + // other commands + switch (cmd) + { + default: + Host_Error ("Illegible server message, previous was %s\n", svc_strings[lastcmd]); //johnfitz -- added svc_strings[lastcmd] + break; + + case svc_nop: +// Con_Printf ("svc_nop\n"); + break; + + case svc_time: + cl.mtime[1] = cl.mtime[0]; + cl.mtime[0] = MSG_ReadFloat (); + break; + + case svc_clientdata: + CL_ParseClientdata (); //johnfitz -- removed bits parameter, we will read this inside CL_ParseClientdata() + break; + + case svc_version: + i = MSG_ReadLong (); + //johnfitz -- support multiple protocols + if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) + Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); + cl.protocol = i; + //johnfitz + break; + + case svc_disconnect: + Host_EndGame ("Server disconnected\n"); + + case svc_print: + Con_Printf ("%s", MSG_ReadString ()); + break; + + case svc_centerprint: + //johnfitz -- log centerprints to console + str = MSG_ReadString (); + SCR_CenterPrint (str); + Con_LogCenterPrint (str); + //johnfitz + break; + + case svc_stufftext: + Cbuf_AddText (MSG_ReadString ()); + break; + + case svc_damage: + V_ParseDamage (); + break; + + case svc_serverinfo: + CL_ParseServerInfo (); + vid.recalc_refdef = true; // leave intermission full screen + break; + + case svc_setangle: + for (i=0 ; i<3 ; i++) + cl.viewangles[i] = MSG_ReadAngle (); + break; + + case svc_setview: + cl.viewentity = MSG_ReadShort (); + break; + + case svc_lightstyle: + i = MSG_ReadByte (); + if (i >= MAX_LIGHTSTYLES) + Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); + Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); + cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); + //johnfitz -- save extra info + if (cl_lightstyle[i].length) + { + total = 0; + cl_lightstyle[i].peak = 'a'; + for (j=0; j>3, i&7); + break; + + case svc_updatename: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); + strcpy (cl.scores[i].name, MSG_ReadString ()); + break; + + case svc_updatefrags: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); + cl.scores[i].frags = MSG_ReadShort (); + break; + + case svc_updatecolors: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); + cl.scores[i].colors = MSG_ReadByte (); + CL_NewTranslation (i); + break; + + case svc_particle: + R_ParseParticleEffect (); + break; + + case svc_spawnbaseline: + i = MSG_ReadShort (); + // must use CL_EntityNum() to force cl.num_entities up + CL_ParseBaseline (CL_EntityNum(i), 1); // johnfitz -- added second parameter + break; + + case svc_spawnstatic: + CL_ParseStatic (1); //johnfitz -- added parameter + break; + + case svc_temp_entity: + CL_ParseTEnt (); + break; + + case svc_setpause: + { + cl.paused = MSG_ReadByte (); + + if (cl.paused) + { + CDAudio_Pause (); + } + else + { + CDAudio_Resume (); + } + } + break; + + case svc_signonnum: + i = MSG_ReadByte (); + if (i <= cls.signon) + Host_Error ("Received signon %i when at %i", i, cls.signon); + cls.signon = i; + //johnfitz -- if signonnum==2, signon packet has been fully parsed, so check for excessive static ents and efrags + if (i == 2) + { + if (cl.num_statics > 128) + Con_Warning ("%i static entities exceeds standard limit of 128.\n", cl.num_statics); + R_CheckEfrags (); + } + //johnfitz + CL_SignonReply (); + break; + + case svc_killedmonster: + cl.stats[STAT_MONSTERS]++; + break; + + case svc_foundsecret: + cl.stats[STAT_SECRETS]++; + break; + + case svc_updatestat: + i = MSG_ReadByte (); + if (i < 0 || i >= MAX_CL_STATS) + Sys_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadLong ();; + break; + + case svc_spawnstaticsound: + CL_ParseStaticSound (1); //johnfitz -- added parameter + break; + + case svc_cdtrack: + cl.cdtrack = MSG_ReadByte (); + cl.looptrack = MSG_ReadByte (); + if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) + CDAudio_Play ((byte)cls.forcetrack, true); + else + CDAudio_Play ((byte)cl.cdtrack, true); + break; + + case svc_intermission: + cl.intermission = 1; + cl.completed_time = cl.time; + vid.recalc_refdef = true; // go to full screen + break; + + case svc_finale: + cl.intermission = 2; + cl.completed_time = cl.time; + vid.recalc_refdef = true; // go to full screen + //johnfitz -- log centerprints to console + str = MSG_ReadString (); + SCR_CenterPrint (str); + Con_LogCenterPrint (str); + //johnfitz + break; + + case svc_cutscene: + cl.intermission = 3; + cl.completed_time = cl.time; + vid.recalc_refdef = true; // go to full screen + //johnfitz -- log centerprints to console + str = MSG_ReadString (); + SCR_CenterPrint (str); + Con_LogCenterPrint (str); + //johnfitz + break; + + case svc_sellscreen: + Cmd_ExecuteString ("help", src_command); + break; + + //johnfitz -- new svc types + case svc_skybox: + Sky_LoadSkyBox (MSG_ReadString()); + break; + + case svc_bf: + Cmd_ExecuteString ("bf", src_command); + break; + + case svc_fog: + Fog_ParseServerMessage (); + break; + + case svc_spawnbaseline2: //PROTOCOL_FITZQUAKE + i = MSG_ReadShort (); + // must use CL_EntityNum() to force cl.num_entities up + CL_ParseBaseline (CL_EntityNum(i), 2); + break; + + case svc_spawnstatic2: //PROTOCOL_FITZQUAKE + CL_ParseStatic (2); + break; + + case svc_spawnstaticsound2: //PROTOCOL_FITZQUAKE + CL_ParseStaticSound (2); + break; + //johnfitz + } + + lastcmd = cmd; //johnfitz + } +} diff --git a/Quake/cl_tent.c b/Quake/cl_tent.c new file mode 100644 index 00000000..ea63497d --- /dev/null +++ b/Quake/cl_tent.c @@ -0,0 +1,364 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_tent.c -- client side temporary entities + +#include "quakedef.h" + +int num_temp_entities; +entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; +beam_t cl_beams[MAX_BEAMS]; + +sfx_t *cl_sfx_wizhit; +sfx_t *cl_sfx_knighthit; +sfx_t *cl_sfx_tink1; +sfx_t *cl_sfx_ric1; +sfx_t *cl_sfx_ric2; +sfx_t *cl_sfx_ric3; +sfx_t *cl_sfx_r_exp3; + +/* +================= +CL_ParseTEnt +================= +*/ +void CL_InitTEnts (void) +{ + cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); + cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); + cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); + cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); + cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); + cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); + cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); +} + +/* +================= +CL_ParseBeam +================= +*/ +void CL_ParseBeam (model_t *m) +{ + int ent; + vec3_t start, end; + beam_t *b; + int i; + + ent = MSG_ReadShort (); + + start[0] = MSG_ReadCoord (); + start[1] = MSG_ReadCoord (); + start[2] = MSG_ReadCoord (); + + end[0] = MSG_ReadCoord (); + end[1] = MSG_ReadCoord (); + end[2] = MSG_ReadCoord (); + +// override any beam with the same entity + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->entity == ent) + { + b->entity = ent; + b->model = m; + b->endtime = cl.time + 0.2; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + +// find a free beam + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = ent; + b->model = m; + b->endtime = cl.time + 0.2; + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + } + + //johnfitz -- less spammy overflow message + if (!dev_overflows.beams || dev_overflows.beams + CONSOLE_RESPAM_TIME < realtime ) + { + Con_Printf ("Beam list overflow!\n"); + dev_overflows.beams = realtime; + } + //johnfitz +} + +/* +================= +CL_ParseTEnt +================= +*/ +void CL_ParseTEnt (void) +{ + int type; + vec3_t pos; + dlight_t *dl; + int rnd; + int colorStart, colorLength; + + type = MSG_ReadByte (); + switch (type) + { + case TE_WIZSPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 20, 30); + S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); + break; + + case TE_KNIGHTSPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 226, 20); + S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); + break; + + case TE_SPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); +#ifdef GLTEST + Test_Spawn (pos); +#else + R_RunParticleEffect (pos, vec3_origin, 0, 10); +#endif + if ( rand() % 5 ) + S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + case TE_SUPERSPIKE: // super spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 0, 20); + + if ( rand() % 5 ) + S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + + case TE_GUNSHOT: // bullet hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 0, 20); + break; + + case TE_EXPLOSION: // rocket explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_ParticleExplosion (pos); + dl = CL_AllocDlight (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = cl.time + 0.5; + dl->decay = 300; + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_TAREXPLOSION: // tarbaby explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_BlobExplosion (pos); + + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_LIGHTNING1: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true)); + break; + + case TE_LIGHTNING2: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true)); + break; + + case TE_LIGHTNING3: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true)); + break; + +// PGM 01/21/97 + case TE_BEAM: // grappling hook beam + CL_ParseBeam (Mod_ForName("progs/beam.mdl", true)); + break; +// PGM 01/21/97 + + case TE_LAVASPLASH: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_LavaSplash (pos); + break; + + case TE_TELEPORT: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_TeleportSplash (pos); + break; + + case TE_EXPLOSION2: // color mapped explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + colorStart = MSG_ReadByte (); + colorLength = MSG_ReadByte (); + R_ParticleExplosion2 (pos, colorStart, colorLength); + dl = CL_AllocDlight (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = cl.time + 0.5; + dl->decay = 300; + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + default: + Sys_Error ("CL_ParseTEnt: bad type"); + } +} + + +/* +================= +CL_NewTempEntity +================= +*/ +entity_t *CL_NewTempEntity (void) +{ + entity_t *ent; + + if (cl_numvisedicts == MAX_VISEDICTS) + return NULL; + if (num_temp_entities == MAX_TEMP_ENTITIES) + return NULL; + ent = &cl_temp_entities[num_temp_entities]; + memset (ent, 0, sizeof(*ent)); + num_temp_entities++; + cl_visedicts[cl_numvisedicts] = ent; + cl_numvisedicts++; + + ent->colormap = vid.colormap; + return ent; +} + + +/* +================= +CL_UpdateTEnts +================= +*/ +void CL_UpdateTEnts (void) +{ + int i, j; //johnfitz -- use j instead of using i twice, so we don't corrupt memory + beam_t *b; + vec3_t dist, org; + float d; + entity_t *ent; + float yaw, pitch; + float forward; + + num_temp_entities = 0; + + srand ((int) (cl.time * 1000)); //johnfitz -- freeze beams when paused + +// update lightning + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + continue; + + // if coming from the player, update the start position + if (b->entity == cl.viewentity) + { + VectorCopy (cl_entities[cl.viewentity].origin, b->start); + } + + // calculate pitch and yaw + VectorSubtract (b->end, b->start, dist); + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (int) (atan2(dist[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + // add new entities for the lightning + VectorCopy (b->start, org); + d = VectorNormalize(dist); + while (d > 0) + { + ent = CL_NewTempEntity (); + if (!ent) + return; + VectorCopy (org, ent->origin); + ent->model = b->model; + ent->angles[0] = pitch; + ent->angles[1] = yaw; + ent->angles[2] = rand()%360; + + //johnfitz -- use j instead of using i twice, so we don't corrupt memory + for (j=0 ; j<3 ; j++) + org[j] += dist[j]*30; + d -= 30; + } + } +} diff --git a/Quake/client.h b/Quake/client.h new file mode 100644 index 00000000..ff217d39 --- /dev/null +++ b/Quake/client.h @@ -0,0 +1,369 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// client.h + +typedef struct +{ + vec3_t viewangles; + +// intended velocities + float forwardmove; + float sidemove; + float upmove; +} usercmd_t; + +typedef struct +{ + int length; + char map[MAX_STYLESTRING]; + char average; //johnfitz + char peak; //johnfitz +} lightstyle_t; + +typedef struct +{ + char name[MAX_SCOREBOARDNAME]; + float entertime; + int frags; + int colors; // two 4 bit fields + byte translations[VID_GRADES*256]; +} scoreboard_t; + +typedef struct +{ + int destcolor[3]; + int percent; // 0-256 +} cshift_t; + +#define CSHIFT_CONTENTS 0 +#define CSHIFT_DAMAGE 1 +#define CSHIFT_BONUS 2 +#define CSHIFT_POWERUP 3 +#define NUM_CSHIFTS 4 + +#define NAME_LENGTH 64 + + +// +// client_state_t should hold all pieces of the client state +// + +#define SIGNONS 4 // signon messages to receive before connected + +#define MAX_DLIGHTS 64 //johnfitz -- was 32 +typedef struct +{ + vec3_t origin; + float radius; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + vec3_t color; //johnfitz -- lit support via lordhavoc +} dlight_t; + + +#define MAX_BEAMS 32 //johnfitz -- was 24 +typedef struct +{ + int entity; + struct model_s *model; + float endtime; + vec3_t start, end; +} beam_t; + +#define MAX_EFRAGS 2048 //johnfitz -- was 640 + +#define MAX_MAPSTRING 2048 +#define MAX_DEMOS 8 +#define MAX_DEMONAME 16 + +typedef enum { +ca_dedicated, // a dedicated server with no ability to start a client +ca_disconnected, // full screen console with no connection +ca_connected // valid netcon, talking to a server +} cactive_t; + +// +// the client_static_t structure is persistant through an arbitrary number +// of server connections +// +typedef struct +{ + cactive_t state; + +// personalization data sent to server + char mapstring[MAX_QPATH]; + char spawnparms[MAX_MAPSTRING]; // to restart a level + +// demo loop control + int demonum; // -1 = don't play demos + char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing + +// demo recording info must be here, because record is started before +// entering a map (and clearing client_state_t) + qboolean demorecording; + qboolean demoplayback; + qboolean timedemo; + int forcetrack; // -1 = use normal cd track + FILE *demofile; + int td_lastframe; // to meter out one message a frame + int td_startframe; // host_framecount at start + float td_starttime; // realtime at second frame of timedemo + + +// connection information + int signon; // 0 to SIGNONS + struct qsocket_s *netcon; + sizebuf_t message; // writing buffer to send to server + +} client_static_t; + +extern client_static_t cls; + +// +// the client_state_t structure is wiped completely at every +// server signon +// +typedef struct +{ + int movemessages; // since connecting to this server + // throw out the first couple, so the player + // doesn't accidentally do something the + // first frame + usercmd_t cmd; // last command sent to the server + +// information for local display + int stats[MAX_CL_STATS]; // health, etc + int items; // inventory bit flags + float item_gettime[32]; // cl.time of aquiring item, for blinking + float faceanimtime; // use anim frame if cl.time < this + + cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups + cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types + +// the client maintains its own idea of view angles, which are +// sent to the server each frame. The server sets punchangle when +// the view is temporarliy offset, and an angle reset commands at the start +// of each level and after teleporting. + vec3_t mviewangles[2]; // during demo playback viewangles is lerped + // between these + vec3_t viewangles; + + vec3_t mvelocity[2]; // update by server, used for lean+bob + // (0 is newest) + vec3_t velocity; // lerped between mvelocity[0] and [1] + + vec3_t punchangle; // temporary offset + +// pitch drifting vars + float idealpitch; + float pitchvel; + qboolean nodrift; + float driftmove; + double laststop; + + float viewheight; + float crouch; // local amount for smoothing stepups + + qboolean paused; // send over by server + qboolean onground; + qboolean inwater; + + int intermission; // don't change view angle, full screen, etc + int completed_time; // latched at intermission start + + double mtime[2]; // the timestamp of last two messages + double time; // clients view of time, should be between + // servertime and oldservertime to generate + // a lerp point for other data + double oldtime; // previous cl.time, time-oldtime is used + // to decay light values and smooth step ups + + + float last_received_message; // (realtime) for net trouble icon + +// +// information that is static for the entire time connected to a server +// + struct model_s *model_precache[MAX_MODELS]; + struct sfx_s *sound_precache[MAX_SOUNDS]; + + char levelname[128]; // for display on solo scoreboard //johnfitz -- was 40. + int viewentity; // cl_entitites[cl.viewentity] = player + int maxclients; + int gametype; + +// refresh related state + struct model_s *worldmodel; // cl_entitites[0].model + struct efrag_s *free_efrags; + int num_entities; // held in cl_entities array + int num_statics; // held in cl_staticentities array + entity_t viewent; // the gun model + + int cdtrack, looptrack; // cd audio + +// frag scoreboard + scoreboard_t *scores; // [cl.maxclients] + + unsigned protocol; //johnfitz +} client_state_t; + + +// +// cvars +// +extern cvar_t cl_name; +extern cvar_t cl_color; + +extern cvar_t cl_upspeed; +extern cvar_t cl_forwardspeed; +extern cvar_t cl_backspeed; +extern cvar_t cl_sidespeed; + +extern cvar_t cl_movespeedkey; + +extern cvar_t cl_yawspeed; +extern cvar_t cl_pitchspeed; + +extern cvar_t cl_anglespeedkey; + +extern cvar_t cl_autofire; + +extern cvar_t cl_shownet; +extern cvar_t cl_nolerp; + +extern cvar_t cl_pitchdriftspeed; +extern cvar_t lookspring; +extern cvar_t lookstrafe; +extern cvar_t sensitivity; + +extern cvar_t m_pitch; +extern cvar_t m_yaw; +extern cvar_t m_forward; +extern cvar_t m_side; + + +#define MAX_TEMP_ENTITIES 256 //johnfitz -- was 64 +#define MAX_STATIC_ENTITIES 512 //johnfitz -- was 128 +#define MAX_VISEDICTS 1024 //johnfitz -- was 256 + +extern client_state_t cl; + +// FIXME, allocate dynamically +extern efrag_t cl_efrags[MAX_EFRAGS]; +extern entity_t cl_static_entities[MAX_STATIC_ENTITIES]; +extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +extern dlight_t cl_dlights[MAX_DLIGHTS]; +extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; +extern beam_t cl_beams[MAX_BEAMS]; +extern entity_t *cl_visedicts[MAX_VISEDICTS]; +extern int cl_numvisedicts; + +extern entity_t *cl_entities; //johnfitz -- was a static array, now on hunk +extern int cl_max_edicts; //johnfitz -- only changes when new map loads + +//============================================================================= + +// +// cl_main +// +dlight_t *CL_AllocDlight (int key); +void CL_DecayLights (void); + +void CL_Init (void); + +void CL_EstablishConnection (char *host); +void CL_Signon1 (void); +void CL_Signon2 (void); +void CL_Signon3 (void); +void CL_Signon4 (void); + +void CL_Disconnect (void); +void CL_Disconnect_f (void); +void CL_NextDemo (void); + +// +// cl_input +// +typedef struct +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +extern kbutton_t in_mlook, in_klook; +extern kbutton_t in_strafe; +extern kbutton_t in_speed; + +void CL_InitInput (void); +void CL_SendCmd (void); +void CL_SendMove (usercmd_t *cmd); + +void CL_ParseTEnt (void); +void CL_UpdateTEnts (void); + +void CL_ClearState (void); + + +int CL_ReadFromServer (void); +void CL_WriteToServer (usercmd_t *cmd); +void CL_BaseMove (usercmd_t *cmd); + + +float CL_KeyState (kbutton_t *key); +char *Key_KeynumToString (int keynum); + +// +// cl_demo.c +// +void CL_StopPlayback (void); +int CL_GetMessage (void); + +void CL_Stop_f (void); +void CL_Record_f (void); +void CL_PlayDemo_f (void); +void CL_TimeDemo_f (void); + +// +// cl_parse.c +// +void CL_ParseServerMessage (void); +void CL_NewTranslation (int slot); + +// +// view +// +void V_StartPitchDrift (void); +void V_StopPitchDrift (void); + +void V_RenderView (void); +//void V_UpdatePalette (void); //johnfitz +void V_Register (void); +void V_ParseDamage (void); +void V_SetContentsColor (int contents); + + +// +// cl_tent +// +void CL_InitTEnts (void); +void CL_SignonReply (void); diff --git a/Quake/cmd.c b/Quake/cmd.c new file mode 100644 index 00000000..4115638f --- /dev/null +++ b/Quake/cmd.c @@ -0,0 +1,797 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cmd.c -- Quake script command processing module + +#include "quakedef.h" + +void Cmd_ForwardToServer (void); + +#define MAX_ALIAS_NAME 32 + +#define CMDLINE_LENGTH 256 //johnfitz -- mirrored in common.c + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +cmdalias_t *cmd_alias; + +int trashtest; +int *trashspot; + +qboolean cmd_wait; + +//============================================================================= + +/* +============ +Cmd_Wait_f + +Causes execution of the remainder of the command buffer to be delayed until +next frame. This allows commands like: +bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" +============ +*/ +void Cmd_Wait_f (void) +{ + cmd_wait = true; +} + +/* +============================================================================= + + COMMAND BUFFER + +============================================================================= +*/ + +sizebuf_t cmd_text; + +/* +============ +Cbuf_Init +============ +*/ +void Cbuf_Init (void) +{ + SZ_Alloc (&cmd_text, 8192); // space for commands and script files +} + + +/* +============ +Cbuf_AddText + +Adds command text at the end of the buffer +============ +*/ +void Cbuf_AddText (char *text) +{ + int l; + + l = Q_strlen (text); + + if (cmd_text.cursize + l >= cmd_text.maxsize) + { + Con_Printf ("Cbuf_AddText: overflow\n"); + return; + } + + SZ_Write (&cmd_text, text, Q_strlen (text)); +} + + +/* +============ +Cbuf_InsertText + +Adds command text immediately after the current command +Adds a \n to the text +FIXME: actually change the command buffer to do less copying +============ +*/ +void Cbuf_InsertText (char *text) +{ + char *temp; + int templen; + +// copy off any commands still remaining in the exec buffer + templen = cmd_text.cursize; + if (templen) + { + temp = Z_Malloc (templen); + Q_memcpy (temp, cmd_text.data, templen); + SZ_Clear (&cmd_text); + } + else + temp = NULL; // shut up compiler + +// add the entire text of the file + Cbuf_AddText (text); + +// add the copied off data + if (templen) + { + SZ_Write (&cmd_text, temp, templen); + Z_Free (temp); + } +} + +/* +============ +Cbuf_Execute +============ +*/ +void Cbuf_Execute (void) +{ + int i; + char *text; + char line[1024]; + int quotes; + + while (cmd_text.cursize) + { +// find a \n or ; line break + text = (char *)cmd_text.data; + + quotes = 0; + for (i=0 ; i< cmd_text.cursize ; i++) + { + if (text[i] == '"') + quotes++; + if ( !(quotes&1) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + + memcpy (line, text, i); + line[i] = 0; + +// delete the text from the command buffer and move remaining commands down +// this is necessary because commands (exec, alias) can insert data at the +// beginning of the text buffer + + if (i == cmd_text.cursize) + cmd_text.cursize = 0; + else + { + i++; + cmd_text.cursize -= i; + Q_memcpy (text, text+i, cmd_text.cursize); + } + +// execute the command line + Cmd_ExecuteString (line, src_command); + + if (cmd_wait) + { // skip out while text still remains in buffer, leaving it + // for next frame + cmd_wait = false; + break; + } + } +} + +/* +============================================================================== + + SCRIPT COMMANDS + +============================================================================== +*/ + +/* +=============== +Cmd_StuffCmds_f -- johnfitz -- rewritten to read the "cmdline" cvar, for use with dynamic mod loading + +Adds command line parameters as script statements +Commands lead with a +, and continue until a - or another + +quake +prog jctest.qp +cmd amlev1 +quake -nosound +cmd amlev1 +=============== +*/ +void Cmd_StuffCmds_f (void) +{ + extern cvar_t cmdline; + char cmds[CMDLINE_LENGTH]; + int i, j, plus; + + plus = true; + j = 0; + for (i=0; cmdline.string[i]; i++) + { + if (cmdline.string[i] == '+') + { + plus = true; + if (j > 0) + { + cmds[j-1] = ';'; + cmds[j++] = ' '; + } + } + else if (cmdline.string[i] == '-' && + (i==0 || cmdline.string[i-1] == ' ')) //johnfitz -- allow hypenated map names with +map + plus = false; + else if (plus) + cmds[j++] = cmdline.string[i]; + } + cmds[j] = 0; + + Cbuf_InsertText (cmds); +} + + +/* +=============== +Cmd_Exec_f +=============== +*/ +void Cmd_Exec_f (void) +{ + char *f; + int mark; + + if (Cmd_Argc () != 2) + { + Con_Printf ("exec : execute a script file\n"); + return; + } + + mark = Hunk_LowMark (); + f = (char *)COM_LoadHunkFile (Cmd_Argv(1)); + if (!f) + { + Con_Printf ("couldn't exec %s\n",Cmd_Argv(1)); + return; + } + Con_Printf ("execing %s\n",Cmd_Argv(1)); + + Cbuf_InsertText (f); + Hunk_FreeToLowMark (mark); +} + + +/* +=============== +Cmd_Echo_f + +Just prints the rest of the line to the console +=============== +*/ +void Cmd_Echo_f (void) +{ + int i; + + for (i=1 ; inext, i++) + Con_SafePrintf (" %s: %s", a->name, a->value); + if (i) + Con_SafePrintf ("%i alias command(s)\n", i); + else + Con_SafePrintf ("no alias commands found\n"); + break; + case 2: //output current alias string + for (a = cmd_alias ; a ; a=a->next) + if (!strcmp(Cmd_Argv(1), a->name)) + Con_Printf (" %s: %s", a->name, a->value); + break; + default: //set alias string + s = Cmd_Argv(1); + if (strlen(s) >= MAX_ALIAS_NAME) + { + Con_Printf ("Alias name is too long\n"); + return; + } + + // if the alias allready exists, reuse it + for (a = cmd_alias ; a ; a=a->next) + { + if (!strcmp(s, a->name)) + { + Z_Free (a->value); + break; + } + } + + if (!a) + { + a = Z_Malloc (sizeof(cmdalias_t)); + a->next = cmd_alias; + cmd_alias = a; + } + strcpy (a->name, s); + + // copy the rest of the command line + cmd[0] = 0; // start out with a null string + c = Cmd_Argc(); + for (i=2 ; i< c ; i++) + { + strcat (cmd, Cmd_Argv(i)); + if (i != c) + strcat (cmd, " "); + } + strcat (cmd, "\n"); + + a->value = CopyString (cmd); + break; + } +} + +/* +=============== +Cmd_Unalias_f -- johnfitz +=============== +*/ +void Cmd_Unalias_f (void) +{ + cmdalias_t *a, *prev; + + switch (Cmd_Argc()) + { + default: + case 1: + Con_Printf("unalias : delete alias\n"); + break; + case 2: + for (prev = a = cmd_alias; a; a = a->next) + { + if (!strcmp(Cmd_Argv(1), a->name)) + { + prev->next = a->next; + Z_Free (a->value); + Z_Free (a); + prev = a; + return; + } + prev = a; + } + break; + } +} + +/* +=============== +Cmd_Unaliasall_f -- johnfitz +=============== +*/ +void Cmd_Unaliasall_f (void) +{ + cmdalias_t *blah; + + while (cmd_alias) + { + blah = cmd_alias->next; + Z_Free(cmd_alias->value); + Z_Free(cmd_alias); + cmd_alias = blah; + } +} + +/* +============================================================================= + + COMMAND EXECUTION + +============================================================================= +*/ + +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; +} cmd_function_t; + + +#define MAX_ARGS 80 + +static int cmd_argc; +static char *cmd_argv[MAX_ARGS]; +static char *cmd_null_string = ""; +static char *cmd_args = NULL; + +cmd_source_t cmd_source; + +//johnfitz -- better tab completion +//static cmd_function_t *cmd_functions; // possible commands to execute +cmd_function_t *cmd_functions; // possible commands to execute +//johnfitz + +/* +============ +Cmd_List_f -- johnfitz +============ +*/ +void Cmd_List_f (void) +{ + cmd_function_t *cmd; + char *partial; + int len, count; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = Q_strlen(partial); + } + else + { + partial = NULL; + len = 0; + } + + count=0; + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (partial && Q_strncmp (partial,cmd->name, len)) + { + continue; + } + Con_SafePrintf (" %s\n", cmd->name); + count++; + } + + Con_SafePrintf ("%i commands", count); + if (partial) + { + Con_SafePrintf (" beginning with \"%s\"", partial); + } + Con_SafePrintf ("\n"); +} + +/* +============ +Cmd_Init +============ +*/ +void Cmd_Init (void) +{ + Cmd_AddCommand ("cmdlist", Cmd_List_f); //johnfitz + Cmd_AddCommand ("unalias", Cmd_Unalias_f); //johnfitz + Cmd_AddCommand ("unaliasall", Cmd_Unaliasall_f); //johnfitz + + Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f); + Cmd_AddCommand ("exec",Cmd_Exec_f); + Cmd_AddCommand ("echo",Cmd_Echo_f); + Cmd_AddCommand ("alias",Cmd_Alias_f); + Cmd_AddCommand ("cmd", Cmd_ForwardToServer); + Cmd_AddCommand ("wait", Cmd_Wait_f); +} + +/* +============ +Cmd_Argc +============ +*/ +int Cmd_Argc (void) +{ + return cmd_argc; +} + +/* +============ +Cmd_Argv +============ +*/ +char *Cmd_Argv (int arg) +{ + if ( (unsigned)arg >= cmd_argc ) + return cmd_null_string; + return cmd_argv[arg]; +} + +/* +============ +Cmd_Args +============ +*/ +char *Cmd_Args (void) +{ + return cmd_args; +} + + +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +============ +*/ +void Cmd_TokenizeString (char *text) +{ + int i; + +// clear the args from the last string + for (i=0 ; inext) + { + if (!Q_strcmp (cmd_name, cmd->name)) + { + Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); + return; + } + } + + cmd = Hunk_Alloc (sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->function = function; + + //johnfitz -- insert each entry in alphabetical order + if (cmd_functions == NULL || strcmp(cmd->name, cmd_functions->name) < 0) //insert at front + { + cmd->next = cmd_functions; + cmd_functions = cmd; + } + else //insert later + { + prev = cmd_functions; + cursor = cmd_functions->next; + while ((cursor != NULL) && (strcmp(cmd->name, cursor->name) > 0)) + { + prev = cursor; + cursor = cursor->next; + } + cmd->next = prev->next; + prev->next = cmd; + } + //johnfitz +} + +/* +============ +Cmd_Exists +============ +*/ +qboolean Cmd_Exists (char *cmd_name) +{ + cmd_function_t *cmd; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcmp (cmd_name,cmd->name)) + return true; + } + + return false; +} + + + +/* +============ +Cmd_CompleteCommand +============ +*/ +char *Cmd_CompleteCommand (char *partial) +{ + cmd_function_t *cmd; + int len; + + len = Q_strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncmp (partial,cmd->name, len)) + return cmd->name; + + return NULL; +} + +/* +============ +Cmd_ExecuteString + +A complete command line has been parsed, so try to execute it +FIXME: lookupnoadd the token to speed search? +============ +*/ +void Cmd_ExecuteString (char *text, cmd_source_t src) +{ + cmd_function_t *cmd; + cmdalias_t *a; + + cmd_source = src; + Cmd_TokenizeString (text); + +// execute the command line + if (!Cmd_Argc()) + return; // no tokens + +// check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcasecmp (cmd_argv[0],cmd->name)) + { + cmd->function (); + return; + } + } + +// check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!Q_strcasecmp (cmd_argv[0], a->name)) + { + Cbuf_InsertText (a->value); + return; + } + } + +// check cvars + if (!Cvar_Command ()) + Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0)); + +} + + +/* +=================== +Cmd_ForwardToServer + +Sends the entire command line over to the server +=================== +*/ +void Cmd_ForwardToServer (void) +{ + if (cls.state != ca_connected) + { + Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); + return; + } + + if (cls.demoplayback) + return; // not really connected + + MSG_WriteByte (&cls.message, clc_stringcmd); + if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0) + { + SZ_Print (&cls.message, Cmd_Argv(0)); + SZ_Print (&cls.message, " "); + } + if (Cmd_Argc() > 1) + SZ_Print (&cls.message, Cmd_Args()); + else + SZ_Print (&cls.message, "\n"); +} + + +/* +================ +Cmd_CheckParm + +Returns the position (1 to argc-1) in the command's argument list +where the given parameter apears, or 0 if not present +================ +*/ + +int Cmd_CheckParm (char *parm) +{ + int i; + + if (!parm) + Sys_Error ("Cmd_CheckParm: NULL"); + + for (i = 1; i < Cmd_Argc (); i++) + if (! Q_strcasecmp (parm, Cmd_Argv (i))) + return i; + + return 0; +} diff --git a/Quake/cmd.h b/Quake/cmd.h new file mode 100644 index 00000000..a495c633 --- /dev/null +++ b/Quake/cmd.h @@ -0,0 +1,121 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// cmd.h -- Command buffer and command execution + +//=========================================================================== + +/* + +Any number of commands can be added in a frame, from several different sources. +Most commands come from either keybindings or console line input, but remote +servers can also send across commands and entire text files can be execed. + +The + command line options are also added to the command buffer. + +The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); + +*/ + +void Cbuf_Init (void); +// allocates an initial text buffer that will grow as needed + +void Cbuf_AddText (char *text); +// as new commands are generated from the console or keybindings, +// the text is added to the end of the command buffer. + +void Cbuf_InsertText (char *text); +// when a command wants to issue other commands immediately, the text is +// inserted at the beginning of the buffer, before any remaining unexecuted +// commands. + +void Cbuf_Execute (void); +// Pulls off \n terminated lines of text from the command buffer and sends +// them through Cmd_ExecuteString. Stops when the buffer is empty. +// Normally called once per frame, but may be explicitly invoked. +// Do not call inside a command function! + +//=========================================================================== + +/* + +Command execution takes a null terminated string, breaks it into tokens, +then searches for a command or variable that matches the first token. + +Commands can come from three sources, but the handler functions may choose +to dissallow the action or forward it to a remote server if the source is +not apropriate. + +*/ + +typedef void (*xcommand_t) (void); + +typedef enum +{ + src_client, // came in over a net connection as a clc_stringcmd + // host_client will be valid during this state. + src_command // from the command buffer +} cmd_source_t; + +extern cmd_source_t cmd_source; + +void Cmd_Init (void); + +void Cmd_AddCommand (char *cmd_name, xcommand_t function); +// called by the init functions of other parts of the program to +// register commands and functions to call for them. +// The cmd_name is referenced later, so it should not be in temp memory + +qboolean Cmd_Exists (char *cmd_name); +// used by the cvar code to check for cvar / command name overlap + +char *Cmd_CompleteCommand (char *partial); +// attempts to match a partial command for automatic command line completion +// returns NULL if nothing fits + +int Cmd_Argc (void); +char *Cmd_Argv (int arg); +char *Cmd_Args (void); +// The functions that execute commands get their parameters with these +// functions. Cmd_Argv () will return an empty string, not a NULL +// if arg > argc, so string operations are allways safe. + +int Cmd_CheckParm (char *parm); +// Returns the position (1 to argc-1) in the command's argument list +// where the given parameter apears, or 0 if not present + +void Cmd_TokenizeString (char *text); +// Takes a null terminated string. Does not need to be /n terminated. +// breaks the string up into arg tokens. + +void Cmd_ExecuteString (char *text, cmd_source_t src); +// Parses a single line of text into arguments and tries to execute it. +// The text can come from the command buffer, a remote client, or stdin. + +void Cmd_ForwardToServer (void); +// adds the current command line as a clc_stringcmd to the client message. +// things like godmode, noclip, etc, are commands directed to the server, +// so when they are typed in at the console, they will need to be forwarded. + +void Cmd_Print (char *text); +// used by command functions to send output to either the graphics console or +// passed as a print message to the client + diff --git a/Quake/common.c b/Quake/common.c new file mode 100644 index 00000000..1da41e35 --- /dev/null +++ b/Quake/common.c @@ -0,0 +1,1886 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// common.c -- misc functions used in client and server + +#include "quakedef.h" + +#define NUM_SAFE_ARGVS 7 + +static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1]; +static char *argvdummy = " "; + +static char *safeargvs[NUM_SAFE_ARGVS] = + {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"}; + +cvar_t registered = {"registered","0"}; +cvar_t cmdline = {"cmdline","", false, true}; + +qboolean com_modified; // set true if using non-id files + +int com_nummissionpacks; //johnfitz + +qboolean proghack; + +int static_registered = 1; // only for startup check, then set + +qboolean msg_suppress_1 = 0; + +void COM_InitFilesystem (void); + +// if a packfile directory differs from this, it is assumed to be hacked +#define PAK0_COUNT 339 +#define PAK0_CRC 32981 + +char com_token[1024]; +int com_argc; +char **com_argv; + +#define CMDLINE_LENGTH 256 //johnfitz -- mirrored in cmd.c +char com_cmdline[CMDLINE_LENGTH]; + +qboolean standard_quake = true, rogue, hipnotic; + +// this graphic needs to be in the pak file to use registered features +unsigned short pop[] = +{ + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000 +,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000 +,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600 +,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563 +,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564 +,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564 +,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563 +,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500 +,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200 +,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000 +,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000 +}; + +/* + + +All 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. + +The "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 only used during +filesystem initialization. + +The "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. + +The "cache directory" is only used during development to save network bandwidth, +especially over ISDN / T1 lines. If there is a cache directory specified, when +a file is found by the normal search path, it will be mirrored into the cache +directory, then opened there. + +FIXME: +The 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. + +*/ + +//============================================================================ + + +// ClearLink is used for new headnodes +void ClearLink (link_t *l) +{ + l->prev = l->next = l; +} + +void RemoveLink (link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; +} + +void InsertLinkBefore (link_t *l, link_t *before) +{ + l->next = before; + l->prev = before->prev; + l->prev->next = l; + l->next->prev = l; +} +void InsertLinkAfter (link_t *l, link_t *after) +{ + l->next = after->next; + l->prev = after; + l->prev->next = l; + l->next->prev = l; +} + +/* +============================================================================ + + LIBRARY REPLACEMENT FUNCTIONS + +============================================================================ +*/ + +void Q_memset (void *dest, int fill, int count) +{ + int i; + + if ( (((long)dest | count) & 3) == 0) + { + count >>= 2; + fill = fill | (fill<<8) | (fill<<16) | (fill<<24); + for (i=0 ; i>=2; + for (i=0 ; i= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + if (!c1) + return 0; // strings are equal +// s1++; +// s2++; + } + + return -1; +} + +int Q_strcasecmp (char *s1, char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +int Q_atoi (char *str) +{ + int val; + int sign; + int c; + + if (*str == '-') + { + sign = -1; + str++; + } + else + sign = 1; + + val = 0; + +// +// check for hex +// + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val<<4) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val<<4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val<<4) + c - 'A' + 10; + else + return val*sign; + } + } + +// +// check for character +// + if (str[0] == '\'') + { + return sign * str[1]; + } + +// +// assume decimal +// + while (1) + { + c = *str++; + if (c <'0' || c > '9') + return val*sign; + val = val*10 + c - '0'; + } + + return 0; +} + + +float Q_atof (char *str) +{ + double val; + int sign; + int c; + int decimal, total; + + if (*str == '-') + { + sign = -1; + str++; + } + else + sign = 1; + + val = 0; + +// +// check for hex +// + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val*16) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val*16) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val*16) + c - 'A' + 10; + else + return val*sign; + } + } + +// +// check for character +// + if (str[0] == '\'') + { + return sign * str[1]; + } + +// +// assume decimal +// + decimal = -1; + total = 0; + while (1) + { + c = *str++; + if (c == '.') + { + decimal = total; + continue; + } + if (c <'0' || c > '9') + break; + val = val*10 + c - '0'; + total++; + } + + if (decimal == -1) + return val*sign; + while (total > decimal) + { + val /= 10; + total--; + } + + return val*sign; +} + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +qboolean bigendien; + +short (*BigShort) (short l); +short (*LittleShort) (short l); +int (*BigLong) (int l); +int (*LittleLong) (int l); +float (*BigFloat) (float l); +float (*LittleFloat) (float l); + +short ShortSwap (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short ShortNoSwap (short l) +{ + return l; +} + +int LongSwap (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LongNoSwap (int l) +{ + return l; +} + +float FloatSwap (float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + return dat2.f; +} + +float FloatNoSwap (float f) +{ + return f; +} + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +// +// writing functions +// + +void MSG_WriteChar (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < -128 || c > 127) + Sys_Error ("MSG_WriteChar: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteByte (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < 0 || c > 255) + Sys_Error ("MSG_WriteByte: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteShort (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < ((short)0x8000) || c > (short)0x7fff) + Sys_Error ("MSG_WriteShort: range error"); +#endif + + buf = SZ_GetSpace (sb, 2); + buf[0] = c&0xff; + buf[1] = c>>8; +} + +void MSG_WriteLong (sizebuf_t *sb, int c) +{ + byte *buf; + + buf = SZ_GetSpace (sb, 4); + buf[0] = c&0xff; + buf[1] = (c>>8)&0xff; + buf[2] = (c>>16)&0xff; + buf[3] = c>>24; +} + +void MSG_WriteFloat (sizebuf_t *sb, float f) +{ + union + { + float f; + int l; + } dat; + + + dat.f = f; + dat.l = LittleLong (dat.l); + + SZ_Write (sb, &dat.l, 4); +} + +void MSG_WriteString (sizebuf_t *sb, char *s) +{ + if (!s) + SZ_Write (sb, "", 1); + else + SZ_Write (sb, s, Q_strlen(s)+1); +} + +//johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096 +void MSG_WriteCoord16 (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, Q_rint(f*8)); +} + +//johnfitz -- 16.8 fixed point coords, max range +-32768 +void MSG_WriteCoord24 (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, f); + MSG_WriteByte (sb, (int)(f*255)%255); +} + +//johnfitz -- 32-bit float coords +void MSG_WriteCoord32f (sizebuf_t *sb, float f) +{ + MSG_WriteFloat (sb, f); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f) +{ + MSG_WriteCoord16 (sb, f); +} + +void MSG_WriteAngle (sizebuf_t *sb, float f) +{ + MSG_WriteByte (sb, Q_rint(f * 256.0 / 360.0) & 255); //johnfitz -- use Q_rint instead of (int) +} + +//johnfitz -- for PROTOCOL_FITZQUAKE +void MSG_WriteAngle16 (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, Q_rint(f * 65536.0 / 360.0) & 65535); +} +//johnfitz + +// +// reading functions +// +int msg_readcount; +qboolean msg_badread; + +void MSG_BeginReading (void) +{ + msg_readcount = 0; + msg_badread = false; +} + +// returns -1 and sets msg_badread if no more characters are available +int MSG_ReadChar (void) +{ + int c; + + if (msg_readcount+1 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (signed char)net_message.data[msg_readcount]; + msg_readcount++; + + return c; +} + +int MSG_ReadByte (void) +{ + int c; + + if (msg_readcount+1 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (unsigned char)net_message.data[msg_readcount]; + msg_readcount++; + + return c; +} + +int MSG_ReadShort (void) +{ + int c; + + if (msg_readcount+2 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (short)(net_message.data[msg_readcount] + + (net_message.data[msg_readcount+1]<<8)); + + msg_readcount += 2; + + return c; +} + +int MSG_ReadLong (void) +{ + int c; + + if (msg_readcount+4 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = net_message.data[msg_readcount] + + (net_message.data[msg_readcount+1]<<8) + + (net_message.data[msg_readcount+2]<<16) + + (net_message.data[msg_readcount+3]<<24); + + msg_readcount += 4; + + return c; +} + +float MSG_ReadFloat (void) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = net_message.data[msg_readcount]; + dat.b[1] = net_message.data[msg_readcount+1]; + dat.b[2] = net_message.data[msg_readcount+2]; + dat.b[3] = net_message.data[msg_readcount+3]; + msg_readcount += 4; + + dat.l = LittleLong (dat.l); + + return dat.f; +} + +char *MSG_ReadString (void) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +//johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096 +float MSG_ReadCoord16 (void) +{ + return MSG_ReadShort() * (1.0/8); +} + +//johnfitz -- 16.8 fixed point coords, max range +-32768 +float MSG_ReadCoord24 (void) +{ + return MSG_ReadShort() + MSG_ReadByte() * (1.0/255); +} + +//johnfitz -- 32-bit float coords +float MSG_ReadCoord32f (void) +{ + return MSG_ReadFloat(); +} + +float MSG_ReadCoord (void) +{ + return MSG_ReadCoord16(); +} + +float MSG_ReadAngle (void) +{ + return MSG_ReadChar() * (360.0/256); +} + +//johnfitz -- for PROTOCOL_FITZQUAKE +float MSG_ReadAngle16 (void) +{ + return MSG_ReadShort() * (360.0 / 65536); +} +//johnfitz + + + +//=========================================================================== + +void SZ_Alloc (sizebuf_t *buf, int startsize) +{ + if (startsize < 256) + startsize = 256; + buf->data = Hunk_AllocName (startsize, "sizebuf"); + buf->maxsize = startsize; + buf->cursize = 0; +} + + +void SZ_Free (sizebuf_t *buf) +{ +// Z_Free (buf->data); +// buf->data = NULL; +// buf->maxsize = 0; + buf->cursize = 0; +} + +void SZ_Clear (sizebuf_t *buf) +{ + buf->cursize = 0; +} + +void *SZ_GetSpace (sizebuf_t *buf, int length) +{ + void *data; + + if (buf->cursize + length > buf->maxsize) + { + if (!buf->allowoverflow) + Sys_Error ("SZ_GetSpace: overflow without allowoverflow set"); + + if (length > buf->maxsize) + Sys_Error ("SZ_GetSpace: %i is > full buffer size", length); + + buf->overflowed = true; + Con_Printf ("SZ_GetSpace: overflow"); + SZ_Clear (buf); + } + + data = buf->data + buf->cursize; + buf->cursize += length; + + return data; +} + +void SZ_Write (sizebuf_t *buf, void *data, int length) +{ + Q_memcpy (SZ_GetSpace(buf,length),data,length); +} + +void SZ_Print (sizebuf_t *buf, char *data) +{ + int len; + + len = Q_strlen(data)+1; + +// byte * cast to keep VC++ happy + if (buf->data[buf->cursize-1]) + Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0 + else + Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0 +} + + +//============================================================================ + + +/* +============ +COM_SkipPath +============ +*/ +char *COM_SkipPath (char *pathname) +{ + char *last; + + last = pathname; + while (*pathname) + { + if (*pathname=='/') + last = pathname+1; + pathname++; + } + return last; +} + +/* +============ +COM_StripExtension +============ +*/ +void COM_StripExtension (char *in, char *out) +{ + while (*in && *in != '.') + *out++ = *in++; + *out = 0; +} + +/* +============ +COM_FileExtension +============ +*/ +char *COM_FileExtension (char *in) +{ + static char exten[8]; + int i; + + while (*in && *in != '.') + in++; + if (!*in) + return ""; + in++; + for (i=0 ; i<7 && *in ; i++,in++) + exten[i] = *in; + exten[i] = 0; + return exten; +} + +/* +============ +COM_FileBase +============ +*/ +void COM_FileBase (char *in, char *out) +{ + char *s, *s2; + + s = in + strlen(in) - 1; + + while (s != in && *s != '.') + s--; + + for (s2 = s ; *s2 && *s2 != '/' ; s2--) + ; + + if (s-s2 < 2) + strcpy (out,"?model?"); + else + { + s--; + strncpy (out,s2+1, s-s2); + out[s-s2] = 0; + } +} + + +/* +================== +COM_DefaultExtension +================== +*/ +void COM_DefaultExtension (char *path, char *extension) +{ + char *src; +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + + +/* +================ +COM_CheckParm + +Returns the position (1 to argc-1) in the program's argument list +where the given parameter apears, or 0 if not present +================ +*/ +int COM_CheckParm (char *parm) +{ + int i; + + for (i=1 ; inext) + { + if (s->pack) + { + Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); + } + else + Con_Printf ("%s\n", s->filename); + } +} + +/* +============ +COM_WriteFile + +The filename will be prefixed by the current game directory +============ +*/ +void COM_WriteFile (char *filename, void *data, int len) +{ + int handle; + char name[MAX_OSPATH]; + + Sys_mkdir (com_gamedir); //johnfitz -- if we've switched to a nonexistant gamedir, create it now so we don't crash + + sprintf (name, "%s/%s", com_gamedir, filename); + + handle = Sys_FileOpenWrite (name); + if (handle == -1) + { + Sys_Printf ("COM_WriteFile: failed on %s\n", name); + return; + } + + Sys_Printf ("COM_WriteFile: %s\n", name); + Sys_FileWrite (handle, data, len); + Sys_FileClose (handle); +} + +/* +============ +COM_CreatePath +============ +*/ +void COM_CreatePath (char *path) +{ + char *ofs; + + for (ofs = path+1 ; *ofs ; ofs++) + { + if (*ofs == '/') + { // create the directory + *ofs = 0; + Sys_mkdir (path); + *ofs = '/'; + } + } +} + +/* +=========== +COM_CopyFile + +Copies a file over from the net to the local cache, creating any directories +needed. This is for the convenience of developers using ISDN from home. +=========== +*/ +void COM_CopyFile (char *netpath, char *cachepath) +{ + int in, out; + int remaining, count; + char buf[4096]; + + remaining = Sys_FileOpenRead (netpath, &in); + COM_CreatePath (cachepath); // create directories up to the cache file + out = Sys_FileOpenWrite (cachepath); + + while (remaining) + { + if (remaining < sizeof(buf)) + count = remaining; + else + count = sizeof(buf); + Sys_FileRead (in, buf, count); + Sys_FileWrite (out, buf, count); + remaining -= count; + } + + Sys_FileClose (in); + Sys_FileClose (out); +} + +/* +=========== +COM_FindFile + +Finds the file in the search path. +Sets com_filesize and one of handle or file +=========== +*/ +int COM_FindFile (char *filename, int *handle, FILE **file) +{ + searchpath_t *search; + char netpath[MAX_OSPATH]; + char cachepath[MAX_OSPATH]; + pack_t *pak; + int i; + int findtime, cachetime; + + if (file && handle) + Sys_Error ("COM_FindFile: both handle and file set"); + if (!file && !handle) + Sys_Error ("COM_FindFile: neither handle or file set"); + +// +// search through the path, one element at a time +// + search = com_searchpaths; + if (proghack) + { // gross hack to use quake 1 progs with quake 2 maps + if (!strcmp(filename, "progs.dat")) + search = search->next; + } + + for ( ; search ; search = search->next) + { + // is the element a pak file? + if (search->pack) + { + // look through all the pak file elements + pak = search->pack; + for (i=0 ; inumfiles ; i++) + if (!strcmp (pak->files[i].name, filename)) + { // found it! + Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename); + if (handle) + { + *handle = pak->handle; + Sys_FileSeek (pak->handle, pak->files[i].filepos); + } + else + { // open a new file on the pakfile + *file = fopen (pak->filename, "rb"); + if (*file) + fseek (*file, pak->files[i].filepos, SEEK_SET); + } + com_filesize = pak->files[i].filelen; + return com_filesize; + } + } + else + { + // check a file in the directory tree + if (!static_registered) + { // if not a registered version, don't ever go beyond base + if ( strchr (filename, '/') || strchr (filename,'\\')) + continue; + } + + sprintf (netpath, "%s/%s",search->filename, filename); + + findtime = Sys_FileTime (netpath); + if (findtime == -1) + continue; + + // see if the file needs to be updated in the cache + if (!com_cachedir[0]) + strcpy (cachepath, netpath); + else + { +#if defined(_WIN32) + if ((strlen(netpath) < 2) || (netpath[1] != ':')) + sprintf (cachepath,"%s%s", com_cachedir, netpath); + else + sprintf (cachepath,"%s%s", com_cachedir, netpath+2); +#else + sprintf (cachepath,"%s%s", com_cachedir, netpath); +#endif + + cachetime = Sys_FileTime (cachepath); + + if (cachetime < findtime) + COM_CopyFile (netpath, cachepath); + strcpy (netpath, cachepath); + } + + Sys_Printf ("FindFile: %s\n",netpath); + com_filesize = Sys_FileOpenRead (netpath, &i); + if (handle) + *handle = i; + else + { + Sys_FileClose (i); + *file = fopen (netpath, "rb"); + } + return com_filesize; + } + + } + + Sys_Printf ("FindFile: can't find %s\n", filename); + + if (handle) + *handle = -1; + else + *file = NULL; + com_filesize = -1; + return -1; +} + + +/* +=========== +COM_OpenFile + +filename never has a leading slash, but may contain directory walks +returns a handle and a length +it may actually be inside a pak file +=========== +*/ +int COM_OpenFile (char *filename, int *handle) +{ + return COM_FindFile (filename, handle, NULL); +} + +/* +=========== +COM_FOpenFile + +If the requested file is inside a packfile, a new FILE * will be opened +into the file. +=========== +*/ +int COM_FOpenFile (char *filename, FILE **file) +{ + return COM_FindFile (filename, NULL, file); +} + +/* +============ +COM_CloseFile + +If it is a pak file handle, don't really close it +============ +*/ +void COM_CloseFile (int h) +{ + searchpath_t *s; + + for (s = com_searchpaths ; s ; s=s->next) + if (s->pack && s->pack->handle == h) + return; + + Sys_FileClose (h); +} + + +/* +============ +COM_LoadFile + +Filename are reletive to the quake directory. +Allways appends a 0 byte. +============ +*/ +cache_user_t *loadcache; +byte *loadbuf; +int loadsize; +byte *COM_LoadFile (char *path, int usehunk) +{ + int h; + byte *buf; + char base[32]; + int len; + + buf = NULL; // quiet compiler warning + +// look for it in the filesystem or pack files + len = COM_OpenFile (path, &h); + if (h == -1) + return NULL; + +// extract the filename base name for hunk tag + COM_FileBase (path, base); + + if (usehunk == 1) + buf = Hunk_AllocName (len+1, base); + else if (usehunk == 2) + buf = Hunk_TempAlloc (len+1); + else if (usehunk == 0) + buf = Z_Malloc (len+1); + else if (usehunk == 3) + buf = Cache_Alloc (loadcache, len+1, base); + else if (usehunk == 4) + { + if (len+1 > loadsize) + buf = Hunk_TempAlloc (len+1); + else + buf = loadbuf; + } + else + Sys_Error ("COM_LoadFile: bad usehunk"); + + if (!buf) + Sys_Error ("COM_LoadFile: not enough space for %s", path); + + ((byte *)buf)[len] = 0; + + Draw_BeginDisc (); + Sys_FileRead (h, buf, len); + COM_CloseFile (h); + + return buf; +} + +byte *COM_LoadHunkFile (char *path) +{ + return COM_LoadFile (path, 1); +} + +byte *COM_LoadTempFile (char *path) +{ + return COM_LoadFile (path, 2); +} + +void COM_LoadCacheFile (char *path, struct cache_user_s *cu) +{ + loadcache = cu; + COM_LoadFile (path, 3); +} + +// uses temp hunk if larger than bufsize +byte *COM_LoadStackFile (char *path, void *buffer, int bufsize) +{ + byte *buf; + + loadbuf = (byte *)buffer; + loadsize = bufsize; + buf = COM_LoadFile (path, 4); + + return buf; +} + +/* +================= +COM_LoadPackFile -- johnfitz -- modified based on topaz's tutorial + +Takes an explicit (not game tree related) path to a pak file. + +Loads the header and directory, adding the files at the beginning +of the list so they override previous pack files. +================= +*/ +pack_t *COM_LoadPackFile (char *packfile) +{ + dpackheader_t header; + int i; + packfile_t *newfiles; + int numpackfiles; + pack_t *pack; + int packhandle; + dpackfile_t info[MAX_FILES_IN_PACK]; + unsigned short crc; + + if (Sys_FileOpenRead (packfile, &packhandle) == -1) + return NULL; + Sys_FileRead (packhandle, (void *)&header, sizeof(header)); + if (header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K') + Sys_Error ("%s is not a packfile", packfile); + header.dirofs = LittleLong (header.dirofs); + header.dirlen = LittleLong (header.dirlen); + + numpackfiles = header.dirlen / sizeof(dpackfile_t); + + if (numpackfiles > MAX_FILES_IN_PACK) + Sys_Error ("%s has %i files", packfile, numpackfiles); + + if (numpackfiles != PAK0_COUNT) + com_modified = true; // not the original file + + //johnfitz -- dynamic gamedir loading + //Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile"); + newfiles = Z_Malloc(numpackfiles * sizeof(packfile_t)); + //johnfitz + + Sys_FileSeek (packhandle, header.dirofs); + Sys_FileRead (packhandle, (void *)info, header.dirlen); + + // crc the directory to check for modifications + CRC_Init (&crc); + for (i = 0; i < header.dirlen ; i++) + CRC_ProcessByte (&crc, ((byte *)info)[i]); + if (crc != PAK0_CRC) + com_modified = true; + + // parse the directory + for (i = 0; i < numpackfiles ; i++) + { + strcpy (newfiles[i].name, info[i].name); + newfiles[i].filepos = LittleLong(info[i].filepos); + newfiles[i].filelen = LittleLong(info[i].filelen); + } + + //johnfitz -- dynamic gamedir loading + //pack = Hunk_Alloc (sizeof (pack_t)); + pack = Z_Malloc (sizeof (pack_t)); + //johnfitz + + strcpy (pack->filename, packfile); + pack->handle = packhandle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + + //Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); + return pack; +} + +/* +================= +COM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial +================= +*/ +void COM_AddGameDirectory (char *dir) +{ + int i; + searchpath_t *search; + pack_t *pak; + char pakfile[MAX_OSPATH]; + + strcpy (com_gamedir, dir); + + // add the directory to the search path + search = Z_Malloc(sizeof(searchpath_t)); + strcpy (search->filename, dir); + search->next = com_searchpaths; + com_searchpaths = search; + + // add any pak files in the format pak0.pak pak1.pak, ... + for (i = 0; ; i++) + { + sprintf (pakfile, "%s/pak%i.pak", dir, i); + pak = COM_LoadPackFile (pakfile); + if (!pak) + break; + search = Z_Malloc(sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + } +} + +/* +================= +COM_InitFilesystem +================= +*/ +void COM_InitFilesystem () //johnfitz -- modified based on topaz's tutorial +{ + int i, j; + char basedir[MAX_OSPATH]; + searchpath_t *search; + + i = COM_CheckParm ("-basedir"); + if (i && i < com_argc-1) + strcpy (basedir, com_argv[i+1]); + else + strcpy (basedir, host_parms.basedir); + + j = strlen (basedir); + if (j > 0) + { + if ((basedir[j-1] == '\\') || (basedir[j-1] == '/')) + basedir[j-1] = 0; + } + + i = COM_CheckParm ("-cachedir"); + if (i && i < com_argc-1) + { + if (com_argv[i+1][0] == '-') + com_cachedir[0] = 0; + else + strcpy (com_cachedir, com_argv[i+1]); + } + else if (host_parms.cachedir) + strcpy (com_cachedir, host_parms.cachedir); + else + com_cachedir[0] = 0; + + // start up with GAMENAME by default (id1) + COM_AddGameDirectory (va("%s/"GAMENAME, basedir) ); + strcpy (com_gamedir, va("%s/"GAMENAME, basedir)); + + //johnfitz -- track number of mission packs added + //since we don't want to allow the "game" command to strip them away + com_nummissionpacks = 0; + if (COM_CheckParm ("-rogue")) + { + COM_AddGameDirectory (va("%s/rogue", basedir) ); + com_nummissionpacks++; + } + if (COM_CheckParm ("-hipnotic")) + { + COM_AddGameDirectory (va("%s/hipnotic", basedir) ); + com_nummissionpacks++; + } + if (COM_CheckParm ("-quoth")) + { + COM_AddGameDirectory (va("%s/quoth", basedir) ); + com_nummissionpacks++; + } + //johnfitz + + i = COM_CheckParm ("-game"); + if (i && i < com_argc-1) + { + com_modified = true; + COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1])); + } + + i = COM_CheckParm ("-path"); + if (i) + { + com_modified = true; + com_searchpaths = NULL; + while (++i < com_argc) + { + if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-') + break; + search = Hunk_Alloc (sizeof(searchpath_t)); + if (!strcmp(COM_FileExtension(com_argv[i]), "pak") ) + { + search->pack = COM_LoadPackFile (com_argv[i]); + if (!search->pack) + Sys_Error ("Couldn't load packfile: %s", com_argv[i]); + } + else + strcpy (search->filename, com_argv[i]); + search->next = com_searchpaths; + com_searchpaths = search; + } + } + + if (COM_CheckParm ("-proghack")) + proghack = true; +} + + diff --git a/Quake/common.h b/Quake/common.h new file mode 100644 index 00000000..88c85e17 --- /dev/null +++ b/Quake/common.h @@ -0,0 +1,186 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// comndef.h -- general definitions + +#if !defined BYTE_DEFINED +typedef unsigned char byte; +#define BYTE_DEFINED 1 +#endif + +#undef true +#undef false + +typedef enum {false, true} qboolean; + +//============================================================================ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; // if false, do a Sys_Error + qboolean overflowed; // set to true if the buffer size failed + byte *data; + int maxsize; + int cursize; +} sizebuf_t; + +void SZ_Alloc (sizebuf_t *buf, int startsize); +void SZ_Free (sizebuf_t *buf); +void SZ_Clear (sizebuf_t *buf); +void *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, void *data, int length); +void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf + +//============================================================================ + +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + + +void ClearLink (link_t *l); +void RemoveLink (link_t *l); +void InsertLinkBefore (link_t *l, link_t *before); +void InsertLinkAfter (link_t *l, link_t *after); + +// (type *)STRUCT_FROM_LINK(link_t *link, type, member) +// ent = STRUCT_FROM_LINK(link,entity_t,order) +// FIXME: remove this mess! +#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) + +//============================================================================ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define Q_MAXCHAR ((char)0x7f) +#define Q_MAXSHORT ((short)0x7fff) +#define Q_MAXINT ((int)0x7fffffff) +#define Q_MAXLONG ((int)0x7fffffff) +#define Q_MAXFLOAT ((int)0x7fffffff) + +#define Q_MINCHAR ((char)0x80) +#define Q_MINSHORT ((short)0x8000) +#define Q_MININT ((int)0x80000000) +#define Q_MINLONG ((int)0x80000000) +#define Q_MINFLOAT ((int)0x7fffffff) + +//============================================================================ + +extern qboolean bigendien; + +extern short (*BigShort) (short l); +extern short (*LittleShort) (short l); +extern int (*BigLong) (int l); +extern int (*LittleLong) (int l); +extern float (*BigFloat) (float l); +extern float (*LittleFloat) (float l); + +//============================================================================ + +void MSG_WriteChar (sizebuf_t *sb, int c); +void MSG_WriteByte (sizebuf_t *sb, int c); +void MSG_WriteShort (sizebuf_t *sb, int c); +void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteFloat (sizebuf_t *sb, float f); +void MSG_WriteString (sizebuf_t *sb, char *s); +void MSG_WriteCoord (sizebuf_t *sb, float f); +void MSG_WriteAngle (sizebuf_t *sb, float f); +void MSG_WriteAngle16 (sizebuf_t *sb, float f); //johnfitz + +extern int msg_readcount; +extern qboolean msg_badread; // set if a read goes beyond end of message + +void MSG_BeginReading (void); +int MSG_ReadChar (void); +int MSG_ReadByte (void); +int MSG_ReadShort (void); +int MSG_ReadLong (void); +float MSG_ReadFloat (void); +char *MSG_ReadString (void); + +float MSG_ReadCoord (void); +float MSG_ReadAngle (void); +float MSG_ReadAngle16 (void); //johnfitz + +//============================================================================ + +void Q_memset (void *dest, int fill, int count); +void Q_memcpy (void *dest, void *src, int count); +int Q_memcmp (void *m1, void *m2, int count); +void Q_strcpy (char *dest, char *src); +void Q_strncpy (char *dest, char *src, int count); +int Q_strlen (char *str); +char *Q_strrchr (char *s, char c); +void Q_strcat (char *dest, char *src); +int Q_strcmp (char *s1, char *s2); +int Q_strncmp (char *s1, char *s2, int count); +int Q_strcasecmp (char *s1, char *s2); +int Q_strncasecmp (char *s1, char *s2, int n); +int Q_atoi (char *str); +float Q_atof (char *str); + +//============================================================================ + +extern char com_token[1024]; +extern qboolean com_eof; + +char *COM_Parse (char *data); + + +extern int com_argc; +extern char **com_argv; + +int COM_CheckParm (char *parm); +void COM_Init (char *path); +void COM_InitArgv (int argc, char **argv); + +char *COM_SkipPath (char *pathname); +void COM_StripExtension (char *in, char *out); +void COM_FileBase (char *in, char *out); +void COM_DefaultExtension (char *path, char *extension); + +char *va(char *format, ...); +// does a varargs printf into a temp buffer + + +//============================================================================ + +extern int com_filesize; +struct cache_user_s; + +extern char com_gamedir[MAX_OSPATH]; + +void COM_WriteFile (char *filename, void *data, int len); +int COM_OpenFile (char *filename, int *hndl); +int COM_FOpenFile (char *filename, FILE **file); +void COM_CloseFile (int h); + +byte *COM_LoadStackFile (char *path, void *buffer, int bufsize); +byte *COM_LoadTempFile (char *path); +byte *COM_LoadHunkFile (char *path); +void COM_LoadCacheFile (char *path, struct cache_user_s *cu); + + +extern struct cvar_s registered; + +extern qboolean standard_quake, rogue, hipnotic; diff --git a/Quake/console.c b/Quake/console.c new file mode 100644 index 00000000..7c8dfb53 --- /dev/null +++ b/Quake/console.c @@ -0,0 +1,1124 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// console.c + +#ifdef NeXT +#include +#endif +#ifndef _MSC_VER +#include +#endif +#include +#include "quakedef.h" + +int con_linewidth; + +float con_cursorspeed = 4; + +#define CON_TEXTSIZE 65536 //johnfitz -- new default size +#define CON_MINSIZE 16384 //johnfitz -- old default, now the minimum size +int con_buffersize; //johnfitz -- user can now override default + +qboolean con_forcedup; // because no entities to refresh + +int con_totallines; // total lines in console scrollback +int con_backscroll; // lines up from bottom to display +int con_current; // where next message will be printed +int con_x; // offset in current line for next print +char *con_text=0; + +cvar_t con_notifytime = {"con_notifytime","3"}; //seconds +cvar_t con_logcenterprint = {"con_logcenterprint", "1"}; //johnfitz + +char con_lastcenterstring[1024]; //johnfitz + +#define NUM_CON_TIMES 4 +float con_times[NUM_CON_TIMES]; // realtime time the line was generated + // for transparent notify lines + +int con_vislines; + +qboolean con_debuglog; + +#define MAXCMDLINE 256 +extern char key_lines[32][MAXCMDLINE]; +extern int edit_line; +extern int key_linepos; + +qboolean con_initialized; + +extern void M_Menu_Main_f (void); + +/* +================ +Con_Quakebar -- johnfitz -- returns a bar of the desired length, but never wider than the console + +includes a newline, unless len >= con_linewidth. +================ +*/ +char *Con_Quakebar (int len) +{ + static char bar[42]; + int i; + + len = min(len, sizeof(bar) - 2); + len = min(len, con_linewidth); + + bar[0] = '\35'; + for (i = 1; i < len - 1; i++) + bar[i] = '\36'; + bar[len-1] = '\37'; + + if (len < con_linewidth) + { + bar[len] = '\n'; + bar[len+1] = 0; + } + else + bar[len] = 0; + + return bar; +} + +/* +================ +Con_ToggleConsole_f +================ +*/ +void Con_ToggleConsole_f (void) +{ + extern int history_line; //johnfitz + + if (key_dest == key_console) + { + if (cls.state == ca_connected) + { + IN_Activate(); + key_dest = key_game; + key_lines[edit_line][1] = 0; // clear any typing + key_linepos = 1; + con_backscroll = 0; //johnfitz -- toggleconsole should return you to the bottom of the scrollback + history_line = edit_line; //johnfitz -- it should also return you to the bottom of the command history + } + else + { + M_Menu_Main_f (); + } + } + else + { + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_console; + } + + SCR_EndLoadingPlaque (); + memset (con_times, 0, sizeof(con_times)); +} + +/* +================ +Con_Clear_f +================ +*/ +void Con_Clear_f (void) +{ + if (con_text) + Q_memset (con_text, ' ', con_buffersize); //johnfitz -- con_buffersize replaces CON_TEXTSIZE + con_backscroll = 0; //johnfitz -- if console is empty, being scrolled up is confusing +} + +/* +================ +Con_Dump_f -- johnfitz -- adapted from quake2 source +================ +*/ +void Con_Dump_f (void) +{ + int l, x; + char *line; + FILE *f; + char buffer[1024]; + char name[MAX_OSPATH]; + +#if 1 + //johnfitz -- there is a security risk in writing files with an arbitrary filename. so, + //until stuffcmd is crippled to alleviate this risk, just force the default filename. + sprintf (name, "%s/condump.txt", com_gamedir); +#else + if (Cmd_Argc() > 2) + { + Con_Printf ("usage: condump \n"); + return; + } + + if (Cmd_Argc() > 1) + { + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".txt"); + } + else + sprintf (name, "%s/condump.txt", com_gamedir); +#endif + + COM_CreatePath (name); + f = fopen (name, "w"); + if (!f) + { + Con_Printf ("ERROR: couldn't open file.\n", name); + return; + } + + // skip initial empty lines + for (l = con_current - con_totallines + 1 ; l <= con_current ; l++) + { + line = con_text + (l%con_totallines)*con_linewidth; + for (x=0 ; x=0 ; x--) + { + if (buffer[x] == ' ') + buffer[x] = 0; + else + break; + } + for (x=0; buffer[x]; x++) + buffer[x] &= 0x7f; + + fprintf (f, "%s\n", buffer); + } + + fclose (f); + Con_Printf ("Dumped console text to %s.\n", name); +} + +/* +================ +Con_ClearNotify +================ +*/ +void Con_ClearNotify (void) +{ + int i; + + for (i=0 ; i> 3) - 2; //johnfitz -- use vid.conwidth instead of vid.width + + if (width == con_linewidth) + return; + + oldwidth = con_linewidth; + con_linewidth = width; + oldtotallines = con_totallines; + con_totallines = con_buffersize / con_linewidth; //johnfitz -- con_buffersize replaces CON_TEXTSIZE + numlines = oldtotallines; + + if (con_totallines < numlines) + numlines = con_totallines; + + numchars = oldwidth; + + if (con_linewidth < numchars) + numchars = con_linewidth; + + mark = Hunk_LowMark (); //johnfitz + tbuf = Hunk_Alloc (con_buffersize); //johnfitz + + Q_memcpy (tbuf, con_text, con_buffersize);//johnfitz -- con_buffersize replaces CON_TEXTSIZE + Q_memset (con_text, ' ', con_buffersize);//johnfitz -- con_buffersize replaces CON_TEXTSIZE + + for (i=0 ; i con_totallines - (glheight>>3) - 1) + con_backscroll = con_totallines - (glheight>>3) - 1; + //johnfitz + + con_x = 0; + con_current++; + Q_memset (&con_text[(con_current%con_totallines)*con_linewidth] + , ' ', con_linewidth); +} + +/* +================ +Con_Print + +Handles cursor positioning, line wrapping, etc +All console printing must go through this in order to be logged to disk +If no console is visible, the notify window will pop up. +================ +*/ +void Con_Print (char *txt) +{ + int y; + int c, l; + static int cr; + int mask; + + //con_backscroll = 0; //johnfitz -- better console scrolling + + if (txt[0] == 1) + { + mask = 128; // go to colored text + S_LocalSound ("misc/talk.wav"); + // play talk wav + txt++; + } + else if (txt[0] == 2) + { + mask = 128; // go to colored text + txt++; + } + else + mask = 0; + + + while ( (c = *txt) ) + { + // count word length + for (l=0 ; l< con_linewidth ; l++) + if ( txt[l] <= ' ') + break; + + // word wrap + if (l != con_linewidth && (con_x + l > con_linewidth) ) + con_x = 0; + + txt++; + + if (cr) + { + con_current--; + cr = false; + } + + + if (!con_x) + { + Con_Linefeed (); + // mark time for transparent overlay + if (con_current >= 0) + con_times[con_current % NUM_CON_TIMES] = realtime; + } + + switch (c) + { + case '\n': + con_x = 0; + break; + + case '\r': + con_x = 0; + cr = 1; + break; + + default: // display character and advance + y = con_current % con_totallines; + con_text[y*con_linewidth+con_x] = c | mask; + con_x++; + if (con_x >= con_linewidth) + con_x = 0; + break; + } + + } +} + + +/* +================ +Con_DebugLog +================ +*/ +void Con_DebugLog(char *file, char *fmt, ...) +{ + va_list argptr; + static char data[1024]; + int fd; + + va_start(argptr, fmt); + vsprintf(data, fmt, argptr); + va_end(argptr); + fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666); + write(fd, data, strlen(data)); + close(fd); +} + + +/* +================ +Con_Printf + +Handles cursor positioning, line wrapping, etc +================ +*/ +#define MAXPRINTMSG 4096 +// FIXME: make a buffer size safe vsprintf? +void Con_Printf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + static qboolean inupdate; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + +// also echo to debugging console + Sys_Printf ("%s", msg); + +// log all messages to file + if (con_debuglog) + Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg); + + if (!con_initialized) + return; + + if (cls.state == ca_dedicated) + return; // no graphics mode + +// write it to the scrollable buffer + Con_Print (msg); + +// update the screen if the console is displayed + if (cls.signon != SIGNONS && !scr_disabled_for_loading ) + { + // protect against infinite loop if something in SCR_UpdateScreen calls + // Con_Printd + if (!inupdate) + { + inupdate = true; + SCR_UpdateScreen (); + inupdate = false; + } + } +} + +/* +================ +Con_Warning -- johnfitz -- prints a warning to the console +================ +*/ +void Con_Warning (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Con_SafePrintf ("\x02Warning: "); + Con_Printf ("%s", msg); +} + +/* +================ +Con_DPrintf + +A Con_Printf that only shows up if the "developer" cvar is set +================ +*/ +void Con_DPrintf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + if (!developer.value) + return; // don't confuse non-developers with techie stuff... + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Con_SafePrintf ("%s", msg); //johnfitz -- was Con_Printf +} + +/* +================ +Con_DPrintf2 -- johnfitz -- only prints if "developer" >= 2 + +currently not used +================ +*/ +void Con_DPrintf2 (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + if (developer.value >= 2) + { + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Con_Printf ("%s", msg); + } +} + + +/* +================== +Con_SafePrintf + +Okay to call even when the screen can't be updated +================== +*/ +void Con_SafePrintf (char *fmt, ...) +{ + va_list argptr; + char msg[1024]; + int temp; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + Con_Printf ("%s", msg); + scr_disabled_for_loading = temp; +} + +/* +================ +Con_CenterPrintf -- johnfitz -- pad each line with spaces to make it appear centered +================ +*/ +void Con_CenterPrintf (int linewidth, char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; //the original message + char line[MAXPRINTMSG]; //one line from the message + char spaces[21]; //buffer for spaces + char *src, *dst; + int len, s; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + linewidth = min (linewidth, con_linewidth); + for (src = msg; *src; ) + { + dst = line; + while (*src && *src != '\n') + *dst++ = *src++; + *dst = 0; + if (*src == '\n') + src++; + + len = strlen(line); + if (len < linewidth) + { + s = (linewidth-len)/2; + memset (spaces, ' ', s); + spaces[s] = 0; + Con_Printf ("%s%s\n", spaces, line); + } + else + Con_Printf ("%s\n", line); + } +} + +/* +================== +Con_LogCenterPrint -- johnfitz -- echo centerprint message to the console +================== +*/ +void Con_LogCenterPrint (char *str) +{ + if (!strcmp(str, con_lastcenterstring)) + return; //ignore duplicates + + if (cl.gametype == GAME_DEATHMATCH && con_logcenterprint.value != 2) + return; //don't log in deathmatch + + strcpy(con_lastcenterstring, str); + + if (con_logcenterprint.value) + { + Con_Printf (Con_Quakebar(40)); + Con_CenterPrintf (40, "%s\n", str); + Con_Printf (Con_Quakebar(40)); + Con_ClearNotify (); + } +} + +/* +============================================================================== + + TAB COMPLETION + +============================================================================== +*/ + +//johnfitz -- tab completion stuff +//unique defs +char key_tabpartial[MAXCMDLINE]; +typedef struct tab_s +{ + char *name; + char *type; + struct tab_s *next; + struct tab_s *prev; +} tab_t; +tab_t *tablist; + +//defs from elsewhere +extern qboolean keydown[256]; +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; +} cmd_function_t; +extern cmd_function_t *cmd_functions; +#define MAX_ALIAS_NAME 32 +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; +extern cmdalias_t *cmd_alias; + +/* +============ +AddToTabList -- johnfitz + +tablist is a doubly-linked loop, alphabetized by name +============ +*/ +void AddToTabList (char *name, char *type) +{ + tab_t *t,*insert; + + t = Hunk_Alloc(sizeof(tab_t)); + t->name = name; + t->type = type; + + if (!tablist) //create list + { + tablist = t; + t->next = t; + t->prev = t; + } + else if (strcmp(name, tablist->name) < 0) //insert at front + { + t->next = tablist; + t->prev = tablist->prev; + t->next->prev = t; + t->prev->next = t; + tablist = t; + } + else //insert later + { + insert = tablist; + do + { + if (strcmp(name, insert->name) < 0) + break; + insert = insert->next; + } while (insert != tablist); + + t->next = insert; + t->prev = insert->prev; + t->next->prev = t; + t->prev->next = t; + } +} + +/* +============ +BuildTabList -- johnfitz +============ +*/ +void BuildTabList (char *partial) +{ + cmdalias_t *alias; + cvar_t *cvar; + cmd_function_t *cmd; + int len; + + tablist = NULL; + len = strlen(partial); + + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!Q_strncmp (partial, cvar->name, len)) + AddToTabList (cvar->name, "cvar"); + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncmp (partial,cmd->name, len)) + AddToTabList (cmd->name, "command"); + + for (alias=cmd_alias ; alias ; alias=alias->next) + if (!Q_strncmp (partial, alias->name, len)) + AddToTabList (alias->name, "alias"); +} + +/* +============ +Con_TabComplete -- johnfitz +============ +*/ +void Con_TabComplete (void) +{ + char partial[MAXCMDLINE]; + char *match; + static char *c; + tab_t *t; + int mark, i; + +// if editline is empty, return + if (key_lines[edit_line][1] == 0) + return; + +// get partial string (space -> cursor) + if (!Q_strlen(key_tabpartial)) //first time through, find new insert point. (Otherwise, use previous.) + { + //work back from cursor until you find a space, quote, semicolon, or prompt + c = key_lines[edit_line] + key_linepos - 1; //start one space left of cursor + while (*c!=' ' && *c!='\"' && *c!=';' && c!=key_lines[edit_line]) + c--; + c++; //start 1 char after the seperator we just found + } + for (i = 0; c + i < key_lines[edit_line] + key_linepos; i++) + partial[i] = c[i]; + partial[i] = 0; + +//if partial is empty, return + if (partial[0] == 0) + return; + +//trim trailing space becuase it screws up string comparisons + if (i > 0 && partial[i-1] == ' ') + partial[i-1] = 0; + +// find a match + mark = Hunk_LowMark(); + if (!Q_strlen(key_tabpartial)) //first time through + { + Q_strcpy (key_tabpartial, partial); + BuildTabList (key_tabpartial); + + if (!tablist) + return; + + //print list + t = tablist; + do + { + Con_SafePrintf(" %s (%s)\n", t->name, t->type); + t = t->next; + } while (t != tablist); + + //get first match + match = tablist->name; + } + else + { + BuildTabList (key_tabpartial); + + if (!tablist) + return; + + //find current match -- can't save a pointer because the list will be rebuilt each time + t = tablist; + do + { + if (!Q_strcmp(t->name, partial)) + break; + t = t->next; + } while (t != tablist); + + //use prev or next to find next match + match = keydown[K_SHIFT] ? t->prev->name : t->next->name; + } + Hunk_FreeToLowMark(mark); //it's okay to free it here becuase match is a pointer to persistent data + +// insert new match into edit line + Q_strcpy (partial, match); //first copy match string + Q_strcat (partial, key_lines[edit_line] + key_linepos); //then add chars after cursor + Q_strcpy (c, partial); //now copy all of this into edit line + key_linepos = c - key_lines[edit_line] + Q_strlen(match); //set new cursor position + +// if cursor is at end of string, let's append a space to make life easier + if (key_lines[edit_line][key_linepos] == 0) + { + key_lines[edit_line][key_linepos] = ' '; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + } +} + +/* +============================================================================== + +DRAWING + +============================================================================== +*/ + +/* +================ +Con_DrawNotify + +Draws the last few lines of output transparently over the game top +================ +*/ +void Con_DrawNotify (void) +{ + int x, v; + char *text; + int i; + float time; + extern char chat_buffer[]; + + GL_SetCanvas (CANVAS_CONSOLE); //johnfitz + v = vid.conheight; //johnfitz + + for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++) + { + if (i < 0) + continue; + time = con_times[i % NUM_CON_TIMES]; + if (time == 0) + continue; + time = realtime - time; + if (time > con_notifytime.value) + continue; + text = con_text + (i % con_totallines)*con_linewidth; + + clearnotify = 0; + + for (x = 0 ; x < con_linewidth ; x++) + Draw_Character ( (x+1)<<3, v, text[x]); + + v += 8; + + scr_tileclear_updates = 0; //johnfitz + } + + + if (key_dest == key_message) + { + char *say_prompt; //johnfitz + + clearnotify = 0; + + x = 0; + + //johnfitz -- distinguish say and say_team + if (team_message) + say_prompt = "say_team:"; + else + say_prompt = "say:"; + //johnfitz + + Draw_String (8, v, say_prompt); //johnfitz + + while(chat_buffer[x]) + { + Draw_Character ( (x+strlen(say_prompt)+2)<<3, v, chat_buffer[x]); //johnfitz + x++; + } + Draw_Character ( (x+strlen(say_prompt)+2)<<3, v, 10+((int)(realtime*con_cursorspeed)&1)); //johnfitz + v += 8; + + scr_tileclear_updates = 0; //johnfitz + } +} + +/* +================ +Con_DrawInput -- johnfitz -- modified to allow insert editing + +The input line scrolls horizontally if typing goes beyond the right edge +================ +*/ +void Con_DrawInput (void) +{ + extern qpic_t *pic_ovr, *pic_ins; //johnfitz -- new cursor handling + extern double key_blinktime; + extern int key_insert; + int i, len; + char c[256], *text; + + if (key_dest != key_console && !con_forcedup) + return; // don't draw anything + + text = strcpy(c, key_lines[edit_line]); + +// pad with one space so we can draw one past the string (in case the cursor is there) + len = strlen(key_lines[edit_line]); + text[len] = ' '; + text[len+1] = 0; + +// prestep if horizontally scrolling + if (key_linepos >= con_linewidth) + text += 1 + key_linepos - con_linewidth; + +// draw input string + for (i=0; i <= strlen(text) - 1; i++) //only write enough letters to go from *text to cursor + Draw_Character ((i+1)<<3, vid.conheight - 16, text[i]); + +// johnfitz -- new cursor handling + if (!((int)((realtime-key_blinktime)*con_cursorspeed) & 1)) + Draw_Pic ((key_linepos+1)<<3, vid.conheight - 16, key_insert ? pic_ins : pic_ovr); +} + +/* +================ +Con_DrawConsole -- johnfitz -- heavy revision + +Draws the console with the solid background +The typing input line at the bottom should only be drawn if typing is allowed +================ +*/ +void Con_DrawConsole (int lines, qboolean drawinput) +{ + int i, x, y, j, sb, rows; + char ver[32]; + char *text; + + if (lines <= 0) + return; + + con_vislines = lines * vid.conheight / glheight; + GL_SetCanvas (CANVAS_CONSOLE); + +// draw the background + Draw_ConsoleBackground (); + +// draw the buffer text + rows = (con_vislines+7)/8; + y = vid.conheight - rows*8; + rows -= 2; //for input and version lines + sb = (con_backscroll) ? 2 : 0; + + for (i = con_current - rows + 1 ; i <= con_current - sb ; i++, y+=8) + { + j = i - con_backscroll; + if (j<0) + j = 0; + text = con_text + (j % con_totallines)*con_linewidth; + + for (x=0 ; x> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} + +//johnfitz -- texture crc +unsigned short CRC_Block (byte *start, int count) +{ + unsigned short crc; + + CRC_Init (&crc); + while (count--) + crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++]; + + return crc; +} diff --git a/Quake/crc.h b/Quake/crc.h new file mode 100644 index 00000000..10cceddf --- /dev/null +++ b/Quake/crc.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); +unsigned short CRC_Block (byte *start, int count); //johnfitz -- texture crc diff --git a/Quake/cvar.c b/Quake/cvar.c new file mode 100644 index 00000000..b6c1587d --- /dev/null +++ b/Quake/cvar.c @@ -0,0 +1,481 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cvar.c -- dynamic variable tracking + +#include "quakedef.h" + +cvar_t *cvar_vars; +char *cvar_null_string = ""; + +//============================================================================== +// +// USER COMMANDS +// +//============================================================================== + +void Cvar_Reset (char *name); //johnfitz + +/* +============ +Cvar_List_f -- johnfitz +============ +*/ +void Cvar_List_f (void) +{ + cvar_t *cvar; + char *partial; + int len, count; + + if (Cmd_Argc() > 1) + { + partial = Cmd_Argv (1); + len = Q_strlen(partial); + } + else + { + partial = NULL; + len = 0; + } + + count=0; + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + { + if (partial && Q_strncmp (partial,cvar->name, len)) + { + continue; + } + Con_SafePrintf ("%s%s %s \"%s\"\n", + cvar->archive ? "*" : " ", + cvar->server ? "s" : " ", + cvar->name, + cvar->string); + count++; + } + + Con_SafePrintf ("%i cvars", count); + if (partial) + { + Con_SafePrintf (" beginning with \"%s\"", partial); + } + Con_SafePrintf ("\n"); +} + +/* +============ +Cvar_Inc_f -- johnfitz +============ +*/ +void Cvar_Inc_f (void) +{ + switch (Cmd_Argc()) + { + default: + case 1: + Con_Printf("inc [amount] : increment cvar\n"); + break; + case 2: + Cvar_SetValue (Cmd_Argv(1), Cvar_VariableValue(Cmd_Argv(1)) + 1); + break; + case 3: + Cvar_SetValue (Cmd_Argv(1), Cvar_VariableValue(Cmd_Argv(1)) + Q_atof(Cmd_Argv(2))); + break; + } +} + +/* +============ +Cvar_Toggle_f -- johnfitz +============ +*/ +void Cvar_Toggle_f (void) +{ + switch (Cmd_Argc()) + { + default: + case 1: + Con_Printf("toggle : toggle cvar\n"); + break; + case 2: + if (Cvar_VariableValue(Cmd_Argv(1))) + Cvar_Set (Cmd_Argv(1), "0"); + else + Cvar_Set (Cmd_Argv(1), "1"); + break; + } +} + +/* +============ +Cvar_Cycle_f -- johnfitz +============ +*/ +void Cvar_Cycle_f (void) +{ + int i; + + if (Cmd_Argc() < 3) + { + Con_Printf("cycle : cycle cvar through a list of values\n"); + return; + } + + //loop through the args until you find one that matches the current cvar value. + //yes, this will get stuck on a list that contains the same value twice. + //it's not worth dealing with, and i'm not even sure it can be dealt with. + + for (i=2;i : reset cvar to default\n"); + break; + case 2: + Cvar_Reset (Cmd_Argv(1)); + break; + } +} + +/* +============ +Cvar_ResetAll_f -- johnfitz +============ +*/ +void Cvar_ResetAll_f (void) +{ + cvar_t *var; + + for (var = cvar_vars; var; var = var->next) + Cvar_Reset (var->name); +} + +//============================================================================== +// +// INIT +// +//============================================================================== + +/* +============ +Cvar_Init -- johnfitz +============ +*/ + +void Cvar_Init (void) +{ + Cmd_AddCommand ("cvarlist", Cvar_List_f); + Cmd_AddCommand ("toggle", Cvar_Toggle_f); + Cmd_AddCommand ("cycle", Cvar_Cycle_f); + Cmd_AddCommand ("inc", Cvar_Inc_f); + Cmd_AddCommand ("reset", Cvar_Reset_f); + Cmd_AddCommand ("resetall", Cvar_ResetAll_f); +} + +//============================================================================== +// +// CVAR FUNCTIONS +// +//============================================================================== + +/* +============ +Cvar_FindVar +============ +*/ +cvar_t *Cvar_FindVar (char *var_name) +{ + cvar_t *var; + + for (var=cvar_vars ; var ; var=var->next) + if (!Q_strcmp (var_name, var->name)) + return var; + + return NULL; +} + +/* +============ +Cvar_VariableValue +============ +*/ +float Cvar_VariableValue (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return 0; + return Q_atof (var->string); +} + + +/* +============ +Cvar_VariableString +============ +*/ +char *Cvar_VariableString (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return cvar_null_string; + return var->string; +} + + +/* +============ +Cvar_CompleteVariable +============ +*/ +char *Cvar_CompleteVariable (char *partial) +{ + cvar_t *cvar; + int len; + + len = Q_strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!Q_strncmp (partial,cvar->name, len)) + return cvar->name; + + return NULL; +} + +/* +============ +Cvar_Reset -- johnfitz +============ +*/ +void Cvar_Reset (char *name) +{ + cvar_t *var; + + var = Cvar_FindVar (name); + if (!var) + Con_Printf ("variable \"%s\" not found\n", name); + else + Cvar_Set (var->name, var->default_string); +} + +/* +============ +Cvar_Set +============ +*/ +void Cvar_Set (char *var_name, char *value) +{ + cvar_t *var; + qboolean changed; + + var = Cvar_FindVar (var_name); + if (!var) + { // there is an error in C code if this happens + Con_Printf ("Cvar_Set: variable %s not found\n", var_name); + return; + } + + changed = Q_strcmp(var->string, value); + + Z_Free (var->string); // free the old value string + + var->string = Z_Malloc (Q_strlen(value)+1); + Q_strcpy (var->string, value); + var->value = Q_atof (var->string); + + //johnfitz -- during initialization, update default too + if (!host_initialized) + { + Z_Free (var->default_string); + var->default_string = Z_Malloc (Q_strlen(value)+1); + Q_strcpy (var->default_string, value); + } + //johnfitz + + if (var->server && changed) + { + if (sv.active) + SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string); + } + + //johnfitz + if(var->callback && changed) + var->callback(); + //johnfitz +} + +/* +============ +Cvar_SetValue +============ +*/ +void Cvar_SetValue (char *var_name, float value) +{ + char val[32]; + + sprintf (val, "%f",value); + Cvar_Set (var_name, val); +} + +/* +============ +Cvar_RegisterVariable + +Adds a freestanding variable to the variable list. +============ +*/ +void Cvar_RegisterVariable (cvar_t *variable, void *function) +{ + char *oldstr; + cvar_t *cursor,*prev; //johnfitz -- sorted list insert + +// first check to see if it has allready been defined + if (Cvar_FindVar (variable->name)) + { + Con_Printf ("Can't register variable %s, allready defined\n", variable->name); + return; + } + +// check for overlap with a command + if (Cmd_Exists (variable->name)) + { + Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name); + return; + } + +// copy the value off, because future sets will Z_Free it + oldstr = variable->string; + variable->string = Z_Malloc (Q_strlen(variable->string)+1); + Q_strcpy (variable->string, oldstr); + variable->value = Q_atof (variable->string); + + //johnfitz -- save initial value for "reset" command + variable->default_string = Z_Malloc (Q_strlen(variable->string)+1); + Q_strcpy (variable->default_string, oldstr); + //johnfitz + +// link the variable in + + //johnfitz -- insert each entry in alphabetical order + if (cvar_vars == NULL || strcmp(variable->name, cvar_vars->name) < 0) //insert at front + { + variable->next = cvar_vars; + cvar_vars = variable; + } + else //insert later + { + prev = cvar_vars; + cursor = cvar_vars->next; + while (cursor && (strcmp(variable->name, cursor->name) > 0)) + { + prev = cursor; + cursor = cursor->next; + } + variable->next = prev->next; + prev->next = variable; + } + //johnfitz + + variable->callback = function; //johnfitz +} + +/* +============ +Cvar_Command + +Handles variable inspection and changing from the console +============ +*/ +qboolean Cvar_Command (void) +{ + cvar_t *v; + +// check variables + v = Cvar_FindVar (Cmd_Argv(0)); + if (!v) + return false; + +// perform a variable print or set + if (Cmd_Argc() == 1) + { + Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); + return true; + } + + Cvar_Set (v->name, Cmd_Argv(1)); + return true; +} + + +/* +============ +Cvar_WriteVariables + +Writes lines containing "set variable value" for all variables +with the archive flag set to true. +============ +*/ +void Cvar_WriteVariables (FILE *f) +{ + cvar_t *var; + + for (var = cvar_vars ; var ; var = var->next) + if (var->archive) + fprintf (f, "%s \"%s\"\n", var->name, var->string); +} + diff --git a/Quake/cvar.h b/Quake/cvar.h new file mode 100644 index 00000000..7964b6e7 --- /dev/null +++ b/Quake/cvar.h @@ -0,0 +1,100 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cvar.h + +/* + +cvar_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 +in C code. + +it is sufficient to initialize a cvar_t with just the first two fields, or +you can add a ,true flag for variables that you want saved to the configuration +file when the game is quit: + +cvar_t r_draworder = {"r_draworder","1"}; +cvar_t scr_screensize = {"screensize","1",true}; + +Cvars 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: +Cvar_RegisterVariable (&host_framerate); + + +C code usually just references a cvar in place: +if ( r_draworder.value ) + +It could optionally ask for the value to be looked up for a string name: +if (Cvar_VariableValue ("r_draworder")) + +Interpreted prog code can access cvars with the cvar(name) or +cvar_set (name, value) internal functions: +teamplay = cvar("teamplay"); +cvar_set ("registered", "1"); + +The user can access cvars from the console in two ways: +r_draworder prints the current value +r_draworder 0 sets the current value to 0 +Cvars are restricted from having the same names as commands to keep this +interface from being ambiguous. +*/ + +typedef struct cvar_s +{ + char *name; + char *string; + qboolean archive; // set to true to cause it to be saved to vars.rc + qboolean server; // notifies players when changed + float value; + struct cvar_s *next; + char *default_string; //johnfitz -- remember defaults for reset function + void (*callback) (void); //johnfitz +} cvar_t; + +void Cvar_RegisterVariable (cvar_t *variable, void *function); //johnfitz -- cvar callback +// registers a cvar that allready has the name, string, and optionally the +// archive elements set. + +void Cvar_Set (char *var_name, char *value); +// equivelant to " " typed at the console + +void Cvar_SetValue (char *var_name, float value); +// expands value to a string and calls Cvar_Set + +float Cvar_VariableValue (char *var_name); +// returns 0 if not defined or non numeric + +char *Cvar_VariableString (char *var_name); +// returns an empty string if not defined + +char *Cvar_CompleteVariable (char *partial); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +qboolean Cvar_Command (void); +// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known +// command. Returns true if the command was a variable reference that +// was handled. (print or change) + +void Cvar_WriteVariables (FILE *f); +// Writes lines containing "set variable value" for all variables +// with the archive flag set to true. + +cvar_t *Cvar_FindVar (char *var_name); + +extern cvar_t *cvar_vars; diff --git a/Quake/d_ifacea.h b/Quake/d_ifacea.h new file mode 100644 index 00000000..407416ab --- /dev/null +++ b/Quake/d_ifacea.h @@ -0,0 +1,99 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// d_ifacea.h +// +// Include file for asm driver interface. +// + +// +// !!! note that this file must match the corresponding C structures in +// d_iface.h at all times !!! +// + +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define ALIAS_ONSEAM 0x0020 + +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define TURB_TEX_SIZE 64 // base turbulent texture size + +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define CYCLE 128 + +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define MAXHEIGHT 1024 + +// !!! if this is changed, it must be changed in quakedef.h too !!! +#define CACHE_SIZE 32 // used to align key data structures + +// particle_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +// driver-usable fields +#define pt_org 0 +#define pt_color 12 +// drivers never touch the following fields +#define pt_next 16 +#define pt_vel 20 +#define pt_ramp 32 +#define pt_die 36 +#define pt_type 40 +#define pt_size 44 + +#define PARTICLE_Z_CLIP 8.0 + +// finalvert_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define fv_v 0 // !!! if this is moved, cases where the !!! + // !!! address of this field is pushed in !!! + // !!! d_polysa.s must be changed !!! +#define fv_flags 24 +#define fv_reserved 28 +#define fv_size 32 +#define fv_shift 5 + + +// stvert_t structure +// !!! if this is changed, it must be changed in modelgen.h too !!! +#define stv_onseam 0 +#define stv_s 4 +#define stv_t 8 +#define stv_size 12 + + +// trivertx_t structure +// !!! if this is changed, it must be changed in modelgen.h too !!! +#define tv_v 0 +#define tv_lightnormalindex 3 +#define tv_size 4 + +// affinetridesc_t structure +// !!! if this is changed, it must be changed in d_iface.h too !!! +#define atd_pskin 0 +#define atd_pskindesc 4 +#define atd_skinwidth 8 +#define atd_skinheight 12 +#define atd_ptriangles 16 +#define atd_pfinalverts 20 +#define atd_numtriangles 24 +#define atd_drawtype 28 +#define atd_seamfixupX16 32 +#define atd_size 36 + diff --git a/Quake/draw.h b/Quake/draw.h new file mode 100644 index 00000000..66b4e244 --- /dev/null +++ b/Quake/draw.h @@ -0,0 +1,41 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.h -- these are the only functions outside the refresh allowed +// to touch the vid buffer + +extern qpic_t *draw_disc; // also used on sbar + +void Draw_Init (void); +void Draw_Character (int x, int y, int num); +void Draw_DebugChar (char num); +void Draw_Pic (int x, int y, qpic_t *pic); +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom); //johnfitz -- more parameters +void Draw_ConsoleBackground (void); //johnfitz -- removed parameter int lines +void Draw_BeginDisc (void); +void Draw_TileClear (int x, int y, int w, int h); +void Draw_Fill (int x, int y, int w, int h, int c, float alpha); //johnfitz -- added alpha +void Draw_FadeScreen (void); +void Draw_String (int x, int y, char *str); +qpic_t *Draw_PicFromWad (char *name); +qpic_t *Draw_CachePic (char *path); + +//void GL_SetCanvas (canvastype newcanvas); //johnfitz diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c new file mode 100644 index 00000000..0b63062d --- /dev/null +++ b/Quake/gl_draw.c @@ -0,0 +1,810 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.c -- 2d drawing + +#include "quakedef.h" + +//extern unsigned char d_15to8table[65536]; //johnfitz -- never used + +cvar_t scr_conalpha = {"scr_conalpha", "1"}; //johnfitz + +qpic_t *draw_disc; +qpic_t *draw_backtile; + +gltexture_t *char_texture; //johnfitz +qpic_t *pic_ovr, *pic_ins; //johnfitz -- new cursor handling +qpic_t *pic_nul; //johnfitz -- for missing gfx, don't crash + +//johnfitz -- new pics +byte pic_ovr_data[8][8] = +{ + {255,255,255,255,255,255,255,255}, + {255, 15, 15, 15, 15, 15, 15,255}, + {255, 15, 15, 15, 15, 15, 15, 2}, + {255, 15, 15, 15, 15, 15, 15, 2}, + {255, 15, 15, 15, 15, 15, 15, 2}, + {255, 15, 15, 15, 15, 15, 15, 2}, + {255, 15, 15, 15, 15, 15, 15, 2}, + {255,255, 2, 2, 2, 2, 2, 2}, +}; + +byte pic_ins_data[9][8] = +{ + { 15, 15,255,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + { 15, 15, 2,255,255,255,255,255}, + {255, 2, 2,255,255,255,255,255}, +}; + +byte pic_nul_data[8][8] = +{ + {252,252,252,252, 0, 0, 0, 0}, + {252,252,252,252, 0, 0, 0, 0}, + {252,252,252,252, 0, 0, 0, 0}, + {252,252,252,252, 0, 0, 0, 0}, + { 0, 0, 0, 0,252,252,252,252}, + { 0, 0, 0, 0,252,252,252,252}, + { 0, 0, 0, 0,252,252,252,252}, + { 0, 0, 0, 0,252,252,252,252}, +}; + +byte pic_stipple_data[8][8] = +{ + {255, 0, 0, 0,255, 0, 0, 0}, + { 0, 0,255, 0, 0, 0,255, 0}, + {255, 0, 0, 0,255, 0, 0, 0}, + { 0, 0,255, 0, 0, 0,255, 0}, + {255, 0, 0, 0,255, 0, 0, 0}, + { 0, 0,255, 0, 0, 0,255, 0}, + {255, 0, 0, 0,255, 0, 0, 0}, + { 0, 0,255, 0, 0, 0,255, 0}, +}; + +byte pic_crosshair_data[8][8] = +{ + {255,255,255,255,255,255,255,255}, + {255,255,255, 8, 9,255,255,255}, + {255,255,255, 6, 8, 2,255,255}, + {255, 6, 8, 8, 6, 8, 8,255}, + {255,255, 2, 8, 8, 2, 2, 2}, + {255,255,255, 7, 8, 2,255,255}, + {255,255,255,255, 2, 2,255,255}, + {255,255,255,255,255,255,255,255}, +}; +//johnfitz + +typedef struct +{ + gltexture_t *gltexture; + float sl, tl, sh, th; +} glpic_t; + +canvastype currentcanvas = CANVAS_NONE; //johnfitz -- for GL_SetCanvas + +//============================================================================== +// +// PIC CACHING +// +//============================================================================== + +typedef struct cachepic_s +{ + char name[MAX_QPATH]; + qpic_t pic; + byte padding[32]; // for appended glpic +} cachepic_t; + +#define MAX_CACHED_PICS 128 +cachepic_t menu_cachepics[MAX_CACHED_PICS]; +int menu_numcachepics; + +byte menuplyr_pixels[4096]; + +// scrap allocation +// Allocate all the little status bar obejcts into a single texture +// to crutch up stupid hardware / drivers + +#define MAX_SCRAPS 2 +#define BLOCK_WIDTH 256 +#define BLOCK_HEIGHT 256 + +int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; +byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT]; //johnfitz -- removed *4 after BLOCK_HEIGHT +qboolean scrap_dirty; +gltexture_t *scrap_textures[MAX_SCRAPS]; //johnfitz + +/* +================ +Scrap_AllocBlock + +returns an index into scrap_texnums[] and the position inside it +================ +*/ +int Scrap_AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + //int bestx; unused -- kristian + int texnum; + + for (texnum=0 ; texnum= best) + break; + if (scrap_allocated[texnum][i+j] > best2) + best2 = scrap_allocated[texnum][i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i=0 ; idata; + + // load little ones into the scrap + if (p->width < 64 && p->height < 64) + { + int x, y; + int i, j, k; + int texnum; + + texnum = Scrap_AllocBlock (p->width, p->height, &x, &y); + scrap_dirty = true; + k = 0; + for (i=0 ; iheight ; i++) + for (j=0 ; jwidth ; j++, k++) + scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k]; + gl->gltexture = scrap_textures[texnum]; //johnfitz -- changed to an array + //johnfitz -- no longer go from 0.01 to 0.99 + gl->sl = x/(float)BLOCK_WIDTH; + gl->sh = (x+p->width)/(float)BLOCK_WIDTH; + gl->tl = y/(float)BLOCK_WIDTH; + gl->th = (y+p->height)/(float)BLOCK_WIDTH; + } + else + { + char texturename[64]; //johnfitz + sprintf (texturename, "%s:%s", WADFILENAME, name); //johnfitz + + offset = (unsigned)p - (unsigned)wad_base + sizeof(int)*2; //johnfitz + + gl->gltexture = TexMgr_LoadImage (NULL, texturename, p->width, p->height, SRC_INDEXED, p->data, WADFILENAME, + offset, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr + gl->sl = 0; + gl->sh = (float)p->width/(float)TexMgr_PadConditional(p->width); //johnfitz + gl->tl = 0; + gl->th = (float)p->height/(float)TexMgr_PadConditional(p->height); //johnfitz + } + + return p; +} + +/* +================ +Draw_CachePic +================ +*/ +qpic_t *Draw_CachePic (char *path) +{ + cachepic_t *pic; + int i; + qpic_t *dat; + glpic_t *gl; + + for (pic=menu_cachepics, i=0 ; iname)) + return &pic->pic; + + if (menu_numcachepics == MAX_CACHED_PICS) + Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); + menu_numcachepics++; + strcpy (pic->name, path); + +// +// load the pic from disk +// + dat = (qpic_t *)COM_LoadTempFile (path); + if (!dat) + Sys_Error ("Draw_CachePic: failed to load %s", path); + SwapPic (dat); + + // HACK HACK HACK --- we need to keep the bytes for + // the translatable player picture just for the menu + // configuration dialog + if (!strcmp (path, "gfx/menuplyr.lmp")) + memcpy (menuplyr_pixels, dat->data, dat->width*dat->height); + + pic->pic.width = dat->width; + pic->pic.height = dat->height; + + gl = (glpic_t *)pic->pic.data; + gl->gltexture = TexMgr_LoadImage (NULL, path, dat->width, dat->height, SRC_INDEXED, dat->data, path, + sizeof(int)*2, TEXPREF_ALPHA | TEXPREF_PAD | TEXPREF_NOPICMIP); //johnfitz -- TexMgr + gl->sl = 0; + gl->sh = (float)dat->width/(float)TexMgr_PadConditional(dat->width); //johnfitz + gl->tl = 0; + gl->th = (float)dat->height/(float)TexMgr_PadConditional(dat->height); //johnfitz + + return &pic->pic; +} + +/* +================ +Draw_MakePic -- johnfitz -- generate pics from internal data +================ +*/ +qpic_t *Draw_MakePic (char *name, int width, int height, byte *data) +{ + int flags = TEXPREF_NEAREST | TEXPREF_ALPHA | TEXPREF_PERSIST | TEXPREF_NOPICMIP | TEXPREF_PAD; + qpic_t *pic; + glpic_t *gl; + + pic = Hunk_Alloc (sizeof(qpic_t) - 4 + sizeof (glpic_t)); + pic->width = width; + pic->height = height; + + gl = (glpic_t *)pic->data; + gl->gltexture = TexMgr_LoadImage (NULL, name, width, height, SRC_INDEXED, data, "", (unsigned)data, flags); + gl->sl = 0; + gl->sh = (float)width/(float)TexMgr_PadConditional(width); + gl->tl = 0; + gl->th = (float)height/(float)TexMgr_PadConditional(height); + + return pic; +} + +//============================================================================== +// +// INIT +// +//============================================================================== + +/* +=============== +Draw_LoadPics -- johnfitz +=============== +*/ +void Draw_LoadPics (void) +{ + byte *data; + unsigned offset; + + data = W_GetLumpName ("conchars"); + if (!data) Sys_Error ("Draw_LoadPics: couldn't load conchars"); + offset = (unsigned)data - (unsigned)wad_base; + char_texture = TexMgr_LoadImage (NULL, WADFILENAME":conchars", 128, 128, SRC_INDEXED, data, + WADFILENAME, offset, TEXPREF_ALPHA | TEXPREF_NEAREST | TEXPREF_NOPICMIP | TEXPREF_CONCHARS); + + draw_disc = Draw_PicFromWad ("disc"); + draw_backtile = Draw_PicFromWad ("backtile"); +} + +/* +=============== +Draw_NewGame -- johnfitz +=============== +*/ +void Draw_NewGame (void) +{ + //gltexture_t *glt; unused -- kristian + cachepic_t *pic; + int i; + + // empty scrap and reallocate gltextures + memset(&scrap_allocated, 0, sizeof(scrap_allocated)); + memset(&scrap_texels, 255, sizeof(scrap_texels)); + Scrap_Upload (); //creates 2 empty gltextures + + // reload wad pics + W_LoadWadFile (); //johnfitz -- filename is now hard-coded for honesty + Draw_LoadPics (); + SCR_LoadPics (); + Sbar_LoadPics (); + + // empty lmp cache + for (pic = menu_cachepics, i = 0; i < menu_numcachepics; pic++, i++) + pic->name[0] = 0; + menu_numcachepics = 0; +} + +/* +=============== +Draw_Init -- johnfitz -- rewritten +=============== +*/ +void Draw_Init (void) +{ + Cvar_RegisterVariable (&scr_conalpha, NULL); + + // clear scrap and allocate gltextures + memset(&scrap_allocated, 0, sizeof(scrap_allocated)); + memset(&scrap_texels, 255, sizeof(scrap_texels)); + Scrap_Upload (); //creates 2 empty textures + + // create internal pics + pic_ins = Draw_MakePic ("ins", 8, 9, &pic_ins_data[0][0]); + pic_ovr = Draw_MakePic ("ovr", 8, 8, &pic_ovr_data[0][0]); + pic_nul = Draw_MakePic ("nul", 8, 8, &pic_nul_data[0][0]); + + // load game pics + Draw_LoadPics (); +} + +//============================================================================== +// +// 2D DRAWING +// +//============================================================================== + +/* +================ +Draw_CharacterQuad -- johnfitz -- seperate function to spit out verts +================ +*/ +void Draw_CharacterQuad (int x, int y, char num) +{ + int row, col; + float frow, fcol, size; + + row = num>>4; + col = num&15; + + frow = row*0.0625; + fcol = col*0.0625; + size = 0.0625; + + glTexCoord2f (fcol, frow); + glVertex2f (x, y); + glTexCoord2f (fcol + size, frow); + glVertex2f (x+8, y); + glTexCoord2f (fcol + size, frow + size); + glVertex2f (x+8, y+8); + glTexCoord2f (fcol, frow + size); + glVertex2f (x, y+8); +} + +/* +================ +Draw_Character -- johnfitz -- modified to call Draw_CharacterQuad +================ +*/ +void Draw_Character (int x, int y, int num) +{ + if (y <= -8) + return; // totally off screen + + num &= 255; + + if (num == 32) + return; //don't waste verts on spaces + + GL_Bind (char_texture); + glBegin (GL_QUADS); + + Draw_CharacterQuad (x, y, (char) num); + + glEnd (); +} + +/* +================ +Draw_String -- johnfitz -- modified to call Draw_CharacterQuad +================ +*/ +void Draw_String (int x, int y, char *str) +{ + if (y <= -8) + return; // totally off screen + + GL_Bind (char_texture); + glBegin (GL_QUADS); + + while (*str) + { + if (*str != 32) //don't waste verts on spaces + Draw_CharacterQuad (x, y, *str); + str++; + x += 8; + } + + glEnd (); +} + +/* +============= +Draw_Pic -- johnfitz -- modified +============= +*/ +void Draw_Pic (int x, int y, qpic_t *pic) +{ + glpic_t *gl; + + if (scrap_dirty) + Scrap_Upload (); + gl = (glpic_t *)pic->data; + GL_Bind (gl->gltexture); + glBegin (GL_QUADS); + glTexCoord2f (gl->sl, gl->tl); + glVertex2f (x, y); + glTexCoord2f (gl->sh, gl->tl); + glVertex2f (x+pic->width, y); + glTexCoord2f (gl->sh, gl->th); + glVertex2f (x+pic->width, y+pic->height); + glTexCoord2f (gl->sl, gl->th); + glVertex2f (x, y+pic->height); + glEnd (); +} + +/* +============= +Draw_TransPicTranslate -- johnfitz -- rewritten to use texmgr to do translation + +Only used for the player color selection menu +============= +*/ +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom) +{ + static int oldtop = -2; + static int oldbottom = -2; + gltexture_t *glt; + + if (top != oldtop || bottom != oldbottom) + { + oldtop = top; + oldbottom = bottom; + glt = ((glpic_t *)pic->data)->gltexture; + TexMgr_ReloadImage (glt, top, bottom); + } + Draw_Pic (x, y, pic); +} + +/* +================ +Draw_ConsoleBackground -- johnfitz -- rewritten +================ +*/ +void Draw_ConsoleBackground (void) +{ + qpic_t *pic; + float alpha; + + pic = Draw_CachePic ("gfx/conback.lmp"); + pic->width = vid.conwidth; + pic->height = vid.conheight; + + alpha = (con_forcedup) ? 1.0 : scr_conalpha.value; + +// GL_SetCanvas (CANVAS_CONSOLE); //in case this is called from weird places + + if (alpha > 0.0) + { + if (alpha < 1.0) + { + glEnable (GL_BLEND); + glColor4f (1,1,1,alpha); + glDisable (GL_ALPHA_TEST); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + + Draw_Pic (0, 0, pic); + + if (alpha < 1.0) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glEnable (GL_ALPHA_TEST); + glDisable (GL_BLEND); + glColor4f (1,1,1,1); + } + } +} + + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void Draw_TileClear (int x, int y, int w, int h) +{ + glpic_t *gl; + + gl = (glpic_t *)draw_backtile->data; + + glColor3f (1,1,1); + GL_Bind (gl->gltexture); + glBegin (GL_QUADS); + glTexCoord2f (x/64.0, y/64.0); + glVertex2f (x, y); + glTexCoord2f ( (x+w)/64.0, y/64.0); + glVertex2f (x+w, y); + glTexCoord2f ( (x+w)/64.0, (y+h)/64.0); + glVertex2f (x+w, y+h); + glTexCoord2f ( x/64.0, (y+h)/64.0 ); + glVertex2f (x, y+h); + glEnd (); +} + +/* +============= +Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void Draw_Fill (int x, int y, int w, int h, int c, float alpha) //johnfitz -- added alpha +{ + byte *pal = (byte *)d_8to24table; //johnfitz -- use d_8to24table instead of host_basepal + + glDisable (GL_TEXTURE_2D); + glEnable (GL_BLEND); //johnfitz -- for alpha + glDisable (GL_ALPHA_TEST); //johnfitz -- for alpha + glColor4f (pal[c*4]/255.0, pal[c*4+1]/255.0, pal[c*4+2]/255.0, alpha); //johnfitz -- added alpha + + glBegin (GL_QUADS); + glVertex2f (x,y); + glVertex2f (x+w, y); + glVertex2f (x+w, y+h); + glVertex2f (x, y+h); + glEnd (); + + glColor3f (1,1,1); + glDisable (GL_BLEND); //johnfitz -- for alpha + glEnable (GL_ALPHA_TEST); //johnfitz -- for alpha + glEnable (GL_TEXTURE_2D); +} + +/* +================ +Draw_FadeScreen -- johnfitz -- revised +================ +*/ +void Draw_FadeScreen (void) +{ + GL_SetCanvas (CANVAS_DEFAULT); + + glEnable (GL_BLEND); + glDisable (GL_ALPHA_TEST); + glDisable (GL_TEXTURE_2D); + glColor4f (0, 0, 0, 0.5); + glBegin (GL_QUADS); + + glVertex2f (0,0); + glVertex2f (glwidth, 0); + glVertex2f (glwidth, glheight); + glVertex2f (0, glheight); + + glEnd (); + glColor4f (1,1,1,1); + glEnable (GL_TEXTURE_2D); + glEnable (GL_ALPHA_TEST); + glDisable (GL_BLEND); + + Sbar_Changed(); +} + +/* +================ +Draw_BeginDisc + +Draws the little blue disc in the corner of the screen. +Call before beginning any disc IO. +================ +*/ +void Draw_BeginDisc (void) +{ + int viewport[4]; //johnfitz + canvastype oldcanvas; //johnfitz + + if (!draw_disc) + return; + + //johnfitz -- intel video workarounds from Baker + if (isIntelVideo) + return; + //johnfitz + + //johnfitz -- canvas and matrix stuff + glGetIntegerv (GL_VIEWPORT, viewport); + glMatrixMode(GL_PROJECTION); + glPushMatrix (); + glMatrixMode(GL_MODELVIEW); + glPushMatrix (); + oldcanvas = currentcanvas; + GL_SetCanvas (CANVAS_TOPRIGHT); + currentcanvas = oldcanvas; // a bit of a hack, since GL_SetCanvas doesn't know we are going to pop the stack + //johnfitz + + glDrawBuffer (GL_FRONT); + Draw_Pic (320 - 24, 0, draw_disc); + glDrawBuffer (GL_BACK); + + //johnfitz -- restore everything so that 3d rendering isn't fucked up + glMatrixMode(GL_PROJECTION); + glPopMatrix (); + glMatrixMode(GL_MODELVIEW); + glPopMatrix (); + glViewport (viewport[0], viewport[1], viewport[2], viewport[3]); + //johnfitz +} + +/* +================ +GL_SetCanvas -- johnfitz -- support various canvas types +================ +*/ +void GL_SetCanvas (canvastype newcanvas) +{ + extern vrect_t scr_vrect; + float s, w; + int lines; + + if (newcanvas == currentcanvas) + return; + + currentcanvas = newcanvas; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + + switch(newcanvas) + { + case CANVAS_DEFAULT: + glOrtho (0, glwidth, glheight, 0, -99999, 99999); + glViewport (glx, gly, glwidth, glheight); + break; + case CANVAS_CONSOLE: + lines = vid.conheight - (scr_con_current * vid.conheight / glheight); + glOrtho (0, vid.conwidth, vid.conheight + lines, lines, -99999, 99999); + glViewport (glx, gly, glwidth, glheight); + break; + case CANVAS_MENU: + s = min ((float)glwidth / 320.0, (float)glheight / 200.0); + s = CLAMP (1.0, scr_menuscale.value, s); + glOrtho (0, 320, 200, 0, -99999, 99999); + glViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 320*s, 200*s); + break; + case CANVAS_SBAR: + s = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); + if (cl.gametype == GAME_DEATHMATCH) + { + glOrtho (0, glwidth / s, 48, 0, -99999, 99999); + glViewport (glx, gly, glwidth, 48*s); + } + else + { + glOrtho (0, 320, 48, 0, -99999, 99999); + glViewport (glx + (glwidth - 320*s) / 2, gly, 320*s, 48*s); + } + break; + case CANVAS_WARPIMAGE: + glOrtho (0, 128, 0, 128, -99999, 99999); + glViewport (glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize); + break; + case CANVAS_CROSSHAIR: //0,0 is center of viewport + s = CLAMP (1.0, scr_crosshaircale.value, 10.0); + glOrtho (scr_vrect.width/-2/s, scr_vrect.width/2/s, scr_vrect.height/2/s, scr_vrect.height/-2/s, -99999, 99999); + glViewport (scr_vrect.x, glheight - scr_vrect.y - scr_vrect.height, scr_vrect.width & ~1, scr_vrect.height & ~1); + break; + case CANVAS_BOTTOMLEFT: //used by devstats + s = (float)glwidth/vid.conwidth; //use console scale + glOrtho (0, 320, 200, 0, -99999, 99999); + glViewport (glx, gly, 320*s, 200*s); + break; + case CANVAS_BOTTOMRIGHT: //used by fps/clock + s = (float)glwidth/vid.conwidth; //use console scale + glOrtho (0, 320, 200, 0, -99999, 99999); + glViewport (glx+glwidth-320*s, gly, 320*s, 200*s); + break; + case CANVAS_TOPRIGHT: //used by disc + s = 1; + glOrtho (0, 320, 200, 0, -99999, 99999); + glViewport (glx+glwidth-320*s, gly+glheight-200*s, 320*s, 200*s); + break; + default: + Sys_Error ("GL_SetCanvas: bad canvas type"); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity (); +} + +/* +================ +GL_Set2D -- johnfitz -- rewritten +================ +*/ +void GL_Set2D (void) +{ + currentcanvas = -1; + GL_SetCanvas (CANVAS_DEFAULT); + + glDisable (GL_DEPTH_TEST); + glDisable (GL_CULL_FACE); + glDisable (GL_BLEND); + glEnable (GL_ALPHA_TEST); + glColor4f (1,1,1,1); +} diff --git a/Quake/gl_fog.c b/Quake/gl_fog.c new file mode 100644 index 00000000..38cea5d4 --- /dev/null +++ b/Quake/gl_fog.c @@ -0,0 +1,386 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +//gl_fog.c -- global and volumetric fog + +#include "quakedef.h" + +//============================================================================== +// +// GLOBAL FOG +// +//============================================================================== + +float fog_density; +float fog_red; +float fog_green; +float fog_blue; + +float old_density; +float old_red; +float old_green; +float old_blue; + +float fade_time; //duration of fade +float fade_done; //time when fade will be done + +/* +============= +Fog_Update + +update internal variables +============= +*/ +void Fog_Update (float density, float red, float green, float blue, float time) +{ + //save previous settings for fade + if (time > 0) + { + //check for a fade in progress + if (fade_done > cl.time) + { + float f;//, d; unused -- kristian + + f = (fade_done - cl.time) / fade_time; + old_density = f * old_density + (1.0 - f) * fog_density; + old_red = f * old_red + (1.0 - f) * fog_red; + old_green = f * old_green + (1.0 - f) * fog_green; + old_blue = f * old_blue + (1.0 - f) * fog_blue; + } + else + { + old_density = fog_density; + old_red = fog_red; + old_green = fog_green; + old_blue = fog_blue; + } + } + + fog_density = density; + fog_red = red; + fog_green = green; + fog_blue = blue; + fade_time = time; + fade_done = cl.time + time; +} + +/* +============= +Fog_ParseServerMessage + +handle an SVC_FOG message from server +============= +*/ +void Fog_ParseServerMessage (void) +{ + float density, red, green, blue, time; + + density = MSG_ReadByte() / 255.0; + red = MSG_ReadByte() / 255.0; + green = MSG_ReadByte() / 255.0; + blue = MSG_ReadByte() / 255.0; + time = max(0.0, MSG_ReadShort() / 100.0); + + Fog_Update (density, red, green, blue, time); +} + +/* +============= +Fog_FogCommand_f + +handle the 'fog' console command +============= +*/ +void Fog_FogCommand_f (void) +{ + switch (Cmd_Argc()) + { + default: + case 1: + Con_Printf("usage:\n"); + Con_Printf(" fog \n"); + Con_Printf(" fog \n"); + Con_Printf(" fog \n"); + Con_Printf("current values:\n"); + Con_Printf(" \"density\" is \"%f\"\n", fog_density); + Con_Printf(" \"red\" is \"%f\"\n", fog_red); + Con_Printf(" \"green\" is \"%f\"\n", fog_green); + Con_Printf(" \"blue\" is \"%f\"\n", fog_blue); + break; + case 2: + Fog_Update(max(0.0, atof(Cmd_Argv(1))), + fog_red, + fog_green, + fog_blue, + 0.0); + break; + case 3: //TEST + Fog_Update(max(0.0, atof(Cmd_Argv(1))), + fog_red, + fog_green, + fog_blue, + atof(Cmd_Argv(2))); + break; + case 4: + Fog_Update(fog_density, + CLAMP(0.0, atof(Cmd_Argv(1)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), + 0.0); + break; + case 5: + Fog_Update(fmax(0.0, atof(Cmd_Argv(1))), + CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(4)), 1.0), + 0.0); + break; + case 6: //TEST + Fog_Update(fmax(0.0, atof(Cmd_Argv(1))), + CLAMP(0.0, atof(Cmd_Argv(2)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(3)), 1.0), + CLAMP(0.0, atof(Cmd_Argv(4)), 1.0), + atof(Cmd_Argv(5))); + break; + } +} + +/* +============= +Fog_ParseWorldspawn + +called at map load +============= +*/ +void Fog_ParseWorldspawn (void) +{ + char key[128], value[4096]; + char *data; + + //initially no fog + fog_density = 0.0; + old_density = 0.0; + fade_time = 0.0; + fade_done = 0.0; + + data = COM_Parse(cl.worldmodel->entities); + if (!data) + return; // error + if (com_token[0] != '{') + return; // error + while (1) + { + data = COM_Parse(data); + if (!data) + return; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); + else + strcpy(key, com_token); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + data = COM_Parse(data); + if (!data) + return; // error + strcpy(value, com_token); + + if (!strcmp("fog", key)) + { + sscanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue); + } + } +} + +/* +============= +Fog_GetColor + +calculates fog color for this frame, taking into account fade times +============= +*/ +float *Fog_GetColor (void) +{ + static float c[4]; + float f; + int i; + + if (fade_done > cl.time) + { + f = (fade_done - cl.time) / fade_time; + c[0] = f * old_red + (1.0 - f) * fog_red; + c[1] = f * old_green + (1.0 - f) * fog_green; + c[2] = f * old_blue + (1.0 - f) * fog_blue; + c[3] = 1.0; + } + else + { + c[0] = fog_red; + c[1] = fog_green; + c[2] = fog_blue; + c[3] = 1.0; + } + + //find closest 24-bit RGB value, so solid-colored sky can match the fog perfectly + for (i=0;i<3;i++) + c[i] = (float)(Q_rint(c[i] * 255)) / 255.0f; + + return c; +} + +/* +============= +Fog_GetDensity + +returns current density of fog +============= +*/ +float Fog_GetDensity (void) +{ + float f; + + if (fade_done > cl.time) + { + f = (fade_done - cl.time) / fade_time; + return f * old_density + (1.0 - f) * fog_density; + } + else + return fog_density; +} + +/* +============= +Fog_SetupFrame + +called at the beginning of each frame +============= +*/ +void Fog_SetupFrame (void) +{ + glFogfv(GL_FOG_COLOR, Fog_GetColor()); + glFogf(GL_FOG_DENSITY, Fog_GetDensity() / 64.0); +} + +/* +============= +Fog_EnableGFog + +called before drawing stuff that should be fogged +============= +*/ +void Fog_EnableGFog (void) +{ + if (Fog_GetDensity() > 0) + glEnable(GL_FOG); +} + +/* +============= +Fog_DisableGFog + +called after drawing stuff that should be fogged +============= +*/ +void Fog_DisableGFog (void) +{ + if (Fog_GetDensity() > 0) + glDisable(GL_FOG); +} + +/* +============= +Fog_StartAdditive + +called before drawing stuff that is additive blended -- sets fog color to black +============= +*/ +void Fog_StartAdditive (void) +{ + vec3_t color = {0,0,0}; + + if (Fog_GetDensity() > 0) + glFogfv(GL_FOG_COLOR, color); +} + +/* +============= +Fog_StopAdditive + +called after drawing stuff that is additive blended -- restores fog color +============= +*/ +void Fog_StopAdditive (void) +{ + if (Fog_GetDensity() > 0) + glFogfv(GL_FOG_COLOR, Fog_GetColor()); +} + +//============================================================================== +// +// VOLUMETRIC FOG +// +//============================================================================== + +cvar_t r_vfog = {"r_vfog", "1"}; + +void Fog_DrawVFog (void){} +void Fog_MarkModels (void){} + +//============================================================================== +// +// INIT +// +//============================================================================== + +/* +============= +Fog_NewMap + +called whenever a map is loaded +============= +*/ +void Fog_NewMap (void) +{ + Fog_ParseWorldspawn (); //for global fog + Fog_MarkModels (); //for volumetric fog +} + +/* +============= +Fog_Init + +called when quake initializes +============= +*/ +void Fog_Init (void) +{ + Cmd_AddCommand ("fog",Fog_FogCommand_f); + + //Cvar_RegisterVariable (&r_vfog, NULL); + + //set up global fog + fog_density = 0.0; + fog_red = 0.3; + fog_green = 0.3; + fog_blue = 0.3; + + glFogi(GL_FOG_MODE, GL_EXP2); +} diff --git a/Quake/gl_mesh.c b/Quake/gl_mesh.c new file mode 100644 index 00000000..d0396216 --- /dev/null +++ b/Quake/gl_mesh.c @@ -0,0 +1,413 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// gl_mesh.c: triangle model functions + +#include "quakedef.h" + + + +/* +================================================================= + +ALIAS MODEL DISPLAY LIST GENERATION + +================================================================= +*/ + +model_t *aliasmodel; +aliashdr_t *paliashdr; + +qboolean used[8192]; + +// the command list holds counts and s/t values that are valid for +// every frame +int commands[8192]; +int numcommands; + +// all frames will have their vertexes rearranged and expanded +// so they are in the order expected by the command list +int vertexorder[8192]; +int numorder; + +int allverts, alltris; + +int stripverts[128]; +int striptris[128]; +int stripcount; + +/* +================ +StripLength +================ +*/ +int StripLength (int starttri, int startv) +{ + int m1, m2; + int j; + mtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + stripverts[0] = last->vertindex[(startv)%3]; + stripverts[1] = last->vertindex[(startv+1)%3]; + stripverts[2] = last->vertindex[(startv+2)%3]; + + striptris[0] = starttri; + stripcount = 1; + + m1 = last->vertindex[(startv+2)%3]; + m2 = last->vertindex[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] ; jnumtris ; j++, check++) + { + if (check->facesfront != last->facesfront) + continue; + for (k=0 ; k<3 ; k++) + { + if (check->vertindex[k] != m1) + continue; + if (check->vertindex[ (k+1)%3 ] != m2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + if (stripcount & 1) + m2 = check->vertindex[ (k+2)%3 ]; + else + m1 = check->vertindex[ (k+2)%3 ]; + + stripverts[stripcount+2] = check->vertindex[ (k+2)%3 ]; + striptris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jnumtris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + +/* +=========== +FanLength +=========== +*/ +int FanLength (int starttri, int startv) +{ + int m1, m2; + int j; + mtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + stripverts[0] = last->vertindex[(startv)%3]; + stripverts[1] = last->vertindex[(startv+1)%3]; + stripverts[2] = last->vertindex[(startv+2)%3]; + + striptris[0] = starttri; + stripcount = 1; + + m1 = last->vertindex[(startv+0)%3]; + m2 = last->vertindex[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] ; jnumtris ; j++, check++) + { + if (check->facesfront != last->facesfront) + continue; + for (k=0 ; k<3 ; k++) + { + if (check->vertindex[k] != m1) + continue; + if (check->vertindex[ (k+1)%3 ] != m2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + m2 = check->vertindex[ (k+2)%3 ]; + + stripverts[stripcount+2] = m2; + striptris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jnumtris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + +/* +================ +BuildTris + +Generate a list of trifans or strips +for the model, which holds for all frames +================ +*/ +void BuildTris (void) +{ + int i, j, k; + int startv; + /* unused -- kristian + mtriangle_t *last, *check; + int m1, m2; + int striplength; + trivertx_t *v; + mtriangle_t *tv; + int index; + */ + float s, t; + int len, bestlen, besttype; + int bestverts[1024]; + int besttris[1024]; + int type; + + // + // build tristrips + // + numorder = 0; + numcommands = 0; + memset (used, 0, sizeof(used)); + for (i=0 ; inumtris ; i++) + { + // pick an unused triangle and start the trifan + if (used[i]) + continue; + + bestlen = 0; + for (type = 0 ; type < 2 ; type++) +// type = 1; + { + for (startv =0 ; startv < 3 ; startv++) + { + if (type == 1) + len = StripLength (i, startv); + else + len = FanLength (i, startv); + if (len > bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; jskinwidth / 2; // on back side + s = (s + 0.5) / pheader->skinwidth; + t = (t + 0.5) / pheader->skinheight; + + *(float *)&commands[numcommands++] = s; + *(float *)&commands[numcommands++] = t; + } + } + + commands[numcommands++] = 0; // end of list marker + + Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); + + allverts += numorder; + alltris += pheader->numtris; +} + + +/* +================ +GL_MakeAliasModelDisplayLists +================ +*/ +void GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr) +{ + int i, j; + int *cmds; + trivertx_t *verts; + /* unused -- kristian + maliasgroup_t *paliasgroup; + char cache[MAX_QPATH], fullpath[MAX_OSPATH], *c; + FILE *f; + int len; + byte *data; + */ + float hscale, vscale; //johnfitz -- padded skins + int count; //johnfitz -- precompute texcoords for padded skins + int *loadcmds; //johnfitz + + //johnfitz -- padded skins + hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth); + vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight); + //johnfitz + + aliasmodel = m; + paliashdr = hdr; // (aliashdr_t *)Mod_Extradata (m); + +//johnfitz -- generate meshes + +#if 1 //always regenerate meshes + + Con_DPrintf ("meshing %s...\n",m->name); + BuildTris (); + +#else //conditional regeneration + + if (gl_alwaysmesh.value) // build it from scratch, and don't bother saving it to disk + { + Con_DPrintf ("meshing %s...\n",m->name); + BuildTris (); + } + else // check disk cache, and rebuild it and save to disk if necessary + { + // FITZQUAKE 0.85 CREATES DIRECTORIES HERE + // + // look for a cached version + // + strcpy (cache, "glquake/"); + COM_StripExtension (m->name+strlen("progs/"), cache+strlen("glquake/")); + strcat (cache, ".ms2"); + + COM_FOpenFile (cache, &f); + if (f) + { + fread (&numcommands, 4, 1, f); + fread (&numorder, 4, 1, f); + fread (&commands, numcommands * sizeof(commands[0]), 1, f); + fread (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f); + fclose (f); + } + else + { + // + // build it from scratch + // + Con_Printf ("meshing %s...\n",m->name); + BuildTris (); + + // + // save out the cached version + // + sprintf (fullpath, "%s/%s", com_gamedir, cache); + f = fopen (fullpath, "wb"); + if (f) + { + fwrite (&numcommands, 4, 1, f); + fwrite (&numorder, 4, 1, f); + fwrite (&commands, numcommands * sizeof(commands[0]), 1, f); + fwrite (&vertexorder, numorder * sizeof(vertexorder[0]), 1, f); + fclose (f); + } + } + } +#endif +//johnfitz + + + // save the data out + + paliashdr->poseverts = numorder; + + cmds = Hunk_Alloc (numcommands * 4); + paliashdr->commands = (byte *)cmds - (byte *)paliashdr; + + //johnfitz -- precompute texcoords for padded skins + loadcmds = commands; + while(1) + { + *cmds++ = count = *loadcmds++; + + if (!count) + break; + + if (count < 0) + count = -count; + + do + { + *(float *)cmds++ = hscale * (*(float *)loadcmds++); + *(float *)cmds++ = vscale * (*(float *)loadcmds++); + } while (--count); + } + //johnfitz + + verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts * sizeof(trivertx_t)); + paliashdr->posedata = (byte *)verts - (byte *)paliashdr; + for (i=0 ; inumposes ; i++) + for (j=0 ; jname, "notexture"); + r_notexture_mip->height = r_notexture_mip->width = 32; + + r_notexture_mip2 = Hunk_AllocName (sizeof(texture_t), "r_notexture_mip2"); + strcpy (r_notexture_mip2->name, "notexture2"); + r_notexture_mip2->height = r_notexture_mip2->width = 32; + //johnfitz +} + +/* +=============== +Mod_Extradata + +Caches the data if needed +=============== +*/ +void *Mod_Extradata (model_t *mod) +{ + void *r; + + r = Cache_Check (&mod->cache); + if (r) + return r; + + Mod_LoadModel (mod, true); + + if (!mod->cache.data) + Sys_Error ("Mod_Extradata: caching failed"); + return mod->cache.data; +} + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + mplane_t *plane; + + if (!model || !model->nodes) + Sys_Error ("Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents < 0) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte *Mod_DecompressVis (byte *in, model_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->numleafs+7)>>3; + out = decompressed; + +#if 0 + memcpy (out, in, row); +#else + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +#endif + + return decompressed; +} + +byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model) +{ + if (leaf == model->leafs) + return mod_novis; + return Mod_DecompressVis (leaf->compressed_vis, model); +} + +/* +=================== +Mod_ClearAll +=================== +*/ +void Mod_ClearAll (void) +{ + int i; + model_t *mod; + + for (i=0 , mod=mod_known ; itype != mod_alias) + { + mod->needload = true; + TexMgr_FreeTexturesForOwner (mod); //johnfitz + } +} + +/* +================== +Mod_FindName + +================== +*/ +model_t *Mod_FindName (char *name) +{ + int i; + model_t *mod; + + if (!name[0]) + Sys_Error ("Mod_FindName: NULL name"); //johnfitz -- was "Mod_ForName" + +// +// search the currently loaded models +// + for (i=0 , mod=mod_known ; iname, name) ) + break; + + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); + strcpy (mod->name, name); + mod->needload = true; + mod_numknown++; + } + + return mod; +} + +/* +================== +Mod_TouchModel + +================== +*/ +void Mod_TouchModel (char *name) +{ + model_t *mod; + + mod = Mod_FindName (name); + + if (!mod->needload) + { + if (mod->type == mod_alias) + Cache_Check (&mod->cache); + } +} + +/* +================== +Mod_LoadModel + +Loads a model into the cache +================== +*/ +model_t *Mod_LoadModel (model_t *mod, qboolean crash) +{ + void *d; + unsigned *buf; + byte stackbuf[1024]; // avoid dirtying the cache heap + + if (!mod->needload) + { + if (mod->type == mod_alias) + { + d = Cache_Check (&mod->cache); + if (d) + return mod; + } + else + return mod; // not cached at all + } + +// +// because the world is so huge, load it one piece at a time +// + if (!crash) + { + + } + +// +// load the file +// + buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); + if (!buf) + { + if (crash) + Sys_Error ("Mod_LoadModel: %s not found", mod->name); //johnfitz -- was "Mod_NumForName" + return NULL; + } + +// +// allocate a new model +// + COM_FileBase (mod->name, loadname); + + loadmodel = mod; + +// +// fill it in +// + +// call the apropriate loader + mod->needload = false; + + switch (LittleLong(*(unsigned *)buf)) + { + case IDPOLYHEADER: + Mod_LoadAliasModel (mod, buf); + break; + + case IDSPRITEHEADER: + Mod_LoadSpriteModel (mod, buf); + break; + + default: + Mod_LoadBrushModel (mod, buf); + break; + } + + return mod; +} + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *Mod_ForName (char *name, qboolean crash) +{ + model_t *mod; + + mod = Mod_FindName (name); + + return Mod_LoadModel (mod, crash); +} + + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +byte *mod_base; + +/* +================= +Mod_CheckFullbrights -- johnfitz +================= +*/ +qboolean Mod_CheckFullbrights (byte *pixels, int count) +{ + int i; + for (i = 0; i < count; i++) + if (*pixels++ > 223) + return true; + return false; +} + +/* +================= +Mod_LoadTextures +================= +*/ +void Mod_LoadTextures (lump_t *l) +{ + int i, j, pixels, num, max, altmax; + miptex_t *mt; + texture_t *tx, *tx2; + texture_t *anims[10]; + texture_t *altanims[10]; + dmiptexlump_t *m; +//johnfitz -- more variables + char texturename[64]; + int nummiptex; + unsigned offset; + int mark, fwidth, fheight; + char filename[MAX_OSPATH], filename2[MAX_OSPATH], mapname[MAX_OSPATH]; + byte *data; + FILE *f; + extern byte *hunk_base; +//johnfitz + + //johnfitz -- don't return early if no textures; still need to create dummy texture + if (!l->filelen) + { + Con_Printf ("Mod_LoadTextures: no textures in bsp file\n"); + nummiptex = 0; + } + else + { + m = (dmiptexlump_t *)(mod_base + l->fileofs); + m->nummiptex = LittleLong (m->nummiptex); + nummiptex = m->nummiptex; + } + //johnfitz + + loadmodel->numtextures = nummiptex + 2; //johnfitz -- need 2 dummy texture chains for missing textures + loadmodel->textures = Hunk_AllocName (loadmodel->numtextures * sizeof(*loadmodel->textures) , loadname); + + for (i=0 ; idataofs[i] = LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) + continue; + mt = (miptex_t *)((byte *)m + m->dataofs[i]); + mt->width = LittleLong (mt->width); + mt->height = LittleLong (mt->height); + for (j=0 ; joffsets[j] = LittleLong (mt->offsets[j]); + + if ( (mt->width & 15) || (mt->height & 15) ) + Sys_Error ("Texture %s is not 16 aligned", mt->name); + pixels = mt->width*mt->height/64*85; + tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + loadmodel->textures[i] = tx; + + memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + // the pixels immediately follow the structures + memcpy ( tx+1, mt+1, pixels); + + tx->update_warp = false; //johnfitz + tx->warpimage = NULL; //johnfitz + tx->fullbright = NULL; //johnfitz + + //johnfitz -- lots of changes + if (!isDedicated) //no texture uploading for dedicated server + { + if (!Q_strncasecmp(tx->name,"sky",3)) //sky texture //also note -- was Q_strncmp, changed to match qbsp + Sky_LoadTexture (tx); + else if (tx->name[0] == '*') //warping texture + { + //external textures -- first look in "textures/mapname/" then look in "textures/" + mark = Hunk_LowMark(); + COM_StripExtension (loadmodel->name + 5, mapname); + sprintf (filename, "textures/%s/#%s", mapname, tx->name+1); //this also replaces the '*' with a '#' + data = Image_LoadImage (filename, &fwidth, &fheight); + if (!data) + { + sprintf (filename, "textures/#%s", tx->name+1); + data = Image_LoadImage (filename, &fwidth, &fheight); + } + + //now load whatever we found + if (data) //load external image + { + strcpy (texturename, filename); + tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, fwidth, fheight, + SRC_RGBA, data, filename, 0, TEXPREF_NONE); + } + else //use the texture from the bsp file + { + sprintf (texturename, "%s:%s", loadmodel->name, tx->name); + offset = (unsigned)(mt+1) - (unsigned)mod_base; + tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, + SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_NONE); + } + + //now create the warpimage, using dummy data from the hunk to create the initial image + Hunk_Alloc (gl_warpimagesize*gl_warpimagesize*4); //make sure hunk is big enough so we don't reach an illegal address + Hunk_FreeToLowMark (mark); + sprintf (texturename, "%s_warp", texturename); + tx->warpimage = TexMgr_LoadImage (loadmodel, texturename, gl_warpimagesize, + gl_warpimagesize, SRC_RGBA, hunk_base, "", (unsigned)hunk_base, TEXPREF_NOPICMIP | TEXPREF_WARPIMAGE); + tx->update_warp = true; + } + else //regular texture + { + //external textures -- first look in "textures/mapname/" then look in "textures/" + mark = Hunk_LowMark (); + COM_StripExtension (loadmodel->name + 5, mapname); + sprintf (filename, "textures/%s/%s", mapname, tx->name); + data = Image_LoadImage (filename, &fwidth, &fheight); + if (!data) + { + sprintf (filename, "textures/%s", tx->name); + data = Image_LoadImage (filename, &fwidth, &fheight); + } + + //now load whatever we found + if (data) //load external image + { + tx->gltexture = TexMgr_LoadImage (loadmodel, filename, fwidth, fheight, + SRC_RGBA, data, filename, 0, TEXPREF_MIPMAP); + + //now try to load glow/luma image from the same place + Hunk_FreeToLowMark (mark); + sprintf (filename2, "%s_glow", filename); + data = Image_LoadImage (filename2, &fwidth, &fheight); + if (!data) + sprintf (filename2, "%s_luma", filename); + data = Image_LoadImage (filename2, &fwidth, &fheight); + + if (data) + tx->fullbright = TexMgr_LoadImage (loadmodel, filename2, fwidth, fheight, + SRC_RGBA, data, filename, 0, TEXPREF_MIPMAP ); + } + else //use the texture from the bsp file + { + sprintf (texturename, "%s:%s", loadmodel->name, tx->name); + offset = (unsigned)(mt+1) - (unsigned)mod_base; + if (Mod_CheckFullbrights ((byte *)(tx+1), pixels)) + { + tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, + SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_NOBRIGHT); + sprintf (texturename, "%s:%s_glow", loadmodel->name, tx->name); + tx->fullbright = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, + SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP | TEXPREF_FULLBRIGHT); + } + else + { + tx->gltexture = TexMgr_LoadImage (loadmodel, texturename, tx->width, tx->height, + SRC_INDEXED, (byte *)(tx+1), loadmodel->name, offset, TEXPREF_MIPMAP); + } + } + Hunk_FreeToLowMark (mark); + } + } + //johnfitz + } + + //johnfitz -- last 2 slots in array should be filled with dummy textures + loadmodel->textures[loadmodel->numtextures-2] = r_notexture_mip; //for lightmapped surfs + loadmodel->textures[loadmodel->numtextures-1] = r_notexture_mip2; //for SURF_DRAWTILED surfs + +// +// sequence the animations +// + for (i=0 ; itextures[i]; + if (!tx || tx->name[0] != '+') + continue; + if (tx->anim_next) + continue; // allready sequenced + + // find the number of frames in the animation + memset (anims, 0, sizeof(anims)); + memset (altanims, 0, sizeof(altanims)); + + max = tx->name[1]; + altmax = 0; + if (max >= 'a' && max <= 'z') + max -= 'a' - 'A'; + if (max >= '0' && max <= '9') + { + max -= '0'; + altmax = 0; + anims[max] = tx; + max++; + } + else if (max >= 'A' && max <= 'J') + { + altmax = max - 'A'; + max = 0; + altanims[altmax] = tx; + altmax++; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + + for (j=i+1 ; jtextures[j]; + if (!tx2 || tx2->name[0] != '+') + continue; + if (strcmp (tx2->name+2, tx->name+2)) + continue; + + num = tx2->name[1]; + if (num >= 'a' && num <= 'z') + num -= 'a' - 'A'; + if (num >= '0' && num <= '9') + { + num -= '0'; + anims[num] = tx2; + if (num+1 > max) + max = num + 1; + } + else if (num >= 'A' && num <= 'J') + { + num = num - 'A'; + altanims[num] = tx2; + if (num+1 > altmax) + altmax = num+1; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + } + +#define ANIM_CYCLE 2 + // link them all together + for (j=0 ; jname); + tx2->anim_total = max * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = anims[ (j+1)%max ]; + if (altmax) + tx2->alternate_anims = altanims[0]; + } + for (j=0 ; jname); + tx2->anim_total = altmax * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = altanims[ (j+1)%altmax ]; + if (max) + tx2->alternate_anims = anims[0]; + } + } +} + +/* +================= +Mod_LoadLighting -- johnfitz -- replaced with lit support code via lordhavoc +================= +*/ +void Mod_LoadLighting (lump_t *l) +{ + // + int i; + byte *in, *out, *data; + byte d; + char litfilename[1024]; + loadmodel->lightdata = NULL; + // LordHavoc: check for a .lit file + strcpy(litfilename, loadmodel->name); + COM_StripExtension(litfilename, litfilename); + strcat(litfilename, ".lit"); + data = (byte*) COM_LoadHunkFile (litfilename); + if (data) + { + if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + { + i = LittleLong(((int *)data)[1]); + if (i == 1) + { + Con_DPrintf("%s loaded", litfilename); + loadmodel->lightdata = data + 8; + return; + } + else + Con_Printf("Unknown .lit file version (%d)\n", i); + } + else + Con_Printf("Corrupt .lit file (old version?), ignoring\n"); + } + // LordHavoc: no .lit found, expand the white lighting data to color + if (!l->filelen) + return; + loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, litfilename); + in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write + out = loadmodel->lightdata; + memcpy (in, mod_base + l->fileofs, l->filelen); + for (i = 0;i < l->filelen;i++) + { + d = *in++; + *out++ = d; + *out++ = d; + *out++ = d; + } +} + + +/* +================= +Mod_LoadVisibility +================= +*/ +void Mod_LoadVisibility (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->visdata = NULL; + return; + } + loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadEntities +================= +*/ +void Mod_LoadEntities (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->entities = NULL; + return; + } + loadmodel->entities = Hunk_AllocName ( l->filelen, loadname); + memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen); +} + + +/* +================= +Mod_LoadVertexes +================= +*/ +void Mod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); + } +} + +/* +================= +Mod_LoadEdges +================= +*/ +void Mod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* +================= +Mod_LoadTexinfo +================= +*/ +void Mod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out; + int i, j, count, miptex; + float len1, len2; + int missing = 0; //johnfitz + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + len1 = Length (out->vecs[0]); + len2 = Length (out->vecs[1]); + len1 = (len1 + len2)/2; + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; +#if 0 + if (len1 + len2 < 0.001) + out->mipadjust = 1; // don't crash + else + out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 ); +#endif + + miptex = LittleLong (in->miptex); + out->flags = LittleLong (in->flags); + + //johnfitz -- rewrote this section + if (miptex >= loadmodel->numtextures-1 || !loadmodel->textures[miptex]) + { + if (out->flags & TEX_SPECIAL) + out->texture = loadmodel->textures[loadmodel->numtextures-1]; + else + out->texture = loadmodel->textures[loadmodel->numtextures-2]; + out->flags |= TEX_MISSING; + missing++; + } + else + { + out->texture = loadmodel->textures[miptex]; + } + //johnfitz + } + + //johnfitz: report missing textures + if (missing && loadmodel->numtextures > 1) + Con_Printf ("Mod_LoadTexinfo: one or more textures is missing from BSP file\n", missing); + //johnfitz +} + +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ +void CalcSurfaceExtents (msurface_t *s) +{ + float mins[2], maxs[2], val; + int i,j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = floor(mins[i]/16); + bmaxs[i] = ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + + if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 2000) //johnfitz -- was 512 in glquake, 256 in winquake + Sys_Error ("Bad surface extents"); + } +} + +/* +================ +Mod_PolyForUnlitSurface -- johnfitz -- creates polys for unlightmapped surfaces (sky and water) + +TODO: merge this into BuildSurfaceDisplayList? +================ +*/ +void Mod_PolyForUnlitSurface (msurface_t *fa) +{ + vec3_t verts[64]; + int numverts, i, lindex; + float *vec; + // texture_t *t; unused -- kristian + glpoly_t *poly; + float texscale; + + if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) + texscale = (1.0/128.0); //warp animation repeats every 128 + else + texscale = (1.0/32.0); //to match r_notexture_mip + + // convert edges back to a normal polygon + numverts = 0; + for (i=0 ; inumedges ; i++) + { + lindex = loadmodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + else + vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + VectorCopy (vec, verts[numverts]); + numverts++; + } + + //create the poly + poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = NULL; + fa->polys = poly; + poly->numverts = numverts; + for (i=0, vec=(float *)verts; iverts[i]); + poly->verts[i][3] = DotProduct(vec, fa->texinfo->vecs[0]) * texscale; + poly->verts[i][4] = DotProduct(vec, fa->texinfo->vecs[1]) * texscale; + } +} + +/* +================= +Mod_CalcSurfaceBounds -- johnfitz -- calculate bounding box for per-surface frustum culling +================= +*/ +void Mod_CalcSurfaceBounds (msurface_t *s) +{ + int i, e; + mvertex_t *v; + + s->mins[0] = s->mins[1] = s->mins[2] = 9999; + s->maxs[0] = s->maxs[1] = s->maxs[2] = -9999; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + if (s->mins[0] > v->position[0]) + s->mins[0] = v->position[0]; + if (s->mins[1] > v->position[1]) + s->mins[1] = v->position[1]; + if (s->mins[2] > v->position[2]) + s->mins[2] = v->position[2]; + + if (s->maxs[0] < v->position[0]) + s->maxs[0] = v->position[0]; + if (s->maxs[1] < v->position[1]) + s->maxs[1] = v->position[1]; + if (s->maxs[2] < v->position[2]) + s->maxs[2] = v->position[2]; + } +} + +/* +================= +Mod_LoadFaces +================= +*/ +void Mod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + //johnfitz -- warn mappers about exceeding old limits + if (count > 32767) + Con_Warning ("%i faces exceeds standard limit of 32767.\n", count); + //johnfitz + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo); + + CalcSurfaceExtents (out); + + Mod_CalcSurfaceBounds (out); //johnfitz -- for per-surface frustum culling + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + (i * 3); //johnfitz -- lit support via lordhavoc (was "+ i") + + //johnfitz -- this section rewritten + if (!Q_strncasecmp(out->texinfo->texture->name,"sky",3)) // sky surface //also note -- was Q_strncmp, changed to match qbsp + { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + Mod_PolyForUnlitSurface (out); //no more subdivision + } + else if (out->texinfo->texture->name[0] == '*') // warp surface + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + Mod_PolyForUnlitSurface (out); + GL_SubdivideSurface (out); + } + else if (out->texinfo->flags & TEX_MISSING) // texture is missing from bsp + { + if (out->samples) //lightmapped + { + out->flags |= SURF_NOTEXTURE; + } + else // not lightmapped + { + out->flags |= (SURF_NOTEXTURE | SURF_DRAWTILED); + Mod_PolyForUnlitSurface (out); + } + } + //johnfitz + } +} + + +/* +================= +Mod_SetParent +================= +*/ +void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +/* +================= +Mod_LoadNodes +================= +*/ +void Mod_LoadNodes (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + //johnfitz -- warn mappers about exceeding old limits + if (count > 32767) + Con_Warning ("%i nodes exceeds standard limit of 32767.\n", count); + //johnfitz + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = (unsigned short)LittleShort (in->firstface); //johnfitz -- explicit cast as unsigned short + out->numsurfaces = (unsigned short)LittleShort (in->numfaces); //johnfitz -- explicit cast as unsigned short + + for (j=0 ; j<2 ; j++) + { + //johnfitz -- hack to handle nodes > 32k, adapted from darkplaces + p = (unsigned short)LittleShort(in->children[j]); + if (p < count) + out->children[j] = loadmodel->nodes + p; + else + { + p = 65535 - p; //note this uses 65535 intentionally, -1 is leaf 0 + if (p < loadmodel->numleafs) + out->children[j] = (mnode_t *)(loadmodel->leafs + p); + else + { + Con_Printf("Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\n", p, loadmodel->numleafs); + out->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf + } + } + //johnfitz + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* +================= +Mod_LoadLeafs +================= +*/ +void Mod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + //johnfitz + if (count > 32767) + Host_Error ("Mod_LoadLeafs: %i leafs exceeds limit of 32767.\n", count); + //johnfitz + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->firstmarksurface = loadmodel->marksurfaces + (unsigned short)LittleShort(in->firstmarksurface); //johnfitz -- unsigned short + out->nummarksurfaces = (unsigned short)LittleShort(in->nummarksurfaces); //johnfitz -- unsigned short + + p = LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = NULL; + else + out->compressed_vis = loadmodel->visdata + p; + out->efrags = NULL; + + for (j=0 ; j<4 ; j++) + out->ambient_sound_level[j] = in->ambient_level[j]; + + //johnfitz -- removed code to mark surfaces as SURF_UNDERWATER + } +} + +/* +================= +Mod_LoadClipnodes +================= +*/ +void Mod_LoadClipnodes (lump_t *l) +{ + dclipnode_t *in; + mclipnode_t *out; //johnfitz -- was dclipnode_t + int i, count; + hull_t *hull; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + //johnfitz -- warn about exceeding old limits + if (count > 32767) + Con_Warning ("%i clipnodes exceeds standard limit of 32767.\n", count); + //johnfitz + + loadmodel->clipnodes = out; + loadmodel->numclipnodes = count; + + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 32; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 64; + + for (i=0 ; iplanenum = LittleLong(in->planenum); + + //johnfitz -- bounds check + if (out->planenum < 0 || out->planenum >= loadmodel->numplanes) + Host_Error ("Mod_LoadClipnodes: planenum out of bounds"); + //johnfitz + + //johnfitz -- support clipnodes > 32k + out->children[0] = (unsigned short)LittleShort(in->children[0]); + out->children[1] = (unsigned short)LittleShort(in->children[1]); + if (out->children[0] >= count) + out->children[0] -= 65536; + if (out->children[1] >= count) + out->children[1] -= 65536; + //johnfitz + } +} + +/* +================= +Mod_MakeHull0 + +Duplicate the drawing hull structure as a clipping hull +================= +*/ +void Mod_MakeHull0 (void) +{ + mnode_t *in, *child; + mclipnode_t *out; //johnfitz -- was dclipnode_t + int i, j, count; + hull_t *hull; + + hull = &loadmodel->hulls[0]; + + in = loadmodel->nodes; + count = loadmodel->numnodes; + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + + for (i=0 ; iplanenum = in->plane - loadmodel->planes; + for (j=0 ; j<2 ; j++) + { + child = in->children[j]; + if (child->contents < 0) + out->children[j] = child->contents; + else + out->children[j] = child - loadmodel->nodes; + } + } +} + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void Mod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + //johnfitz -- warn mappers about exceeding old limits + if (count > 32767) + Con_Warning ("%i marksurfaces exceeds standard limit of 32767.\n", count); + //johnfitz + + for ( i=0 ; i= loadmodel->numsurfaces) + Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* +================= +Mod_LoadSurfedges +================= +*/ +void Mod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*2*sizeof(*out), loadname); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + +/* +================= +RadiusFromBounds +================= +*/ +float RadiusFromBounds (vec3_t mins, vec3_t maxs) +{ + int i; + vec3_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return Length (corner); +} + +/* +================= +Mod_LoadSubmodels +================= +*/ +void Mod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + dmodel_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + for (j=0 ; jheadnode[j] = LittleLong (in->headnode[j]); + out->visleafs = LittleLong (in->visleafs); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } + + // johnfitz -- check world visleafs -- adapted from bjp + out = loadmodel->submodels; + + if (out->visleafs > MAX_MAP_LEAFS) + Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", out->visleafs, MAX_MAP_LEAFS, loadmodel->name); + + if (out->visleafs > 8192) + Con_Warning ("%i visleafs exceeds standard limit of 8192.\n", out->visleafs); + //johnfitz +} + +/* +================= +Mod_BoundsFromClipNode -- johnfitz + +update the model's clipmins and clipmaxs based on each node's plane. + +This works because of the way brushes are expanded in hull generation. +Each brush will include all six axial planes, which bound that brush. +Therefore, the bounding box of the hull can be constructed entirely +from axial planes found in the clipnodes for that hull. +================= +*/ +void Mod_BoundsFromClipNode (model_t *mod, int hull, int nodenum) +{ + mplane_t *plane; + mclipnode_t *node; + + if (nodenum < 0) + return; //hit a leafnode + + node = &mod->clipnodes[nodenum]; + plane = mod->hulls[hull].planes + node->planenum; + switch (plane->type) + { + + case PLANE_X: + if (plane->signbits == 1) + mod->clipmins[0] = min (mod->clipmins[0], -plane->dist - mod->hulls[hull].clip_mins[0]); + else + mod->clipmaxs[0] = max (mod->clipmaxs[0], plane->dist - mod->hulls[hull].clip_maxs[0]); + break; + case PLANE_Y: + if (plane->signbits == 2) + mod->clipmins[1] = min (mod->clipmins[1], -plane->dist - mod->hulls[hull].clip_mins[1]); + else + mod->clipmaxs[1] = max (mod->clipmaxs[1], plane->dist - mod->hulls[hull].clip_maxs[1]); + break; + case PLANE_Z: + if (plane->signbits == 4) + mod->clipmins[2] = min (mod->clipmins[2], -plane->dist - mod->hulls[hull].clip_mins[2]); + else + mod->clipmaxs[2] = max (mod->clipmaxs[2], plane->dist - mod->hulls[hull].clip_maxs[2]); + break; + default: + //skip nonaxial planes; don't need them + break; + } + + Mod_BoundsFromClipNode (mod, hull, node->children[0]); + Mod_BoundsFromClipNode (mod, hull, node->children[1]); +} + +/* +================= +Mod_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i, j; + dheader_t *header; + dmodel_t *bm; + float radius; //johnfitz + + loadmodel->type = mod_brush; + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) + Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); + Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); + Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]); + Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (&header->lumps[LUMP_NODES]); + Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]); + Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); + Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); + + Mod_MakeHull0 (); + + mod->numframes = 2; // regular and alternate animation + +// +// set up the submodels (FIXME: this is confusing) +// + + // johnfitz -- okay, so that i stop getting confused every time i look at this loop, here's how it works: + // we're looping through the submodels starting at 0. Submodel 0 is the main model, so we don't have to + // worry about clobbering data the first time through, since it's the same data. At the end of the loop, + // we create a new copy of the data to use the next time through. + for (i=0 ; inumsubmodels ; i++) + { + bm = &mod->submodels[i]; + + mod->hulls[0].firstclipnode = bm->headnode[0]; + for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; + mod->hulls[j].lastclipnode = mod->numclipnodes-1; + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + + VectorCopy (bm->maxs, mod->maxs); + VectorCopy (bm->mins, mod->mins); + + //johnfitz -- calculate rotate bounds and yaw bounds + radius = RadiusFromBounds (mod->mins, mod->maxs); + mod->rmaxs[0] = mod->rmaxs[1] = mod->rmaxs[2] = mod->ymaxs[0] = mod->ymaxs[1] = mod->ymaxs[2] = radius; + mod->rmins[0] = mod->rmins[1] = mod->rmins[2] = mod->ymins[0] = mod->ymins[1] = mod->ymins[2] = -radius; + //johnfitz + + //johnfitz -- correct physics cullboxes so that outlying clip brushes on doors and stuff are handled right + if (i > 0 || strcmp(mod->name, sv.modelname) != 0) //skip submodel 0 of sv.worldmodel, which is the actual world + { + // start with the hull0 bounds + VectorCopy (mod->maxs, mod->clipmaxs); + VectorCopy (mod->mins, mod->clipmins); + + // process hull1 (we don't need to process hull2 becuase there's + // no such thing as a brush that appears in hull2 but not hull1) + //Mod_BoundsFromClipNode (mod, 1, mod->hulls[1].firstclipnode); // (disabled for now becuase it fucks up on rotating models) + } + //johnfitz + + mod->numleafs = bm->visleafs; + + if (i < mod->numsubmodels-1) + { // duplicate the basic information + char name[10]; + + sprintf (name, "*%i", i+1); + loadmodel = Mod_FindName (name); + *loadmodel = *mod; + strcpy (loadmodel->name, name); + mod = loadmodel; + } + } +} + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +aliashdr_t *pheader; + +stvert_t stverts[MAXALIASVERTS]; +mtriangle_t triangles[MAXALIASTRIS]; + +// a pose is a single set of vertexes. a frame may be +// an animating sequence of poses +trivertx_t *poseverts[MAXALIASFRAMES]; +int posenum; + +byte **player_8bit_texels_tbl; +byte *player_8bit_texels; + +/* +================= +Mod_LoadAliasFrame +================= +*/ +void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame) +{ + trivertx_t *pframe, *pinframe; + int i, j; + daliasframe_t *pdaliasframe; + + pdaliasframe = (daliasframe_t *)pin; + + strcpy (frame->name, pdaliasframe->name); + frame->firstpose = posenum; + frame->numposes = 1; + + for (i=0 ; i<3 ; i++) + { + // these are byte values, so we don't have to worry about + // endianness + frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i]; + frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i]; + } + + + pinframe = (trivertx_t *)(pdaliasframe + 1); + + poseverts[posenum] = pinframe; + posenum++; + + pinframe += pheader->numverts; + + return (void *)pinframe; +} + + +/* +================= +Mod_LoadAliasGroup +================= +*/ +void *Mod_LoadAliasGroup (void * pin, maliasframedesc_t *frame) +{ + daliasgroup_t *pingroup; + int i, numframes; + daliasinterval_t *pin_intervals; + void *ptemp; + + pingroup = (daliasgroup_t *)pin; + + numframes = LittleLong (pingroup->numframes); + + frame->firstpose = posenum; + frame->numposes = numframes; + + for (i=0 ; i<3 ; i++) + { + // these are byte values, so we don't have to worry about endianness + frame->bboxmin.v[i] = pingroup->bboxmin.v[i]; + frame->bboxmax.v[i] = pingroup->bboxmax.v[i]; + } + + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + + frame->interval = LittleFloat (pin_intervals->interval); + + pin_intervals += numframes; + + ptemp = (void *)pin_intervals; + + for (i=0 ; inumverts; + } + + return ptemp; +} + +//========================================================= + + +/* +================= +Mod_FloodFillSkin + +Fill background pixels so mipmapping doesn't have haloes - Ed +================= +*/ + +typedef struct +{ + short x, y; +} floodfill_t; + +extern unsigned d_8to24table[]; + +// must be a power of 2 +#define FLOODFILL_FIFO_SIZE 0x1000 +#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) + +#define FLOODFILL_STEP( off, dx, dy ) \ +{ \ + if (pos[off] == fillcolor) \ + { \ + pos[off] = 255; \ + fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ + } \ + else if (pos[off] != 255) fdc = pos[off]; \ +} + +void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) +{ + byte fillcolor = *skin; // assume this is the pixel to fill + floodfill_t fifo[FLOODFILL_FIFO_SIZE]; + int inpt = 0, outpt = 0; + int filledcolor = -1; + int i; + + if (filledcolor == -1) + { + filledcolor = 0; + // attempt to find opaque black + for (i = 0; i < 256; ++i) + if (d_8to24table[i] == (255 << 0)) // alpha 1.0 + { + filledcolor = i; + break; + } + } + + // can't fill to filled color or to transparent color (used as visited marker) + if ((fillcolor == filledcolor) || (fillcolor == 255)) + { + //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); + return; + } + + fifo[inpt].x = 0, fifo[inpt].y = 0; + inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; + + while (outpt != inpt) + { + int x = fifo[outpt].x, y = fifo[outpt].y; + int fdc = filledcolor; + byte *pos = &skin[x + skinwidth * y]; + + outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; + + if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); + if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); + if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); + if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); + skin[x + skinwidth * y] = fdc; + } +} + +/* +=============== +Mod_LoadAllSkins +=============== +*/ +void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) +{ + int i, j, k, size, groupskins; + char name[32]; + byte *copy, *skin, *texels; + daliasskingroup_t *pinskingroup; + daliasskininterval_t *pinskinintervals; + int padx, pady, ii, jj; //johnfitz -- padded player skin + char fbr_mask_name[64]; //johnfitz -- added for fullbright support + unsigned offset; //johnfitz + + skin = (byte *)(pskintype + 1); + + if (numskins < 1 || numskins > MAX_SKINS) + Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); + + size = pheader->skinwidth * pheader->skinheight; + + for (i=0 ; itype == ALIAS_SKIN_SINGLE) + { + Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight ); + + // save 8 bit texels for the player model to remap + texels = Hunk_AllocName(size, loadname); + pheader->texels[i] = texels - (byte *)pheader; + memcpy (texels, (byte *)(pskintype + 1), size); + + //johnfitz -- rewritten + sprintf (name, "%s:frame%i", loadmodel->name, i); + offset = (unsigned)(pskintype+1) - (unsigned)mod_base; + if (Mod_CheckFullbrights ((byte *)(pskintype+1), size)) + { + pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT); + sprintf (fbr_mask_name, "%s:frame%i_glow", loadmodel->name, i); + pheader->fbtextures[i][0] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT); + } + else + { + pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, TEXPREF_PAD); + pheader->fbtextures[i][0] = NULL; + } + + pheader->gltextures[i][3] = pheader->gltextures[i][2] = pheader->gltextures[i][1] = pheader->gltextures[i][0]; + pheader->fbtextures[i][3] = pheader->fbtextures[i][2] = pheader->fbtextures[i][1] = pheader->fbtextures[i][0]; + //johnfitz + + pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + size); + } + else + { + // animating skin group. yuck. + pskintype++; + pinskingroup = (daliasskingroup_t *)pskintype; + groupskins = LittleLong (pinskingroup->numskins); + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + + pskintype = (void *)(pinskinintervals + groupskins); + + for (j=0 ; jskinwidth, pheader->skinheight ); + if (j == 0) { + texels = Hunk_AllocName(size, loadname); + pheader->texels[i] = texels - (byte *)pheader; + memcpy (texels, (byte *)(pskintype), size); + } + + //johnfitz -- rewritten + sprintf (name, "%s:frame%i_%i", loadmodel->name, i,j); + offset = (unsigned)(pskintype) - (unsigned)mod_base; //johnfitz + if (Mod_CheckFullbrights ((byte *)(pskintype), size)) + { + pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_NOBRIGHT); + sprintf (fbr_mask_name, "%s:frame%i_%i_glow", loadmodel->name, i,j); + pheader->fbtextures[i][j&3] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD | TEXPREF_FULLBRIGHT); + } + else + { + pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, TEXPREF_PAD); + pheader->fbtextures[i][j&3] = NULL; + } + //johnfitz + + pskintype = (daliasskintype_t *)((byte *)(pskintype) + size); + } + k = j; + for (/* */; j < 4; j++) + pheader->gltextures[i][j&3] = + pheader->gltextures[i][j - k]; + } + } + + return (void *)pskintype; +} + +//========================================================================= + +/* +================= +Mod_CalcAliasBounds -- johnfitz -- calculate bounds of alias model for nonrotated, yawrotated, and fullrotated cases +================= +*/ +void Mod_CalcAliasBounds (aliashdr_t *a) +{ + int i,j,k; + float dist, yawradius, radius; + vec3_t v; + + //clear out all data + for (i=0; i<3;i++) + { + loadmodel->mins[i] = loadmodel->ymins[i] = loadmodel->rmins[i] = 999999; + loadmodel->maxs[i] = loadmodel->ymaxs[i] = loadmodel->rmaxs[i] = -999999; + radius = yawradius = 0; + } + + //process verts + for (i=0 ; inumposes; i++) + for (j=0; jnumverts; j++) + { + for (k=0; k<3;k++) + v[k] = poseverts[i][j].v[k] * pheader->scale[k] + pheader->scale_origin[k]; + + for (k=0; k<3;k++) + { + loadmodel->mins[k] = min (loadmodel->mins[k], v[k]); + loadmodel->maxs[k] = max (loadmodel->maxs[k], v[k]); + } + dist = v[0] * v[0] + v[1] * v[1]; + if (yawradius < dist) + yawradius = dist; + dist += v[2] * v[2]; + if (radius < dist) + radius = dist; + } + + //rbounds will be used when entity has nonzero pitch or roll + radius = sqrt(radius); + loadmodel->rmins[0] = loadmodel->rmins[1] = loadmodel->rmins[2] = -radius; + loadmodel->rmaxs[0] = loadmodel->rmaxs[1] = loadmodel->rmaxs[2] = radius; + + //ybounds will be used when entity has nonzero yaw + yawradius = sqrt(yawradius); + loadmodel->ymins[0] = loadmodel->ymins[1] = -yawradius; + loadmodel->ymaxs[0] = loadmodel->ymaxs[1] = yawradius; + loadmodel->ymins[2] = loadmodel->mins[2]; + loadmodel->ymaxs[2] = loadmodel->maxs[2]; +} + +/* +================= +Mod_SetExtraFlags -- johnfitz -- set up extra flags that aren't in the mdl +================= +*/ +void Mod_SetExtraFlags (model_t *mod) +{ + extern cvar_t r_nolerp_list; + char *s; + int i; + + if (!mod || !mod->name || mod->type != mod_alias) + return; + + mod->flags &= 0xFF; //only preserve first byte + + // nolerp flag + for (s=r_nolerp_list.string; *s; s += i+1, i=0) + { + //search forwards to the next comma or end of string + for (i=0; s[i] != ',' && s[i] != 0; i++) ; + + //compare it to the model name + if (!strncmp(mod->name, s, i)) + { + mod->flags |= MOD_NOLERP; + break; + } + } + + // noshadow flag (TODO: make this a cvar list) + if (!strcmp (mod->name, "progs/flame2.mdl") || + !strcmp (mod->name, "progs/flame.mdl") || + !strcmp (mod->name, "progs/bolt1.mdl") || + !strcmp (mod->name, "progs/bolt2.mdl") || + !strcmp (mod->name, "progs/bolt3.mdl") || + !strcmp (mod->name, "progs/laser.mdl")) + mod->flags |= MOD_NOSHADOW; + + // fullbright hack (TODO: make this a cvar list) + if (!strcmp (mod->name, "progs/flame2.mdl") || + !strcmp (mod->name, "progs/flame.mdl") || + !strcmp (mod->name, "progs/boss.mdl")) + mod->flags |= MOD_FBRIGHTHACK; +} + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i, j; + mdl_t *pinmodel; + stvert_t *pinstverts; + dtriangle_t *pintriangles; + int version, numframes;//, numskins; unused -- kristian + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + int start, end, total; + + start = Hunk_LowMark (); + + pinmodel = (mdl_t *)buffer; + mod_base = (byte *)buffer; //johnfitz + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0]); + pheader = Hunk_AllocName (size, loadname); + + mod->flags = LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pheader->boundingradius = LittleFloat (pinmodel->boundingradius); + pheader->numskins = LittleLong (pinmodel->numskins); + pheader->skinwidth = LittleLong (pinmodel->skinwidth); + pheader->skinheight = LittleLong (pinmodel->skinheight); + + if (pheader->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pheader->numverts = LittleLong (pinmodel->numverts); + + if (pheader->numverts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pheader->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pheader->numtris = LittleLong (pinmodel->numtris); + + if (pheader->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pheader->numframes = LittleLong (pinmodel->numframes); + numframes = pheader->numframes; + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO; + mod->synctype = LittleLong (pinmodel->synctype); + mod->numframes = pheader->numframes; + + for (i=0 ; i<3 ; i++) + { + pheader->scale[i] = LittleFloat (pinmodel->scale[i]); + pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); + pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); + } + + +// +// load the skins +// + pskintype = (daliasskintype_t *)&pinmodel[1]; + pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype); + +// +// load base s and t vertices +// + pinstverts = (stvert_t *)pskintype; + + for (i=0 ; inumverts ; i++) + { + stverts[i].onseam = LittleLong (pinstverts[i].onseam); + stverts[i].s = LittleLong (pinstverts[i].s); + stverts[i].t = LittleLong (pinstverts[i].t); + } + +// +// load triangle lists +// + pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts]; + + for (i=0 ; inumtris ; i++) + { + triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); + + for (j=0 ; j<3 ; j++) + { + triangles[i].vertindex[j] = + LittleLong (pintriangles[i].vertindex[j]); + } + } + +// +// load the frames +// + posenum = 0; + pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris]; + + for (i=0 ; itype); + if (frametype == ALIAS_SINGLE) + pframetype = (daliasframetype_t *) Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]); + else + pframetype = (daliasframetype_t *) Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]); + } + + pheader->numposes = posenum; + + mod->type = mod_alias; + + Mod_SetExtraFlags (mod); //johnfitz + + Mod_CalcAliasBounds (pheader); //johnfitz + + // + // build the draw lists + // + GL_MakeAliasModelDisplayLists (mod, pheader); + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +} + +//============================================================================= + +/* +================= +Mod_LoadSpriteFrame +================= +*/ +void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum) +{ + dspriteframe_t *pinframe; + mspriteframe_t *pspriteframe; + int width, height, size, origin[2];//, i; unused -- kristian + /* unused -- kristian + unsigned short *ppixout; + byte *ppixin; + */ + char name[64]; + unsigned offset; //johnfitz + + pinframe = (dspriteframe_t *)pin; + + width = LittleLong (pinframe->width); + height = LittleLong (pinframe->height); + size = width * height; + + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t),loadname); + + Q_memset (pspriteframe, 0, sizeof (mspriteframe_t)); + + *ppframe = pspriteframe; + + pspriteframe->width = width; + pspriteframe->height = height; + origin[0] = LittleLong (pinframe->origin[0]); + origin[1] = LittleLong (pinframe->origin[1]); + + pspriteframe->up = origin[1]; + pspriteframe->down = origin[1] - height; + pspriteframe->left = origin[0]; + pspriteframe->right = width + origin[0]; + + //johnfitz -- image might be padded + pspriteframe->smax = (float)width/(float)TexMgr_PadConditional(width); + pspriteframe->tmax = (float)height/(float)TexMgr_PadConditional(height); + //johnfitz + + sprintf (name, "%s:frame%i", loadmodel->name, framenum); + offset = (unsigned)(pinframe+1) - (unsigned)mod_base; //johnfitz + pspriteframe->gltexture = + TexMgr_LoadImage (loadmodel, name, width, height, SRC_INDEXED, (byte *)(pinframe + 1), + loadmodel->name, offset, TEXPREF_PAD | TEXPREF_ALPHA | TEXPREF_NOPICMIP); //johnfitz -- TexMgr + + return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size); +} + + +/* +================= +Mod_LoadSpriteGroup +================= +*/ +void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum) +{ + dspritegroup_t *pingroup; + mspritegroup_t *pspritegroup; + int i, numframes; + dspriteinterval_t *pin_intervals; + float *poutintervals; + void *ptemp; + + pingroup = (dspritegroup_t *)pin; + + numframes = LittleLong (pingroup->numframes); + + pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) + + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname); + + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_t *)pspritegroup; + + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + + pspritegroup->intervals = poutintervals; + + for (i=0 ; iinterval); + if (*poutintervals <= 0.0) + Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i], framenum * 100 + i); + } + + return ptemp; +} + + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void Mod_LoadSpriteModel (model_t *mod, void *buffer) +{ + int i; + int version; + dsprite_t *pin; + msprite_t *psprite; + int numframes; + int size; + dspriteframetype_t *pframetype; + + pin = (dsprite_t *)buffer; + mod_base = (byte *)buffer; //johnfitz + + version = LittleLong (pin->version); + if (version != SPRITE_VERSION) + Sys_Error ("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE_VERSION); + + numframes = LittleLong (pin->numframes); + + size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); + + psprite = Hunk_AllocName (size, loadname); + + mod->cache.data = psprite; + + psprite->type = LittleLong (pin->type); + psprite->maxwidth = LittleLong (pin->width); + psprite->maxheight = LittleLong (pin->height); + psprite->beamlength = LittleFloat (pin->beamlength); + mod->synctype = LittleLong (pin->synctype); + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2; + mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2; + mod->mins[2] = -psprite->maxheight/2; + mod->maxs[2] = psprite->maxheight/2; + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); + + mod->numframes = numframes; + + pframetype = (dspriteframetype_t *)(pin + 1); + + for (i=0 ; itype); + psprite->frames[i].type = frametype; + + if (frametype == SPR_SINGLE) + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteFrame (pframetype + 1, + &psprite->frames[i].frameptr, i); + } + else + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteGroup (pframetype + 1, + &psprite->frames[i].frameptr, i); + } + } + + mod->type = mod_sprite; +} + +//============================================================================= + +/* +================ +Mod_Print +================ +*/ +void Mod_Print (void) +{ + int i; + model_t *mod; + + Con_SafePrintf ("Cached models:\n"); //johnfitz -- safeprint instead of print + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + Con_SafePrintf ("%8p : %s\n", mod->cache.data, mod->name); //johnfitz -- safeprint instead of print + } + Con_Printf ("%i models\n",mod_numknown); //johnfitz -- print the total too +} + + diff --git a/Quake/gl_model.h b/Quake/gl_model.h new file mode 100644 index 00000000..c31f3a52 --- /dev/null +++ b/Quake/gl_model.h @@ -0,0 +1,454 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __MODEL__ +#define __MODEL__ + +#include "modelgen.h" +#include "spritegn.h" + +/* + +d*_t structures are on-disk representations +m*_t structures are in-memory + +*/ + +// entity effects + +#define EF_BRIGHTFIELD 1 +#define EF_MUZZLEFLASH 2 +#define EF_BRIGHTLIGHT 4 +#define EF_DIMLIGHT 8 + + +/* +============================================================================== + +BRUSH MODELS + +============================================================================== +*/ + + +// +// in memory representation +// +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + vec3_t position; +} mvertex_t; + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + + +// plane_t structure +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +typedef struct texture_s +{ + char name[16]; + unsigned width, height; + struct gltexture_s *gltexture; //johnfitz -- pointer to gltexture + struct gltexture_s *fullbright; //johnfitz -- fullbright mask texture + struct gltexture_s *warpimage; //johnfitz -- for water animation + qboolean update_warp; //johnfitz -- update warp this frame + struct msurface_s *texturechain; // for texture chains + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frmae 1 use these + unsigned offsets[MIPLEVELS]; // four mip maps stored +} texture_t; + + +#define SURF_PLANEBACK 2 +#define SURF_DRAWSKY 4 +#define SURF_DRAWSPRITE 8 +#define SURF_DRAWTURB 0x10 +#define SURF_DRAWTILED 0x20 +#define SURF_DRAWBACKGROUND 0x40 +#define SURF_UNDERWATER 0x80 +#define SURF_NOTEXTURE 0x100 //johnfitz + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +typedef struct +{ + float vecs[2][4]; + float mipadjust; + texture_t *texture; + int flags; +} mtexinfo_t; + +#define VERTEXSIZE 7 + +typedef struct glpoly_s +{ + struct glpoly_s *next; + struct glpoly_s *chain; + int numverts; + float verts[4][VERTEXSIZE]; // variable sized (xyz s1t1 s2t2) +} glpoly_t; + +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + qboolean culled; // johnfitz -- for frustum culling + float mins[3]; // johnfitz -- for frustum culling + float maxs[3]; // johnfitz -- for frustum culling + + mplane_t *plane; + int flags; + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + + short texturemins[2]; + short extents[2]; + + int light_s, light_t; // gl lightmap coordinates + + glpoly_t *polys; // multiple if warped + struct msurface_s *texturechain; + + mtexinfo_t *texinfo; + +// lighting info + int dlightframe; + int dlightbits; + + int lightmaptexturenum; + byte styles[MAXLIGHTMAPS]; + int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + qboolean cached_dlight; // true if dynamic light in cache + byte *samples; // [numstyles*surfsize] +} msurface_t; + +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + float minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + byte *compressed_vis; + efrag_t *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_t; + +//johnfitz -- for clipnodes>32k +typedef struct mclipnode_s +{ + int planenum; + int children[2]; // negative numbers are contents +} mclipnode_t; +//johnfitz + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + mclipnode_t *clipnodes; //johnfitz -- was dclipnode_t + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; + +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + + +// FIXME: shorten these? +typedef struct mspriteframe_s +{ + int width, height; + float up, down, left, right; + float smax, tmax; //johnfitz -- image might be padded + struct gltexture_s *gltexture; +} mspriteframe_t; + +typedef struct +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +typedef struct +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +typedef struct +{ + int type; + int maxwidth; + int maxheight; + int numframes; + float beamlength; // remove? + void *cachespot; // remove? + mspriteframedesc_t frames[1]; +} msprite_t; + + +/* +============================================================================== + +ALIAS MODELS + +Alias models are position independent, so the cache manager can move them. +============================================================================== +*/ + +typedef struct +{ + int firstpose; + int numposes; + float interval; + trivertx_t bboxmin; + trivertx_t bboxmax; + int frame; + char name[16]; +} maliasframedesc_t; + +typedef struct +{ + trivertx_t bboxmin; + trivertx_t bboxmax; + int frame; +} maliasgroupframedesc_t; + +typedef struct +{ + int numframes; + int intervals; + maliasgroupframedesc_t frames[1]; +} maliasgroup_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct mtriangle_s { + int facesfront; + int vertindex[3]; +} mtriangle_t; + + +#define MAX_SKINS 32 +typedef struct { + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; + + int numposes; + int poseverts; + int posedata; // numposes*poseverts trivert_t + int commands; // gl command list with embedded s/t + struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz + struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz + int texels[MAX_SKINS]; // only for player skins + maliasframedesc_t frames[1]; // variable sized +} aliashdr_t; + +#define MAXALIASVERTS 2000 //johnfitz -- was 1024 +#define MAXALIASFRAMES 256 +#define MAXALIASTRIS 2048 +extern aliashdr_t *pheader; +extern stvert_t stverts[MAXALIASVERTS]; +extern mtriangle_t triangles[MAXALIASTRIS]; +extern trivertx_t *poseverts[MAXALIASFRAMES]; + +//=================================================================== + +// +// Whole model +// + +typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t; + +#define EF_ROCKET 1 // leave a trail +#define EF_GRENADE 2 // leave a trail +#define EF_GIB 4 // leave a trail +#define EF_ROTATE 8 // rotate (bonus items) +#define EF_TRACER 16 // green split trail +#define EF_ZOMGIB 32 // small blood trail +#define EF_TRACER2 64 // orange split trail + rotate +#define EF_TRACER3 128 // purple trail + +//johnfitz -- extra flags for rendering +#define MOD_NOLERP 256 //don't lerp when animating +#define MOD_NOSHADOW 512 //don't cast a shadow +#define MOD_FBRIGHTHACK 1024 //when fullbrights are disabled, use a hack to render this model brighter +//johnfitz + +typedef struct model_s +{ + char name[MAX_QPATH]; + qboolean needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + +// +// volume occupied by the model graphics +// + vec3_t mins, maxs; + vec3_t ymins, ymaxs; //johnfitz -- bounds for entities with nonzero yaw + vec3_t rmins, rmaxs; //johnfitz -- bounds for entities with nonzero pitch or roll + //johnfitz -- removed float radius; + +// +// solid volume for clipping +// + qboolean clipbox; + vec3_t clipmins, clipmaxs; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + mclipnode_t *clipnodes; //johnfitz -- was dclipnode_t + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + byte *lightdata; + char *entities; + +// +// additional model data +// + cache_user_t cache; // only access through Mod_Extradata + +} model_t; + +//============================================================================ + +void Mod_Init (void); +void Mod_ClearAll (void); +model_t *Mod_ForName (char *name, qboolean crash); +void *Mod_Extradata (model_t *mod); // handles caching +void Mod_TouchModel (char *name); + +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); + +#endif // __MODEL__ diff --git a/Quake/gl_refrag.c b/Quake/gl_refrag.c new file mode 100644 index 00000000..20a6a044 --- /dev/null +++ b/Quake/gl_refrag.c @@ -0,0 +1,244 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_efrag.c + +#include "quakedef.h" + +mnode_t *r_pefragtopnode; + + +//=========================================================================== + +/* +=============================================================================== + + ENTITY FRAGMENT FUNCTIONS + +=============================================================================== +*/ + +efrag_t **lastlink; + +vec3_t r_emins, r_emaxs; + +entity_t *r_addent; + + +/* +================ +R_RemoveEfrags + +Call when removing an object from the world or moving it to another position +================ +*/ +void R_RemoveEfrags (entity_t *ent) +{ + efrag_t *ef, *old, *walk, **prev; + + ef = ent->efrag; + + while (ef) + { + prev = &ef->leaf->efrags; + while (1) + { + walk = *prev; + if (!walk) + break; + if (walk == ef) + { // remove this fragment + *prev = ef->leafnext; + break; + } + else + prev = &walk->leafnext; + } + + old = ef; + ef = ef->entnext; + + // put it on the free list + old->entnext = cl.free_efrags; + cl.free_efrags = old; + } + + ent->efrag = NULL; +} + +/* +=================== +R_SplitEntityOnNode +=================== +*/ +void R_SplitEntityOnNode (mnode_t *node) +{ + efrag_t *ef; + mplane_t *splitplane; + mleaf_t *leaf; + int sides; + + if (node->contents == CONTENTS_SOLID) + { + return; + } + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (!r_pefragtopnode) + r_pefragtopnode = node; + + leaf = (mleaf_t *)node; + +// grab an efrag off the free list + ef = cl.free_efrags; + if (!ef) + { + //johnfitz -- less spammy overflow message + if (!dev_overflows.efrags || dev_overflows.efrags + CONSOLE_RESPAM_TIME < realtime ) + { + Con_Printf ("Too many efrags!\n"); + dev_overflows.efrags = realtime; + } + //johnfitz + return; // no free fragments... + } + cl.free_efrags = cl.free_efrags->entnext; + + ef->entity = r_addent; + +// add the entity link + *lastlink = ef; + lastlink = &ef->entnext; + ef->entnext = NULL; + +// set the leaf links + ef->leaf = leaf; + ef->leafnext = leaf->efrags; + leaf->efrags = ef; + + return; + } + +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); + + if (sides == 3) + { + // split on this plane + // if this is the first splitter of this bmodel, remember it + if (!r_pefragtopnode) + r_pefragtopnode = node; + } + +// recurse down the contacted sides + if (sides & 1) + R_SplitEntityOnNode (node->children[0]); + + if (sides & 2) + R_SplitEntityOnNode (node->children[1]); +} + +/* +=========== +R_CheckEfrags -- johnfitz -- check for excessive efrag count +=========== +*/ +void R_CheckEfrags (void) +{ + efrag_t *ef; + int count; + + if (cls.signon < 2) + return; //don't spam when still parsing signon packet full of static ents + + for (count=MAX_EFRAGS, ef = cl.free_efrags; ef; count--, ef = ef->entnext) + ; + + if (count > 640 && dev_peakstats.efrags <= 640) + Con_Warning ("%i efrags exceeds standard limit of 640.\n", count); + + dev_stats.efrags = count; + dev_peakstats.efrags = max(count, dev_peakstats.efrags); +} + +/* +=========== +R_AddEfrags +=========== +*/ +void R_AddEfrags (entity_t *ent) +{ + model_t *entmodel; + int i; + + if (!ent->model) + return; + + r_addent = ent; + + lastlink = &ent->efrag; + r_pefragtopnode = NULL; + + entmodel = ent->model; + + for (i=0 ; i<3 ; i++) + { + r_emins[i] = ent->origin[i] + entmodel->mins[i]; + r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; + } + + R_SplitEntityOnNode (cl.worldmodel->nodes); + + ent->topnode = r_pefragtopnode; + + R_CheckEfrags (); //johnfitz +} + + +/* +================ +R_StoreEfrags -- johnfitz -- pointless switch statement removed. +================ +*/ +void R_StoreEfrags (efrag_t **ppefrag) +{ + entity_t *pent; + efrag_t *pefrag; + + while ((pefrag = *ppefrag) != NULL) + { + pent = pefrag->entity; + + if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) + { + cl_visedicts[cl_numvisedicts++] = pent; + pent->visframe = r_framecount; + } + + ppefrag = &pefrag->leafnext; + } +} + + diff --git a/Quake/gl_rlight.c b/Quake/gl_rlight.c new file mode 100644 index 00000000..09183888 --- /dev/null +++ b/Quake/gl_rlight.c @@ -0,0 +1,391 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_light.c + +#include "quakedef.h" + +int r_dlightframecount; + +extern cvar_t r_flatlightstyles; //johnfitz + +/* +================== +R_AnimateLight +================== +*/ +void R_AnimateLight (void) +{ + int i,j,k; + +// +// light animations +// 'm' is normal light, 'a' is no light, 'z' is double bright + i = (int)(cl.time*10); + for (j=0 ; jradius * 0.35; + + VectorSubtract (light->origin, r_origin, v); + if (Length (v) < rad) + { // view is inside the dlight + AddLightBlend (1, 0.5, 0, light->radius * 0.0003); + return; + } + + glBegin (GL_TRIANGLE_FAN); + glColor3f (0.2,0.1,0.0); + for (i=0 ; i<3 ; i++) + v[i] = light->origin[i] - vpn[i]*rad; + glVertex3fv (v); + glColor3f (0,0,0); + for (i=16 ; i>=0 ; i--) + { + a = i/16.0 * M_PI*2; + for (j=0 ; j<3 ; j++) + v[j] = light->origin[j] + vright[j]*cos(a)*rad + + vup[j]*sin(a)*rad; + glVertex3fv (v); + } + glEnd (); +} + +/* +============= +R_RenderDlights +============= +*/ +void R_RenderDlights (void) +{ + int i; + dlight_t *l; + + if (!gl_flashblend.value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + glDepthMask (0); + glDisable (GL_TEXTURE_2D); + glShadeModel (GL_SMOOTH); + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + + l = cl_dlights; + for (i=0 ; idie < cl.time || !l->radius) + continue; + R_RenderDlight (l); + } + + glColor3f (1,1,1); + glDisable (GL_BLEND); + glEnable (GL_TEXTURE_2D); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask (1); +} + + +/* +============================================================================= + +DYNAMIC LIGHTS + +============================================================================= +*/ + +/* +============= +R_MarkLights -- johnfitz -- rewritten to use LordHavoc's lighting speedup +============= +*/ +void R_MarkLights (dlight_t *light, int bit, mnode_t *node) +{ + mplane_t *splitplane; + msurface_t *surf; + vec3_t impact; + float dist, l, maxdist; + int i, j, s, t; + +start: + + if (node->contents < 0) + return; + + splitplane = node->plane; + if (splitplane->type < 3) + dist = light->origin[splitplane->type] - splitplane->dist; + else + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->radius) + { + node = node->children[0]; + goto start; + } + if (dist < -light->radius) + { + node = node->children[1]; + goto start; + } + + maxdist = light->radius*light->radius; +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + for (j=0 ; j<3 ; j++) + impact[j] = light->origin[j] - surf->plane->normal[j]*dist; + // clamp center of light to corner and check brightness + l = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0]; + s = l+0.5;if (s < 0) s = 0;else if (s > surf->extents[0]) s = surf->extents[0]; + s = l - s; + l = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1]; + t = l+0.5;if (t < 0) t = 0;else if (t > surf->extents[1]) t = surf->extents[1]; + t = l - t; + // compare to minimum light + if ((s*s+t*t+dist*dist) < maxdist) + { + if (surf->dlightframe != r_dlightframecount) // not dynamic until now + { + surf->dlightbits = bit; + surf->dlightframe = r_dlightframecount; + } + else // already dynamic + surf->dlightbits |= bit; + } + } + + if (node->children[0]->contents >= 0) + R_MarkLights (light, bit, node->children[0]); + if (node->children[1]->contents >= 0) + R_MarkLights (light, bit, node->children[1]); +} + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + if (gl_flashblend.value) + return; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = cl_dlights; + + for (i=0 ; idie < cl.time || !l->radius) + continue; + R_MarkLights ( l, 1<nodes ); + } +} + + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +mplane_t *lightplane; +vec3_t lightspot; +vec3_t lightcolor; //johnfitz -- lit support via lordhavoc + +/* +============= +RecursiveLightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc +============= +*/ +int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end) +{ + float front, back, frac; + vec3_t mid; + +loc0: + if (node->contents < 0) + return false; // didn't hit anything + +// calculate mid point + if (node->plane->type < 3) + { + front = start[node->plane->type] - node->plane->dist; + back = end[node->plane->type] - node->plane->dist; + } + else + { + front = DotProduct(start, node->plane->normal) - node->plane->dist; + back = DotProduct(end, node->plane->normal) - node->plane->dist; + } + + // LordHavoc: optimized recursion + if ((back < 0) == (front < 0)) +// return RecursiveLightPoint (color, node->children[front < 0], start, end); + { + node = node->children[front < 0]; + goto loc0; + } + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + if (RecursiveLightPoint (color, node->children[front < 0], start, mid)) + return true; // hit something + else + { + int i, ds, dt; + msurface_t *surf; + // check for impact on this node + VectorCopy (mid, lightspot); + lightplane = node->plane; + + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i = 0;i < node->numsurfaces;i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + ds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]); + dt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]); + + if (ds < surf->texturemins[0] || dt < surf->texturemins[1]) + continue; + + ds -= surf->texturemins[0]; + dt -= surf->texturemins[1]; + + if (ds > surf->extents[0] || dt > surf->extents[1]) + continue; + + if (surf->samples) + { + // LordHavoc: enhanced to interpolate lighting + byte *lightmap; + int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0; + float scale; + line3 = ((surf->extents[0]>>4)+1)*3; + + lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color + + for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++) + { + scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0; + r00 += (float) lightmap[ 0] * scale;g00 += (float) lightmap[ 1] * scale;b00 += (float) lightmap[2] * scale; + r01 += (float) lightmap[ 3] * scale;g01 += (float) lightmap[ 4] * scale;b01 += (float) lightmap[5] * scale; + r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale; + r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale; + lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting + } + + color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00))); + color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00))); + color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00))); + } + return true; // success + } + + // go down back side + return RecursiveLightPoint (color, node->children[front >= 0], mid, end); + } +} + +/* +============= +R_LightPoint -- johnfitz -- replaced entire function for lit support via lordhavoc +============= +*/ +int R_LightPoint (vec3_t p) +{ + vec3_t end; + + if (!cl.worldmodel->lightdata) + { + lightcolor[0] = lightcolor[1] = lightcolor[2] = 255; + return 255; + } + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 8192; //johnfitz -- was 2048 + + lightcolor[0] = lightcolor[1] = lightcolor[2] = 0; + RecursiveLightPoint (lightcolor, cl.worldmodel->nodes, p, end); + return ((lightcolor[0] + lightcolor[1] + lightcolor[2]) * (1.0f / 3.0f)); +} diff --git a/Quake/gl_rmain.c b/Quake/gl_rmain.c new file mode 100644 index 00000000..c74f2e9b --- /dev/null +++ b/Quake/gl_rmain.c @@ -0,0 +1,860 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_main.c + +#include "quakedef.h" + +qboolean r_cache_thrash; // compatability + +vec3_t modelorg, r_entorigin; +entity_t *currententity; + +int r_visframecount; // bumped when going to a new PVS +int r_framecount; // used for dlight push checking + +mplane_t frustum[4]; + +//johnfitz -- rendering statistics +int rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys; +int rs_dynamiclightmaps, rs_brushpasses, rs_aliaspasses, rs_skypasses; +float rs_megatexels; + +qboolean envmap; // true during envmap command capture + +// +// view origin +// +vec3_t vup; +vec3_t vpn; +vec3_t vright; +vec3_t r_origin; + +float r_world_matrix[16]; +float r_base_world_matrix[16]; + +float r_fovx, r_fovy; //johnfitz -- rendering fov may be different becuase of r_waterwarp and r_stereo + +// +// screen size info +// +refdef_t r_refdef; + +mleaf_t *r_viewleaf, *r_oldviewleaf; + +int d_lightstylevalue[256]; // 8.8 fraction of base light value + + +cvar_t r_norefresh = {"r_norefresh","0"}; +cvar_t r_drawentities = {"r_drawentities","1"}; +cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; +cvar_t r_speeds = {"r_speeds","0"}; +cvar_t r_fullbright = {"r_fullbright","0"}; +cvar_t r_lightmap = {"r_lightmap","0"}; +cvar_t r_shadows = {"r_shadows","0"}; +cvar_t r_wateralpha = {"r_wateralpha","1"}; +cvar_t r_dynamic = {"r_dynamic","1"}; +cvar_t r_novis = {"r_novis","0"}; + +cvar_t gl_finish = {"gl_finish","0"}; +cvar_t gl_clear = {"gl_clear","0"}; +cvar_t gl_cull = {"gl_cull","1"}; +cvar_t gl_smoothmodels = {"gl_smoothmodels","1"}; +cvar_t gl_affinemodels = {"gl_affinemodels","0"}; +cvar_t gl_polyblend = {"gl_polyblend","1"}; +cvar_t gl_flashblend = {"gl_flashblend","1"}; +cvar_t gl_playermip = {"gl_playermip","0"}; +cvar_t gl_nocolors = {"gl_nocolors","0"}; + +//johnfitz -- new cvars +cvar_t r_stereo = {"r_stereo","0"}; +cvar_t r_stereodepth = {"r_stereodepth","128"}; +cvar_t r_clearcolor = {"r_clearcolor","2", true}; +cvar_t r_drawflat = {"r_drawflat","0"}; +cvar_t r_flatlightstyles = {"r_flatlightstyles", "0"}; +cvar_t gl_fullbrights = {"gl_fullbrights", "1", true}; +cvar_t gl_farclip = {"gl_farclip", "16384", true}; +cvar_t gl_overbright = {"gl_overbright", "1", true}; +cvar_t gl_overbright_models = {"gl_overbright_models", "1", true}; +cvar_t r_oldskyleaf = {"r_oldskyleaf", "0"}; +cvar_t r_drawworld = {"r_drawworld", "1"}; +cvar_t r_showtris = {"r_showtris", "0"}; +cvar_t r_showbboxes = {"r_showbboxes", "0"}; +cvar_t r_lerpmodels = {"r_lerpmodels", "1"}; +cvar_t r_lerpmove = {"r_lerpmove", "1"}; +cvar_t r_nolerp_list = {"r_nolerp_list", "progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl"}; +//johnfitz + +/* +================= +R_CullBox -- johnfitz -- replaced with new function from lordhavoc + +Returns true if the box is completely outside the frustum +================= +*/ +qboolean R_CullBox (vec3_t emins, vec3_t emaxs) +{ + int i; + mplane_t *p; + for (i = 0;i < 4;i++) + { + p = frustum + i; + switch(p->signbits) + { + default: + case 0: + if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist) + return true; + break; + case 1: + if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2] < p->dist) + return true; + break; + case 2: + if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist) + return true; + break; + case 3: + if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2] < p->dist) + return true; + break; + case 4: + if (p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist) + return true; + break; + case 5: + if (p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2] < p->dist) + return true; + break; + case 6: + if (p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist) + return true; + break; + case 7: + if (p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2] < p->dist) + return true; + break; + } + } + return false; +} +/* +=============== +R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation +=============== +*/ +qboolean R_CullModelForEntity (entity_t *e) +{ + vec3_t mins, maxs; + + if (e->angles[0] || e->angles[2]) //pitch or roll + { + VectorAdd (e->origin, e->model->rmins, mins); + VectorAdd (e->origin, e->model->rmaxs, maxs); + } + else if (e->angles[1]) //yaw + { + VectorAdd (e->origin, e->model->ymins, mins); + VectorAdd (e->origin, e->model->ymaxs, maxs); + } + else //no rotation + { + VectorAdd (e->origin, e->model->mins, mins); + VectorAdd (e->origin, e->model->maxs, maxs); + } + + return R_CullBox (mins, maxs); +} + +/* +=============== +R_RotateForEntity -- johnfitz -- modified to take origin and angles instead of pointer to entity +=============== +*/ +void R_RotateForEntity (vec3_t origin, vec3_t angles) +{ + glTranslatef (origin[0], origin[1], origin[2]); + glRotatef (angles[1], 0, 0, 1); + glRotatef (-angles[0], 0, 1, 0); + glRotatef (angles[2], 1, 0, 0); +} + +/* +============= +GL_PolygonOffset -- johnfitz + +negative offset moves polygon closer to camera +============= +*/ +void GL_PolygonOffset (int offset) +{ + if (offset > 0) + { + glEnable (GL_POLYGON_OFFSET_FILL); + glEnable (GL_POLYGON_OFFSET_LINE); + glPolygonOffset(1, offset); + } + else if (offset < 0) + { + glEnable (GL_POLYGON_OFFSET_FILL); + glEnable (GL_POLYGON_OFFSET_LINE); + glPolygonOffset(-1, offset); + } + else + { + glDisable (GL_POLYGON_OFFSET_FILL); + glDisable (GL_POLYGON_OFFSET_LINE); + } +} + +//============================================================================== +// +// SETUP FRAME +// +//============================================================================== + +int SignbitsForPlane (mplane_t *out) +{ + int bits, j; + + // for fast box on planeside test + + bits = 0; + for (j=0 ; j<3 ; j++) + { + if (out->normal[j] < 0) + bits |= 1<contents); + V_CalcBlend (); + + r_cache_thrash = false; + + //johnfitz -- calculate r_fovx and r_fovy here + r_fovx = r_refdef.fov_x; + r_fovy = r_refdef.fov_y; + if (r_waterwarp.value) + { + int contents = Mod_PointInLeaf (r_origin, cl.worldmodel)->contents; + if (contents == CONTENTS_WATER || contents == CONTENTS_SLIME || contents == CONTENTS_LAVA) + { + //variance is a percentage of width, where width = 2 * tan(fov / 2) otherwise the effect is too dramatic at high FOV and too subtle at low FOV. what a mess! + r_fovx = atan(tan(DEG2RAD(r_refdef.fov_x) / 2) * (0.97 + sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180; + r_fovy = atan(tan(DEG2RAD(r_refdef.fov_y) / 2) * (1.03 - sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180; + } + } + //johnfitz + + R_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars + + R_MarkSurfaces (); //johnfitz -- create texture chains from PVS + + R_CullSurfaces (); //johnfitz -- do after R_SetFrustum and R_MarkSurfaces + + R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear + + R_Clear (); + + //johnfitz -- cheat-protect some draw modes + r_drawflat_cheatsafe = r_fullbright_cheatsafe = r_lightmap_cheatsafe = false; + r_drawworld_cheatsafe = true; + if (cl.maxclients == 1) + { + if (!r_drawworld.value) r_drawworld_cheatsafe = false; + + if (r_drawflat.value) r_drawflat_cheatsafe = true; + else if (r_fullbright.value || !cl.worldmodel->lightdata) r_fullbright_cheatsafe = true; + else if (r_lightmap.value) r_lightmap_cheatsafe = true; + } + //johnfitz +} + +//============================================================================== +// +// RENDER VIEW +// +//============================================================================== + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (qboolean alphapass) //johnfitz -- added parameter +{ + extern cvar_t r_vfog; //johnfitz + int i; + + if (!r_drawentities.value) + return; + + //johnfitz -- sprites are not a special case + for (i=0 ; ialpha) < 1 && !alphapass) || + (ENTALPHA_DECODE(currententity->alpha) == 1 && alphapass)) + continue; + + //johnfitz -- chasecam + if (currententity == &cl_entities[cl.viewentity]) + currententity->angles[0] *= 0.3; + //johnfitz + + switch (currententity->model->type) + { + case mod_alias: + R_DrawAliasModel (currententity); + break; + case mod_brush: + R_DrawBrushModel (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + } + } +} + +/* +============= +R_DrawViewModel -- johnfitz -- gutted +============= +*/ +void R_DrawViewModel (void) +{ + if (!r_drawviewmodel.value || !r_drawentities.value || chase_active.value || envmap) + return; + + if (cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0) + return; + + currententity = &cl.viewent; + if (!currententity->model) + return; + + //johnfitz -- this fixes a crash + if (currententity->model->type != mod_alias) + return; + //johnfitz + + // hack the depth range to prevent view model from poking into walls + glDepthRange (0, 0.3); + R_DrawAliasModel (currententity); + glDepthRange (0, 1); +} + +/* +================ +R_EmitWirePoint -- johnfitz -- draws a wireframe cross shape for point entities +================ +*/ +void R_EmitWirePoint (vec3_t origin) +{ + int size=8; + + glBegin (GL_LINES); + glVertex3f (origin[0]-size, origin[1], origin[2]); + glVertex3f (origin[0]+size, origin[1], origin[2]); + glVertex3f (origin[0], origin[1]-size, origin[2]); + glVertex3f (origin[0], origin[1]+size, origin[2]); + glVertex3f (origin[0], origin[1], origin[2]-size); + glVertex3f (origin[0], origin[1], origin[2]+size); + glEnd (); +} + +/* +================ +R_EmitWireBox -- johnfitz -- draws one axis aligned bounding box +================ +*/ +void R_EmitWireBox (vec3_t mins, vec3_t maxs) +{ + glBegin (GL_QUAD_STRIP); + glVertex3f (mins[0], mins[1], mins[2]); + glVertex3f (mins[0], mins[1], maxs[2]); + glVertex3f (maxs[0], mins[1], mins[2]); + glVertex3f (maxs[0], mins[1], maxs[2]); + glVertex3f (maxs[0], maxs[1], mins[2]); + glVertex3f (maxs[0], maxs[1], maxs[2]); + glVertex3f (mins[0], maxs[1], mins[2]); + glVertex3f (mins[0], maxs[1], maxs[2]); + glVertex3f (mins[0], mins[1], mins[2]); + glVertex3f (mins[0], mins[1], maxs[2]); + glEnd (); +} + +/* +================ +R_ShowBoundingBoxes -- johnfitz + +draw bounding boxes -- the server-side boxes, not the renderer cullboxes +================ +*/ +void R_ShowBoundingBoxes (void) +{ + extern edict_t *sv_player; + vec3_t mins,maxs; + edict_t *ed; + int i; + + if (!r_showbboxes.value || cl.maxclients > 1 || !r_drawentities.value || !sv.active) + return; + + glDisable (GL_DEPTH_TEST); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + GL_PolygonOffset (OFFSET_SHOWTRIS); + glDisable (GL_TEXTURE_2D); + glDisable (GL_CULL_FACE); + glColor3f (1,1,1); + + for (i=0, ed=NEXT_EDICT(sv.edicts) ; iv.mins[0] == ed->v.maxs[0] && ed->v.mins[1] == ed->v.maxs[1] && ed->v.mins[2] == ed->v.maxs[2]) + { + //point entity + R_EmitWirePoint (ed->v.origin); + } + else + { + //box entity + VectorAdd (ed->v.mins, ed->v.origin, mins); + VectorAdd (ed->v.maxs, ed->v.origin, maxs); + R_EmitWireBox (mins, maxs); + } + } + + glColor3f (1,1,1); + glEnable (GL_TEXTURE_2D); + glEnable (GL_CULL_FACE); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + GL_PolygonOffset (OFFSET_NONE); + glEnable (GL_DEPTH_TEST); + + Sbar_Changed (); //so we don't get dots collecting on the statusbar +} + +/* +================ +R_ShowTris -- johnfitz +================ +*/ +void R_ShowTris (void) +{ + extern cvar_t r_particles; + int i; + + if (r_showtris.value < 1 || r_showtris.value > 2 || cl.maxclients > 1) + return; + + if (r_showtris.value == 1) + glDisable (GL_DEPTH_TEST); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + GL_PolygonOffset (OFFSET_SHOWTRIS); + glDisable (GL_TEXTURE_2D); + glColor3f (1,1,1); +// glEnable (GL_BLEND); +// glBlendFunc (GL_ONE, GL_ONE); + + if (r_drawworld.value) + { + R_DrawTextureChains_ShowTris (); + } + + if (r_drawentities.value) + { + for (i=0 ; iangles[0] *= 0.3; + + switch (currententity->model->type) + { + case mod_brush: + R_DrawBrushModel_ShowTris (currententity); + break; + case mod_alias: + R_DrawAliasModel_ShowTris (currententity); + break; + case mod_sprite: + R_DrawSpriteModel (currententity); + break; + default: + break; + } + } + + // viewmodel + currententity = &cl.viewent; + if (r_drawviewmodel.value + && !chase_active.value + && !envmap + && cl.stats[STAT_HEALTH] > 0 + && !(cl.items & IT_INVISIBILITY) + && currententity->model + && currententity->model->type == mod_alias) + { + glDepthRange (0, 0.3); + R_DrawAliasModel_ShowTris (currententity); + glDepthRange (0, 1); + } + } + + if (r_particles.value) + { + R_DrawParticles_ShowTris (); + } + +// glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// glDisable (GL_BLEND); + glColor3f (1,1,1); + glEnable (GL_TEXTURE_2D); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + GL_PolygonOffset (OFFSET_NONE); + if (r_showtris.value == 1) + glEnable (GL_DEPTH_TEST); + + Sbar_Changed (); //so we don't get dots collecting on the statusbar +} + +/* +================ +R_DrawShadows +================ +*/ +void R_DrawShadows (void) +{ + int i; + + if (!r_shadows.value || !r_drawentities.value || r_drawflat_cheatsafe || r_lightmap_cheatsafe) + return; + + for (i=0 ; imodel->type != mod_alias) + continue; + + if (currententity == &cl.viewent) + return; + + GL_DrawAliasShadow (currententity); + } +} + +/* +================ +R_RenderScene +================ +*/ +void R_RenderScene (void) +{ + R_SetupScene (); //johnfitz -- this does everything that should be done once per call to RenderScene + + Fog_EnableGFog (); //johnfitz + + Sky_DrawSky (); //johnfitz + + R_DrawWorld (); + + S_ExtraUpdate (); // don't let sound get messed up if going slow + + R_DrawShadows (); //johnfitz -- render entity shadows + + R_DrawEntitiesOnList (false); //johnfitz -- false means this is the pass for nonalpha entities + + R_DrawTextureChains_Water (); //johnfitz -- drawn here since they might have transparency + + R_DrawEntitiesOnList (true); //johnfitz -- true means this is the pass for alpha entities + + R_RenderDlights (); //triangle fan dlights -- johnfitz -- moved after water + + R_DrawParticles (); + + Fog_DisableGFog (); //johnfitz + + R_DrawViewModel (); //johnfitz -- moved here from R_RenderView + + R_ShowTris (); //johnfitz + + R_ShowBoundingBoxes (); //johnfitz + +#ifdef GLTEST + Test_Draw (); +#endif +} + +/* +================ +R_RenderView +================ +*/ +void R_RenderView (void) +{ + double time1, time2; + + if (r_norefresh.value) + return; + + if (!cl.worldmodel) + Sys_Error ("R_RenderView: NULL worldmodel"); + + if (r_speeds.value) + { + glFinish (); + time1 = Sys_FloatTime (); + + //johnfitz -- rendering statistics + rs_brushpolys = rs_aliaspolys = rs_skypolys = rs_particles = rs_fogpolys = rs_megatexels = + rs_dynamiclightmaps = rs_aliaspasses = rs_skypasses = rs_brushpasses = 0; + } + else if (gl_finish.value) + glFinish (); + + R_SetupView (); //johnfitz -- this does everything that should be done once per frame + + //johnfitz -- stereo rendering -- full of hacky goodness + if (r_stereo.value) + { + float eyesep = CLAMP(-8.0f, r_stereo.value, 8.0f); + float fdepth = CLAMP(32.0f, r_stereodepth.value, 1024.0f); + + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + + //render left eye (red) + glColorMask(1, 0, 0, 1); + VectorMA (r_refdef.vieworg, -0.5f * eyesep, vright, r_refdef.vieworg); + frustum_skew = 0.5 * eyesep * NEARCLIP / fdepth; + srand((int) (cl.time * 1000)); //sync random stuff between eyes + + R_RenderScene (); + + //render right eye (cyan) + glClear (GL_DEPTH_BUFFER_BIT); + glColorMask(0, 1, 1, 1); + VectorMA (r_refdef.vieworg, 1.0f * eyesep, vright, r_refdef.vieworg); + frustum_skew = -frustum_skew; + srand((int) (cl.time * 1000)); //sync random stuff between eyes + + R_RenderScene (); + + //restore + glColorMask(1, 1, 1, 1); + VectorMA (r_refdef.vieworg, -0.5f * eyesep, vright, r_refdef.vieworg); + frustum_skew = 0.0f; + } + else + { + R_RenderScene (); + } + //johnfitz + + //johnfitz -- modified r_speeds output + time2 = Sys_FloatTime (); + if (r_speeds.value == 2) + Con_Printf ("%3i ms %4i/%4i wpoly %4i/%4i epoly %3i lmap %4i/%4i sky %1.1f mtex\n", + (int)((time2-time1)*1000), + rs_brushpolys, + rs_brushpasses, + rs_aliaspolys, + rs_aliaspasses, + rs_dynamiclightmaps, + rs_skypolys, + rs_skypasses, + TexMgr_FrameUsage ()); + else if (r_speeds.value) + Con_Printf ("%3i ms %4i wpoly %4i epoly %3i lmap\n", + (int)((time2-time1)*1000), + rs_brushpolys, + rs_aliaspolys, + rs_dynamiclightmaps); + //johnfitz +} + diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c new file mode 100644 index 00000000..4e253947 --- /dev/null +++ b/Quake/gl_rmisc.c @@ -0,0 +1,405 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_misc.c + +#include "quakedef.h" + +//johnfitz -- new cvars +extern cvar_t r_stereo; +extern cvar_t r_stereodepth; +extern cvar_t r_clearcolor; +extern cvar_t r_drawflat; +extern cvar_t r_flatlightstyles; +extern cvar_t gl_fullbrights; +extern cvar_t gl_farclip; +extern cvar_t gl_overbright; +extern cvar_t gl_overbright_models; +extern cvar_t r_waterquality; +extern cvar_t r_oldwater; +extern cvar_t r_waterwarp; +extern cvar_t r_oldskyleaf; +extern cvar_t r_drawworld; +extern cvar_t r_showtris; +extern cvar_t r_showbboxes; +extern cvar_t r_lerpmodels; +extern cvar_t r_lerpmove; +extern cvar_t r_nolerp_list; +//johnfitz + +extern float load_subdivide_size; //johnfitz -- remember what subdivide_size value was when this map was loaded + +extern cvar_t gl_subdivide_size; //johnfitz -- moved here from gl_model.c + +extern gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz + +void R_NoLerpList_f (void); //johnfitz + +/* +==================== +GL_Overbright_f -- johnfitz +==================== +*/ +void GL_Overbright_f (void) +{ + R_RebuildAllLightmaps (); +} + +/* +==================== +GL_Fullbrights_f -- johnfitz +==================== +*/ +void GL_Fullbrights_f (void) +{ + TexMgr_ReloadNobrightImages (); +} + +/* +==================== +R_SetClearColor_f -- johnfitz +==================== +*/ +void R_SetClearColor_f (void) +{ + byte *rgb; + int s; + + s = (int)r_clearcolor.value & 0xFF; + rgb = (byte*)(d_8to24table + s); + glClearColor (rgb[0]/255.0,rgb[1]/255.0,rgb[2]/255.0,0); +} + +/* +==================== +R_Novis_f -- johnfitz +==================== +*/ +void R_Novis_f (void) +{ + extern int vis_changed; + vis_changed = 1; +} + +/* +==================== +R_OldSkyLeaf_f -- johnfitz +==================== +*/ +void R_OldSkyLeaf_f (void) +{ + extern int vis_changed; + vis_changed = 1; +} + +/* +=============== +R_Envmap_f + +Grab six views for environment mapping tests +=============== +*/ +void R_Envmap_f (void) +{ + byte buffer[256*256*4]; + // char name[1024]; unused -- kristian + + glDrawBuffer (GL_FRONT); + glReadBuffer (GL_FRONT); + envmap = true; + + r_refdef.vrect.x = 0; + r_refdef.vrect.y = 0; + r_refdef.vrect.width = 256; + r_refdef.vrect.height = 256; + + r_refdef.viewangles[0] = 0; + r_refdef.viewangles[1] = 0; + r_refdef.viewangles[2] = 0; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env0.rgb", buffer, sizeof(buffer)); + + r_refdef.viewangles[1] = 90; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env1.rgb", buffer, sizeof(buffer)); + + r_refdef.viewangles[1] = 180; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env2.rgb", buffer, sizeof(buffer)); + + r_refdef.viewangles[1] = 270; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env3.rgb", buffer, sizeof(buffer)); + + r_refdef.viewangles[0] = -90; + r_refdef.viewangles[1] = 0; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env4.rgb", buffer, sizeof(buffer)); + + r_refdef.viewangles[0] = 90; + r_refdef.viewangles[1] = 0; + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + R_RenderView (); + glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + COM_WriteFile ("env5.rgb", buffer, sizeof(buffer)); + + envmap = false; + glDrawBuffer (GL_BACK); + glReadBuffer (GL_BACK); + GL_EndRendering (); +} + +/* +=============== +R_Init +=============== +*/ +void R_Init (void) +{ + // extern byte *hunk_base; unused -- kristian + extern cvar_t gl_finish; + + Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); + Cmd_AddCommand ("envmap", R_Envmap_f); + Cmd_AddCommand ("pointfile", R_ReadPointFile_f); + + Cvar_RegisterVariable (&r_norefresh, NULL); + Cvar_RegisterVariable (&r_lightmap, NULL); + Cvar_RegisterVariable (&r_fullbright, NULL); + Cvar_RegisterVariable (&r_drawentities, NULL); + Cvar_RegisterVariable (&r_drawviewmodel, NULL); + Cvar_RegisterVariable (&r_shadows, NULL); + Cvar_RegisterVariable (&r_wateralpha, NULL); + Cvar_RegisterVariable (&r_dynamic, NULL); + Cvar_RegisterVariable (&r_novis, R_Novis_f); + Cvar_RegisterVariable (&r_speeds, NULL); + + Cvar_RegisterVariable (&gl_finish, NULL); + Cvar_RegisterVariable (&gl_clear, NULL); + Cvar_RegisterVariable (&gl_cull, NULL); + Cvar_RegisterVariable (&gl_smoothmodels, NULL); + Cvar_RegisterVariable (&gl_affinemodels, NULL); + Cvar_RegisterVariable (&gl_polyblend, NULL); + Cvar_RegisterVariable (&gl_flashblend, NULL); + Cvar_RegisterVariable (&gl_playermip, NULL); + Cvar_RegisterVariable (&gl_nocolors, NULL); + + //johnfitz -- new cvars + Cvar_RegisterVariable (&r_stereo, NULL); + Cvar_RegisterVariable (&r_stereodepth, NULL); + Cvar_RegisterVariable (&r_clearcolor, R_SetClearColor_f); + Cvar_RegisterVariable (&r_waterquality, NULL); + Cvar_RegisterVariable (&r_oldwater, NULL); + Cvar_RegisterVariable (&r_waterwarp, NULL); + Cvar_RegisterVariable (&r_drawflat, NULL); + Cvar_RegisterVariable (&r_flatlightstyles, NULL); + Cvar_RegisterVariable (&r_oldskyleaf, R_OldSkyLeaf_f); + Cvar_RegisterVariable (&r_drawworld, NULL); + Cvar_RegisterVariable (&r_showtris, NULL); + Cvar_RegisterVariable (&r_showbboxes, NULL); + Cvar_RegisterVariable (&gl_farclip, NULL); + Cvar_RegisterVariable (&gl_fullbrights, GL_Fullbrights_f); + Cvar_RegisterVariable (&gl_overbright, GL_Overbright_f); + Cvar_RegisterVariable (&gl_overbright_models, NULL); + Cvar_RegisterVariable (&r_lerpmodels, NULL); + Cvar_RegisterVariable (&r_lerpmove, NULL); + Cvar_RegisterVariable (&r_nolerp_list, R_NoLerpList_f); + //johnfitz + + Cvar_RegisterVariable (&gl_subdivide_size, NULL); //johnfitz -- moved here from gl_model.c + + R_InitParticles (); + R_SetClearColor_f (); //johnfitz + + Sky_Init (); //johnfitz + Fog_Init (); //johnfitz + +#ifdef GLTEST + Test_Init (); +#endif +} + +/* +=============== +R_NoLerpList_f -- johnfitz -- called when r_nolerp_list cvar changes +=============== +*/ +void R_NoLerpList_f (void) +{ + int i; + + for (i=0; i < MAX_MODELS; i++) + Mod_SetExtraFlags (cl.model_precache[i]); +} + +/* +=============== +R_TranslatePlayerSkin -- johnfitz -- rewritten. also, only handles new colors, not new skins +=============== +*/ +void R_TranslatePlayerSkin (int playernum) +{ + int top, bottom; + + top = (cl.scores[playernum].colors & 0xf0)>>4; + bottom = cl.scores[playernum].colors &15; + + //FIXME: if gl_nocolors is on, then turned off, the textures may be out of sync with the scoreboard colors. + if (!gl_nocolors.value) + if (playertextures[playernum]) + TexMgr_ReloadImage (playertextures[playernum], top, bottom); +} + +/* +=============== +R_TranslateNewPlayerSkin -- johnfitz -- split off of TranslatePlayerSkin -- this is called when +the skin or model actually changes, instead of just new colors +added bug fix from bengt jardup +=============== +*/ +void R_TranslateNewPlayerSkin (int playernum) +{ + char name[64]; + byte *pixels; + aliashdr_t *paliashdr; + int skinnum; + +//get correct texture pixels + currententity = &cl_entities[1+playernum]; + + if (!currententity->model || currententity->model->type != mod_alias) + return; + + paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); + + skinnum = currententity->skinnum; + + //TODO: move these tests to the place where skinnum gets received from the server + if (skinnum < 0 || skinnum >= paliashdr->numskins) + { + Con_DPrintf("(%d): Invalid player skin #%d\n", playernum, skinnum); + skinnum = 0; + } + + pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place! + +//upload new image + sprintf(name, "player_%i", playernum); + playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight, + SRC_INDEXED, pixels, paliashdr->gltextures[skinnum][0]->source_file, paliashdr->gltextures[skinnum][0]->source_offset, TEXPREF_PAD | TEXPREF_OVERWRITE); + +//now recolor it + R_TranslatePlayerSkin (playernum); +} + +/* +=============== +R_NewGame -- johnfitz -- handle a game switch +=============== +*/ +void R_NewGame (void) +{ + int i; + + //clear playertexture pointers (the textures themselves were freed by texmgr_newgame) + for (i=0; inumleafs ; i++) + cl.worldmodel->leafs[i].efrags = NULL; + + r_viewleaf = NULL; + R_ClearParticles (); + + GL_BuildLightmaps (); + + r_framecount = 0; //johnfitz -- paranoid? + r_visframecount = 0; //johnfitz -- paranoid? + + Sky_NewMap (); //johnfitz -- skybox in worldspawn + Fog_NewMap (); //johnfitz -- global fog in worldspawn + + load_subdivide_size = gl_subdivide_size.value; //johnfitz -- is this the right place to set this? +} + +/* +==================== +R_TimeRefresh_f + +For program optimization +==================== +*/ +void R_TimeRefresh_f (void) +{ + int i; + float start, stop, time; + /* unused -- kristian + int startangle; + vrect_t vr; + */ + + glDrawBuffer (GL_FRONT); + glFinish (); + + start = Sys_FloatTime (); + for (i=0 ; i<128 ; i++) + { + r_refdef.viewangles[1] = i/128.0*360.0; + R_RenderView (); + } + + glFinish (); + stop = Sys_FloatTime (); + time = stop-start; + Con_Printf ("%f seconds (%f fps)\n", time, 128/time); + + glDrawBuffer (GL_BACK); + GL_EndRendering (); +} + +void D_FlushCaches (void) +{ +} diff --git a/Quake/gl_screen.c b/Quake/gl_screen.c new file mode 100644 index 00000000..63700f0f --- /dev/null +++ b/Quake/gl_screen.c @@ -0,0 +1,1071 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// screen.c -- master for refresh, status bar, console, chat, notify, etc + +#include "quakedef.h" + +/* + +background clear +rendering +turtle/net/ram icons +sbar +centerprint / slow centerprint +notify lines +intermission / finale overlay +loading plaque +console +menu + +required background clears +required update regions + + +syncronous draw mode or async +One off screen buffer, with updates either copied or xblited +Need to double buffer? + + +async draw will require the refresh area to be cleared, because it will be +xblited, but sync draw can just ignore it. + +sync +draw + +CenterPrint () +SlowPrint () +Screen_Update (); +Con_Printf (); + +net +turn off messages option + +the refresh is allways rendered, unless the console is full screen + + +console is: + notify lines + half + full + + +*/ + + +int glx, gly, glwidth, glheight; + +float scr_con_current; +float scr_conlines; // lines of console to display + +float oldscreensize, oldfov, oldsbarscale, oldsbaralpha; //johnfitz -- added oldsbarscale and oldsbaralpha + +//johnfitz -- new cvars +cvar_t scr_menuscale = {"scr_menuscale", "1", true}; +cvar_t scr_sbarscale = {"scr_sbarscale", "1", true}; +cvar_t scr_sbaralpha = {"scr_sbaralpha", "1", true}; +cvar_t scr_conwidth = {"scr_conwidth", "0", true}; +cvar_t scr_conscale = {"scr_conscale", "1", true}; +cvar_t scr_crosshaircale = {"scr_crosshaircale", "1", true}; +cvar_t scr_showfps = {"scr_showfps", "0"}; +cvar_t scr_clock = {"scr_clock", "0"}; +//johnfitz + +cvar_t scr_viewsize = {"viewsize","100", true}; +cvar_t scr_fov = {"fov","90"}; // 10 - 170 +cvar_t scr_conspeed = {"scr_conspeed","300"}; +cvar_t scr_centertime = {"scr_centertime","2"}; +cvar_t scr_showram = {"showram","1"}; +cvar_t scr_showturtle = {"showturtle","0"}; +cvar_t scr_showpause = {"showpause","1"}; +cvar_t scr_printspeed = {"scr_printspeed","8"}; +cvar_t gl_triplebuffer = {"gl_triplebuffer", "1", true }; + +extern cvar_t crosshair; + +qboolean scr_initialized; // ready to draw + +qpic_t *scr_ram; +qpic_t *scr_net; +qpic_t *scr_turtle; + +int clearconsole; +int clearnotify; + +int sb_lines; + +viddef_t vid; // global video state + +vrect_t scr_vrect; + +qboolean scr_disabled_for_loading; +qboolean scr_drawloading; +float scr_disabled_time; + +qboolean block_drawing; + +int scr_tileclear_updates = 0; //johnfitz + +void SCR_ScreenShot_f (void); + +/* +=============================================================================== + +CENTER PRINTING + +=============================================================================== +*/ + +char scr_centerstring[1024]; +float scr_centertime_start; // for slow victory printing +float scr_centertime_off; +int scr_center_lines; +int scr_erase_lines; +int scr_erase_center; + +/* +============== +SCR_CenterPrint + +Called for important messages that should stay in the center of the screen +for a few moments +============== +*/ +void SCR_CenterPrint (char *str) //update centerprint data +{ + strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); + scr_centertime_off = scr_centertime.value; + scr_centertime_start = cl.time; + +// count the number of lines for centering + scr_center_lines = 1; + while (*str) + { + if (*str == '\n') + scr_center_lines++; + str++; + } +} + +void SCR_DrawCenterString (void) //actually do the drawing +{ + char *start; + int l; + int j; + int x, y; + int remaining; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + +// the finale prints the characters one at a time + if (cl.intermission) + remaining = scr_printspeed.value * (cl.time - scr_centertime_start); + else + remaining = 9999; + + scr_erase_center = 0; + start = scr_centerstring; + + if (scr_center_lines <= 4) + y = 200*0.35; //johnfitz -- 320x200 coordinate system + else + y = 48; + + do + { + // scan the width of the line + for (l=0 ; l<40 ; l++) + if (start[l] == '\n' || !start[l]) + break; + x = (320 - l*8)/2; //johnfitz -- 320x200 coordinate system + for (j=0 ; j scr_erase_lines) + scr_erase_lines = scr_center_lines; + + scr_centertime_off -= host_frametime; + + if (scr_centertime_off <= 0 && !cl.intermission) + return; + if (key_dest != key_game) + return; + if (cl.paused) //johnfitz -- don't show centerprint during a pause + return; + + SCR_DrawCenterString (); +} + +//============================================================================= + +/* +==================== +CalcFovy +==================== +*/ +float CalcFovy (float fov_x, float width, float height) +{ + float a, x; + + if (fov_x < 1 || fov_x > 179) + Sys_Error ("Bad fov: %f", fov_x); + + x = width/tan(fov_x/360*M_PI); + a = atan (height/x); + a = a*360/M_PI; + return a; +} + +/* +================= +SCR_CalcRefdef + +Must be called whenever vid changes +Internal use only +================= +*/ +static void SCR_CalcRefdef (void) +{ + float size, scale; //johnfitz -- scale + /* unused -- kristian + vrect_t vrect; + int h; + */ + vid.recalc_refdef = 0; + +// force the status bar to redraw + Sbar_Changed (); + + scr_tileclear_updates = 0; //johnfitz + +// bound viewsize + if (scr_viewsize.value < 30) + Cvar_Set ("viewsize","30"); + if (scr_viewsize.value > 120) + Cvar_Set ("viewsize","120"); + +// bound fov + if (scr_fov.value < 10) + Cvar_Set ("fov","10"); + if (scr_fov.value > 170) + Cvar_Set ("fov","170"); + + //johnfitz -- rewrote this section + size = scr_viewsize.value; + scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); + + if (size >= 120 || cl.intermission || scr_sbaralpha.value < 1) //johnfitz -- scr_sbaralpha.value + sb_lines = 0; + else if (size >= 110) + sb_lines = 24 * scale; + else + sb_lines = 48 * scale; + + size = fmin(scr_viewsize.value, 100) / 100; + //johnfitz + + //johnfitz -- rewrote this section + r_refdef.vrect.width = fmax(glwidth * size, 96); //no smaller than 96, for icons + r_refdef.vrect.height = fmin(glheight * size, glheight - sb_lines); //make room for sbar + r_refdef.vrect.x = (glwidth - r_refdef.vrect.width)/2; + r_refdef.vrect.y = (glheight - sb_lines - r_refdef.vrect.height)/2; + //johnfitz + + r_refdef.fov_x = scr_fov.value; + r_refdef.fov_y = CalcFovy (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); + + scr_vrect = r_refdef.vrect; +} + + +/* +================= +SCR_SizeUp_f + +Keybinding command +================= +*/ +void SCR_SizeUp_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value+10); + vid.recalc_refdef = 1; +} + + +/* +================= +SCR_SizeDown_f + +Keybinding command +================= +*/ +void SCR_SizeDown_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value-10); + vid.recalc_refdef = 1; +} + +/* +================== +SCR_Conwidth_f -- johnfitz -- called when scr_conwidth or scr_conscale changes +================== +*/ +void SCR_Conwidth_f (void) +{ + vid.conwidth = (scr_conwidth.value > 0) ? (int)scr_conwidth.value : (scr_conscale.value > 0) ? (int)(vid.width/scr_conscale.value) : vid.width; + vid.conwidth = CLAMP (320, vid.conwidth, vid.width); + vid.conwidth &= 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; +} + +//============================================================================ + +/* +================== +SCR_LoadPics -- johnfitz +================== +*/ +void SCR_LoadPics (void) +{ + scr_ram = Draw_PicFromWad ("ram"); + scr_net = Draw_PicFromWad ("net"); + scr_turtle = Draw_PicFromWad ("turtle"); +} +/* +================== +SCR_Init +================== +*/ +void SCR_Init (void) +{ + //johnfitz -- new cvars + Cvar_RegisterVariable (&scr_menuscale, NULL); + Cvar_RegisterVariable (&scr_sbarscale, NULL); + Cvar_RegisterVariable (&scr_sbaralpha, NULL); + Cvar_RegisterVariable (&scr_conwidth, &SCR_Conwidth_f); + Cvar_RegisterVariable (&scr_conscale, &SCR_Conwidth_f); + Cvar_RegisterVariable (&scr_crosshaircale, NULL); + Cvar_RegisterVariable (&scr_showfps, NULL); + Cvar_RegisterVariable (&scr_clock, NULL); + //johnfitz + + Cvar_RegisterVariable (&scr_fov, NULL); + Cvar_RegisterVariable (&scr_viewsize, NULL); + Cvar_RegisterVariable (&scr_conspeed, NULL); + Cvar_RegisterVariable (&scr_showram, NULL); + Cvar_RegisterVariable (&scr_showturtle, NULL); + Cvar_RegisterVariable (&scr_showpause, NULL); + Cvar_RegisterVariable (&scr_centertime, NULL); + Cvar_RegisterVariable (&scr_printspeed, NULL); + Cvar_RegisterVariable (&gl_triplebuffer, NULL); + + Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); + Cmd_AddCommand ("sizeup",SCR_SizeUp_f); + Cmd_AddCommand ("sizedown",SCR_SizeDown_f); + + SCR_LoadPics (); //johnfitz + + scr_initialized = true; +} + +//============================================================================ + +/* +============== +SCR_DrawFPS -- johnfitz +============== +*/ +void SCR_DrawFPS (void) +{ + static double oldtime = 0, fps = 0; + static int oldframecount = 0; + double time; + char str[12]; + int x, y, frames; + + time = realtime - oldtime; + frames = r_framecount - oldframecount; + + if (time < 0 || frames < 0) + { + oldtime = realtime; + oldframecount = r_framecount; + return; + } + + if (time > 0.75) //update value every 3/4 second + { + fps = frames / time; + oldtime = realtime; + oldframecount = r_framecount; + } + + if (scr_showfps.value) //draw it + { + sprintf (str, "%4.0f fps", fps); + x = 320 - (strlen(str)<<3); + y = 200 - 8; + if (scr_clock.value) y -= 8; //make room for clock + GL_SetCanvas (CANVAS_BOTTOMRIGHT); + Draw_String (x, y, str); + scr_tileclear_updates = 0; + } + +} + +/* +============== +SCR_DrawClock -- johnfitz +============== +*/ +void SCR_DrawClock (void) +{ + char str[9]; + + if (scr_clock.value == 1) + { + int minutes, seconds; + + minutes = cl.time / 60; + seconds = ((int)cl.time)%60; + + sprintf (str,"%i:%i%i", minutes, seconds/10, seconds%10); + } + else + return; + + //draw it + GL_SetCanvas (CANVAS_BOTTOMRIGHT); + Draw_String (320 - (strlen(str)<<3), 200 - 8, str); + + scr_tileclear_updates = 0; +} + +/* +============== +SCR_DrawDevStats +============== +*/ +void SCR_DrawDevStats (void) +{ + char str[40]; + int y = 25-9; //9=number of lines to print + int x = 0; //margin + + if (!devstats.value) + return; + + GL_SetCanvas (CANVAS_BOTTOMLEFT); + + Draw_Fill (x, y*8, 19*8, 9*8, 0, 0.5); //dark rectangle + + sprintf (str, "devstats |Curr Peak"); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "---------+---------"); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Edicts |%4i %4i", dev_stats.edicts, dev_peakstats.edicts); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Packet |%4i %4i", dev_stats.packetsize, dev_peakstats.packetsize); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Visedicts|%4i %4i", dev_stats.visedicts, dev_peakstats.visedicts); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Efrags |%4i %4i", dev_stats.efrags, dev_peakstats.efrags); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Dlights |%4i %4i", dev_stats.dlights, dev_peakstats.dlights); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Beams |%4i %4i", dev_stats.beams, dev_peakstats.beams); + Draw_String (x, (y++)*8-x, str); + + sprintf (str, "Tempents |%4i %4i", dev_stats.tempents, dev_peakstats.tempents); + Draw_String (x, (y++)*8-x, str); +} + +/* +============== +SCR_DrawRam +============== +*/ +void SCR_DrawRam (void) +{ + if (!scr_showram.value) + return; + + if (!r_cache_thrash) + return; + + GL_SetCanvas (CANVAS_DEFAULT); //johnfitz + + Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram); +} + +/* +============== +SCR_DrawTurtle +============== +*/ +void SCR_DrawTurtle (void) +{ + static int count; + + if (!scr_showturtle.value) + return; + + if (host_frametime < 0.1) + { + count = 0; + return; + } + + count++; + if (count < 3) + return; + + GL_SetCanvas (CANVAS_DEFAULT); //johnfitz + + Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); +} + +/* +============== +SCR_DrawNet +============== +*/ +void SCR_DrawNet (void) +{ + if (realtime - cl.last_received_message < 0.3) + return; + if (cls.demoplayback) + return; + + GL_SetCanvas (CANVAS_DEFAULT); //johnfitz + + Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); +} + +/* +============== +DrawPause +============== +*/ +void SCR_DrawPause (void) +{ + qpic_t *pic; + + if (!cl.paused) + return; + + if (!scr_showpause.value) // turn off for screenshots + return; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + pic = Draw_CachePic ("gfx/pause.lmp"); + Draw_Pic ( (320 - pic->width)/2, (240 - 48 - pic->height)/2, pic); //johnfitz -- stretched menus + + scr_tileclear_updates = 0; //johnfitz +} + +/* +============== +SCR_DrawLoading +============== +*/ +void SCR_DrawLoading (void) +{ + qpic_t *pic; + + if (!scr_drawloading) + return; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + pic = Draw_CachePic ("gfx/loading.lmp"); + Draw_Pic ( (320 - pic->width)/2, (240 - 48 - pic->height)/2, pic); //johnfitz -- stretched menus + + scr_tileclear_updates = 0; //johnfitz +} + +/* +============== +SCR_DrawCrosshair -- johnfitz +============== +*/ +void SCR_DrawCrosshair (void) +{ + if (!crosshair.value) + return; + + GL_SetCanvas (CANVAS_CROSSHAIR); + Draw_Character (-4, -4, '+'); //0,0 is center of viewport +} + + + +//============================================================================= + + +/* +================== +SCR_SetUpToDrawConsole +================== +*/ +void SCR_SetUpToDrawConsole (void) +{ + //johnfitz -- let's hack away the problem of slow console when host_timescale is <0 + extern cvar_t host_timescale; + float timescale; + //johnfitz + + Con_CheckResize (); + + if (scr_drawloading) + return; // never a console with loading plaque + +// decide on the height of the console + con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; + + if (con_forcedup) + { + scr_conlines = glheight; //full screen //johnfitz -- glheight instead of vid.height + scr_con_current = scr_conlines; + } + else if (key_dest == key_console) + scr_conlines = glheight/2; //half screen //johnfitz -- glheight instead of vid.height + else + scr_conlines = 0; //none visible + + timescale = (host_timescale.value > 0) ? host_timescale.value : 1; //johnfitz -- timescale + + if (scr_conlines < scr_con_current) + { + scr_con_current -= scr_conspeed.value*host_frametime/timescale; //johnfitz -- timescale + if (scr_conlines > scr_con_current) + scr_con_current = scr_conlines; + + } + else if (scr_conlines > scr_con_current) + { + scr_con_current += scr_conspeed.value*host_frametime/timescale; //johnfitz -- timescale + if (scr_conlines < scr_con_current) + scr_con_current = scr_conlines; + } + + if (clearconsole++ < vid.numpages) + Sbar_Changed (); + + if (!con_forcedup && scr_con_current) + scr_tileclear_updates = 0; //johnfitz +} + +/* +================== +SCR_DrawConsole +================== +*/ +void SCR_DrawConsole (void) +{ + if (scr_con_current) + { + Con_DrawConsole (scr_con_current, true); + clearconsole = 0; + } + else + { + if (key_dest == key_game || key_dest == key_message) + Con_DrawNotify (); // only draw notify in game + } +} + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + +/* +================== +SCR_ScreenShot_f -- johnfitz -- rewritten to use Image_WriteTGA +================== +*/ +void SCR_ScreenShot_f (void) +{ + byte *buffer; + char tganame[16]; //johnfitz -- was [80] + char checkname[MAX_OSPATH]; + int i; + +// find a file name to save it to + for (i=0; i<10000; i++) + { + sprintf (tganame, "fitz%04i.tga", i); + sprintf (checkname, "%s/%s", com_gamedir, tganame); + if (Sys_FileTime(checkname) == -1) + break; // file doesn't exist + } + if (i == 10000) + { + Con_Printf ("SCR_ScreenShot_f: Couldn't find an unused filename\n"); + return; + } + +//get data + buffer = malloc(glwidth*glheight*3); + glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer); + +// now write the file + if (Image_WriteTGA (tganame, buffer, glwidth, glheight, 24, false)) + Con_Printf ("Wrote %s\n", tganame); + else + Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); + + free (buffer); +} + + +//============================================================================= + + +/* +=============== +SCR_BeginLoadingPlaque + +================ +*/ +void SCR_BeginLoadingPlaque (void) +{ + S_StopAllSounds (true); + + if (cls.state != ca_connected) + return; + if (cls.signon != SIGNONS) + return; + +// redraw with no console and the loading plaque + Con_ClearNotify (); + scr_centertime_off = 0; + scr_con_current = 0; + + scr_drawloading = true; + Sbar_Changed (); + SCR_UpdateScreen (); + scr_drawloading = false; + + scr_disabled_for_loading = true; + scr_disabled_time = realtime; +} + +/* +=============== +SCR_EndLoadingPlaque + +================ +*/ +void SCR_EndLoadingPlaque (void) +{ + scr_disabled_for_loading = false; + Con_ClearNotify (); +} + +//============================================================================= + +char *scr_notifystring; +qboolean scr_drawdialog; + +void SCR_DrawNotifyString (void) +{ + char *start; + int l; + int j; + int x, y; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + start = scr_notifystring; + + y = 200 * 0.35; //johnfitz -- stretched overlays + + do + { + // scan the width of the line + for (l=0 ; l<40 ; l++) + if (start[l] == '\n' || !start[l]) + break; + x = (320 - l*8)/2; //johnfitz -- stretched overlays + for (j=0 ; j time1) + return false; + //johnfitz + + return key_lastpress == 'y'; +} + + +//============================================================================= + +//johnfitz -- deleted SCR_BringDownConsole + + +/* +================== +SCR_TileClear -- johnfitz -- modified to use glwidth/glheight instead of vid.width/vid.height + also fixed the dimentions of right and top panels + also added scr_tileclear_updates +================== +*/ +void SCR_TileClear (void) +{ + if (scr_tileclear_updates >= vid.numpages && !gl_clear.value && !isIntelVideo) //intel video workarounds from Baker + return; + scr_tileclear_updates++; + + if (r_refdef.vrect.x > 0) + { + // left + Draw_TileClear (0, + 0, + r_refdef.vrect.x, + glheight - sb_lines); + // right + Draw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, + 0, + glwidth - r_refdef.vrect.x - r_refdef.vrect.width, + glheight - sb_lines); + } + + if (r_refdef.vrect.y > 0) + { + // top + Draw_TileClear (r_refdef.vrect.x, + 0, + r_refdef.vrect.width, + r_refdef.vrect.y); + // bottom + Draw_TileClear (r_refdef.vrect.x, + r_refdef.vrect.y + r_refdef.vrect.height, + r_refdef.vrect.width, + glheight - r_refdef.vrect.y - r_refdef.vrect.height - sb_lines); + } +} + +/* +================== +SCR_UpdateScreen + +This is called every frame, and can also be called explicitly to flush +text to the screen. + +WARNING: be very careful calling this from elsewhere, because the refresh +needs almost the entire 256k of stack space! +================== +*/ +void SCR_UpdateScreen (void) +{ + // vrect_t vrect; unused -- kristian + + if (block_drawing) + return; + + vid.numpages = 2 + (gl_triplebuffer.value ? 1 : 0); //johnfitz -- in case gl_triplebuffer is not 0 or 1 + + if (scr_disabled_for_loading) + { + if (realtime - scr_disabled_time > 60) + { + scr_disabled_for_loading = false; + Con_Printf ("load failed.\n"); + } + else + return; + } + + if (!scr_initialized || !con_initialized) + return; // not initialized yet + + + GL_BeginRendering (&glx, &gly, &glwidth, &glheight); + + // + // determine size of refresh window + // + + if (oldfov != scr_fov.value) + { + oldfov = scr_fov.value; + vid.recalc_refdef = true; + } + + if (oldscreensize != scr_viewsize.value) + { + oldscreensize = scr_viewsize.value; + vid.recalc_refdef = true; + } + + //johnfitz -- added oldsbarscale and oldsbaralpha + if (oldsbarscale != scr_sbarscale.value) + { + oldsbarscale = scr_sbarscale.value; + vid.recalc_refdef = true; + } + + if (oldsbaralpha != scr_sbaralpha.value) + { + oldsbaralpha = scr_sbaralpha.value; + vid.recalc_refdef = true; + } + //johnfitz + + if (vid.recalc_refdef) + SCR_CalcRefdef (); + +// +// do 3D refresh drawing, and then update the screen +// + SCR_SetUpToDrawConsole (); + + V_RenderView (); + + GL_Set2D (); + + //FIXME: only call this when needed + SCR_TileClear (); + + if (scr_drawdialog) //new game confirm + { + Sbar_Draw (); + Draw_FadeScreen (); + SCR_DrawNotifyString (); + } + else if (scr_drawloading) //loading + { + SCR_DrawLoading (); + Sbar_Draw (); + } + else if (cl.intermission == 1 && key_dest == key_game) //end of level + { + Sbar_IntermissionOverlay (); + } + else if (cl.intermission == 2 && key_dest == key_game) //end of episode + { + Sbar_FinaleOverlay (); + SCR_CheckDrawCenterString (); + } + else + { + SCR_DrawCrosshair (); //johnfitz + SCR_DrawRam (); + SCR_DrawNet (); + SCR_DrawTurtle (); + SCR_DrawPause (); + SCR_CheckDrawCenterString (); + Sbar_Draw (); + SCR_DrawDevStats (); //johnfitz + SCR_DrawFPS (); //johnfitz + SCR_DrawClock (); //johnfitz + SCR_DrawConsole (); + M_Draw (); + } + + V_UpdateBlend (); //johnfitz -- V_UpdatePalette cleaned up and renamed + + GL_EndRendering (); +} + diff --git a/Quake/gl_sky.c b/Quake/gl_sky.c new file mode 100644 index 00000000..ce3be049 --- /dev/null +++ b/Quake/gl_sky.c @@ -0,0 +1,1017 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +//gl_sky.c + +#include "quakedef.h" + +#define MAX_CLIP_VERTS 64 + +float Fog_GetDensity(void); +float *Fog_GetColor(void); + +extern model_t *loadmodel; +extern int rs_skypolys; //for r_speeds readout +extern int rs_skypasses; //for r_speeds readout +float skyflatcolor[3]; +float skymins[2][6], skymaxs[2][6]; + +char skybox_name[32] = ""; //name of current skybox, or "" if no skybox + +gltexture_t *skybox_textures[6]; +gltexture_t *solidskytexture, *alphaskytexture; + +extern cvar_t gl_farclip; +cvar_t r_fastsky = {"r_fastsky", "0"}; +cvar_t r_sky_quality = {"r_sky_quality", "12"}; +cvar_t r_skyalpha = {"r_skyalpha", "1"}; +cvar_t r_skyfog = {"r_skyfog","0.5"}; + +int skytexorder[6] = {0,2,1,3,4,5}; //for skybox + +vec3_t skyclip[6] = { + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; + +int st_to_vec[6][3] = +{ + {3,-1,2}, + {-3,1,2}, + {1,3,2}, + {-1,-3,2}, + {-2,-1,3}, // straight up + {2,-1,-3} // straight down +}; + +int vec_to_st[6][3] = +{ + {-2,3,1}, + {2,3,-1}, + {1,3,2}, + {-1,3,-2}, + {-2,-1,3}, + {-2,1,-3} +}; + +//============================================================================== +// +// INIT +// +//============================================================================== + +/* +============= +Sky_LoadTexture + +A sky texture is 256*128, with the left side being a masked overlay +============== +*/ +void Sky_LoadTexture (texture_t *mt) +{ + char texturename[64]; + int i, j, p, r, g, b, count; + byte *src; + static byte front_data[128*128]; //FIXME: Hunk_Alloc + static byte back_data[128*128]; //FIXME: Hunk_Alloc + unsigned *rgba; + + src = (byte *)mt + mt->offsets[0]; + +// extract back layer and upload + for (i=0 ; i<128 ; i++) + for (j=0 ; j<128 ; j++) + back_data[(i*128) + j] = src[i*256 + j + 128]; + + sprintf(texturename, "%s:%s_back", loadmodel->name, mt->name); + solidskytexture = TexMgr_LoadImage (loadmodel, texturename, 128, 128, SRC_INDEXED, back_data, "", (unsigned)back_data, TEXPREF_NONE); + +// extract front layer and upload + for (i=0 ; i<128 ; i++) + for (j=0 ; j<128 ; j++) + { + front_data[(i*128) + j] = src[i*256 + j]; + if (front_data[(i*128) + j] == 0) + front_data[(i*128) + j] = 255; + } + + sprintf(texturename, "%s:%s_front", loadmodel->name, mt->name); + alphaskytexture = TexMgr_LoadImage (loadmodel, texturename, 128, 128, SRC_INDEXED, front_data, "", (unsigned)front_data, TEXPREF_ALPHA); + +// calculate r_fastsky color based on average of all opaque foreground colors + r = g = b = count = 0; + for (i=0 ; i<128 ; i++) + for (j=0 ; j<128 ; j++) + { + p = src[i*256 + j]; + if (p != 0) + { + rgba = &d_8to24table[p]; + r += ((byte *)rgba)[0]; + g += ((byte *)rgba)[1]; + b += ((byte *)rgba)[2]; + count++; + } + } + skyflatcolor[0] = (float)r/(count*255); + skyflatcolor[1] = (float)g/(count*255); + skyflatcolor[2] = (float)b/(count*255); +} + +/* +================== +Sky_LoadSkyBox +================== +*/ +char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; +void Sky_LoadSkyBox (char *name) +{ + int i, mark, width, height; + // FILE *f; unused -- kristian + char filename[MAX_OSPATH]; + byte *data; + qboolean nonefound = true; + + if (strcmp(skybox_name, name) == 0) + return; //no change + + //purge old textures + for (i=0; i<6; i++) + { + if (skybox_textures[i] && skybox_textures[i] != notexture) + TexMgr_FreeTexture (skybox_textures[i]); + skybox_textures[i] = NULL; + } + + //turn off skybox if sky is set to "" + if (name[0] == 0) + { + skybox_name[0] = 0; + return; + } + + //load textures + for (i=0; i<6; i++) + { + mark = Hunk_LowMark (); + sprintf (filename, "gfx/env/%s%s", name, suf[i]); + data = Image_LoadImage (filename, &width, &height); + if (data) + { + skybox_textures[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, SRC_RGBA, data, filename, 0, TEXPREF_NONE); + nonefound = false; + } + else + { + Con_Printf ("Couldn't load %s\n", filename); + skybox_textures[i] = notexture; + } + Hunk_FreeToLowMark (mark); + } + + if (nonefound) // go back to scrolling sky if skybox is totally missing + { + for (i=0; i<6; i++) + { + if (skybox_textures[i] && skybox_textures[i] != notexture) + TexMgr_FreeTexture (skybox_textures[i]); + skybox_textures[i] = NULL; + } + skybox_name[0] = 0; + return; + } + + strcpy(skybox_name, name); +} + +/* +================= +Sky_NewMap +================= +*/ +void Sky_NewMap (void) +{ + char key[128], value[4096]; + char *data; + int i; + + // + // initially no sky + // + skybox_name[0] = 0; + for (i=0; i<6; i++) + skybox_textures[i] = NULL; + + // + // read worldspawn (this is so ugly, and shouldn't it be done on the server?) + // + data = cl.worldmodel->entities; + if (!data) + return; //FIXME: how could this possibly ever happen? -- if there's no + // worldspawn then the sever wouldn't send the loadmap message to the client + + data = COM_Parse(data); + if (!data) //should never happen + return; // error + if (com_token[0] != '{') //should never happen + return; // error + while (1) + { + data = COM_Parse(data); + if (!data) + return; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); + else + strcpy(key, com_token); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + data = COM_Parse(data); + if (!data) + return; // error + strcpy(value, com_token); + + if (!strcmp("sky", key)) + Sky_LoadSkyBox(value); + +#if 1 //also accept non-standard keys + else if (!strcmp("skyname", key)) //half-life + Sky_LoadSkyBox(value); + else if (!strcmp("qlsky", key)) //quake lives + Sky_LoadSkyBox(value); +#endif + } +} + +/* +================= +Sky_SkyCommand_f +================= +*/ +void Sky_SkyCommand_f (void) +{ + switch (Cmd_Argc()) + { + case 1: + Con_Printf("\"sky\" is \"%s\"\n", skybox_name); + break; + case 2: + Sky_LoadSkyBox(Cmd_Argv(1)); + break; + default: + Con_Printf("usage: sky \n"); + } +} + +/* +============= +Sky_Init +============= +*/ +void Sky_Init (void) +{ + int i; + + Cvar_RegisterVariable (&r_fastsky, NULL); + Cvar_RegisterVariable (&r_sky_quality, NULL); + Cvar_RegisterVariable (&r_skyalpha, NULL); + Cvar_RegisterVariable (&r_skyfog, NULL); + + Cmd_AddCommand ("sky",Sky_SkyCommand_f); + + for (i=0; i<6; i++) + skybox_textures[i] = NULL; +} + +//============================================================================== +// +// PROCESS SKY SURFS +// +//============================================================================== + +/* +================= +Sky_ProjectPoly + +update sky bounds +================= +*/ +void Sky_ProjectPoly (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + + // decide which face it maps to + VectorCopy (vec3_origin, v); + for (i=0, vp=vecs ; i av[1] && av[0] > av[2]) + { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } + else if (av[1] > av[2] && av[1] > av[0]) + { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } + else + { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i=0 ; i 0) + dv = vecs[j - 1]; + else + dv = -vecs[-j - 1]; + + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[-j -1] / dv; + else + s = vecs[j-1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[-j -1] / dv; + else + t = vecs[j-1] / dv; + + if (s < skymins[0][axis]) + skymins[0][axis] = s; + if (t < skymins[1][axis]) + skymins[1][axis] = t; + if (s > skymaxs[0][axis]) + skymaxs[0][axis] = s; + if (t > skymaxs[1][axis]) + skymaxs[1][axis] = t; + } +} + +/* +================= +Sky_ClipPoly +================= +*/ +void Sky_ClipPoly (int nump, vec3_t vecs, int stage) +{ + float *norm; + float *v; + qboolean front, back; + float d, e; + float dists[MAX_CLIP_VERTS]; + int sides[MAX_CLIP_VERTS]; + vec3_t newv[2][MAX_CLIP_VERTS]; + int newc[2]; + int i, j; + + if (nump > MAX_CLIP_VERTS-2) + Sys_Error ("Sky_ClipPoly: MAX_CLIP_VERTS"); + if (stage == 6) // fully clipped + { + Sky_ProjectPoly (nump, vecs); + return; + } + + front = back = false; + norm = skyclip[stage]; + for (i=0, v = vecs ; i ON_EPSILON) + { + front = true; + sides[i] = SIDE_FRONT; + } + else if (d < ON_EPSILON) + { + back = true; + sides[i] = SIDE_BACK; + } + else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) + { // not clipped + Sky_ClipPoly (nump, vecs, stage+1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy (vecs, (vecs+(i*3)) ); + newc[0] = newc[1] = 0; + + for (i=0, v = vecs ; inumverts ; i++) + VectorSubtract (p->verts[i], r_origin, verts[i]); + Sky_ClipPoly (p->numverts, verts[0], 0); + } +} + +/* +================ +Sky_ProcessTextureChains -- handles sky polys in world model +================ +*/ +void Sky_ProcessTextureChains (void) +{ + int i; + msurface_t *s; + texture_t *t; + + if (!r_drawworld_cheatsafe) + return; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || !(t->texturechain->flags & SURF_DRAWSKY)) + continue; + + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + Sky_ProcessPoly (s->polys); + } +} + +/* +================ +Sky_ProcessEntities -- handles sky polys on brush models +================ +*/ +void Sky_ProcessEntities (void) +{ + entity_t *e; + msurface_t *s; + glpoly_t *p; + int i,j,k,mark; + float dot; + qboolean rotated; + vec3_t temp, forward, right, up; + + if (!r_drawentities.value) + return; + + for (i=0 ; imodel->type != mod_brush) + continue; + + if (R_CullModelForEntity(e)) + continue; + + if (e->alpha == ENTALPHA_ZERO) + continue; + + VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + rotated = true; + AngleVectors (e->angles, forward, right, up); + VectorCopy (modelorg, temp); + modelorg[0] = DotProduct (temp, forward); + modelorg[1] = -DotProduct (temp, right); + modelorg[2] = DotProduct (temp, up); + } + else + rotated = false; + + s = &e->model->surfaces[e->model->firstmodelsurface]; + + for (j=0 ; jmodel->nummodelsurfaces ; j++, s++) + { + if (s->flags & SURF_DRAWSKY) + { + dot = DotProduct (modelorg, s->plane->normal) - s->plane->dist; + if (((s->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(s->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + //copy the polygon and translate manually, since Sky_ProcessPoly needs it to be in world space + mark = Hunk_LowMark(); + p = Hunk_Alloc (sizeof(*s->polys)); //FIXME: don't allocate for each poly + p->numverts = s->polys->numverts; + for (k=0; knumverts; k++) + { + if (rotated) + { + p->verts[k][0] = e->origin[0] + s->polys->verts[k][0] * forward[0] + - s->polys->verts[k][1] * right[0] + + s->polys->verts[k][2] * up[0]; + p->verts[k][1] = e->origin[1] + s->polys->verts[k][0] * forward[1] + - s->polys->verts[k][1] * right[1] + + s->polys->verts[k][2] * up[1]; + p->verts[k][2] = e->origin[2] + s->polys->verts[k][0] * forward[2] + - s->polys->verts[k][1] * right[2] + + s->polys->verts[k][2] * up[2]; + } + else + VectorAdd(s->polys->verts[k], e->origin, p->verts[k]); + } + Sky_ProcessPoly (p); + Hunk_FreeToLowMark (mark); + } + } + } + } +} + +//============================================================================== +// +// RENDER SKYBOX +// +//============================================================================== + +/* +============== +Sky_EmitSkyBoxVertex +============== +*/ +void Sky_EmitSkyBoxVertex (float s, float t, int axis) +{ + vec3_t v, b; + int j, k; + float w, h; + + b[0] = s * gl_farclip.value / sqrt(3.0); + b[1] = t * gl_farclip.value / sqrt(3.0); + b[2] = gl_farclip.value / sqrt(3.0); + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + v[j] += r_origin[j]; + } + + // convert from range [-1,1] to [0,1] + s = (s+1)*0.5; + t = (t+1)*0.5; + + // avoid bilerp seam + w = skybox_textures[skytexorder[axis]]->width; + h = skybox_textures[skytexorder[axis]]->height; + s = s * (w-1)/w + 0.5/w; + t = t * (h-1)/h + 0.5/h; + + t = 1.0 - t; + glTexCoord2f (s, t); + glVertex3fv (v); +} + +/* +============== +Sky_DrawSkyBox + +FIXME: eliminate cracks by adding an extra vert on tjuncs +============== +*/ +void Sky_DrawSkyBox (void) +{ + int i; + /* unused -- kristian + , j, k; + vec3_t v; + float s, t; + */ + + for (i=0 ; i<6 ; i++) + { + if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) + continue; + + GL_Bind (skybox_textures[skytexorder[i]]); + +#if 1 //FIXME: this is to avoid tjunctions until i can do it the right way + skymins[0][i] = -1; + skymins[1][i] = -1; + skymaxs[0][i] = 1; + skymaxs[1][i] = 1; +#endif + glBegin (GL_QUADS); + Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i); + Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i); + Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i); + Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i); + glEnd (); + + rs_skypolys++; + rs_skypasses++; + + if (Fog_GetDensity() > 0 && r_skyfog.value > 0) + { + float *c; + + c = Fog_GetColor(); + glEnable (GL_BLEND); + glDisable (GL_TEXTURE_2D); + glColor4f (c[0],c[1],c[2], CLAMP(0.0,r_skyfog.value,1.0)); + + glBegin (GL_QUADS); + Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i); + Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i); + Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i); + Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i); + glEnd (); + + glColor3f (1, 1, 1); + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + + rs_skypasses++; + } + } +} + +//============================================================================== +// +// RENDER CLOUDS +// +//============================================================================== + +/* +============== +Sky_SetBoxVert +============== +*/ +void Sky_SetBoxVert (float s, float t, int axis, vec3_t v) +{ + vec3_t b; + int j, k; + + b[0] = s * gl_farclip.value / sqrt(3.0); + b[1] = t * gl_farclip.value / sqrt(3.0); + b[2] = gl_farclip.value / sqrt(3.0); + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + v[j] = -b[-k - 1]; + else + v[j] = b[k - 1]; + v[j] += r_origin[j]; + } +} + +/* +============= +Sky_GetTexCoord +============= +*/ +void Sky_GetTexCoord (vec3_t v, float speed, float *s, float *t) +{ + vec3_t dir; + float length, scroll; + + VectorSubtract (v, r_origin, dir); + dir[2] *= 3; // flatten the sphere + + length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]; + length = sqrt (length); + length = 6*63/length; + + scroll = cl.time*speed; + scroll -= (int)scroll & ~127; + + *s = (scroll + dir[0] * length) * (1.0/128); + *t = (scroll + dir[1] * length) * (1.0/128); +} + +/* +=============== +Sky_DrawFaceQuad +=============== +*/ +void Sky_DrawFaceQuad (glpoly_t *p) +{ + float s, t; + float *v; + int i; + + if (gl_mtexable && r_skyalpha.value >= 1.0) + { + GL_Bind (solidskytexture); + GL_EnableMultitexture(); + GL_Bind (alphaskytexture); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + + glBegin (GL_QUADS); + for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) + { + Sky_GetTexCoord (v, 8, &s, &t); + GL_MTexCoord2fFunc (TEXTURE0, s, t); + Sky_GetTexCoord (v, 16, &s, &t); + GL_MTexCoord2fFunc (TEXTURE1, s, t); + glVertex3fv (v); + } + glEnd (); + + GL_DisableMultitexture(); + + rs_skypolys++; + rs_skypasses++; + } + else + { + GL_Bind (solidskytexture); + + if (r_skyalpha.value < 1.0) + glColor3f (1, 1, 1); + + glBegin (GL_QUADS); + for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) + { + Sky_GetTexCoord (v, 8, &s, &t); + glTexCoord2f (s, t); + glVertex3fv (v); + } + glEnd (); + + GL_Bind (alphaskytexture); + glEnable (GL_BLEND); + + if (r_skyalpha.value < 1.0) + glColor4f (1, 1, 1, r_skyalpha.value); + + glBegin (GL_QUADS); + for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) + { + Sky_GetTexCoord (v, 16, &s, &t); + glTexCoord2f (s, t); + glVertex3fv (v); + } + glEnd (); + + glDisable (GL_BLEND); + + rs_skypolys++; + rs_skypasses += 2; + } + + if (Fog_GetDensity() > 0 && r_skyfog.value > 0) + { + float *c; + + c = Fog_GetColor(); + glEnable (GL_BLEND); + glDisable (GL_TEXTURE_2D); + glColor4f (c[0],c[1],c[2], CLAMP(0.0,r_skyfog.value,1.0)); + + glBegin (GL_QUADS); + for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE) + glVertex3fv (v); + glEnd (); + + glColor3f (1, 1, 1); + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + + rs_skypasses++; + } +} + +/* +============== +Sky_DrawFace +============== +*/ + +void Sky_DrawFace (int axis) +{ + glpoly_t *p; + vec3_t verts[4]; + int i, j, start; + float di,qi,dj,qj; + vec3_t vup, vright, temp, temp2; + + Sky_SetBoxVert(-1.0, -1.0, axis, verts[0]); + Sky_SetBoxVert(-1.0, 1.0, axis, verts[1]); + Sky_SetBoxVert(1.0, 1.0, axis, verts[2]); + Sky_SetBoxVert(1.0, -1.0, axis, verts[3]); + + start = Hunk_LowMark (); + p = Hunk_Alloc(sizeof(glpoly_t)); + + VectorSubtract(verts[2],verts[3],vup); + VectorSubtract(verts[2],verts[1],vright); + + di = max((int)r_sky_quality.value, 1); + qi = 1.0 / di; + dj = (axis < 4) ? di*2 : di; //subdivide vertically more than horizontally on skybox sides + qj = 1.0 / dj; + + for (i=0; i skymaxs[0][axis]/2+0.5 || + j*qj < skymins[1][axis]/2+0.5 - qj || j*qj > skymaxs[1][axis]/2+0.5) + continue; + + //if (i&1 ^ j&1) continue; //checkerboard test + VectorScale (vright, qi*i, temp); + VectorScale (vup, qj*j, temp2); + VectorAdd(temp,temp2,temp); + VectorAdd(verts[0],temp,p->verts[0]); + + VectorScale (vup, qj, temp); + VectorAdd (p->verts[0],temp,p->verts[1]); + + VectorScale (vright, qi, temp); + VectorAdd (p->verts[1],temp,p->verts[2]); + + VectorAdd (p->verts[0],temp,p->verts[3]); + + Sky_DrawFaceQuad (p); + } + } + Hunk_FreeToLowMark (start); +} + +/* +============== +Sky_DrawSkyLayers + +draws the old-style scrolling cloud layers +============== +*/ +void Sky_DrawSkyLayers (void) +{ + int i; + + if (r_skyalpha.value < 1.0) + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + for (i=0 ; i<6 ; i++) + if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i]) + Sky_DrawFace (i); + + if (r_skyalpha.value < 1.0) + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +} + +/* +============== +Sky_DrawSky + +called once per frame before drawing anything else +============== +*/ +void Sky_DrawSky (void) +{ + int i; + + //in these special render modes, the sky faces are handled in the normal world/brush renderer + if (r_drawflat_cheatsafe || r_lightmap_cheatsafe ) + return; + + // + // reset sky bounds + // + for (i=0 ; i<6 ; i++) + { + skymins[0][i] = skymins[1][i] = 9999; + skymaxs[0][i] = skymaxs[1][i] = -9999; + } + + // + // process world and bmodels: draw flat-shaded sky surfs, and update skybounds + // + Fog_DisableGFog (); + glDisable (GL_TEXTURE_2D); + if (Fog_GetDensity() > 0) + glColor3fv (Fog_GetColor()); + else + glColor3fv (skyflatcolor); + Sky_ProcessTextureChains (); + Sky_ProcessEntities (); + glColor3f (1, 1, 1); + glEnable (GL_TEXTURE_2D); + + // + // render slow sky: cloud layers or skybox + // + if (!r_fastsky.value && !(Fog_GetDensity() > 0 && r_skyfog.value >= 1)) + { + glDepthFunc(GL_GEQUAL); + glDepthMask(0); + + if (skybox_name[0]) + Sky_DrawSkyBox (); + else + Sky_DrawSkyLayers(); + + glDepthMask(1); + glDepthFunc(GL_LEQUAL); + } + + Fog_EnableGFog (); +} \ No newline at end of file diff --git a/Quake/gl_test.c b/Quake/gl_test.c new file mode 100644 index 00000000..bfca05d6 --- /dev/null +++ b/Quake/gl_test.c @@ -0,0 +1,183 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +#ifdef GLTEST + +typedef struct +{ + plane_t *plane; + vec3_t origin; + vec3_t normal; + vec3_t up; + vec3_t right; + vec3_t reflect; + float length; +} puff_t; + +#define MAX_PUFFS 64 + +puff_t puffs[MAX_PUFFS]; + + +void Test_Init (void) +{ +} + + + +plane_t junk; +plane_t *HitPlane (vec3_t start, vec3_t end) +{ + trace_t trace; + +// fill in a default trace + memset (&trace, 0, sizeof(trace_t)); + trace.fraction = 1; + trace.allsolid = true; + VectorCopy (end, trace.endpos); + + SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); + + junk = trace.plane; + return &junk; +} + +void Test_Spawn (vec3_t origin) +{ + int i; + puff_t *p; + vec3_t temp; + vec3_t normal; + vec3_t incoming; + plane_t *plane; + float d; + + for (i=0,p=puffs ; ilength <= 0) + break; + } + if (i == MAX_PUFFS) + return; + + VectorSubtract (r_refdef.vieworg, origin, incoming); + VectorSubtract (origin, incoming, temp); + plane = HitPlane (r_refdef.vieworg, temp); + + VectorNormalize (incoming); + d = DotProduct (incoming, plane->normal); + VectorSubtract (vec3_origin, incoming, p->reflect); + VectorMA (p->reflect, d*2, plane->normal, p->reflect); + + VectorCopy (origin, p->origin); + VectorCopy (plane->normal, p->normal); + + CrossProduct (incoming, p->normal, p->up); + + CrossProduct (p->up, p->normal, p->right); + + p->length = 8; +} + +void DrawPuff (puff_t *p) +{ + vec3_t pts[2][3]; + int i, j; + float s, d; + + for (i=0 ; i<2 ; i++) + { + if (i == 1) + { + s = 6; + d = p->length; + } + else + { + s = 2; + d = 0; + } + + for (j=0 ; j<3 ; j++) + { + pts[i][0][j] = p->origin[j] + p->up[j]*s + p->reflect[j]*d; + pts[i][1][j] = p->origin[j] + p->right[j]*s + p->reflect[j]*d; + pts[i][2][j] = p->origin[j] + -p->right[j]*s + p->reflect[j]*d; + } + } + + glColor3f (1, 0, 0); + +#if 0 + glBegin (GL_LINES); + glVertex3fv (p->origin); + glVertex3f (p->origin[0] + p->length*p->reflect[0], + p->origin[1] + p->length*p->reflect[1], + p->origin[2] + p->length*p->reflect[2]); + + glVertex3fv (pts[0][0]); + glVertex3fv (pts[1][0]); + + glVertex3fv (pts[0][1]); + glVertex3fv (pts[1][1]); + + glVertex3fv (pts[0][2]); + glVertex3fv (pts[1][2]); + + glEnd (); +#endif + + glBegin (GL_QUADS); + for (i=0 ; i<3 ; i++) + { + j = (i+1)%3; + glVertex3fv (pts[0][j]); + glVertex3fv (pts[1][j]); + glVertex3fv (pts[1][i]); + glVertex3fv (pts[0][i]); + } + glEnd (); + + glBegin (GL_TRIANGLES); + glVertex3fv (pts[1][0]); + glVertex3fv (pts[1][1]); + glVertex3fv (pts[1][2]); + glEnd (); + + p->length -= host_frametime*2; +} + + +void Test_Draw (void) +{ + int i; + puff_t *p; + + for (i=0, p=puffs ; ilength > 0) + DrawPuff (p); + } +} + +#endif diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c new file mode 100644 index 00000000..f0bf8ac4 --- /dev/null +++ b/Quake/gl_texmgr.c @@ -0,0 +1,1415 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +//gl_texmgr.c -- fitzquake's texture manager. manages opengl texture images + +#include "quakedef.h" + +cvar_t gl_texture_anisotropy = {"gl_texture_anisotropy", "1", true}; +cvar_t gl_max_size = {"gl_max_size", "0"}; +cvar_t gl_picmip = {"gl_picmip", "0"}; +GLint gl_hardware_maxsize; +const int gl_solid_format = 3; +const int gl_alpha_format = 4; + +#define MAX_GLTEXTURES 2048 +gltexture_t *active_gltextures, *free_gltextures; +int numgltextures; + +/* +================================================================================ + + COMMANDS + +================================================================================ +*/ + +typedef struct +{ + int magfilter; + int minfilter; + char *name; +} glmode_t; +glmode_t modes[] = { + {GL_NEAREST, GL_NEAREST, "GL_NEAREST"}, + {GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, "GL_NEAREST_MIPMAP_NEAREST"}, + {GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR, "GL_NEAREST_MIPMAP_LINEAR"}, + {GL_LINEAR, GL_LINEAR, "GL_LINEAR"}, + {GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, "GL_LINEAR_MIPMAP_NEAREST"}, + {GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, "GL_LINEAR_MIPMAP_LINEAR"}, +}; +#define NUM_GLMODES 6 +int gl_texturemode = 5; // bilinear + +/* +=============== +TexMgr_DescribeTextureModes_f -- report available texturemodes +=============== +*/ +void TexMgr_DescribeTextureModes_f (void) +{ + int i; + + for (i=0; iflags & TEXPREF_NEAREST) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + else if (glt->flags & TEXPREF_LINEAR) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else if (glt->flags & TEXPREF_MIPMAP) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, modes[gl_texturemode].magfilter); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, modes[gl_texturemode].minfilter); + } + else + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, modes[gl_texturemode].magfilter); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, modes[gl_texturemode].magfilter); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_texture_anisotropy.value); +} + +/* +=============== +TexMgr_TextureMode_f +=============== +*/ +void TexMgr_TextureMode_f (void) +{ + gltexture_t *glt; + char *arg; + int i; + + switch (Cmd_Argc()) + { + case 1: + Con_Printf ("\"gl_texturemode\" is \"%s\"\n", modes[gl_texturemode].name); + break; + case 2: + arg = Cmd_Argv(1); + if (arg[0] == 'G' || arg[0] == 'g') + { + for (i=0; i= '0' && arg[0] <= '9') + { + i = atoi(arg); + if (i > NUM_GLMODES || i < 1) + { + Con_Printf ("\"%s\" is not a valid texturemode\n", arg); + return; + } + gl_texturemode = i - 1; + } + else + Con_Printf ("\"%s\" is not a valid texturemode\n", arg); + +stuff: + for (glt=active_gltextures; glt; glt=glt->next) + TexMgr_SetFilterModes (glt); + + Sbar_Changed (); //sbar graphics need to be redrawn with new filter mode + + //FIXME: warpimages need to be redrawn, too. + + break; + default: + Con_SafePrintf ("usage: gl_texturemode \n"); + break; + } +} + +/* +=============== +TexMgr_Anisotropy_f -- called when gl_texture_anisotropy changes + +FIXME: this is getting called twice (becuase of the recursive Cvar_SetValue call) +=============== +*/ +void TexMgr_Anisotropy_f (void) +{ + // extern qboolean gl_anisotropy_able; unused -- kristian + extern float gl_max_anisotropy; + gltexture_t *glt; + + Cvar_SetValue ("gl_texture_anisotropy", CLAMP (1.0f, gl_texture_anisotropy.value, gl_max_anisotropy)); + + for (glt=active_gltextures; glt; glt=glt->next) + TexMgr_SetFilterModes (glt); +} + +/* +=============== +TexMgr_Imagelist_f -- report loaded textures +=============== +*/ +void TexMgr_Imagelist_f (void) +{ + float mb; + float texels = 0; + gltexture_t *glt; + extern cvar_t vid_bpp; + + for (glt=active_gltextures; glt; glt=glt->next) + { + Con_SafePrintf (" %4i x%4i %s\n", glt->width, glt->height, glt->name); + if (glt->flags & TEXPREF_MIPMAP) + texels += glt->width * glt->height * 4.0f / 3.0f; + else + texels += (glt->width * glt->height); + } + + mb = texels * (vid_bpp.value / 8.0f) / 0x100000; + Con_Printf ("%i textures %i pixels %1.1f megabytes\n", numgltextures, (int)texels, mb); +} + +/* +=============== +TexMgr_Imagedump_f -- dump all current textures to TGA files +=============== +*/ +void TexMgr_Imagedump_f (void) +{ + char tganame[MAX_OSPATH], tempname[MAX_OSPATH], dirname[MAX_OSPATH]; + gltexture_t *glt; + byte *buffer; + char *c; + + //create directory + sprintf(dirname, "%s/imagedump", com_gamedir); + Sys_mkdir (dirname); + + //loop through textures + for (glt=active_gltextures; glt; glt=glt->next) + { + Q_strcpy(tempname, glt->name); + while (c = strchr(tempname, ':')) *c = '_'; + while (c = strchr(tempname, '/')) *c = '_'; + while (c = strchr(tempname, '*')) *c = '_'; + sprintf(tganame, "imagedump/%s.tga", tempname); + + GL_Bind (glt); + if (glt->flags & TEXPREF_ALPHA) + { + buffer = malloc(glt->width*glt->height*4); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + Image_WriteTGA (tganame, buffer, glt->width, glt->height, 32, true); + } + else + { + buffer = malloc(glt->width*glt->height*3); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); + Image_WriteTGA (tganame, buffer, glt->width, glt->height, 24, true); + } + free (buffer); + } + + Con_Printf ("dumped %i textures to %s\n", numgltextures, dirname); +} + +/* +=============== +TexMgr_FrameUsage -- report texture memory usage for this frame +=============== +*/ +float TexMgr_FrameUsage (void) +{ + float mb; + float texels = 0; + gltexture_t *glt; + extern cvar_t vid_bpp; + + for (glt=active_gltextures; glt; glt=glt->next) + if (glt->visframe == r_framecount) + { + if (glt->flags & TEXPREF_MIPMAP) + texels += glt->width * glt->height * 4.0f / 3.0f; + else + texels += (glt->width * glt->height); + } + + mb = texels * (vid_bpp.value / 8.0f) / 0x100000; + return mb; +} + +/* +================================================================================ + + TEXTURE MANAGER + +================================================================================ +*/ + +/* +================ +TexMgr_FindTexture +================ +*/ +gltexture_t *TexMgr_FindTexture (model_t *owner, char *name) +{ + gltexture_t *glt; + + if (name) + { + for (glt=active_gltextures; glt; glt=glt->next) + if (glt->owner == owner && !strcmp (glt->name, name)) + return glt; + } + + return NULL; +} + +/* +================ +TexMgr_NewTexture +================ +*/ +gltexture_t *TexMgr_NewTexture (void) +{ + gltexture_t *glt; + + if (numgltextures == MAX_GLTEXTURES) + Sys_Error("numgltextures == MAX_GLTEXTURES\n"); + + glt = free_gltextures; + free_gltextures = glt->next; + glt->next = active_gltextures; + active_gltextures = glt; + + glGenTextures(1, (GLuint *)&glt->texnum); + numgltextures++; + return glt; +} + +/* +================ +TexMgr_FreeTexture +================ +*/ +void TexMgr_FreeTexture (gltexture_t *kill) +{ + gltexture_t *glt; + + if (kill == NULL) + { + Con_Printf ("TexMgr_FreeTexture: NULL texture\n"); + return; + } + + if (active_gltextures == kill) + { + active_gltextures = kill->next; + kill->next = free_gltextures; + free_gltextures = kill; + + glDeleteTextures(1, (const GLuint *)&kill->texnum); + numgltextures--; + return; + } + + for (glt = active_gltextures; glt; glt = glt->next) + if (glt->next == kill) + { + glt->next = kill->next; + kill->next = free_gltextures; + free_gltextures = kill; + + glDeleteTextures(1, (const GLuint *)&kill->texnum); + numgltextures--; + return; + } + + Con_Printf ("TexMgr_FreeTexture: not found\n"); +} + +/* +================ +TexMgr_FreeTextures + +compares each bit in "flags" to the one in glt->flags only if that bit is active in "mask" +================ +*/ +void TexMgr_FreeTextures (int flags, int mask) +{ + gltexture_t *glt, *next; + + for (glt = active_gltextures; glt; glt = next) + { + next = glt->next; + if ((glt->flags & mask) == (flags & mask)) + TexMgr_FreeTexture (glt); + } +} + +/* +================ +TexMgr_FreeTexturesForOwner +================ +*/ +void TexMgr_FreeTexturesForOwner (model_t *owner) +{ + gltexture_t *glt, *next; + + for (glt = active_gltextures; glt; glt = next) + { + next = glt->next; + if (glt && glt->owner == owner) + TexMgr_FreeTexture (glt); + } +} + +/* +================================================================================ + + INIT + +================================================================================ +*/ + +/* +================= +TexMgr_LoadPalette -- johnfitz -- was VID_SetPalette, moved here, renamed, rewritten +================= +*/ +void TexMgr_LoadPalette (void) +{ + byte mask[] = {255,255,255,0}; + byte black[] = {0,0,0,255}; + byte *pal, *src, *dst; + int i, mark; + FILE *f; + + COM_FOpenFile ("gfx/palette.lmp", &f); + if (!f) + Sys_Error ("Couldn't load gfx/palette.lmp"); + + mark = Hunk_LowMark (); + pal = Hunk_Alloc (768); + fread (pal, 1, 768, f); + fclose(f); + + //standard palette, 255 is transparent + dst = (byte *)d_8to24table; + src = pal; + for (i=0; i<256; i++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 255; + } + d_8to24table[255] &= *(int *)mask; + + //fullbright palette, 0-223 are black (for additive blending) + src = pal + 224*3; + dst = (byte *)(d_8to24table_fbright) + 224*4; + for (i=224; i<256; i++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 255; + } + for (i=0; i<224; i++) + d_8to24table_fbright[i] = *(int *)black; + + //nobright palette, 224-255 are black (for additive blending) + dst = (byte *)d_8to24table_nobright; + src = pal; + for (i=0; i<256; i++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = 255; + } + for (i=224; i<256; i++) + d_8to24table_nobright[i] = *(int *)black; + + //conchars palette, 0 and 255 are transparent + memcpy(d_8to24table_conchars, d_8to24table, 256*4); + d_8to24table_conchars[0] &= *(int *)mask; + + Hunk_FreeToLowMark (mark); +} + +/* +================ +TexMgr_NewGame +================ +*/ +void TexMgr_NewGame (void) +{ + TexMgr_FreeTextures (0, TEXPREF_PERSIST); //deletes all textures where TEXPREF_PERSIST is unset + TexMgr_LoadPalette (); +} + +/* +============= +TexMgr_RecalcWarpImageSize -- called during init, and after a vid_restart + +choose safe warpimage size and resize existing warpimage textures +============= +*/ +void TexMgr_RecalcWarpImageSize (void) +{ + int mark, oldsize; + gltexture_t *glt; + byte *dummy; + + // + // find the new correct size + // + oldsize = gl_warpimagesize; + + gl_warpimagesize = TexMgr_SafeTextureSize (512); + + while (gl_warpimagesize > vid.width) + gl_warpimagesize >>= 1; + while (gl_warpimagesize > vid.height) + gl_warpimagesize >>= 1; + + if (gl_warpimagesize == oldsize) + return; + + // + // resize the textures in opengl + // + mark = Hunk_LowMark(); + dummy = Hunk_Alloc (gl_warpimagesize*gl_warpimagesize*4); + + for (glt=active_gltextures; glt; glt=glt->next) + { + if (glt->flags & TEXPREF_WARPIMAGE) + { + GL_Bind (glt); + glTexImage2D (GL_TEXTURE_2D, 0, gl_solid_format, gl_warpimagesize, gl_warpimagesize, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummy); + glt->width = glt->height = gl_warpimagesize; + } + } + + Hunk_FreeToLowMark (mark); +} + +/* +================ +TexMgr_Init + +must be called before any texture loading +================ +*/ +void TexMgr_Init (void) +{ + int i; //, mark; unused -- kristian + static byte notexture_data[16] = {159,91,83,255,0,0,0,255,0,0,0,255,159,91,83,255}; //black and pink checker + static byte nulltexture_data[16] = {127,191,255,255,0,0,0,255,0,0,0,255,127,191,255,255}; //black and blue checker + extern texture_t *r_notexture_mip, *r_notexture_mip2; + + // init texture list + free_gltextures = (gltexture_t *) Hunk_AllocName (MAX_GLTEXTURES * sizeof(gltexture_t), "gltextures"); + active_gltextures = NULL; + for (i=0; igltexture = r_notexture_mip2->gltexture = notexture; + + //set safe size for warpimages + gl_warpimagesize = 0; + TexMgr_RecalcWarpImageSize (); +} + +/* +================================================================================ + + IMAGE LOADING + +================================================================================ +*/ + +/* +================ +TexMgr_Pad -- return smallest power of two greater than or equal to s +================ +*/ +int TexMgr_Pad (int s) +{ + int i; + for (i = 1; i < s; i<<=1); + return i; +} + +/* +=============== +TexMgr_SafeTextureSize -- return a size with hardware and user prefs in mind +=============== +*/ +int TexMgr_SafeTextureSize (int s) +{ + s = TexMgr_Pad(s); + if ((int)gl_max_size.value > 0) + s = min(TexMgr_Pad((int)gl_max_size.value), s); + s = min(gl_hardware_maxsize, s); + return s; +} + +/* +================ +TexMgr_PadConditional -- only pad if a texture of that size would be padded. (used for tex coords) +================ +*/ +int TexMgr_PadConditional (int s) +{ + if (s < TexMgr_SafeTextureSize(s)) + return TexMgr_Pad(s); + else + return s; +} + +/* +================ +TexMgr_MipMapW +================ +*/ +unsigned *TexMgr_MipMapW (unsigned *data, int width, int height) +{ + int i, size; + byte *out, *in; + + out = in = (byte *)data; + size = (width*height)>>1; + + for (i=0; i>1; + out[1] = (in[1] + in[5])>>1; + out[2] = (in[2] + in[6])>>1; + out[3] = (in[3] + in[7])>>1; + } + + return data; +} + +/* +================ +TexMgr_MipMapH +================ +*/ +unsigned *TexMgr_MipMapH (unsigned *data, int width, int height) +{ + int i, j; + byte *out, *in; + + out = in = (byte *)data; + height>>=1; + width<<=2; + + for (i=0; i>1; + out[1] = (in[1] + in[width+1])>>1; + out[2] = (in[2] + in[width+2])>>1; + out[3] = (in[3] + in[width+3])>>1; + } + + return data; +} + +/* +================ +TexMgr_ResampleTexture -- bilinear resample +================ +*/ +unsigned *TexMgr_ResampleTexture (unsigned *in, int inwidth, int inheight, qboolean alpha) +{ + byte *nwpx, *nepx, *swpx, *sepx, *dest; + unsigned xfrac, yfrac, x, y, modx, mody, imodx, imody, injump, outjump; + unsigned *out; + int i, j, outwidth, outheight; + + if (inwidth == TexMgr_Pad(inwidth) && inheight == TexMgr_Pad(inheight)) + return in; + + outwidth = TexMgr_Pad(inwidth); + outheight = TexMgr_Pad(inheight); + out = Hunk_Alloc(outwidth*outheight*4); + + xfrac = ((inwidth-1) << 16) / (outwidth-1); + yfrac = ((inheight-1) << 16) / (outheight-1); + y = outjump = 0; + + for (i=0; i>8) & 0xFF; + imody = 256 - mody; + injump = (y>>16) * inwidth; + x = 0; + + for (j=0; j>8) & 0xFF; + imodx = 256 - modx; + + nwpx = (byte *)(in + (x>>16) + injump); + nepx = nwpx + 4; + swpx = nwpx + inwidth*4; + sepx = swpx + 4; + + dest = (byte *)(out + outjump + j); + + dest[0] = (nwpx[0]*imodx*imody + nepx[0]*modx*imody + swpx[0]*imodx*mody + sepx[0]*modx*mody)>>16; + dest[1] = (nwpx[1]*imodx*imody + nepx[1]*modx*imody + swpx[1]*imodx*mody + sepx[1]*modx*mody)>>16; + dest[2] = (nwpx[2]*imodx*imody + nepx[2]*modx*imody + swpx[2]*imodx*mody + sepx[2]*modx*mody)>>16; + if (alpha) + dest[3] = (nwpx[3]*imodx*imody + nepx[3]*modx*imody + swpx[3]*imodx*mody + sepx[3]*modx*mody)>>16; + else + dest[3] = 255; + + x += xfrac; + } + outjump += outwidth; + y += yfrac; + } + + return out; +} + +/* +=============== +TexMgr_AlphaEdgeFix + +eliminate pink edges on sprites, etc. +operates in place on 32bit data +=============== +*/ +void TexMgr_AlphaEdgeFix (byte *data, int width, int height) +{ + int i,j,n=0,b,c[3]={0,0,0},lastrow,thisrow,nextrow,lastpix,thispix,nextpix; + byte *dest = data; + + for (i=0; iwidth, glt->height, glt->flags & TEXPREF_ALPHA); + glt->width = TexMgr_Pad(glt->width); + glt->height = TexMgr_Pad(glt->height); + + // mipmap down + picmip = (glt->flags & TEXPREF_NOPICMIP) ? 0 : max ((int)gl_picmip.value, 0); + mipwidth = TexMgr_SafeTextureSize (glt->width >> picmip); + mipheight = TexMgr_SafeTextureSize (glt->height >> picmip); + while (glt->width > mipwidth) + { + TexMgr_MipMapW (data, glt->width, glt->height); + glt->width >>= 1; + if (glt->flags & TEXPREF_ALPHA) + TexMgr_AlphaEdgeFix ((byte *)data, glt->width, glt->height); + } + while (glt->height > mipheight) + { + TexMgr_MipMapH (data, glt->width, glt->height); + glt->height >>= 1; + if (glt->flags & TEXPREF_ALPHA) + TexMgr_AlphaEdgeFix ((byte *)data, glt->width, glt->height); + } + + // upload + GL_Bind (glt); + internalformat = (glt->flags & TEXPREF_ALPHA) ? gl_alpha_format : gl_solid_format; + glTexImage2D (GL_TEXTURE_2D, 0, internalformat, glt->width, glt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + // upload mipmaps + if (glt->flags & TEXPREF_MIPMAP) + { + mipwidth = glt->width; + mipheight = glt->height; + + for (miplevel=1; mipwidth > 1 || mipheight > 1; miplevel++) + { + if (mipwidth > 1) + { + TexMgr_MipMapW (data, mipwidth, mipheight); + mipwidth >>= 1; + } + if (mipheight > 1) + { + TexMgr_MipMapH (data, mipwidth, mipheight); + mipheight >>= 1; + } + glTexImage2D (GL_TEXTURE_2D, miplevel, internalformat, mipwidth, mipheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + } + } + + // set filter modes + TexMgr_SetFilterModes (glt); +} + +/* +================ +TexMgr_LoadImage8 -- handles 8bit source data, then passes it to LoadImage32 +================ +*/ +void TexMgr_LoadImage8 (gltexture_t *glt, byte *data) +{ + extern cvar_t gl_fullbrights; + qboolean padw = false, padh = false; + byte padbyte; + unsigned int *usepal; + int i; + + // HACK HACK HACK -- taken from tomazquake + if (strstr(glt->name, "shot1sid") && glt->width==32 && glt->height==32 && CRC_Block(data, 1024) == 65393) + { + // This texture in b_shell1.bsp has some of the first 32 pixels painted white. + // They are invisible in software, but look really ugly in GL. So we just copy + // 32 pixels from the bottom to make it look nice. + memcpy (data, data + 32*31, 32); + } + + // detect false alpha cases + if (glt->flags & TEXPREF_ALPHA && !(glt->flags & TEXPREF_CONCHARS)) + { + for (i = 0; i < glt->width*glt->height; i++) + if (data[i] == 255) //transparent index + break; + if (i == glt->width*glt->height) + glt->flags -= TEXPREF_ALPHA; + } + + // choose palette and padbyte + if (glt->flags & TEXPREF_FULLBRIGHT) + { + usepal = d_8to24table_fbright; + padbyte = 0; + } + else if (glt->flags & TEXPREF_NOBRIGHT && gl_fullbrights.value) + { + usepal = d_8to24table_nobright; + padbyte = 0; + } + else if (glt->flags & TEXPREF_CONCHARS) + { + usepal = d_8to24table_conchars; + padbyte = 0; + } + else + { + usepal = d_8to24table; + padbyte = 255; + } + + // pad each dimention, but only if it's not going to be downsampled later + if (glt->flags & TEXPREF_PAD) + { + if (glt->width < TexMgr_SafeTextureSize(glt->width)) + { + data = TexMgr_PadImageW (data, glt->width, glt->height, padbyte); + glt->width = TexMgr_Pad(glt->width); + padw = true; + } + if (glt->height < TexMgr_SafeTextureSize(glt->height)) + { + data = TexMgr_PadImageH (data, glt->width, glt->height, padbyte); + glt->height = TexMgr_Pad(glt->height); + padh = true; + } + } + + // convert to 32bit + data = (byte *)TexMgr_8to32(data, glt->width * glt->height, usepal); + + // fix edges + if (glt->flags & TEXPREF_ALPHA) + TexMgr_AlphaEdgeFix (data, glt->width, glt->height); + else + { + if (padw) + TexMgr_PadEdgeFixW (data, glt->source_width, glt->source_height); + if (padh) + TexMgr_PadEdgeFixH (data, glt->source_width, glt->source_height); + } + + // upload it + TexMgr_LoadImage32 (glt, (unsigned *)data); +} + +/* +================ +TexMgr_LoadLightmap -- handles lightmap data +================ +*/ +void TexMgr_LoadLightmap (gltexture_t *glt, byte *data) +{ + extern int gl_lightmap_format, lightmap_bytes; + + // upload it + GL_Bind (glt); + glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, glt->width, glt->height, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, data); + + // set filter modes + TexMgr_SetFilterModes (glt); +} + +/* +================ +TexMgr_LoadImage -- the one entry point for loading all textures +================ +*/ +gltexture_t *TexMgr_LoadImage (model_t *owner, char *name, int width, int height, enum srcformat format, + byte *data, char *source_file, unsigned source_offset, unsigned flags) +{ + extern int lightmap_bytes; + unsigned short crc; + gltexture_t *glt; + int mark; //, bytes; unused -- kristian + + if (isDedicated) + return NULL; + + // cache check + switch (format) + { + case SRC_INDEXED: + crc = CRC_Block(data, width * height); + break; + case SRC_LIGHTMAP: + crc = CRC_Block(data, width * height * lightmap_bytes); + break; + case SRC_RGBA: + crc = CRC_Block(data, width * height * 4); + break; + } + if ((flags & TEXPREF_OVERWRITE) && (glt = TexMgr_FindTexture (owner, name))) + { + if (glt->source_crc == crc) + return glt; + } + else + glt = TexMgr_NewTexture (); + + // copy data + glt->owner = owner; + strncpy (glt->name, name, sizeof(glt->name)); + glt->width = width; + glt->height = height; + glt->flags = flags; + glt->shirt = -1; + glt->pants = -1; + strncpy (glt->source_file, source_file, sizeof(glt->source_file)); + glt->source_offset = source_offset; + glt->source_format = format; + glt->source_width = width; + glt->source_height = height; + glt->source_crc = crc; + + //upload it + mark = Hunk_LowMark(); + + switch (glt->source_format) + { + case SRC_INDEXED: + TexMgr_LoadImage8 (glt, data); + break; + case SRC_LIGHTMAP: + TexMgr_LoadLightmap (glt, data); + break; + case SRC_RGBA: + TexMgr_LoadImage32 (glt, (unsigned *)data); + break; + } + + Hunk_FreeToLowMark(mark); + + return glt; +} + +/* +================================================================================ + + COLORMAPPING AND TEXTURE RELOADING + +================================================================================ +*/ + +/* +================ +TexMgr_ReloadImage -- reloads a texture, and colormaps it if needed +================ +*/ +void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants) +{ + byte translation[256]; + byte *src, *dst, *data = NULL, *translated; + int mark, size, i; +// +// get source data +// + mark = Hunk_LowMark (); + + if (glt->source_file[0] && glt->source_offset) + { + //lump inside file + data = COM_LoadHunkFile (glt->source_file); + if (!data) + goto invalid; + data += glt->source_offset; + } + else if (glt->source_file[0] && !glt->source_offset) + data = Image_LoadImage (glt->source_file, (int *)&glt->source_width, (int *)&glt->source_height); //simple file + else if (!glt->source_file[0] && glt->source_offset) + data = (byte *) glt->source_offset; //image in memory + + if (!data) + { +invalid: + Con_Printf ("TexMgr_ReloadImage: invalid source for %s\n", glt->name); + Hunk_FreeToLowMark(mark); + return; + } + + glt->width = glt->source_width; + glt->height = glt->source_height; +// +// apply shirt and pants colors +// +// if shirt and pants are -1,-1, use existing shirt and pants colors +// if existing shirt and pants colors are -1,-1, don't bother colormapping + if (shirt > -1 && pants > -1) + { + if (glt->source_format == SRC_INDEXED) + { + glt->shirt = shirt; + glt->pants = pants; + } + else + Con_Printf ("TexMgr_ReloadImage: can't colormap a non SRC_INDEXED texture: %s\n", glt->name); + } + if (glt->shirt > -1 && glt->pants > -1) + { + //create new translation table + for (i=0 ; i<256 ; i++) + translation[i] = i; + + shirt = glt->shirt * 16; + if (shirt < 128) + for (i=0 ; i<16 ; i++) + translation[TOP_RANGE+i] = shirt+i; + else + for (i=0 ; i<16 ; i++) + translation[TOP_RANGE+i] = shirt+15-i; + + pants = glt->pants * 16; + if (pants < 128) + for (i=0 ; i<16 ; i++) + translation[BOTTOM_RANGE+i] = pants+i; + else + for (i=0 ; i<16 ; i++) + translation[BOTTOM_RANGE+i] = pants+15-i; + + //translate texture + size = glt->width * glt->height; + dst = translated = Hunk_Alloc (size); + src = data; + + for (i=0; isource_format) + { + case SRC_INDEXED: + TexMgr_LoadImage8 (glt, data); + break; + case SRC_LIGHTMAP: + TexMgr_LoadLightmap (glt, data); + break; + case SRC_RGBA: + TexMgr_LoadImage32 (glt, (unsigned *)data); + break; + } + + Hunk_FreeToLowMark(mark); +} + +/* +================ +TexMgr_ReloadImages -- reloads all texture images. called only by vid_restart +================ +*/ +void TexMgr_ReloadImages (void) +{ + gltexture_t *glt; + + for (glt=active_gltextures; glt; glt=glt->next) + { + glGenTextures(1, (GLuint *)&glt->texnum); + TexMgr_ReloadImage (glt, -1, -1); + } +} + +/* +================ +TexMgr_ReloadNobrightImages -- reloads all texture that were loaded with the nobright palette. called when gl_fullbrights changes +================ +*/ +void TexMgr_ReloadNobrightImages (void) +{ + gltexture_t *glt; + + for (glt=active_gltextures; glt; glt=glt->next) + if (glt->flags & TEXPREF_NOBRIGHT) + TexMgr_ReloadImage(glt, -1, -1); +} + +/* +================================================================================ + + TEXTURE BINDING / TEXTURE UNIT SWITCHING + +================================================================================ +*/ + +int currenttexture = -1; // to avoid unnecessary texture sets +GLenum TEXTURE0, TEXTURE1; //johnfitz +qboolean mtexenabled = false; + +/* +================ +GL_SelectTexture -- johnfitz -- rewritten +================ +*/ +void GL_SelectTexture (GLenum target) +{ + static GLenum currenttarget; + static int ct0, ct1; + + if (target == currenttarget) + return; + + GL_SelectTextureFunc(target); + + if (target == TEXTURE0) + { + ct1 = currenttexture; + currenttexture = ct0; + } + else //target == TEXTURE1 + { + ct0 = currenttexture; + currenttexture = ct1; + } + + currenttarget = target; +} + +/* +================ +GL_DisableMultitexture -- selects texture unit 0 +================ +*/ +void GL_DisableMultitexture(void) +{ + if (mtexenabled) + { + glDisable(GL_TEXTURE_2D); + GL_SelectTexture(TEXTURE0); //johnfitz -- no longer SGIS specific + mtexenabled = false; + } +} + +/* +================ +GL_EnableMultitexture -- selects texture unit 1 +================ +*/ +void GL_EnableMultitexture(void) +{ + if (gl_mtexable) + { + GL_SelectTexture(TEXTURE1); //johnfitz -- no longer SGIS specific + glEnable(GL_TEXTURE_2D); + mtexenabled = true; + } +} + +/* +================ +GL_Bind -- johnfitz -- heavy revision +================ +*/ +void GL_Bind (gltexture_t *texture) +{ + if (!texture) + texture = nulltexture; + + if (texture->texnum != currenttexture) + { + currenttexture = texture->texnum; + glBindTexture (GL_TEXTURE_2D, currenttexture); + texture->visframe = r_framecount; + } +} diff --git a/Quake/gl_texmgr.h b/Quake/gl_texmgr.h new file mode 100644 index 00000000..180b8406 --- /dev/null +++ b/Quake/gl_texmgr.h @@ -0,0 +1,99 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +//gl_texmgr.h -- fitzquake's texture manager. manages opengl texture images + +#define TEXPREF_NONE 0x0000 +#define TEXPREF_MIPMAP 0x0001 // generate mipmaps +#define TEXPREF_LINEAR 0x0002 // force linear +#define TEXPREF_NEAREST 0x0004 // force nearest +#define TEXPREF_ALPHA 0x0008 // allow alpha +#define TEXPREF_PAD 0x0010 // allow padding +#define TEXPREF_PERSIST 0x0020 // never free +#define TEXPREF_OVERWRITE 0x0040 // overwrite existing same-name texture +#define TEXPREF_NOPICMIP 0x0080 // always load full-sized +#define TEXPREF_FULLBRIGHT 0x0100 // use fullbright mask palette +#define TEXPREF_NOBRIGHT 0x0200 // use nobright mask palette +#define TEXPREF_CONCHARS 0x0400 // use conchars palette +#define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes + +enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA}; + +typedef struct gltexture_s { +//managed by texture manager + unsigned int texnum; + struct gltexture_s *next; + model_t *owner; +//managed by image loading + char name[64]; + unsigned int width; //size of image as it exists in opengl + unsigned int height; //size of image as it exists in opengl + unsigned int flags; + char source_file[MAX_QPATH]; //relative filepath to data source, or "" if source is in memory + unsigned int source_offset; //byte offset into file, or memory address + enum srcformat source_format; //format of pixel data (indexed, lightmap, or rgba) + unsigned int source_width; //size of image in source data + unsigned int source_height; //size of image in source data + unsigned short source_crc; //generated by source data before modifications + char shirt; //0-13 shirt color, or -1 if never colormapped + char pants; //0-13 pants color, or -1 if never colormapped +//used for rendering + int visframe; //matches r_framecount if texture was bound this frame +} gltexture_t; + +gltexture_t *notexture; +gltexture_t *nulltexture; + +unsigned int d_8to24table[256]; +unsigned int d_8to24table_fbright[256]; +unsigned int d_8to24table_nobright[256]; +unsigned int d_8to24table_conchars[256]; +unsigned int d_8to24table_shirt[256]; +unsigned int d_8to24table_pants[256]; + +// TEXTURE MANAGER + +float TexMgr_FrameUsage (void); +gltexture_t *TexMgr_FindTexture (model_t *owner, char *name); +gltexture_t *TexMgr_NewTexture (void); +void TexMgr_FreeTexture (gltexture_t *kill); +void TexMgr_FreeTextures (int flags, int mask); +void TexMgr_FreeTexturesForOwner (model_t *owner); +void TexMgr_NewGame (void); +void TexMgr_Init (void); + +// IMAGE LOADING +gltexture_t *TexMgr_LoadImage (model_t *owner, char *name, int width, int height, enum srcformat format, + byte *data, char *source_file, unsigned source_offset, unsigned flags); +void TexMgr_ReloadImage (gltexture_t *glt, int shirt, int pants); +void TexMgr_ReloadImages (void); +void TexMgr_ReloadNobrightImages (void); + +int TexMgr_Pad(int s); +int TexMgr_SafeTextureSize (int s); +int TexMgr_PadConditional (int s); + +// TEXTURE BINDING & TEXTURE UNIT SWITCHING + +extern qboolean gl_mtexable; + +void GL_DisableMultitexture (void); //selects texture unit 0 +void GL_EnableMultitexture (void); //selects texture unit 1 +void GL_Bind (gltexture_t *texture); diff --git a/Quake/gl_vidnt.c b/Quake/gl_vidnt.c new file mode 100644 index 00000000..102a1033 --- /dev/null +++ b/Quake/gl_vidnt.c @@ -0,0 +1,2856 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// gl_vidnt.c -- NT GL vid component + +#include "quakedef.h" +#include "winquake.h" +#include "resource.h" +#include + +#define MAX_MODE_LIST 600 //johnfitz -- was 30 +#define VID_ROW_SIZE 3 +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 +#define MAXWIDTH 10000 +#define MAXHEIGHT 10000 +#define BASEWIDTH 320 +#define BASEHEIGHT 200 + +#define MODE_WINDOWED 0 +#define NO_MODE (MODE_WINDOWED - 1) +#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1) + +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int dib; + int fullscreen; + int bpp; + int refreshrate; //johnfitz + int halfscreen; + char modedesc[17]; +} vmode_t; + +typedef struct { + int width; + int height; +} lmode_t; + +lmode_t lowresmodes[] = { + {320, 200}, + {320, 240}, + {400, 300}, + {512, 384}, +}; + +const char *gl_vendor; +const char *gl_renderer; +const char *gl_version; +const char *gl_extensions; +const char *wgl_extensions; //johnfitz + +qboolean DDActive; +qboolean scr_skipupdate; + +static vmode_t modelist[MAX_MODE_LIST]; +static int nummodes; +static vmode_t *pcurrentmode; +static vmode_t badmode; + +static DEVMODE gdevmode; +static qboolean vid_initialized = false; +static qboolean windowed, leavecurrentmode; +static qboolean vid_canalttab = false; +static qboolean vid_wassuspended = false; +static int windowed_mouse; +extern qboolean mouseactive; // from in_win.c +static HICON hIcon; + +int DIBWidth, DIBHeight; +RECT WindowRect; +DWORD WindowStyle, ExWindowStyle; + +HWND mainwindow, dibwindow; + +int vid_modenum = NO_MODE; +int vid_realmode; +int vid_default = MODE_WINDOWED; +static int windowed_default; +unsigned char vid_curpal[256*3]; +static qboolean fullsbardraw = false; + +HDC maindc; + +glvert_t glv; + +HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); + +viddef_t vid; // global video state + +//unsigned short d_8to16table[256]; //johnfitz -- never used +//unsigned char d_15to8table[65536]; //johnfitz -- never used + +modestate_t modestate = MS_UNINIT; + +void VID_Menu_Init (void); //johnfitz +void VID_Menu_f (void); //johnfitz +void VID_MenuDraw (void); +void VID_MenuKey (int key); + +LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +void AppActivate(BOOL fActive, BOOL minimize); +char *VID_GetModeDescription (int mode); +void ClearAllStates (void); +void VID_UpdateWindowStatus (void); +void GL_Init (void); + +PROC glArrayElementEXT; +PROC glColorPointerEXT; +PROC glTexCoordPointerEXT; +PROC glVertexPointerEXT; + +typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); + +extern MTEXCOORDFUNC GL_MTexCoord2fFunc = NULL; //johnfitz +extern SELECTTEXFUNC GL_SelectTextureFunc = NULL; //johnfitz + +typedef BOOL (APIENTRY * SETSWAPFUNC) (int); //johnfitz +typedef int (APIENTRY * GETSWAPFUNC) (void); //johnfitz +SETSWAPFUNC wglSwapIntervalEXT = NULL; //johnfitz +GETSWAPFUNC wglGetSwapIntervalEXT = NULL; //johnfitz + +qboolean isPermedia = false; +qboolean isIntelVideo = false; //johnfitz -- intel video workarounds from Baker +qboolean gl_mtexable = false; +qboolean gl_texture_env_combine = false; //johnfitz +qboolean gl_texture_env_add = false; //johnfitz +qboolean gl_swap_control = false; //johnfitz +qboolean gl_anisotropy_able = false; //johnfitz +float gl_max_anisotropy; //johnfitz + +int gl_stencilbits; //johnfitz + +qboolean vid_locked = false; //johnfitz + +void GL_SetupState (void); //johnfitz + +//==================================== + +//johnfitz -- new cvars +cvar_t vid_fullscreen = {"vid_fullscreen", "1", true}; +cvar_t vid_width = {"vid_width", "640", true}; +cvar_t vid_height = {"vid_height", "480", true}; +cvar_t vid_bpp = {"vid_bpp", "16", true}; +cvar_t vid_refreshrate = {"vid_refreshrate", "60", true}; +cvar_t vid_vsync = {"vid_vsync", "0", true}; +//johnfitz + +cvar_t _windowed_mouse = {"_windowed_mouse","1", true}; +cvar_t vid_gamma = {"gamma", "1", true}; //johnfitz -- moved here from view.c + +int window_center_x, window_center_y, window_x, window_y, window_width, window_height; +RECT window_rect; + + + +//========================================================================== +// +// HARDWARE GAMMA -- johnfitz +// +//========================================================================== + +typedef int (WINAPI * RAMPFUNC)(); +RAMPFUNC wglGetDeviceGammaRamp3DFX; +RAMPFUNC wglSetDeviceGammaRamp3DFX; + +unsigned short vid_gammaramp[768]; +unsigned short vid_systemgammaramp[768]; //to restore gamma on exit +unsigned short vid_3dfxgammaramp[768]; //to restore gamma on exit +int vid_gammaworks, vid_3dfxgamma; + +/* +================ +VID_Gamma_SetGamma -- apply gamma correction +================ +*/ +void VID_Gamma_SetGamma (void) +{ + if (maindc) + { + if (vid_gammaworks) + if (SetDeviceGammaRamp(maindc, vid_gammaramp) == false) + Con_Printf ("VID_Gamma_SetGamma: failed on SetDeviceGammaRamp\n"); + + if (vid_3dfxgamma) + if (wglSetDeviceGammaRamp3DFX(maindc, vid_gammaramp) == false) + Con_Printf ("VID_Gamma_SetGamma: failed on wglSetDeviceGammaRamp3DFX\n"); + } +} + +/* +================ +VID_Gamma_Restore -- restore system gamma +================ +*/ +void VID_Gamma_Restore (void) +{ + if (maindc) + { + if (vid_gammaworks) + if (SetDeviceGammaRamp(maindc, vid_systemgammaramp) == false) + Con_Printf ("VID_Gamma_Restore: failed on SetDeviceGammaRamp\n"); + + if (vid_3dfxgamma) + if (wglSetDeviceGammaRamp3DFX(maindc, vid_3dfxgammaramp) == false) + Con_Printf ("VID_Gamma_Restore: failed on wglSetDeviceGammaRamp3DFX\n"); + } +} + +/* +================ +VID_Gamma_Shutdown -- called on exit +================ +*/ +void VID_Gamma_Shutdown (void) +{ + VID_Gamma_Restore (); +} + +/* +================ +VID_Gamma_f -- callback when the cvar changes +================ +*/ +void VID_Gamma_f (void) +{ + static float oldgamma; + int i; + + if (vid_gamma.value == oldgamma) + return; + + oldgamma = vid_gamma.value; + + for (i=0; i<256; i++) + vid_gammaramp[i] = vid_gammaramp[i+256] = vid_gammaramp[i+512] = + CLAMP(0, (int) (255 * pow ((i+0.5)/255.5, vid_gamma.value) + 0.5), 255) << 8; + + VID_Gamma_SetGamma (); +} + +/* +================ +VID_Gamma_Init -- call on init +================ +*/ +void VID_Gamma_Init (void) +{ + vid_gammaworks = vid_3dfxgamma = false; + + if (strstr(gl_extensions, "WGL_3DFX_gamma_control")) + { + wglSetDeviceGammaRamp3DFX = (RAMPFUNC) wglGetProcAddress("wglSetDeviceGammaRamp3DFX"); + wglGetDeviceGammaRamp3DFX = (RAMPFUNC) wglGetProcAddress("wglGetDeviceGammaRamp3DFX"); + + if (wglGetDeviceGammaRamp3DFX (maindc, vid_3dfxgammaramp)) + vid_3dfxgamma = true; + + Con_Printf ("WGL_3DFX_gamma_control found\n"); + } + + if (GetDeviceGammaRamp (maindc, vid_systemgammaramp)) + vid_gammaworks = true; + + Cvar_RegisterVariable (&vid_gamma, VID_Gamma_f); +} + +//========================================================================== + +// direct draw software compatability stuff + +void VID_HandlePause (qboolean pause) +{ +} + +void VID_ForceLockState (int lk) +{ +} + +void VID_LockBuffer (void) +{ +} + +void VID_UnlockBuffer (void) +{ +} + +int VID_ForceUnlockedAndReturnState (void) +{ + return 0; +} + +void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +{ +} + +void D_EndDirectRect (int x, int y, int width, int height) +{ +} + +/* +================ +CenterWindow +================ +*/ +void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify) +{ + RECT rect; + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; + if (CenterX > CenterY*2) + CenterX >>= 1; // dual screens + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); +} + +/* +================ +VID_SetWindowedMode +================ +*/ +qboolean VID_SetWindowedMode (int modenum) +{ + HDC hdc; + int lastmodestate, width, height; + RECT rect; + + lastmodestate = modestate; + + WindowRect.top = WindowRect.left = 0; + + WindowRect.right = modelist[modenum].width; + WindowRect.bottom = modelist[modenum].height; + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + //johnfitz -- if width and height match desktop size, do aguirRe's trick of making the window have no titlebar/borders + if (DIBWidth == GetSystemMetrics(SM_CXSCREEN) && DIBHeight == GetSystemMetrics(SM_CYSCREEN)) + WindowStyle = WS_POPUP; // Window covers entire screen; no caption, borders etc + else + WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + //johnfitz + ExWindowStyle = 0; + + rect = WindowRect; + AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + // Create the DIB window + dibwindow = CreateWindowEx ( + ExWindowStyle, + "FitzQuake", //johnfitz -- was "WinQuake" + "FitzQuake", //johnfitz -- was "GLQuake" + WindowStyle, + rect.left, rect.top, + width, + height, + NULL, + NULL, + global_hInstance, + NULL); + + if (!dibwindow) + Sys_Error ("Couldn't create DIB window"); + + // Center and show the DIB window + CenterWindow(dibwindow, WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, false); + + ShowWindow (dibwindow, SW_SHOWDEFAULT); + UpdateWindow (dibwindow); + + modestate = MS_WINDOWED; + +// because we have set the background brush for the window to NULL +// (to avoid flickering when re-sizing the window on the desktop), +// we clear the window to black when created, otherwise it will be +// empty while Quake starts up. + hdc = GetDC(dibwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(dibwindow, hdc); + + //johnfitz -- stuff + vid.width = modelist[modenum].width; + vid.height = modelist[modenum].height; + vid.conwidth = vid.width & 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; + //johnfitz + + vid.numpages = 2; + + mainwindow = dibwindow; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + +/* +================ +VID_SetFullDIBMode +================ +*/ +qboolean VID_SetFullDIBMode (int modenum) +{ + HDC hdc; + int lastmodestate, width, height; + RECT rect; + + if (!leavecurrentmode) + { + gdevmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT | + DM_DISPLAYFREQUENCY; //johnfitz -- refreshrate + gdevmode.dmBitsPerPel = modelist[modenum].bpp; + gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].halfscreen; + gdevmode.dmPelsHeight = modelist[modenum].height; + gdevmode.dmDisplayFrequency = modelist[modenum].refreshrate; //johnfitz -- refreshrate + gdevmode.dmSize = sizeof (gdevmode); + + if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + Sys_Error ("Couldn't set fullscreen DIB mode"); + } + + lastmodestate = modestate; + modestate = MS_FULLDIB; + + WindowRect.top = WindowRect.left = 0; + + WindowRect.right = modelist[modenum].width; + WindowRect.bottom = modelist[modenum].height; + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + WindowStyle = WS_POPUP; + ExWindowStyle = 0; + + rect = WindowRect; + AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + // Create the DIB window + dibwindow = CreateWindowEx ( + ExWindowStyle, + "FitzQuake", //johnfitz -- was "WinQuake" + "FitzQuake", //johnfitz -- was "GLQuake" + WindowStyle, + rect.left, rect.top, + width, + height, + NULL, + NULL, + global_hInstance, + NULL); + + if (!dibwindow) + Sys_Error ("Couldn't create DIB window"); + + ShowWindow (dibwindow, SW_SHOWDEFAULT); + UpdateWindow (dibwindow); + +// Because we have set the background brush for the window to NULL +// (to avoid flickering when re-sizing the window on the desktop), we +// clear the window to black when created, otherwise it will be +// empty while Quake starts up. + hdc = GetDC(dibwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(dibwindow, hdc); + + //johnfitz -- stuff + vid.width = modelist[modenum].width; + vid.height = modelist[modenum].height; + vid.conwidth = vid.width & 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; + //johnfitz + + vid.numpages = 2; + +// needed because we're not getting WM_MOVE messages fullscreen on NT + window_x = 0; + window_y = 0; + + mainwindow = dibwindow; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + +/* +================ +VID_SetMode +================ +*/ +int VID_SetMode (int modenum) +{ + int original_mode, temp; + qboolean stat; + MSG msg; + HDC hdc; + + if ((windowed && (modenum != 0)) || + (!windowed && (modenum < 1)) || + (!windowed && (modenum >= nummodes))) + { + Sys_Error ("Bad video mode\n"); + } + +// so Con_Printfs don't mess us up by forcing vid and snd updates + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + + CDAudio_Pause (); + + if (vid_modenum == NO_MODE) + original_mode = windowed_default; + else + original_mode = vid_modenum; + + // Set either the fullscreen or windowed mode + if (modelist[modenum].type == MS_WINDOWED) + { + if (_windowed_mouse.value && key_dest == key_game) + { + stat = VID_SetWindowedMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + IN_DeactivateMouse (); + IN_ShowMouse (); + stat = VID_SetWindowedMode(modenum); + } + } + else if (modelist[modenum].type == MS_FULLDIB) + { + stat = VID_SetFullDIBMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + Sys_Error ("VID_SetMode: Bad mode type in modelist"); + } + + //johnfitz -- re-initialize dinput becuase it's tied to the "mainwindow" object + if (COM_CheckParm ("-dinput")) + IN_InitDInput (); + //johnfitz + + window_width = DIBWidth; + window_height = DIBHeight; + VID_UpdateWindowStatus (); + + CDAudio_Resume (); + scr_disabled_for_loading = temp; + + if (!stat) + { + Sys_Error ("Couldn't set video mode"); + } + +// now we try to make sure we get the focus on the mode switch, because +// sometimes in some systems we don't. We grab the foreground, then +// finish setting up, pump all our messages, and sleep for a little while +// to let messages finish bouncing around the system, then we put +// ourselves at the top of the z order, then grab the foreground again, +// Who knows if it helps, but it probably doesn't hurt + SetForegroundWindow (mainwindow); + vid_modenum = modenum; + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + + Sleep (100); + + SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, + SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + SWP_NOCOPYBITS); + + SetForegroundWindow (mainwindow); + +// fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + if (!msg_suppress_1) + Con_SafePrintf ("Video mode %s initialized\n", VID_GetModeDescription (vid_modenum)); + + vid.recalc_refdef = 1; + + return true; +} + +/* +=============== +VID_Vsync_f -- johnfitz +=============== +*/ +void VID_Vsync_f (void) +{ + if (gl_swap_control) + { + if (vid_vsync.value) + { + if (!wglSwapIntervalEXT(1)) + Con_Printf ("VID_Vsync_f: failed on wglSwapIntervalEXT\n"); + } + else + { + if (!wglSwapIntervalEXT(0)) + Con_Printf ("VID_Vsync_f: failed on wglSwapIntervalEXT\n"); + } + } +} + +/* +=================== +VID_Restart -- johnfitz -- change video modes on the fly +=================== +*/ +void VID_Restart (void) +{ + HDC hdc; + HGLRC hrc; + int i; + qboolean mode_changed = false; + vmode_t oldmode; + + if (vid_locked) + return; + +// +// check cvars against current mode +// + if (vid_fullscreen.value) + { + if (modelist[vid_default].type == MS_WINDOWED) + mode_changed = true; + else if (modelist[vid_default].bpp != (int)vid_bpp.value) + mode_changed = true; + else if (modelist[vid_default].refreshrate != (int)vid_refreshrate.value) + mode_changed = true; + } + else + if (modelist[vid_default].type != MS_WINDOWED) + mode_changed = true; + + if (modelist[vid_default].width != (int)vid_width.value || + modelist[vid_default].height != (int)vid_height.value) + mode_changed = true; + + if (mode_changed) + { +// +// decide which mode to set +// + oldmode = modelist[vid_default]; + + if (vid_fullscreen.value) + { + for (i=1; i 0) ? (int)scr_conwidth.value : (scr_conscale.value > 0) ? (int)(vid.width/scr_conscale.value) : vid.width; + vid.conwidth = CLAMP (320, vid.conwidth, vid.width); + vid.conwidth &= 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; + } +// +// keep cvars in line with actual mode +// + Cvar_Set ("vid_width", va("%i", modelist[vid_default].width)); + Cvar_Set ("vid_height", va("%i", modelist[vid_default].height)); + Cvar_Set ("vid_bpp", va("%i", modelist[vid_default].bpp)); + Cvar_Set ("vid_refreshrate", va("%i", modelist[vid_default].refreshrate)); + Cvar_Set ("vid_fullscreen", (windowed) ? "0" : "1"); +} + +/* +================ +VID_Test -- johnfitz -- like vid_restart, but asks for confirmation after switching modes +================ +*/ +void VID_Test (void) +{ + vmode_t oldmode; + qboolean mode_changed = false; + + if (vid_locked) + return; +// +// check cvars against current mode +// + if (vid_fullscreen.value) + { + if (modelist[vid_default].type == MS_WINDOWED) + mode_changed = true; + else if (modelist[vid_default].bpp != (int)vid_bpp.value) + mode_changed = true; + else if (modelist[vid_default].refreshrate != (int)vid_refreshrate.value) + mode_changed = true; + } + else + if (modelist[vid_default].type != MS_WINDOWED) + mode_changed = true; + + if (modelist[vid_default].width != (int)vid_width.value || + modelist[vid_default].height != (int)vid_height.value) + mode_changed = true; + + if (!mode_changed) + return; +// +// now try the switch +// + oldmode = modelist[vid_default]; + + VID_Restart (); + + //pop up confirmation dialoge + if (!SCR_ModalMessage("Would you like to keep this\nvideo mode? (y/n)\n", 5.0f)) + { + //revert cvars and mode + Cvar_Set ("vid_width", va("%i", oldmode.width)); + Cvar_Set ("vid_height", va("%i", oldmode.height)); + Cvar_Set ("vid_bpp", va("%i", oldmode.bpp)); + Cvar_Set ("vid_refreshrate", va("%i", oldmode.refreshrate)); + Cvar_Set ("vid_fullscreen", (oldmode.type == MS_WINDOWED) ? "0" : "1"); + VID_Restart (); + } +} + +/* +================ +VID_Unlock -- johnfitz +================ +*/ +void VID_Unlock (void) +{ + vid_locked = false; + + //sync up cvars in case they were changed during the lock + Cvar_Set ("vid_width", va("%i", modelist[vid_default].width)); + Cvar_Set ("vid_height", va("%i", modelist[vid_default].height)); + Cvar_Set ("vid_bpp", va("%i", modelist[vid_default].bpp)); + Cvar_Set ("vid_refreshrate", va("%i", modelist[vid_default].refreshrate)); + Cvar_Set ("vid_fullscreen", (windowed) ? "0" : "1"); +} + +/* +================ +VID_UpdateWindowStatus +================ +*/ +void VID_UpdateWindowStatus (void) +{ + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + window_center_x = (window_rect.left + window_rect.right) / 2; + window_center_y = (window_rect.top + window_rect.bottom) / 2; + + IN_UpdateClipCursor (); +} + +//============================================================================== +// +// OPENGL STUFF +// +//============================================================================== + +/* +=============== +GL_MakeNiceExtensionsList -- johnfitz +=============== +*/ +char *GL_MakeNiceExtensionsList (const char *in) +{ + char *copy, *token, *out; + int i, count; + + //each space will be replaced by 4 chars, so count the spaces before we malloc + for (i = 0, count = 1; i < strlen(in); i++) + if (in[i] == ' ') + count++; + out = Z_Malloc (strlen(in) + count*3 + 1); //usually about 1-2k + out[0] = 0; + + copy = Z_Malloc(strlen(in) + 1); + strcpy(copy, in); + + for (token = strtok(copy, " "); token; token = strtok(NULL, " ")) + { + strcat(out, "\n "); + strcat(out, token); + } + + Z_Free (copy); + return out; +} + +/* +=============== +GL_Info_f -- johnfitz +=============== +*/ +void GL_Info_f (void) +{ + static char *gl_extensions_nice = NULL; + static char *wgl_extensions_nice = NULL; + + if (!gl_extensions_nice) + gl_extensions_nice = GL_MakeNiceExtensionsList (gl_extensions); + + if (!wgl_extensions_nice) + wgl_extensions_nice = GL_MakeNiceExtensionsList (wgl_extensions); + + Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor); + Con_SafePrintf ("GL_RENDERER: %s\n", gl_renderer); + Con_SafePrintf ("GL_VERSION: %s\n", gl_version); + Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions_nice); + Con_Printf ("WGL_EXTENSIONS: %s\n", wgl_extensions_nice); +} + +/* +=============== +CheckArrayExtensions +=============== +*/ +void CheckArrayExtensions (void) +{ + char *tmp; + + /* check for texture extension */ + tmp = (unsigned char *)glGetString(GL_EXTENSIONS); + while (*tmp) + { + if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0) + { + if ( +((glArrayElementEXT = wglGetProcAddress("glArrayElementEXT")) == NULL) || +((glColorPointerEXT = wglGetProcAddress("glColorPointerEXT")) == NULL) || +((glTexCoordPointerEXT = wglGetProcAddress("glTexCoordPointerEXT")) == NULL) || +((glVertexPointerEXT = wglGetProcAddress("glVertexPointerEXT")) == NULL) ) + { + Sys_Error ("GetProcAddress for vertex extension failed"); + return; + } + return; + } + tmp++; + } + + Sys_Error ("Vertex array extension not present"); +} + +/* +=============== +GL_CheckExtensions -- johnfitz +=============== +*/ +void GL_CheckExtensions (void) +{ + // + // multitexture + // + if (COM_CheckParm("-nomtex")) + Con_Warning ("Mutitexture disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_multitexture")) + { + GL_MTexCoord2fFunc = (void *) wglGetProcAddress("glMultiTexCoord2fARB"); + GL_SelectTextureFunc = (void *) wglGetProcAddress("glActiveTextureARB"); + if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) + { + Con_Printf("FOUND: ARB_multitexture\n"); + TEXTURE0 = GL_TEXTURE0_ARB; + TEXTURE1 = GL_TEXTURE1_ARB; + gl_mtexable = true; + } + else + Con_Warning ("multitexture not supported (wglGetProcAddress failed)\n"); + } + else + if (strstr(gl_extensions, "GL_SGIS_multitexture")) + { + GL_MTexCoord2fFunc = (void *) wglGetProcAddress("glMTexCoord2fSGIS"); + GL_SelectTextureFunc = (void *) wglGetProcAddress("glSelectTextureSGIS"); + if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) + { + Con_Printf("FOUND: SGIS_multitexture\n"); + TEXTURE0 = TEXTURE0_SGIS; + TEXTURE1 = TEXTURE1_SGIS; + gl_mtexable = true; + } + else + Con_Warning ("multitexture not supported (wglGetProcAddress failed)\n"); + + } + else + Con_Warning ("multitexture not supported (extension not found)\n"); + // + // texture_env_combine + // + if (COM_CheckParm("-nocombine")) + Con_Warning ("texture_env_combine disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_texture_env_combine")) + { + Con_Printf("FOUND: ARB_texture_env_combine\n"); + gl_texture_env_combine = true; + } + else + if (strstr(gl_extensions, "GL_EXT_texture_env_combine")) + { + Con_Printf("FOUND: EXT_texture_env_combine\n"); + gl_texture_env_combine = true; + } + else + Con_Warning ("texture_env_combine not supported\n"); + // + // texture_env_add + // + if (COM_CheckParm("-noadd")) + Con_Warning ("texture_env_add disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_texture_env_add")) + { + Con_Printf("FOUND: ARB_texture_env_add\n"); + gl_texture_env_add = true; + } + else + if (strstr(gl_extensions, "GL_EXT_texture_env_add")) + { + Con_Printf("FOUND: EXT_texture_env_add\n"); + gl_texture_env_add = true; + } + else + Con_Warning ("texture_env_add not supported\n"); + + // + // swap control + // + if (strstr(gl_extensions, "GL_EXT_swap_control") || strstr(wgl_extensions, "WGL_EXT_swap_control")) + { + wglSwapIntervalEXT = (SETSWAPFUNC) wglGetProcAddress("wglSwapIntervalEXT"); + wglGetSwapIntervalEXT = (GETSWAPFUNC) wglGetProcAddress("wglGetSwapIntervalEXT"); + + if (wglSwapIntervalEXT && wglGetSwapIntervalEXT) + { + if (!wglSwapIntervalEXT(0)) + Con_Warning ("vertical sync not supported (wglSwapIntervalEXT failed)\n"); + else if (wglGetSwapIntervalEXT() == -1) + Con_Warning ("vertical sync not supported (swap interval is -1.) Make sure you don't have vertical sync disabled in your driver settings.\n"); + else + { + Con_Printf("FOUND: WGL_EXT_swap_control\n"); + gl_swap_control = true; + } + } + else + Con_Warning ("vertical sync not supported (wglGetProcAddress failed)\n"); + } + else + Con_Warning ("vertical sync not supported (extension not found)\n"); + + // + // anisotropic filtering + // + if (strstr(gl_extensions, "GL_EXT_texture_filter_anisotropic")) + { + float test1,test2; + int tex; + + // test to make sure we really have control over it + // 1.0 and 2.0 should always be legal values + glGenTextures(1, &tex); + glBindTexture (GL_TEXTURE_2D, tex); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test1); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f); + glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test2); + glDeleteTextures(1, &tex); + + if (test1 == 1 && test2 == 2) + { + Con_Printf("FOUND: EXT_texture_filter_anisotropic\n"); + gl_anisotropy_able = true; + } + else + Con_Warning ("anisotropic filtering locked by driver. Current driver setting is %f\n", test1); + + //get max value either way, so the menu and stuff know it + glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_anisotropy); + } + else + Con_Warning ("texture_filter_anisotropic not supported\n"); +} + +/* +=============== +GetWGLExtensions -- johnfitz +=============== +*/ +void GetWGLExtensions (void) +{ + const char *(*wglGetExtensionsStringARB) (HDC hdc); + const char *(*wglGetExtensionsStringEXT) (); + + if (wglGetExtensionsStringARB = (void *) wglGetProcAddress ("wglGetExtensionsStringARB")) + wgl_extensions = wglGetExtensionsStringARB (maindc); + else if (wglGetExtensionsStringEXT = (void *) wglGetProcAddress ("wglGetExtensionsStringEXT")) + wgl_extensions = wglGetExtensionsStringEXT (); + else + wgl_extensions = ""; +} + +/* +=============== +GL_SetupState -- johnfitz + +does all the stuff from GL_Init that needs to be done every time a new GL render context is created +GL_Init will still do the stuff that only needs to be done once +=============== +*/ +void GL_SetupState (void) +{ + glClearColor (0.15,0.15,0.15,0); //johnfitz -- originally 1,0,0,0 + glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right + glFrontFace(GL_CW); //johnfitz -- glquake used CCW with backwards culling -- let's do it right + glEnable(GL_TEXTURE_2D); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.666); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glShadeModel (GL_FLAT); + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //johnfitz + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDepthRange (0, 1); //johnfitz -- moved here becuase gl_ztrick is gone. + glDepthFunc (GL_LEQUAL); //johnfitz -- moved here becuase gl_ztrick is gone. +} + +/* +=============== +GL_Init +=============== +*/ +void GL_Init (void) +{ + gl_vendor = glGetString (GL_VENDOR); + gl_renderer = glGetString (GL_RENDERER); + gl_version = glGetString (GL_VERSION); + gl_extensions = glGetString (GL_EXTENSIONS); + + GetWGLExtensions (); //johnfitz + GL_CheckExtensions (); //johnfitz + + Cmd_AddCommand ("gl_info", GL_Info_f); //johnfitz + + Cvar_RegisterVariable (&vid_vsync, VID_Vsync_f); //johnfitz + + if (strnicmp(gl_renderer,"PowerVR",7)==0) + fullsbardraw = true; + + if (strnicmp(gl_renderer,"Permedia",8)==0) + isPermedia = true; + + //johnfitz -- intel video workarounds from Baker + if (!strcmp(gl_vendor, "Intel")) + { + Con_Printf ("Intel Display Adapter detected\n"); + isIntelVideo = true; + } + //johnfitz + +#if 0 + //johnfitz -- confirm presence of stencil buffer + glGetIntegerv(GL_STENCIL_BITS, &gl_stencilbits); + if(!gl_stencilbits) + Con_Warning ("Could not create stencil buffer\n"); + else + Con_Printf ("%i bit stencil buffer\n", gl_stencilbits); +#endif + + GL_SetupState (); //johnfitz +} + +/* +================= +GL_BeginRendering -- sets values of glx, gly, glwidth, glheight +================= +*/ +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + *x = *y = 0; + *width = WindowRect.right - WindowRect.left; + *height = WindowRect.bottom - WindowRect.top; +} + +/* +================= +GL_EndRendering +================= +*/ +void GL_EndRendering (void) +{ + if (!scr_skipupdate || block_drawing) + SwapBuffers(maindc); + +// handle the mouse state when windowed if that's changed + if (modestate == MS_WINDOWED) + { + if (!_windowed_mouse.value) { + if (windowed_mouse) { + IN_DeactivateMouse (); + IN_ShowMouse (); + windowed_mouse = false; + } + } else { + windowed_mouse = true; + if (key_dest == key_game && !mouseactive && ActiveApp) { + IN_ActivateMouse (); + IN_HideMouse (); + } else if (mouseactive && key_dest != key_game) { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + } + } + if (fullsbardraw) + Sbar_Changed(); +} + +void VID_SetDefaultMode (void) +{ + IN_DeactivateMouse (); +} + + +void VID_Shutdown (void) +{ + HGLRC hRC; + HDC hDC; + + if (vid_initialized) + { + vid_canalttab = false; + hRC = wglGetCurrentContext(); + hDC = wglGetCurrentDC(); + + wglMakeCurrent(NULL, NULL); + + if (hRC) + wglDeleteContext(hRC); + + VID_Gamma_Shutdown (); //johnfitz + + if (hDC && dibwindow) + ReleaseDC(dibwindow, hDC); + + if (modestate == MS_FULLDIB) + ChangeDisplaySettings (NULL, 0); + + if (maindc && dibwindow) + ReleaseDC (dibwindow, maindc); + + AppActivate(false, false); + } +} + +//========================================================================== + + +BOOL bSetupPixelFormat(HDC hDC) +{ + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // 32-bit z-buffer + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + int pixelformat; + PIXELFORMATDESCRIPTOR test; //johnfitz + + if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) + { + MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); + return FALSE; + } + + DescribePixelFormat(hDC, pixelformat, sizeof(PIXELFORMATDESCRIPTOR), &test); //johnfitz + + if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE) + { + MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); + return FALSE; + } + + return TRUE; +} + + + +byte scantokey[128] = + { +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', + K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE , 0 , K_HOME, + K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 + K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, + K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 + }; + +byte shiftscantokey[128] = + { +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0 + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1 + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2 + 'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*', + K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE , 0 , K_HOME, + K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 + K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, + K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 + }; + + +/* +======= +MapKey + +Map from windows to quake keynums +======= +*/ +int MapKey (int key) +{ + /* + key = (key>>16)&255; + if (key > 127) + return 0; + if (scantokey[key] == 0) + Con_DPrintf("key 0x%02x has no translation\n", key); + return scantokey[key]; + */ + + int extended; + extern cvar_t cl_keypad; + + extended = (key >> 24) & 1; + + key = (key>>16)&255; + if (key > 127) + return 0; + + key = scantokey[key]; + + if (cl_keypad.value) { + if (extended) { + switch (key) { + case K_ENTER: return KP_ENTER; + case '/': return KP_SLASH; + case K_PAUSE: return KP_NUMLOCK; + }; + } else { + switch (key) { + case K_HOME: return KP_HOME; + case K_UPARROW: return KP_UPARROW; + case K_PGUP: return KP_PGUP; + case K_LEFTARROW: return KP_LEFTARROW; + case K_RIGHTARROW: return KP_RIGHTARROW; + case K_END: return KP_END; + case K_DOWNARROW: return KP_DOWNARROW; + case K_PGDN: return KP_PGDN; + case K_INS: return KP_INS; + case K_DEL: return KP_DEL; + } + } + } else { + // cl_keypad 0, compatibility mode + switch (key) { + case KP_STAR: return '*'; + case KP_MINUS: return '-'; + case KP_5: return '5'; + case KP_PLUS: return '+'; + } + } + + return key; +} + +/* +=================================================================== + +MAIN WINDOW + +=================================================================== +*/ + +/* +================ +ClearAllStates +================ +*/ +void ClearAllStates (void) +{ + //johnfitz -- moved some code into Key_ClearStates + Key_ClearStates (); + IN_ClearStates (); +} + +void AppActivate(BOOL fActive, BOOL minimize) +/**************************************************************************** +* +* Function: AppActivate +* Parameters: fActive - True if app is activating +* +* Description: If the application is activating, then swap the system +* into SYSPAL_NOSTATIC mode so that our palettes will display +* correctly. +* +****************************************************************************/ +{ + MSG msg; + HDC hdc; + int i, t; + static BOOL sound_active; + + ActiveApp = fActive; + Minimized = minimize; + +// enable/disable sound on focus gain/loss + if (!ActiveApp && sound_active) + { + S_BlockSound (); + sound_active = false; + } + else if (ActiveApp && !sound_active) + { + S_UnblockSound (); + sound_active = true; + } + + if (fActive) + { + if (modestate == MS_FULLDIB) + { + IN_ActivateMouse (); + IN_HideMouse (); + if (vid_canalttab && vid_wassuspended) { + vid_wassuspended = false; + ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); + ShowWindow(mainwindow, SW_SHOWNORMAL); + MoveWindow(mainwindow, 0, 0, gdevmode.dmPelsWidth, gdevmode.dmPelsHeight, false); //johnfitz -- alt-tab fix via Baker + } + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && key_dest == key_game) + { + IN_ActivateMouse (); + IN_HideMouse (); + } + VID_Gamma_SetGamma (); //johnfitz + } + + if (!fActive) + { + if (modestate == MS_FULLDIB) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + if (vid_canalttab) { + ChangeDisplaySettings (NULL, 0); + vid_wassuspended = true; + } + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse.value) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + VID_Gamma_Restore (); //johnfitz + } +} + + +/* main window procedure */ +LONG WINAPI MainWndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + int fwKeys, xPos, yPos, fActive, fMinimized, temp; + extern unsigned int uiWheelMessage; + + if ( uMsg == uiWheelMessage ) + uMsg = WM_MOUSEWHEEL; + + switch (uMsg) + { + case WM_KILLFOCUS: + if (modestate == MS_FULLDIB) + ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); + break; + + case WM_CREATE: + break; + + case WM_MOVE: + window_x = (int) LOWORD(lParam); + window_y = (int) HIWORD(lParam); + VID_UpdateWindowStatus (); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + Key_Event (MapKey(lParam), true); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + Key_Event (MapKey(lParam), false); + break; + + case WM_SYSCHAR: + // keep Alt-Space from happening + break; + + // this is complicated because Win32 seems to pack multiple mouse events into + // one update sometimes, so we always check all states and look for events + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + temp = 0; + + if (wParam & MK_LBUTTON) + temp |= 1; + + if (wParam & MK_RBUTTON) + temp |= 2; + + if (wParam & MK_MBUTTON) + temp |= 4; + + IN_MouseEvent (temp); + + break; + + // JACK: This is the mouse wheel with the Intellimouse + // Its delta is either positive or neg, and we generate the proper + // Event. + case WM_MOUSEWHEEL: + if ((short) HIWORD(wParam) > 0) { + Key_Event(K_MWHEELUP, true); + Key_Event(K_MWHEELUP, false); + } else { + Key_Event(K_MWHEELDOWN, true); + Key_Event(K_MWHEELDOWN, false); + } + break; + + case WM_SIZE: + break; + + case WM_CLOSE: + if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) + { + Sys_Quit (); + } + + break; + + case WM_ACTIVATE: + fActive = LOWORD(wParam); + fMinimized = (BOOL) HIWORD(wParam); + AppActivate(!(fActive == WA_INACTIVE), fMinimized); + + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + break; + + case WM_DESTROY: + { + if (dibwindow) + DestroyWindow (dibwindow); + + PostQuitMessage (0); + } + break; + + case MM_MCINOTIFY: + lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + +//========================================================================== +// +// COMMANDS +// +//========================================================================== + +/* +================= +VID_NumModes +================= +*/ +int VID_NumModes (void) +{ + return nummodes; +} + + +/* +================= +VID_GetModePtr +================= +*/ +vmode_t *VID_GetModePtr (int modenum) +{ + + if ((modenum >= 0) && (modenum < nummodes)) + return &modelist[modenum]; + else + return &badmode; +} + + +/* +================= +VID_GetModeDescription +================= +*/ +char *VID_GetModeDescription (int mode) +{ + char *pinfo; + vmode_t *pv; + static char temp[100]; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + if (!leavecurrentmode) + { + pv = VID_GetModePtr (mode); + pinfo = pv->modedesc; + } + else + { + sprintf (temp, "Desktop resolution (%ix%ix%i)", //johnfitz -- added bpp + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height, + modelist[MODE_FULLSCREEN_DEFAULT].bpp); //johnfitz -- added bpp + pinfo = temp; + } + + return pinfo; +} + +// KJB: Added this to return the mode driver name in description for console +/* +================= +VID_GetExtModeDescription +================= +*/ +char *VID_GetExtModeDescription (int mode) +{ + static char pinfo[40]; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + pv = VID_GetModePtr (mode); + if (modelist[mode].type == MS_FULLDIB) + { + if (!leavecurrentmode) + { + sprintf(pinfo,"%s fullscreen", pv->modedesc); + } + else + { + sprintf (pinfo, "Desktop resolution (%ix%ix%i)", //johnfitz -- added bpp + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height, + modelist[MODE_FULLSCREEN_DEFAULT].bpp); //johnfitz -- added bpp + } + } + else + { + if (modestate == MS_WINDOWED) + sprintf(pinfo, "%s windowed", pv->modedesc); + else + sprintf(pinfo, "windowed"); + } + + return pinfo; +} + +/* +================= +VID_DescribeCurrentMode_f +================= +*/ +void VID_DescribeCurrentMode_f (void) +{ + Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); +} + +/* +================= +VID_DescribeModes_f -- johnfitz -- changed formatting, and added refresh rates after each mode. +================= +*/ +void VID_DescribeModes_f (void) +{ + int i, lnummodes, t; + char *pinfo; + vmode_t *pv; + int lastwidth=0, lastheight=0, lastbpp=0, count=0; + + lnummodes = VID_NumModes (); + + t = leavecurrentmode; + leavecurrentmode = 0; + + for (i=1 ; iwidth && lastheight == pv->height && lastbpp == pv->bpp) + { + Con_SafePrintf (",%i", pv->refreshrate); + } + else + { + if (count>0) + Con_SafePrintf ("\n"); + Con_SafePrintf (" %4i x %4i x %i : %i", pv->width, pv->height, pv->bpp, pv->refreshrate); + lastwidth = pv->width; + lastheight = pv->height; + lastbpp = pv->bpp; + count++; + } + } + Con_Printf ("\n%i modes\n", count); + + leavecurrentmode = t; +} + +//========================================================================== +// +// INIT +// +//========================================================================== + +/* +================= +VID_InitDIB +================= +*/ +void VID_InitDIB (HINSTANCE hInstance) +{ + DEVMODE devmode; //johnfitz + WNDCLASS wc; + HDC hdc; + int i; + + /* Register the frame class */ + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = "FitzQuake"; //johnfitz -- was WinQuake + + if (!RegisterClass (&wc) ) + Sys_Error ("Couldn't register window class"); + + modelist[0].type = MS_WINDOWED; + + if (COM_CheckParm("-width")) + modelist[0].width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); + else + modelist[0].width = 640; + + if (modelist[0].width < 320) + modelist[0].width = 320; + + if (COM_CheckParm("-height")) + modelist[0].height= Q_atoi(com_argv[COM_CheckParm("-height")+1]); + else + modelist[0].height = modelist[0].width * 240/320; + + if (modelist[0].height < 200) //johnfitz -- was 240 + modelist[0].height = 200; //johnfitz -- was 240 + + //johnfitz -- get desktop bit depth + hdc = GetDC(NULL); + modelist[0].bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(NULL, hdc); + //johnfitz + + //johnfitz -- get refreshrate + if (EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &devmode)) + modelist[0].refreshrate = devmode.dmDisplayFrequency; + //johnfitz + + sprintf (modelist[0].modedesc, "%dx%dx%d %dHz", //johnfitz -- added bpp, refreshrate + modelist[0].width, + modelist[0].height, + modelist[0].bpp, //johnfitz -- added bpp + modelist[0].refreshrate); //johnfitz -- added refreshrate + + modelist[0].modenum = MODE_WINDOWED; + modelist[0].dib = 1; + modelist[0].fullscreen = 0; + modelist[0].halfscreen = 0; + + nummodes = 1; +} + +/* +================= +VID_InitFullDIB +================= +*/ +void VID_InitFullDIB (HINSTANCE hInstance) +{ + DEVMODE devmode; + int i, modenum, cmodes, originalnummodes, existingmode, numlowresmodes; + int j, bpp, done; + BOOL stat; + +// enumerate >8 bpp modes + originalnummodes = nummodes; + modenum = 0; + + do + { + stat = EnumDisplaySettings (NULL, modenum, &devmode); + + if ((devmode.dmBitsPerPel >= 15) && + (devmode.dmPelsWidth <= MAXWIDTH) && + (devmode.dmPelsHeight <= MAXHEIGHT) && + (nummodes < MAX_MODE_LIST)) + { + devmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT | + DM_DISPLAYFREQUENCY; //johnfitz -- refreshrate + + if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == + DISP_CHANGE_SUCCESSFUL) + { + modelist[nummodes].type = MS_FULLDIB; + modelist[nummodes].width = devmode.dmPelsWidth; + modelist[nummodes].height = devmode.dmPelsHeight; + modelist[nummodes].modenum = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = devmode.dmBitsPerPel; + modelist[nummodes].refreshrate = devmode.dmDisplayFrequency; //johnfitz -- refreshrate + sprintf (modelist[nummodes].modedesc, "%dx%dx%d %dHz", //johnfitz -- refreshrate + devmode.dmPelsWidth, + devmode.dmPelsHeight, + devmode.dmBitsPerPel, + devmode.dmDisplayFrequency); //johnfitz -- refreshrate + + // if the width is more than twice the height, reduce it by half because this + // is probably a dual-screen monitor + if (!COM_CheckParm("-noadjustaspect")) + { + if (modelist[nummodes].width > (modelist[nummodes].height << 1)) + { + modelist[nummodes].width >>= 1; + modelist[nummodes].halfscreen = 1; + sprintf (modelist[nummodes].modedesc, "%dx%dx%d %dHz", //johnfitz -- refreshrate + modelist[nummodes].width, + modelist[nummodes].height, + modelist[nummodes].bpp, + modelist[nummodes].refreshrate); //johnfitz -- refreshrate + } + } + + for (i=originalnummodes, existingmode = 0 ; i=vid_menu_nummodes) + i = 0; + else if (i<0) + i = vid_menu_nummodes-1; + } + + Cvar_SetValue ("vid_width",(float)vid_menu_modes[i].width); + Cvar_SetValue ("vid_height",(float)vid_menu_modes[i].height); + VID_Menu_RebuildBppList (); + VID_Menu_RebuildRateList (); + VID_Menu_CalcAspectRatio (); +} + +/* +================ +VID_Menu_ChooseNextBpp + +chooses next bpp in order, then updates vid_bpp cvar, then updates refreshrate list +================ +*/ +void VID_Menu_ChooseNextBpp (int dir) +{ + int i; + + for (i=0;i=vid_menu_numbpps) + i = 0; + else if (i<0) + i = vid_menu_numbpps-1; + } + + Cvar_SetValue ("vid_bpp",(float)vid_menu_bpps[i]); + VID_Menu_RebuildRateList (); +} + +/* +================ +VID_Menu_ChooseNextRate + +chooses next refresh rate in order, then updates vid_refreshrate cvar +================ +*/ +void VID_Menu_ChooseNextRate (int dir) +{ + int i; + + for (i=0;i=vid_menu_numrates) + i = 0; + else if (i<0) + i = vid_menu_numrates-1; + } + + Cvar_SetValue ("vid_refreshrate",(float)vid_menu_rates[i]); +} + +/* +================ +VID_MenuKey +================ +*/ +void VID_MenuKey (int key) +{ + switch (key) + { + case K_ESCAPE: + VID_SyncCvars (); //sync cvars before leaving menu. FIXME: there are other ways to leave menu + S_LocalSound ("misc/menu1.wav"); + M_Menu_Options_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + video_options_cursor--; + if (video_options_cursor < 0) + video_options_cursor = VIDEO_OPTIONS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + video_options_cursor++; + if (video_options_cursor >= VIDEO_OPTIONS_ITEMS) + video_options_cursor = 0; + break; + + case K_LEFTARROW: + S_LocalSound ("misc/menu3.wav"); + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (-1); + break; + case 1: + VID_Menu_ChooseNextBpp (-1); + break; + case 2: + VID_Menu_ChooseNextRate (-1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + case 5: + default: + break; + } + break; + + case K_RIGHTARROW: + S_LocalSound ("misc/menu3.wav"); + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (1); + break; + case 1: + VID_Menu_ChooseNextBpp (1); + break; + case 2: + VID_Menu_ChooseNextRate (1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + case 5: + default: + break; + } + break; + + case K_ENTER: + m_entersound = true; + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (1); + break; + case 1: + VID_Menu_ChooseNextBpp (1); + break; + case 2: + VID_Menu_ChooseNextRate (1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + Cbuf_AddText ("vid_test\n"); + break; + case 5: + Cbuf_AddText ("vid_restart\n"); + break; + default: + break; + } + break; + + default: + break; + } +} + +/* +================ +VID_MenuDraw +================ +*/ +void VID_MenuDraw (void) +{ + int i = 0; + qpic_t *p; + char *title; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp")); + + //p = Draw_CachePic ("gfx/vidmodes.lmp"); + p = Draw_CachePic ("gfx/p_option.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + // title + title = "Video Options"; + M_PrintWhite ((320-8*strlen(title))/2, 32, title); + + // options + M_Print (16, video_cursor_table[i], " Video mode"); + M_Print (184, video_cursor_table[i], va("%ix%i (%i:%i)", (int)vid_width.value, (int)vid_height.value, vid_menu_rwidth, vid_menu_rheight)); + i++; + + M_Print (16, video_cursor_table[i], " Color depth"); + M_Print (184, video_cursor_table[i], va("%i", (int)vid_bpp.value)); + i++; + + M_Print (16, video_cursor_table[i], " Refresh rate"); + M_Print (184, video_cursor_table[i], va("%i Hz", (int)vid_refreshrate.value)); + i++; + + M_Print (16, video_cursor_table[i], " Fullscreen"); + M_DrawCheckbox (184, video_cursor_table[i], (int)vid_fullscreen.value); + i++; + + M_Print (16, video_cursor_table[i], " Test changes"); + i++; + + M_Print (16, video_cursor_table[i], " Apply changes"); + + // cursor + M_DrawCharacter (168, video_cursor_table[video_options_cursor], 12+((int)(realtime*4)&1)); + + // notes "345678901234567890123456789012345678" +// M_Print (16, 172, "Windowed modes always use the desk- "); +// M_Print (16, 180, "top color depth, and can never be "); +// M_Print (16, 188, "larger than the desktop resolution. "); +} + +/* +================ +VID_Menu_f +================ +*/ +void VID_Menu_f (void) +{ + key_dest = key_menu; + m_state = m_video; + m_entersound = true; + + //set all the cvars to match the current mode when entering the menu + VID_SyncCvars (); + + //set up bpp and rate lists based on current cvars + VID_Menu_RebuildBppList (); + VID_Menu_RebuildRateList (); + + //aspect ratio + VID_Menu_CalcAspectRatio (); +} diff --git a/Quake/gl_vidsdl.c b/Quake/gl_vidsdl.c new file mode 100644 index 00000000..fcd96fdb --- /dev/null +++ b/Quake/gl_vidsdl.c @@ -0,0 +1,1852 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// gl_vidnt.c -- NT GL vid component + +#include "quakedef.h" +#include "resource.h" + +#define MAX_MODE_LIST 600 //johnfitz -- was 30 +#define VID_ROW_SIZE 3 +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 +#define MAXWIDTH 10000 +#define MAXHEIGHT 10000 +#define BASEWIDTH 320 +#define BASEHEIGHT 200 +#define SDL_DEFAULT_FLAGS SDL_OPENGL + +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int dib; + int fullscreen; + int bpp; + int halfscreen; + char modedesc[17]; +} vmode_t; + +typedef struct { + int width; + int height; +} lmode_t; + +lmode_t lowresmodes[] = { + {320, 200}, + {320, 240}, + {400, 300}, + {512, 384}, +}; + +const char *gl_vendor; +const char *gl_renderer; +const char *gl_version; +const char *gl_extensions; + +qboolean DDActive; +qboolean scr_skipupdate; + +static vmode_t modelist[MAX_MODE_LIST]; +static int nummodes; +static vmode_t badmode; + +static qboolean vid_initialized = false; +static qboolean windowed, leavecurrentmode; +static qboolean vid_canalttab = false; +extern qboolean mouseactive; // from in_win.c + +SDL_Surface *draw_context; + +int vid_modenum = NO_MODE; +int vid_realmode; +int vid_default = MODE_WINDOWED; +unsigned char vid_curpal[256*3]; +static qboolean fullsbardraw = false; + +glvert_t glv; +viddef_t vid; // global video state + +//unsigned short d_8to16table[256]; //johnfitz -- never used +//unsigned char d_15to8table[65536]; //johnfitz -- never used + + +PFNGLARRAYELEMENTEXTPROC glArrayElementEXT = NULL; +PFNGLCOLORPOINTEREXTPROC glColorPointerEXT = NULL; +PFNGLTEXCOORDPOINTEREXTPROC glTexCoordPointerEXT = NULL; +PFNGLVERTEXPOINTEREXTPROC glVertexPointerEXT = NULL; + +modestate_t modestate = MODE_WINDOWED; + +void VID_Menu_Init (void); //johnfitz +void VID_Menu_f (void); //johnfitz +void VID_MenuDraw (void); +void VID_MenuKey (int key); + +char *VID_GetModeDescription (int mode); +void ClearAllStates (void); +void VID_UpdateWindowStatus (void); +void GL_Init (void); + +PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc = NULL; //johnfitz +PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc = NULL; //johnfitz + +qboolean isPermedia = false; +qboolean isIntelVideo = false; //johnfitz -- intel video workarounds from Baker +qboolean gl_mtexable = false; +qboolean gl_texture_env_combine = false; //johnfitz +qboolean gl_texture_env_add = false; //johnfitz +qboolean gl_swap_control = false; //johnfitz +qboolean gl_anisotropy_able = false; //johnfitz +float gl_max_anisotropy; //johnfitz + +int gl_stencilbits; //johnfitz + +qboolean vid_locked = false; //johnfitz +qboolean vid_changed = false; + +void GL_SetupState (void); //johnfitz + +//==================================== + +//johnfitz -- new cvars +cvar_t vid_fullscreen = {"vid_fullscreen", "1", true}; +cvar_t vid_width = {"vid_width", "640", true}; +cvar_t vid_height = {"vid_height", "480", true}; +cvar_t vid_bpp = {"vid_bpp", "16", true}; +cvar_t vid_refreshrate = {"vid_refreshrate", "60", true}; +cvar_t vid_vsync = {"vid_vsync", "0", true}; +//johnfitz + +cvar_t _windowed_mouse = {"_windowed_mouse","1", true}; +cvar_t vid_gamma = {"gamma", "1", true}; //johnfitz -- moved here from view.c + +//========================================================================== +// +// HARDWARE GAMMA -- johnfitz +// +//========================================================================== + +//typedef int (WINAPI * RAMPFUNC)(); +//RAMPFUNC wglGetDeviceGammaRamp3DFX; +//RAMPFUNC wglSetDeviceGammaRamp3DFX; + +unsigned short vid_gamma_red[256]; +unsigned short vid_gamma_green[256]; +unsigned short vid_gamma_blue[256]; + +unsigned short vid_sysgamma_red[256]; +unsigned short vid_sysgamma_green[256]; +unsigned short vid_sysgamma_blue[256]; + +int vid_gammaworks; + +/* +================ +VID_Gamma_SetGamma -- apply gamma correction +================ +*/ +void VID_Gamma_SetGamma (void) +{ + if (draw_context && vid_gammaworks) + if (SDL_SetGammaRamp(&vid_gamma_red[0], &vid_gamma_green[0], &vid_gamma_blue[0]) == -1) + Con_Printf ("VID_Gamma_SetGamma: failed on SDL_SetGammaRamp\n"); +} + +/* +================ +VID_Gamma_Restore -- restore system gamma +================ +*/ +void VID_Gamma_Restore (void) +{ + if (draw_context && vid_gammaworks) + if (SDL_SetGammaRamp(&vid_sysgamma_red[0], &vid_sysgamma_green[0], &vid_sysgamma_blue[0]) == -1) + Con_Printf ("VID_Gamma_Restore: failed on SDL_SetGammaRamp\n"); +} + +/* +================ +VID_Gamma_Shutdown -- called on exit +================ +*/ +void VID_Gamma_Shutdown (void) +{ + VID_Gamma_Restore (); +} + +/* +================ +VID_Gamma_f -- callback when the cvar changes +================ +*/ +void VID_Gamma_f (void) +{ + static float oldgamma; + int i; + + if (vid_gamma.value == oldgamma) + return; + + oldgamma = vid_gamma.value; + + for (i=0; i<256; i++) + { + vid_gamma_red[i] = CLAMP(0, (int) (255 * pow ((i+0.5)/255.5, vid_gamma.value) + 0.5), 255) << 8; + vid_gamma_green[i] = vid_gamma_red[i]; + vid_gamma_blue[i] = vid_gamma_red[i]; + } + + VID_Gamma_SetGamma (); +} + +/* +================ +VID_Gamma_Init -- call on init +================ +*/ +void VID_Gamma_Init (void) +{ + vid_gammaworks = false; + + if (SDL_GetGammaRamp (&vid_sysgamma_red[0], &vid_sysgamma_green[0], &vid_sysgamma_blue[0]) != -1) + vid_gammaworks = true; + + Cvar_RegisterVariable (&vid_gamma, VID_Gamma_f); +} + +/* +================ +VID_SetMode +================ +*/ +int VID_SetMode (int modenum) +{ + int temp; + qboolean stat; + long int flags = SDL_DEFAULT_FLAGS; + char caption[50]; + + //TODO: check if video mode is supported using SDL_VideoModeOk + if ((windowed && (modenum != 0)) || + (!windowed && (modenum < 1)) || + (!windowed && (modenum >= nummodes))) + { + Sys_Error ("Bad video mode\n"); + } + +// so Con_Printfs don't mess us up by forcing vid and snd updates + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + + CDAudio_Pause (); + + // set vertical sync + if (gl_swap_control) + { + if (vid_vsync.value) + { + if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1) == -1) + Con_Printf ("VID_Vsync_f: failed on SDL_GL_SetAttribute\n"); + } + else + { + if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0) == -1) + Con_Printf ("VID_Vsync_f: failed on SDL_GL_SetAttribute\n"); + } + } + + if (modelist[modenum].type == MODE_WINDOWED) + { + if (_windowed_mouse.value && key_dest == key_game) + { + draw_context = SDL_SetVideoMode(modelist[modenum].width, modelist[modenum].height, modelist[modenum].bpp, flags); + stat = true; + } + else + { + draw_context = SDL_SetVideoMode(modelist[modenum].width, modelist[modenum].height, modelist[modenum].bpp, flags); + stat = true; + } + modestate = MODE_WINDOWED; + // TODO set icon and title + } + else if (modelist[modenum].type == MODE_FULLSCREEN_DEFAULT) + { + flags |= SDL_FULLSCREEN; + draw_context = SDL_SetVideoMode(modelist[modenum].width, modelist[modenum].height, modelist[modenum].bpp, flags); + + stat = true; + modestate = MODE_FULLSCREEN_DEFAULT; + } + else + { + Sys_Error ("VID_SetMode: Bad mode type in modelist"); + } + + //kristian -- set window caption + sprintf(caption, "FitzQuake (SDL port) Version %1.2f", FITZQUAKE_VERSION); + SDL_WM_SetCaption((const char* )&caption, (const char*)&caption); + + vid.width = modelist[modenum].width; + vid.height = modelist[modenum].height; + vid.conwidth = vid.width & 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; + vid.numpages = 2; + vid.type = modelist[modenum].type; + + VID_UpdateWindowStatus (); + + CDAudio_Resume (); + scr_disabled_for_loading = temp; + + if (!stat) + { + Sys_Error ("Couldn't set video mode"); + } + + vid_modenum = modenum; + + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + if (!msg_suppress_1) + Con_SafePrintf ("Video mode %s initialized\n", VID_GetModeDescription (vid_modenum)); + + vid.recalc_refdef = 1; + + // with SDL, this needs to be done every time the render context is recreated, so I moved it here + TexMgr_ReloadImages (); + GL_SetupState (); + + // no pending changes + vid_changed = false; + + return true; +} + +/* +=================== +VID_Changed_f -- kristian -- notify us that a value has changed that requires a vid_restart +=================== +*/ +void VID_Changed_f (void) +{ + vid_changed = true; +} + +/* +=================== +VID_Restart -- johnfitz -- change video modes on the fly +=================== +*/ +void VID_Restart (void) +{ + int i; + vmode_t oldmode; + + if (vid_locked || !vid_changed) + return; + +// +// decide which mode to set +// + oldmode = modelist[vid_default]; + + if (vid_fullscreen.value) + { + for (i=1; i 0) ? (int)scr_conwidth.value : vid.width; + vid.conwidth = CLAMP (320, vid.conwidth, vid.width); + vid.conwidth &= 0xFFFFFFF8; + vid.conheight = vid.conwidth * vid.height / vid.width; + // +// keep cvars in line with actual mode +// + Cvar_Set ("vid_width", va("%i", modelist[vid_default].width)); + Cvar_Set ("vid_height", va("%i", modelist[vid_default].height)); + Cvar_Set ("vid_bpp", va("%i", modelist[vid_default].bpp)); + Cvar_Set ("vid_fullscreen", (windowed) ? "0" : "1"); +} + +/* +================ +VID_Test -- johnfitz -- like vid_restart, but asks for confirmation after switching modes +================ +*/ +void VID_Test (void) +{ + vmode_t oldmode; + + if (vid_locked || !vid_changed) + return; +// +// now try the switch +// + oldmode = modelist[vid_default]; + + VID_Restart (); + + //pop up confirmation dialoge + if (!SCR_ModalMessage("Would you like to keep this\nvideo mode? (y/n)\n", 5.0f)) + { + //revert cvars and mode + Cvar_Set ("vid_width", va("%i", oldmode.width)); + Cvar_Set ("vid_height", va("%i", oldmode.height)); + Cvar_Set ("vid_bpp", va("%i", oldmode.bpp)); + Cvar_Set ("vid_fullscreen", (oldmode.type == MODE_WINDOWED) ? "0" : "1"); + VID_Restart (); + } +} + +/* +================ +VID_Unlock -- johnfitz +================ +*/ +void VID_Unlock (void) +{ + vid_locked = false; + + //sync up cvars in case they were changed during the lock + Cvar_Set ("vid_width", va("%i", modelist[vid_default].width)); + Cvar_Set ("vid_height", va("%i", modelist[vid_default].height)); + Cvar_Set ("vid_bpp", va("%i", modelist[vid_default].bpp)); + Cvar_Set ("vid_fullscreen", (windowed) ? "0" : "1"); +} + +/* +================ +VID_UpdateWindowStatus +================ +*/ +void VID_UpdateWindowStatus (void) +{ + //IN_UpdateClipCursor (); +} + +//============================================================================== +// +// OPENGL STUFF +// +//============================================================================== + +/* +=============== +GL_MakeNiceExtensionsList -- johnfitz +=============== +*/ +char *GL_MakeNiceExtensionsList (const char *in) +{ + char *copy, *token, *out; + int i, count; + + //each space will be replaced by 4 chars, so count the spaces before we malloc + for (i = 0, count = 1; i < strlen(in); i++) + if (in[i] == ' ') + count++; + out = Z_Malloc (strlen(in) + count*3 + 1); //usually about 1-2k + out[0] = 0; + + copy = Z_Malloc(strlen(in) + 1); + strcpy(copy, in); + + for (token = strtok(copy, " "); token; token = strtok(NULL, " ")) + { + strcat(out, "\n "); + strcat(out, token); + } + + Z_Free (copy); + return out; +} + +/* +=============== +GL_Info_f -- johnfitz +=============== +*/ +void GL_Info_f (void) +{ + static char *gl_extensions_nice = NULL; + + if (!gl_extensions_nice) + gl_extensions_nice = GL_MakeNiceExtensionsList (gl_extensions); + + Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor); + Con_SafePrintf ("GL_RENDERER: %s\n", gl_renderer); + Con_SafePrintf ("GL_VERSION: %s\n", gl_version); + Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions_nice); +} + +/* +=============== +CheckArrayExtensions +=============== +*/ +void CheckArrayExtensions (void) +{ + unsigned char *tmp; + + /* check for texture extension */ + tmp = (GLubyte *)glGetString(GL_EXTENSIONS); + while (*tmp) + { + if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0) + { + if (((glArrayElementEXT = SDL_GL_GetProcAddress("glArrayElementEXT")) == NULL) || + ((glColorPointerEXT = SDL_GL_GetProcAddress("glColorPointerEXT")) == NULL) || + ((glTexCoordPointerEXT = SDL_GL_GetProcAddress("glTexCoordPointerEXT")) == NULL) || + ((glVertexPointerEXT = SDL_GL_GetProcAddress("glVertexPointerEXT")) == NULL) ) + { + Sys_Error ("GetProcAddress for vertex extension failed"); + return; + } + return; + } + tmp++; + } + + Sys_Error ("Vertex array extension not present"); +} + +/* +=============== +GL_CheckExtensions -- johnfitz +=============== +*/ +void GL_CheckExtensions (void) +{ + int swap_control; + + // + // multitexture + // + if (COM_CheckParm("-nomtex")) + Con_Printf ("WARNING: Mutitexture disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_multitexture")) + { + GL_MTexCoord2fFunc = SDL_GL_GetProcAddress("glMultiTexCoord2fARB"); + GL_SelectTextureFunc = SDL_GL_GetProcAddress("glActiveTextureARB"); + if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) + { + Con_Printf("FOUND: ARB_multitexture\n"); + TEXTURE0 = GL_TEXTURE0_ARB; + TEXTURE1 = GL_TEXTURE1_ARB; + gl_mtexable = true; + } + else + Con_Printf ("WARNING: multitexture not supported (SDL_GL_GetProcAddress failed)\n"); + } + else + if (strstr(gl_extensions, "GL_SGIS_multitexture")) + { + GL_MTexCoord2fFunc = SDL_GL_GetProcAddress("glMTexCoord2fSGIS"); + GL_SelectTextureFunc = SDL_GL_GetProcAddress("glSelectTextureSGIS"); + if (GL_MTexCoord2fFunc && GL_SelectTextureFunc) + { + Con_Printf("FOUND: SGIS_multitexture\n"); + TEXTURE0 = TEXTURE0_SGIS; + TEXTURE1 = TEXTURE1_SGIS; + gl_mtexable = true; + } + else + Con_Printf ("WARNING: multitexture not supported (SDL_GL_GetProcAddress failed)\n"); + + } + else + Con_Printf ("WARNING: multitexture not supported (extension not found)\n"); + // + // texture_env_combine + // + if (COM_CheckParm("-nocombine")) + Con_Printf ("WARNING: texture_env_combine disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_texture_env_combine")) + { + Con_Printf("FOUND: ARB_texture_env_combine\n"); + gl_texture_env_combine = true; + } + else + if (strstr(gl_extensions, "GL_EXT_texture_env_combine")) + { + Con_Printf("FOUND: EXT_texture_env_combine\n"); + gl_texture_env_combine = true; + } + else + Con_Printf ("WARNING: texture_env_combine not supported\n"); + +#if 1 + // + // texture_env_add + // + if (COM_CheckParm("-noadd")) + Con_Warning ("texture_env_add disabled at command line\n"); + else + if (strstr(gl_extensions, "GL_ARB_texture_env_add")) + { + Con_Printf("FOUND: ARB_texture_env_add\n"); + gl_texture_env_add = true; + } + else + if (strstr(gl_extensions, "GL_EXT_texture_env_add")) + { + Con_Printf("FOUND: EXT_texture_env_add\n"); + gl_texture_env_add = true; + } + else + Con_Warning ("texture_env_add not supported\n"); +#endif + + // + // swap control + // + if (strstr(gl_extensions, "GL_EXT_swap_control")) + { + if (SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0) == -1) { + Con_Printf("WARNING: vertical sync not supported (SDL_GL_SetAttribute failed)\n"); + } + else + { + if (SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swap_control) == -1) { + Con_Printf("WARNING: vertical sync not supported (SDL_GL_GetAttribute failed). Make sure you don't have vertical sync disabled in your driver settings.\n"); + } else if (swap_control == -1) { + // TODO: check if this is correct - I don't know what SDL returns if vertical sync is disabled + Con_Printf("WARNING: vertical sync not supported (swap interval is -1.) Make sure you don't have vertical sync disabled in your driver settings.\n"); + } + else + { + Con_Printf("FOUND: WGL_EXT_swap_control\n"); + gl_swap_control = true; + } + } + } + else + Con_Printf ("WARNING: vertical sync not supported (extension not found)\n"); + + // + // anisotropic filtering + // + if (strstr(gl_extensions, "GL_EXT_texture_filter_anisotropic")) + { + float test1,test2; + GLuint tex; + + // test to make sure we really have control over it + // 1.0 and 2.0 should always be legal values + glGenTextures(1, &tex); + glBindTexture (GL_TEXTURE_2D, tex); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test1); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f); + glGetTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &test2); + glDeleteTextures(1, &tex); + + if (test1 == 1 && test2 == 2) + { + Con_Printf("FOUND: EXT_texture_filter_anisotropic\n"); + gl_anisotropy_able = true; + } + else + Con_Printf("WARNING: anisotropic filtering locked by driver. Current driver setting is %f\n", test1); + + //get max value either way, so the menu and stuff know it + glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_anisotropy); + } + else + Con_Printf ("WARNING: texture_filter_anisotropic not supported\n"); +} + +/* +=============== +GL_SetupState -- johnfitz + +does all the stuff from GL_Init that needs to be done every time a new GL render context is created +GL_Init will still do the stuff that only needs to be done once +=============== +*/ +void GL_SetupState (void) +{ + glClearColor (0.15,0.15,0.15,0); //johnfitz -- originally 1,0,0,0 + glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right + glFrontFace(GL_CW); //johnfitz -- glquake used CCW with backwards culling -- let's do it right + glEnable(GL_TEXTURE_2D); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.666); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glShadeModel (GL_FLAT); + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //johnfitz + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDepthRange (0, 1); //johnfitz -- moved here becuase gl_ztrick is gone. + glDepthFunc (GL_LEQUAL); //johnfitz -- moved here becuase gl_ztrick is gone. +} + +/* +=============== +GL_Init +=============== +*/ +void GL_Init (void) +{ + gl_vendor = (const char *) glGetString (GL_VENDOR); + gl_renderer = (const char *) glGetString (GL_RENDERER); + gl_version = (const char *) glGetString (GL_VERSION); + gl_extensions = (const char *) glGetString (GL_EXTENSIONS); + + GL_CheckExtensions (); //johnfitz + + Cmd_AddCommand ("gl_info", GL_Info_f); //johnfitz + + Cvar_RegisterVariable (&vid_vsync, VID_Changed_f); //johnfitz + + if (SDL_strncasecmp(gl_renderer,"PowerVR",7)==0) + fullsbardraw = true; + + if (SDL_strncasecmp(gl_renderer,"Permedia",8)==0) + isPermedia = true; +#if 1 + //johnfitz -- intel video workarounds from Baker + if (!strcmp(gl_vendor, "Intel")) + { + Con_Printf ("Intel Display Adapter detected\n"); + isIntelVideo = true; + } + //johnfitz +#endif + +#if 0 + //johnfitz -- confirm presence of stencil buffer + glGetIntegerv(GL_STENCIL_BITS, &gl_stencilbits); + if(!gl_stencilbits) + Con_Printf ("WARNING: Could not create stencil buffer\n"); + else + Con_Printf ("%i bit stencil buffer\n", gl_stencilbits); +#endif + + GL_SetupState (); //johnfitz +} + +/* +================= +GL_BeginRendering -- sets values of glx, gly, glwidth, glheight +================= +*/ +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + *x = *y = 0; + *width = vid.width; + *height = vid.height; +} + +/* +================= +GL_EndRendering +================= +*/ +void GL_EndRendering (void) +{ + if (!scr_skipupdate || block_drawing) + SDL_GL_SwapBuffers(); + + if (fullsbardraw) + Sbar_Changed(); +} + +void VID_SetDefaultMode (void) +{ +} + + +void VID_Shutdown (void) +{ + if (vid_initialized) + { + vid_canalttab = false; + VID_Gamma_Shutdown (); //johnfitz + + SDL_QuitSubSystem(SDL_INIT_VIDEO); + draw_context = NULL; + + PL_VID_Shutdown(); + } +} + +//========================================================================== + +/* +=================================================================== + +MAIN WINDOW + +=================================================================== +*/ + +/* +================ +ClearAllStates +================ +*/ +void ClearAllStates (void) +{ + int i; + +// send an up event for each key, to make sure the server clears them all + for (i=0 ; i<256 ; i++) + { + Key_Event (i, false); + } + + Key_ClearStates (); + IN_ClearStates (); +} + + + +//========================================================================== +// +// COMMANDS +// +//========================================================================== + +/* +================= +VID_NumModes +================= +*/ +int VID_NumModes (void) +{ + return nummodes; +} + + +/* +================= +VID_GetModePtr +================= +*/ +vmode_t *VID_GetModePtr (int modenum) +{ + + if ((modenum >= 0) && (modenum < nummodes)) + return &modelist[modenum]; + else + return &badmode; +} + + +/* +================= +VID_GetModeDescription +================= +*/ +char *VID_GetModeDescription (int mode) +{ + char *pinfo; + vmode_t *pv; + static char temp[100]; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + if (!leavecurrentmode) + { + pv = VID_GetModePtr (mode); + pinfo = pv->modedesc; + } + else + { + sprintf (temp, "Desktop resolution (%ix%ix%i)", //johnfitz -- added bpp + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height, + modelist[MODE_FULLSCREEN_DEFAULT].bpp); //johnfitz -- added bpp + pinfo = temp; + } + + return pinfo; +} + +// KJB: Added this to return the mode driver name in description for console +/* +================= +VID_GetExtModeDescription +================= +*/ +char *VID_GetExtModeDescription (int mode) +{ + static char pinfo[40]; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + pv = VID_GetModePtr (mode); + if (modelist[mode].type == MODE_FULLSCREEN_DEFAULT) + { + if (!leavecurrentmode) + { + sprintf(pinfo,"%s fullscreen", pv->modedesc); + } + else + { + sprintf (pinfo, "Desktop resolution (%ix%ix%i)", //johnfitz -- added bpp + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height, + modelist[MODE_FULLSCREEN_DEFAULT].bpp); //johnfitz -- added bpp + } + } + else + { + if (modestate == MODE_WINDOWED) + sprintf(pinfo, "%s windowed", pv->modedesc); + else + sprintf(pinfo, "windowed"); + } + + return pinfo; +} + +/* +================= +VID_DescribeCurrentMode_f +================= +*/ +void VID_DescribeCurrentMode_f (void) +{ + Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); +} + +/* +================= +VID_DescribeModes_f -- johnfitz -- changed formatting, and added refresh rates after each mode. +================= +*/ +void VID_DescribeModes_f (void) +{ + int i, lnummodes, t; + vmode_t *pv; + int lastwidth=0, lastheight=0, lastbpp=0, count=0; + + lnummodes = VID_NumModes (); + + t = leavecurrentmode; + leavecurrentmode = 0; + + for (i=1 ; iwidth || lastheight != pv->height || lastbpp != pv->bpp) + { + if (count>0) + Con_SafePrintf ("\n"); + Con_SafePrintf (" %4i x %4i x %i", pv->width, pv->height, pv->bpp); + lastwidth = pv->width; + lastheight = pv->height; + lastbpp = pv->bpp; + count++; + } + } + Con_Printf ("\n%i modes\n", count); + + leavecurrentmode = t; +} + +//========================================================================== +// +// INIT +// +//========================================================================== + +/* +================= +VID_InitDIB +================= +*/ +void VID_InitDIB () +{ + const SDL_VideoInfo *info; + + modelist[0].type = MODE_WINDOWED; + + if (COM_CheckParm("-width")) + modelist[0].width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); + else + modelist[0].width = 640; + + if (modelist[0].width < 320) + modelist[0].width = 320; + + if (COM_CheckParm("-height")) + modelist[0].height= Q_atoi(com_argv[COM_CheckParm("-height")+1]); + else + modelist[0].height = modelist[0].width * 240/320; + + if (modelist[0].height < 200) //johnfitz -- was 240 + modelist[0].height = 200; //johnfitz -- was 240 + + info = SDL_GetVideoInfo(); + modelist[0].bpp = info->vfmt->BitsPerPixel; + + sprintf (modelist[0].modedesc, "%dx%dx%d", //johnfitz -- added bpp + modelist[0].width, + modelist[0].height, + modelist[0].bpp); //johnfitz -- added bpp + + modelist[0].modenum = MODE_WINDOWED; + modelist[0].dib = 1; + modelist[0].fullscreen = 0; + modelist[0].halfscreen = 0; + + nummodes = 1; +} + +/* +================= +VID_InitFullDIB +================= +*/ +void VID_InitFullDIB () +{ + SDL_PixelFormat format; + SDL_Rect **modes; + long int flags; + int i, j, k, modenum, originalnummodes, existingmode; + int bpps[3] = {16, 24, 32}; // enumerate >8 bpp modes + + originalnummodes = nummodes; + modenum = 0; + format.palette = NULL; + + // enumerate fullscreen modes + flags = SDL_DEFAULT_FLAGS | SDL_FULLSCREEN; + for (i = 0; i < 3; i++) + { + if (nummodes >= MAX_MODE_LIST) + break; + + format.BitsPerPixel = bpps[i]; + modes = SDL_ListModes(&format, flags); + + if (modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1) + continue; + + for (j = 0; modes[j]; j++) + { + if (modes[j]->w > MAXWIDTH || modes[j]->h > MAXHEIGHT || nummodes >= MAX_MODE_LIST) + continue; + + modelist[nummodes].type = MODE_FULLSCREEN_DEFAULT; + modelist[nummodes].width = modes[j]->w; + modelist[nummodes].height = modes[j]->h; + modelist[nummodes].modenum = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = bpps[i]; + + sprintf (modelist[nummodes].modedesc, "%dx%dx%d", + modelist[nummodes].width, + modelist[nummodes].height, + modelist[nummodes].bpp); //johnfitz -- refreshrate + + // if the width is more than twice the height, reduce it by half because this + // is probably a dual-screen monitor + if (!COM_CheckParm("-noadjustaspect")) + { + if (modelist[nummodes].width > (modelist[nummodes].height << 1)) + { + modelist[nummodes].width >>= 1; + modelist[nummodes].halfscreen = 1; + sprintf (modelist[nummodes].modedesc, "%dx%dx%d", + modelist[nummodes].width, + modelist[nummodes].height, + modelist[nummodes].bpp); + } + } + + for (k=originalnummodes, existingmode = 0 ; k < nummodes ; k++) + { + if ((modelist[nummodes].width == modelist[k].width) && + (modelist[nummodes].height == modelist[k].height) && + (modelist[nummodes].bpp == modelist[k].bpp)) + { + existingmode = 1; + break; + } + } + + if (!existingmode) + { + nummodes++; + } + } + modenum++; + } + + if (nummodes == originalnummodes) + Con_SafePrintf ("No fullscreen DIB modes found\n"); +} + +/* +=================== +VID_Init +=================== +*/ +void VID_Init (void) +{ + const SDL_VideoInfo *info; + int i, existingmode; + int basenummodes, width, height, bpp, findbpp, done; + char gldir[MAX_OSPATH]; + + //johnfitz -- clean up init readouts + //Con_Printf("------------- Init Video -------------\n"); + //Con_Printf("%cVideo Init\n", 2); + //johnfitz + + Cvar_RegisterVariable (&vid_fullscreen, VID_Changed_f); //johnfitz + Cvar_RegisterVariable (&vid_width, VID_Changed_f); //johnfitz + Cvar_RegisterVariable (&vid_height, VID_Changed_f); //johnfitz + Cvar_RegisterVariable (&vid_bpp, VID_Changed_f); //johnfitz + //Cvar_RegisterVariable (&vid_refreshrate, NULL); //johnfitz + Cvar_RegisterVariable (&_windowed_mouse, NULL); + + Cmd_AddCommand ("vid_unlock", VID_Unlock); //johnfitz + Cmd_AddCommand ("vid_restart", VID_Restart); //johnfitz + Cmd_AddCommand ("vid_test", VID_Test); //johnfitz + Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f); + Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f); + + //InitCommonControls(); + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) + Sys_Error("Could not initialize SDL Video"); + + SDL_putenv("SDL_VIDEO_CENTERED=center"); + + VID_InitDIB(); + basenummodes = nummodes = 1; + VID_InitFullDIB(); + + if (COM_CheckParm("-window")) + { + windowed = true; + vid_default = MODE_WINDOWED; + } + else + { + if (nummodes == 1) + Sys_Error ("No RGB fullscreen modes available"); + + windowed = false; + + if (COM_CheckParm("-mode")) + { + vid_default = Q_atoi(com_argv[COM_CheckParm("-mode")+1]); + } + else + { + if (COM_CheckParm("-current")) + { + info = SDL_GetVideoInfo(); + modelist[MODE_FULLSCREEN_DEFAULT].width = info->current_w; + modelist[MODE_FULLSCREEN_DEFAULT].height = info->current_h; + vid_default = MODE_FULLSCREEN_DEFAULT; + leavecurrentmode = 1; + } + else + { + if (COM_CheckParm("-width")) + { + width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); + } + else + { + width = 640; + } + + if (COM_CheckParm("-bpp")) + { + bpp = Q_atoi(com_argv[COM_CheckParm("-bpp")+1]); + findbpp = 0; + } + else + { + bpp = 15; + findbpp = 1; + } + + if (COM_CheckParm("-height")) + height = Q_atoi(com_argv[COM_CheckParm("-height")+1]); + + // if they want to force it, add the specified mode to the list + if (COM_CheckParm("-force") && (nummodes < MAX_MODE_LIST)) + { + modelist[nummodes].type = MODE_FULLSCREEN_DEFAULT; + modelist[nummodes].width = width; + modelist[nummodes].height = height; + modelist[nummodes].modenum = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = bpp; + sprintf (modelist[nummodes].modedesc, "%dx%dx%d", + modelist[nummodes].width, + modelist[nummodes].height, + modelist[nummodes].bpp); + + for (i=nummodes, existingmode = 0 ; i=vid_menu_nummodes) + i = 0; + else if (i<0) + i = vid_menu_nummodes-1; + } + + Cvar_Set ("vid_width",va("%i",vid_menu_modes[i].width)); + Cvar_Set ("vid_height",va("%i",vid_menu_modes[i].height)); + VID_Menu_RebuildBppList (); +} + +/* +================ +VID_Menu_ChooseNextBpp + +chooses next bpp in order, then updates vid_bpp cvar, then updates refreshrate list +================ +*/ +void VID_Menu_ChooseNextBpp (int dir) +{ + int i; + + for (i=0;i=vid_menu_numbpps) + i = 0; + else if (i<0) + i = vid_menu_numbpps-1; + } + + Cvar_Set ("vid_bpp",va("%i",vid_menu_bpps[i])); +} + +/* +================ +VID_Menu_ChooseNextRate + +chooses next refresh rate in order, then updates vid_refreshrate cvar +================ +*/ +void VID_Menu_ChooseNextRate (int dir) +{ + int i; + + for (i=0;i=vid_menu_numrates) + i = 0; + else if (i<0) + i = vid_menu_numrates-1; + } + + Cvar_Set ("vid_refreshrate",va("%i",vid_menu_rates[i])); +} + +/* +================ +VID_MenuKey +================ +*/ +void VID_MenuKey (int key) +{ + switch (key) + { + case K_ESCAPE: + VID_SyncCvars (); //sync cvars before leaving menu. FIXME: there are other ways to leave menu + S_LocalSound ("misc/menu1.wav"); + M_Menu_Options_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + video_options_cursor--; + if (video_options_cursor < 0) + video_options_cursor = VIDEO_OPTIONS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + video_options_cursor++; + if (video_options_cursor >= VIDEO_OPTIONS_ITEMS) + video_options_cursor = 0; + break; + + case K_LEFTARROW: + S_LocalSound ("misc/menu3.wav"); + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (-1); + break; + case 1: + VID_Menu_ChooseNextBpp (-1); + break; + case 2: + VID_Menu_ChooseNextRate (-1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + Cbuf_AddText ("toggle vid_vsync\n"); // kristian + break; + case 5: + case 6: + default: + break; + } + break; + + case K_RIGHTARROW: + S_LocalSound ("misc/menu3.wav"); + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (1); + break; + case 1: + VID_Menu_ChooseNextBpp (1); + break; + case 2: + VID_Menu_ChooseNextRate (1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + Cbuf_AddText ("toggle vid_vsync\n"); + break; + case 5: + case 6: + default: + break; + } + break; + + case K_ENTER: + m_entersound = true; + switch (video_options_cursor) + { + case 0: + VID_Menu_ChooseNextMode (1); + break; + case 1: + VID_Menu_ChooseNextBpp (1); + break; + case 2: + VID_Menu_ChooseNextRate (1); + break; + case 3: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 4: + Cbuf_AddText ("toggle vid_fullscreen\n"); + break; + case 5: + Cbuf_AddText ("vid_test\n"); + break; + case 6: + Cbuf_AddText ("vid_restart\n"); + key_dest = key_game; + m_state = m_none; + IN_Activate(); + break; + default: + break; + } + break; + + default: + break; + } +} + +/* +================ +VID_MenuDraw +================ +*/ +void VID_MenuDraw (void) +{ + int i = 0; + qpic_t *p; + char *title; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp")); + + //p = Draw_CachePic ("gfx/vidmodes.lmp"); + p = Draw_CachePic ("gfx/p_option.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + // title + title = "Video Options"; + M_PrintWhite ((320-8*strlen(title))/2, 32, title); + + // options + M_Print (16, video_cursor_table[i], " Video mode"); + M_Print (216, video_cursor_table[i], va("%ix%i", (int)vid_width.value, (int)vid_height.value)); + i++; + + M_Print (16, video_cursor_table[i], " Color depth"); + M_Print (216, video_cursor_table[i], va("%i", (int)vid_bpp.value)); + i++; + + M_Print (16, video_cursor_table[i], " Refresh rate"); +// M_Print (216, video_cursor_table[i], va("%i Hz", (int)vid_refreshrate.value)); refresh rates are disabled for now -- kristian + M_Print (216, video_cursor_table[i], "N/A"); + i++; + + M_Print (16, video_cursor_table[i], " Fullscreen"); + M_DrawCheckbox (216, video_cursor_table[i], (int)vid_fullscreen.value); + i++; + + // added vsync to the video menu -- kristian + M_Print (16, video_cursor_table[i], " Vertical Sync"); + if (gl_swap_control) + M_DrawCheckbox (216, video_cursor_table[i], (int)vid_vsync.value); + else + M_Print (216, video_cursor_table[i], "N/A"); + + i++; + + M_Print (16, video_cursor_table[i], " Test changes"); + i++; + + M_Print (16, video_cursor_table[i], " Apply changes"); + + // cursor + M_DrawCharacter (200, video_cursor_table[video_options_cursor], 12+((int)(realtime*4)&1)); + + // notes "345678901234567890123456789012345678" +// M_Print (16, 172, "Windowed modes always use the desk- "); +// M_Print (16, 180, "top color depth, and can never be "); +// M_Print (16, 188, "larger than the desktop resolution. "); +} + +/* +================ +VID_Menu_f +================ +*/ +void VID_Menu_f (void) +{ + key_dest = key_menu; + m_state = m_video; + m_entersound = true; + + //set all the cvars to match the current mode when entering the menu + VID_SyncCvars (); + + //set up bpp and rate lists based on current cvars + VID_Menu_RebuildBppList (); +} diff --git a/Quake/gl_warp.c b/Quake/gl_warp.c new file mode 100644 index 00000000..e064086f --- /dev/null +++ b/Quake/gl_warp.c @@ -0,0 +1,267 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +//gl_warp.c -- warping animation support + +#include "quakedef.h" + +extern cvar_t r_drawflat; + +cvar_t r_oldwater = {"r_oldwater", "1"}; +cvar_t r_waterquality = {"r_waterquality", "8"}; +cvar_t r_waterwarp = {"r_waterwarp", "1"}; + +float load_subdivide_size; //johnfitz -- remember what subdivide_size value was when this map was loaded + +float turbsin[] = +{ + #include "gl_warp_sin.h" +}; + +#define WARPCALC(s,t) ((s + turbsin[(int)((t*2)+(cl.time*(128.0/M_PI))) & 255]) * (1.0/64)) //johnfitz -- correct warp +#define WARPCALC2(s,t) ((s + turbsin[(int)((t*0.125+cl.time)*(128.0/M_PI)) & 255]) * (1.0/64)) //johnfitz -- old warp + +//============================================================================== +// +// OLD-STYLE WATER +// +//============================================================================== + +extern model_t *loadmodel; + +msurface_t *warpface; + +cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", true}; + +void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) +{ + int i, j; + float *v; + + mins[0] = mins[1] = mins[2] = 9999; + maxs[0] = maxs[1] = maxs[2] = -9999; + v = verts; + for (i=0 ; i maxs[j]) + maxs[j] = *v; + } +} + +void SubdividePolygon (int numverts, float *verts) +{ + int i, j, k; + vec3_t mins, maxs; + float m; + float *v; + vec3_t front[64], back[64]; + int f, b; + float dist[64]; + float frac; + glpoly_t *poly; + float s, t; + + if (numverts > 60) + Sys_Error ("numverts = %i", numverts); + + BoundPoly (numverts, verts, mins, maxs); + + for (i=0 ; i<3 ; i++) + { + m = (mins[i] + maxs[i]) * 0.5; + m = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5); + if (maxs[i] - m < 8) + continue; + if (m - mins[i] < 8) + continue; + + // cut it + v = verts + i; + for (j=0 ; j= 0) + { + VectorCopy (v, front[f]); + f++; + } + if (dist[j] <= 0) + { + VectorCopy (v, back[b]); + b++; + } + if (dist[j] == 0 || dist[j+1] == 0) + continue; + if ( (dist[j] > 0) != (dist[j+1] > 0) ) + { + // clip point + frac = dist[j] / (dist[j] - dist[j+1]); + for (k=0 ; k<3 ; k++) + front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); + f++; + b++; + } + } + + SubdividePolygon (f, front[0]); + SubdividePolygon (b, back[0]); + return; + } + + poly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = warpface->polys->next; + warpface->polys->next = poly; + poly->numverts = numverts; + for (i=0 ; iverts[i]); + s = DotProduct (verts, warpface->texinfo->vecs[0]); + t = DotProduct (verts, warpface->texinfo->vecs[1]); + poly->verts[i][3] = s; + poly->verts[i][4] = t; + } +} + +/* +================ +GL_SubdivideSurface +================ +*/ +void GL_SubdivideSurface (msurface_t *fa) +{ + vec3_t verts[64]; + int i; + + warpface = fa; + + //the first poly in the chain is the undivided poly for newwater rendering. + //grab the verts from that. + for (i=0; ipolys->numverts; i++) + VectorCopy (fa->polys->verts[i], verts[i]); + + SubdividePolygon (fa->polys->numverts, verts[0]); +} + +/* +================ +DrawWaterPoly -- johnfitz +================ +*/ +void DrawWaterPoly (glpoly_t *p) +{ + float *v; + int i; + + if (load_subdivide_size > 48) + { + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (WARPCALC2(v[3],v[4]), WARPCALC2(v[4],v[3])); + glVertex3fv (v); + } + glEnd (); + } + else + { + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (WARPCALC(v[3],v[4]), WARPCALC(v[4],v[3])); + glVertex3fv (v); + } + glEnd (); + } +} + +//============================================================================== +// +// RENDER-TO-FRAMEBUFFER WATER +// +//============================================================================== + +/* +============= +R_UpdateWarpTextures -- johnfitz -- each frame, update warping textures +============= +*/ +void R_UpdateWarpTextures (void) +{ + texture_t *tx; + int i; + float x, y, x2, warptess; + + if (r_oldwater.value || cl.paused || r_drawflat_cheatsafe || r_lightmap_cheatsafe) + return; + + warptess = 128.0/CLAMP (3.0, floor(r_waterquality.value), 64.0); + + for (i=0; inumtextures; i++) + { + if (!(tx = cl.worldmodel->textures[i])) + continue; + + if (!tx->update_warp) + continue; + + //render warp + GL_SetCanvas (CANVAS_WARPIMAGE); + GL_Bind (tx->gltexture); + for (x=0.0; x<128.0; x=x2) + { + x2 = x + warptess; + glBegin (GL_TRIANGLE_STRIP); + for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors + { + glTexCoord2f (WARPCALC(x,y), WARPCALC(y,x)); + glVertex2f (x,y); + glTexCoord2f (WARPCALC(x2,y), WARPCALC(y,x2)); + glVertex2f (x2,y); + } + glEnd(); + } + + //copy to texture + GL_Bind (tx->warpimage); + glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize); + + tx->update_warp = false; + } + + //if warp render went down into sbar territory, we need to be sure to refresh it next frame + if (gl_warpimagesize + sb_lines > glheight) + Sbar_Changed (); + + //if viewsize is less than 100, we need to redraw the frame around the viewport + scr_tileclear_updates = 0; +} diff --git a/Quake/gl_warp_sin.h b/Quake/gl_warp_sin.h new file mode 100644 index 00000000..3ca2e9c3 --- /dev/null +++ b/Quake/gl_warp_sin.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677, + 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916, + 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998, + 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632, + 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068, + 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368, + 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562, + 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759, + 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222, + 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394, + 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883, + 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398, + 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647, + 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193, + 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281, + 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633, + 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677, + -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916, + -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998, + -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632, + -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068, + -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368, + -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562, + -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759, + -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222, + -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394, + -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883, + -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398, + -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647, + -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193, + -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281, + -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633, diff --git a/Quake/glquake.h b/Quake/glquake.h new file mode 100644 index 00000000..afeedba9 --- /dev/null +++ b/Quake/glquake.h @@ -0,0 +1,274 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// disable data conversion warnings + +void GL_BeginRendering (int *x, int *y, int *width, int *height); +void GL_EndRendering (void); + +//johnfitz -- removed texture object stuff since they are standard in gl 1.1 + +typedef struct +{ + float x, y, z; + float s, t; + float r, g, b; +} glvert_t; + +extern glvert_t glv; + +extern int glx, gly, glwidth, glheight; + +// r_local.h -- private refresh defs + +#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) + // normalizing factor so player model works out to about + // 1 pixel per triangle +#define MAX_LBM_HEIGHT 480 + +#define TILE_SIZE 128 // size of textures generated by R_GenTiledSurf + +#define SKYSHIFT 7 +#define SKYSIZE (1 << SKYSHIFT) +#define SKYMASK (SKYSIZE - 1) + +#define BACKFACE_EPSILON 0.01 + + +void R_TimeRefresh_f (void); +void R_ReadPointFile_f (void); +texture_t *R_TextureAnimation (texture_t *base, int frame); + +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; // NULL is an empty chunk of memory + int lightadj[MAXLIGHTMAPS]; // checked for strobe flush + int dlight; + int size; // including header + unsigned width; + unsigned height; // DEBUG only needed for debug + float mipscale; + struct texture_s *texture; // checked for animating textures + byte data[4]; // width*height elements +} surfcache_t; + + +typedef struct +{ + pixel_t *surfdat; // destination for generated surface + int rowbytes; // destination logical width in bytes + msurface_t *surf; // description for surface to generate + fixed8_t lightadj[MAXLIGHTMAPS]; + // adjust for lightmap levels for dynamic lighting + texture_t *texture; // corrected for animating textures + int surfmip; // mipmapped ratio of surface texels / world pixels + int surfwidth; // in mipmapped texels + int surfheight; // in mipmapped texels +} drawsurf_t; + + +typedef enum { + pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2 +} ptype_t; + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +typedef struct particle_s +{ +// driver-usable fields + vec3_t org; + float color; +// drivers never touch the following fields + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; +} particle_t; + + +//==================================================== + +extern qboolean r_cache_thrash; // compatability +extern vec3_t modelorg, r_entorigin; +extern entity_t *currententity; +extern int r_visframecount; // ??? what difs? +extern int r_framecount; +extern mplane_t frustum[4]; + +// +// view origin +// +extern vec3_t vup; +extern vec3_t vpn; +extern vec3_t vright; +extern vec3_t r_origin; + +// +// screen size info +// +extern refdef_t r_refdef; +extern mleaf_t *r_viewleaf, *r_oldviewleaf; +extern int d_lightstylevalue[256]; // 8.8 fraction of base light value + +extern qboolean envmap; + +extern cvar_t r_norefresh; +extern cvar_t r_drawentities; +extern cvar_t r_drawworld; +extern cvar_t r_drawviewmodel; +extern cvar_t r_speeds; +extern cvar_t r_waterwarp; +extern cvar_t r_fullbright; +extern cvar_t r_lightmap; +extern cvar_t r_shadows; +extern cvar_t r_wateralpha; +extern cvar_t r_dynamic; +extern cvar_t r_novis; + +extern cvar_t gl_clear; +extern cvar_t gl_cull; +extern cvar_t gl_smoothmodels; +extern cvar_t gl_affinemodels; +extern cvar_t gl_polyblend; +extern cvar_t gl_flashblend; +extern cvar_t gl_nocolors; + +extern cvar_t gl_max_size; +extern cvar_t gl_playermip; + +extern float r_world_matrix[16]; + +extern const char *gl_vendor; +extern const char *gl_renderer; +extern const char *gl_version; +extern const char *gl_extensions; + +void R_TranslatePlayerSkin (int playernum); +void R_TranslateNewPlayerSkin (int playernum); //johnfitz -- this handles cases when the actual texture changes + +// Multitexture +#define TEXTURE0_SGIS 0x835E +#define TEXTURE1_SGIS 0x835F + +//#define APIENTRY /* */ + +//johnfitz -- modified multitexture support +/* +typedef void (APIENTRY *SELECTTEXFUNC) (GLenum); +typedef void (APIENTRY *MTEXCOORDFUNC) (GLenum, GLfloat, GLfloat); +extern MTEXCOORDFUNC GL_MTexCoord2fFunc; +extern SELECTTEXFUNC GL_SelectTextureFunc; +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +*/ +//johnfitz + + +extern PFNGLMULTITEXCOORD2FARBPROC GL_MTexCoord2fFunc; +extern PFNGLACTIVETEXTUREARBPROC GL_SelectTextureFunc; +extern GLenum TEXTURE0, TEXTURE1; + +//johnfitz -- anisotropic filtering +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +//johnfitz + +//johnfitz -- polygon offset +#define OFFSET_BMODEL 1 +#define OFFSET_NONE 0 +#define OFFSET_DECAL -1 +#define OFFSET_FOG -2 +#define OFFSET_SHOWTRIS -3 +void GL_PolygonOffset (int); +//johnfitz + +//johnfitz -- GL_EXT_texture_env_combine +//the values for GL_ARB_ are identical +#define GL_COMBINE_EXT 0x8570 +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_RGB_SCALE_EXT 0x8573 +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +extern qboolean gl_texture_env_combine; +//johnfitz + +extern qboolean gl_texture_env_add; //johnfitz -- for GL_EXT_texture_env_add + +extern qboolean isIntelVideo; //johnfitz -- intel video workarounds from Baker + +//johnfitz -- rendering statistics +extern int rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys; +extern int rs_dynamiclightmaps, rs_brushpasses, rs_aliaspasses, rs_skypasses; +extern float rs_megatexels; +//johnfitz + +//johnfitz -- track developer statistics that vary every frame +extern cvar_t devstats; +typedef struct { + int packetsize; + int edicts; + int visedicts; + int efrags; + int tempents; + int beams; + int dlights; +} devstats_t; +devstats_t dev_stats, dev_peakstats; +//johnfitz + +//ohnfitz -- reduce overflow warning spam +typedef struct { + double packetsize; + double efrags; + double beams; +} overflowtimes_t; +overflowtimes_t dev_overflows; //this stores the last time overflow messages were displayed, not the last time overflows occured +#define CONSOLE_RESPAM_TIME 3 // seconds between repeated warning messages +//johnfitz + +//johnfitz -- moved here from r_brush.c +#define MAX_LIGHTMAPS 256 //johnfitz -- was 64 +gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array +//johnfitz + +int gl_warpimagesize; //johnfitz -- for water warp + +qboolean r_drawflat_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe, r_drawworld_cheatsafe; //johnfitz + +//johnfitz -- fog functions called from outside gl_fog.c +void Fog_ParseServerMessage (void); +float *Fog_GetColor (void); +float Fog_GetDensity (void); +void Fog_EnableGFog (void); +void Fog_DisableGFog (void); +void Fog_StartAdditive (void); +void Fog_StopAdditive (void); +void Fog_SetupFrame (void); +void Fog_NewMap (void); +void Fog_Init (void); +//johnfitz diff --git a/Quake/host.c b/Quake/host.c new file mode 100644 index 00000000..4a9d0f48 --- /dev/null +++ b/Quake/host.c @@ -0,0 +1,899 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// host.c -- coordinates spawning and killing of local servers + +#include "quakedef.h" + +/* + +A server can allways be started, even if the system started out as a client +to a remote system. + +A client can NOT be started if the system started as a dedicated server. + +Memory is cleared / released when a server or client begins, not when they end. + +*/ + +quakeparms_t host_parms; + +qboolean host_initialized; // true if into command execution + +double host_frametime; +double host_time; +double realtime; // without any filtering or bounding +double oldrealtime; // last frame run +int host_framecount; + +int host_hunklevel; + +int minimum_memory; + +client_t *host_client; // current client + +jmp_buf host_abortserver; + +byte *host_colormap; + +cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion +cvar_t host_speeds = {"host_speeds","0"}; // set for running times +cvar_t host_maxfps = {"host_maxfps", "72", true}; //johnfitz +cvar_t host_timescale = {"host_timescale", "0"}; //johnfitz +cvar_t max_edicts = {"max_edicts", "1024", true}; //johnfitz + +cvar_t sys_ticrate = {"sys_ticrate","0.05"}; // dedicated server +cvar_t serverprofile = {"serverprofile","0"}; + +cvar_t fraglimit = {"fraglimit","0",false,true}; +cvar_t timelimit = {"timelimit","0",false,true}; +cvar_t teamplay = {"teamplay","0",false,true}; +cvar_t samelevel = {"samelevel","0"}; +cvar_t noexit = {"noexit","0",false,true}; +cvar_t skill = {"skill","1"}; // 0 - 3 +cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2 +cvar_t coop = {"coop","0"}; // 0 or 1 + +cvar_t pausable = {"pausable","1"}; + +cvar_t developer = {"developer","0"}; + +cvar_t temp1 = {"temp1","0"}; + +cvar_t devstats = {"devstats","0"}; //johnfitz -- track developer statistics that vary every frame + +/* +================ +Max_Edicts_f -- johnfitz +================ +*/ +void Max_Edicts_f (void) +{ + static float oldval = 1024; //must match the default value for max_edicts + + //TODO: clamp it here? + + if (max_edicts.value == oldval) + return; + + if (cls.state == ca_connected || sv.active) + Con_Printf ("Changes to max_edicts will not take effect until the next time a map is loaded.\n"); + + oldval = max_edicts.value; +} + +/* +================ +Host_EndGame +================ +*/ +void Host_EndGame (char *message, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,message); + vsprintf (string,message,argptr); + va_end (argptr); + Con_DPrintf ("Host_EndGame: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit + + if (cls.demonum != -1) + CL_NextDemo (); + else + CL_Disconnect (); + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_Error + +This shuts down both the client and server +================ +*/ +void Host_Error (char *error, ...) +{ + va_list argptr; + char string[1024]; + static qboolean inerror = false; + + if (inerror) + Sys_Error ("Host_Error: recursively entered"); + inerror = true; + + SCR_EndLoadingPlaque (); // reenable screen updates + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + Con_Printf ("Host_Error: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit + + CL_Disconnect (); + cls.demonum = -1; + cl.intermission = 0; //johnfitz -- for errors during intermissions (changelevel with no map found, etc.) + + inerror = false; + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_FindMaxClients +================ +*/ +void Host_FindMaxClients (void) +{ + int i; + + svs.maxclients = 1; + + i = COM_CheckParm ("-dedicated"); + if (i) + { + cls.state = ca_dedicated; + if (i != (com_argc - 1)) + { + svs.maxclients = Q_atoi (com_argv[i+1]); + } + else + svs.maxclients = 8; + } + else + cls.state = ca_disconnected; + + i = COM_CheckParm ("-listen"); + if (i) + { + if (cls.state == ca_dedicated) + Sys_Error ("Only one of -dedicated or -listen can be specified"); + if (i != (com_argc - 1)) + svs.maxclients = Q_atoi (com_argv[i+1]); + else + svs.maxclients = 8; + } + if (svs.maxclients < 1) + svs.maxclients = 8; + else if (svs.maxclients > MAX_SCOREBOARD) + svs.maxclients = MAX_SCOREBOARD; + + svs.maxclientslimit = svs.maxclients; + if (svs.maxclientslimit < 4) + svs.maxclientslimit = 4; + svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients"); + + if (svs.maxclients > 1) + Cvar_SetValue ("deathmatch", 1.0); + else + Cvar_SetValue ("deathmatch", 0.0); +} + +/* +======================= +Host_InitLocal +====================== +*/ +void Host_InitLocal (void) +{ + Host_InitCommands (); + + Cvar_RegisterVariable (&host_framerate, NULL); + Cvar_RegisterVariable (&host_speeds, NULL); + Cvar_RegisterVariable (&host_maxfps, NULL); //johnfitz + Cvar_RegisterVariable (&host_timescale, NULL); //johnfitz + + Cvar_RegisterVariable (&max_edicts, Max_Edicts_f); //johnfitz + Cvar_RegisterVariable (&devstats, NULL); //johnfitz + + Cvar_RegisterVariable (&sys_ticrate, NULL); + Cvar_RegisterVariable (&serverprofile, NULL); + + Cvar_RegisterVariable (&fraglimit, NULL); + Cvar_RegisterVariable (&timelimit, NULL); + Cvar_RegisterVariable (&teamplay, NULL); + Cvar_RegisterVariable (&samelevel, NULL); + Cvar_RegisterVariable (&noexit, NULL); + Cvar_RegisterVariable (&skill, NULL); + Cvar_RegisterVariable (&developer, NULL); + Cvar_RegisterVariable (&deathmatch, NULL); + Cvar_RegisterVariable (&coop, NULL); + + Cvar_RegisterVariable (&pausable, NULL); + + Cvar_RegisterVariable (&temp1, NULL); + + Host_FindMaxClients (); + + host_time = 1.0; // so a think at time 0 won't get called +} + + +/* +=============== +Host_WriteConfiguration + +Writes key bindings and archived cvars to config.cfg +=============== +*/ +void Host_WriteConfiguration (void) +{ + FILE *f; + +// dedicated servers initialize the host but don't parse and set the +// config.cfg cvars + if (host_initialized & !isDedicated) + { + f = fopen (va("%s/config.cfg", com_gamedir), "w"); + if (!f) + { + Con_Printf ("Couldn't write config.cfg.\n"); + return; + } + + VID_SyncCvars (); //johnfitz -- write actual current mode to config file, in case cvars were messed with + + Key_WriteBindings (f); + Cvar_WriteVariables (f); + + //johnfitz -- extra commands to preserve state + fprintf (f, "vid_restart\n"); + if (in_mlook.state & 1) fprintf (f, "+mlook\n"); + //johnfitz + + fclose (f); + +//johnfitz -- also save fitzquake.rc +#if 0 + f = fopen (va("%s/fitzquake.rc", GAMENAME), "w"); //always save in id1 + if (!f) + { + Con_Printf ("Couldn't write fitzquake.rc.\n"); + return; + } + + Cvar_WriteVariables (f); + fprintf (f, "vid_restart\n"); + if (in_mlook.state & 1) fprintf (f, "+mlook\n"); + + fclose (f); +#endif +//johnfitz + } +} + + +/* +================= +SV_ClientPrintf + +Sends text across to be displayed +FIXME: make this just a stuffed echo? +================= +*/ +void SV_ClientPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + MSG_WriteByte (&host_client->message, svc_print); + MSG_WriteString (&host_client->message, string); +} + +/* +================= +SV_BroadcastPrintf + +Sends text to all active clients +================= +*/ +void SV_BroadcastPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + int i; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + for (i=0 ; imessage, svc_stufftext); + MSG_WriteString (&host_client->message, string); +} + +/* +===================== +SV_DropClient + +Called when the player is getting totally kicked off the host +if (crash = true), don't bother sending signofs +===================== +*/ +void SV_DropClient (qboolean crash) +{ + int saveSelf; + int i; + client_t *client; + + if (!crash) + { + // send any final messages (don't check for errors) + if (NET_CanSendMessage (host_client->netconnection)) + { + MSG_WriteByte (&host_client->message, svc_disconnect); + NET_SendMessage (host_client->netconnection, &host_client->message); + } + + if (host_client->edict && host_client->spawned) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + saveSelf = pr_global_struct->self; + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram (pr_global_struct->ClientDisconnect); + pr_global_struct->self = saveSelf; + } + + Sys_Printf ("Client %s removed\n",host_client->name); + } + +// break the net connection + NET_Close (host_client->netconnection); + host_client->netconnection = NULL; + +// free the client (the body stays around) + host_client->active = false; + host_client->name[0] = 0; + host_client->old_frags = -999999; + net_activeconnections--; + +// send notification to all clients + for (i=0, client = svs.clients ; iactive) + continue; + MSG_WriteByte (&client->message, svc_updatename); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteString (&client->message, ""); + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteShort (&client->message, 0); + MSG_WriteByte (&client->message, svc_updatecolors); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteByte (&client->message, 0); + } +} + +/* +================== +Host_ShutdownServer + +This only happens at the end of a game, not between levels +================== +*/ +void Host_ShutdownServer(qboolean crash) +{ + int i; + int count; + sizebuf_t buf; + char message[4]; + double start; + + if (!sv.active) + return; + + sv.active = false; + +// stop all client sounds immediately + if (cls.state == ca_connected) + CL_Disconnect (); + +// flush any pending messages - like the score!!! + start = Sys_FloatTime(); + do + { + count = 0; + for (i=0, host_client = svs.clients ; iactive && host_client->message.cursize) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + NET_SendMessage(host_client->netconnection, &host_client->message); + SZ_Clear (&host_client->message); + } + else + { + NET_GetMessage(host_client->netconnection); + count++; + } + } + } + if ((Sys_FloatTime() - start) > 3.0) + break; + } + while (count); + +// make sure all the clients know we're disconnecting + buf.data = message; + buf.maxsize = 4; + buf.cursize = 0; + MSG_WriteByte(&buf, svc_disconnect); + count = NET_SendToAll(&buf, 5); + if (count) + Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); + + for (i=0, host_client = svs.clients ; iactive) + SV_DropClient(crash); + +// +// clear structures +// + memset (&sv, 0, sizeof(sv)); + memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t)); +} + + +/* +================ +Host_ClearMemory + +This clears all the memory used by both the client and server, but does +not reinitialize anything. +================ +*/ +void Host_ClearMemory (void) +{ + Con_DPrintf ("Clearing memory\n"); + D_FlushCaches (); + Mod_ClearAll (); + if (host_hunklevel) + Hunk_FreeToLowMark (host_hunklevel); + + cls.signon = 0; + memset (&sv, 0, sizeof(sv)); + memset (&cl, 0, sizeof(cl)); +} + + +//============================================================================== +// +// Host Frame +// +//============================================================================== + +/* +=================== +Host_FilterTime + +Returns false if the time is too short to run a frame +=================== +*/ +qboolean Host_FilterTime (float time) +{ + float maxfps; //johnfitz + + realtime += time; + + //johnfitz -- max fps cvar + maxfps = CLAMP (10.0, host_maxfps.value, 1000.0); + if (!cls.timedemo && realtime - oldrealtime < 1.0/maxfps) + return false; // framerate is too high + //johnfitz + + host_frametime = realtime - oldrealtime; + oldrealtime = realtime; + + //johnfitz -- host_timescale is more intuitive than host_framerate + if (host_timescale.value > 0) + host_frametime *= host_timescale.value; + //johnfitz + else if (host_framerate.value > 0) + host_frametime = host_framerate.value; + else // don't allow really long or short frames + host_frametime = CLAMP (0.001, host_frametime, 0.1); //johnfitz -- use CLAMP + + return true; +} + +/* +=================== +Host_GetConsoleCommands + +Add them exactly as if they had been typed at the console +=================== +*/ +void Host_GetConsoleCommands (void) +{ + char *cmd; + + while (1) + { + cmd = Sys_ConsoleInput (); + if (!cmd) + break; + Cbuf_AddText (cmd); + } +} + +/* +================== +Host_ServerFrame +================== +*/ +void Host_ServerFrame (void) +{ + int i, active; //johnfitz + edict_t *ent; //johnfitz + +// run the world state + pr_global_struct->frametime = host_frametime; + +// set the time and clear the general datagram + SV_ClearDatagram (); + +// check for new clients + SV_CheckForNewClients (); + +// read client messages + SV_RunClients (); + +// move things around and think +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_Physics (); + +//johnfitz -- devstats + if (cls.signon == SIGNONS) + { + for (i=0, active=0; ifree) + active++; + } + if (active > 600 && dev_peakstats.edicts <= 600) + Con_Warning ("%i edicts exceeds standard limit of 600.\n", active); + dev_stats.edicts = active; + dev_peakstats.edicts = max(active, dev_peakstats.edicts); + } +//johnfitz + +// send all messages to the clients + SV_SendClientMessages (); +} + +/* +================== +Host_Frame + +Runs all active servers +================== +*/ +void _Host_Frame (float time) +{ + static double time1 = 0; + static double time2 = 0; + static double time3 = 0; + int pass1, pass2, pass3; + + if (setjmp (host_abortserver) ) + return; // something bad happened, or the server disconnected + +// keep the random time dependent + rand (); + +// decide the simulation time + if (!Host_FilterTime (time)) + return; // don't run too fast, or packets will flood out + +// get new key events + //Sys_SendKeyEvents (); not needed for SDL + +// allow mice or other external controllers to add commands + IN_Commands (); + +// process console commands + Cbuf_Execute (); + + NET_Poll(); + +// if running the server locally, make intentions now + if (sv.active) + CL_SendCmd (); + +//------------------- +// +// server operations +// +//------------------- + +// check for commands typed to the host + Host_GetConsoleCommands (); + + if (sv.active) + Host_ServerFrame (); + +//------------------- +// +// client operations +// +//------------------- + +// if running the server remotely, send intentions now after +// the incoming messages have been read + if (!sv.active) + CL_SendCmd (); + + host_time += host_frametime; + +// fetch results from server + if (cls.state == ca_connected) + { + CL_ReadFromServer (); + } + +// update video + if (host_speeds.value) + time1 = Sys_FloatTime (); + + SCR_UpdateScreen (); + + CL_RunParticles (); //johnfitz -- seperated from rendering + + if (host_speeds.value) + time2 = Sys_FloatTime (); + +// update audio + if (cls.signon == SIGNONS) + { + S_Update (r_origin, vpn, vright, vup); + CL_DecayLights (); + } + else + S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin); + + CDAudio_Update(); + + if (host_speeds.value) + { + pass1 = (time1 - time3)*1000; + time3 = Sys_FloatTime (); + pass2 = (time2 - time1)*1000; + pass3 = (time3 - time2)*1000; + Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n", + pass1+pass2+pass3, pass1, pass2, pass3); + } + + host_framecount++; + +} + +void Host_Frame (float time) +{ + double time1, time2; + static double timetotal; + static int timecount; + int i, c, m; + + if (!serverprofile.value) + { + _Host_Frame (time); + return; + } + + time1 = Sys_FloatTime (); + _Host_Frame (time); + time2 = Sys_FloatTime (); + + timetotal += time2 - time1; + timecount++; + + if (timecount < 1000) + return; + + m = timetotal*1000/timecount; + timecount = 0; + timetotal = 0; + c = 0; + for (i=0 ; imemsize = minimum_memory; + + host_parms = *parms; + + if (parms->memsize < minimum_memory) + Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000); + + com_argc = parms->argc; + com_argv = parms->argv; + + Memory_Init (parms->membase, parms->memsize); + Cbuf_Init (); + Cmd_Init (); + Cvar_Init (); //johnfitz + V_Init (); + Chase_Init (); + COM_Init (parms->basedir); + Host_InitLocal (); + W_LoadWadFile (); //johnfitz -- filename is now hard-coded for honesty + Key_Init (); + Con_Init (); + M_Init (); + PR_Init (); + Mod_Init (); + NET_Init (); + SV_Init (); + ExtraMaps_Init (); //johnfitz + Modlist_Init (); //johnfitz + + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); + Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); + + if (cls.state != ca_dedicated) + { + host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); + if (!host_colormap) + Sys_Error ("Couldn't load gfx/colormap.lmp"); + + VID_Init (); + IN_Init (); // moved here, SDL inits the input system with the video system -- kristian + TexMgr_Init (); //johnfitz + Draw_Init (); + SCR_Init (); + R_Init (); + S_Init (); + CDAudio_Init (); + Sbar_Init (); + CL_Init (); + } + + Cbuf_InsertText ("exec quake.rc\n"); +// Cbuf_InsertText ("exec fitzquake.rc\n"); //johnfitz (inserted second so it'll be executed first) + + Cbuf_AddText ("\n\nvid_unlock\n"); //johnfitz -- in case the vid mode was locked during vid_init, we can unlock it now. + //note: added two newlines to the front becuase the command buffer swallows one of them. + + Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); + host_hunklevel = Hunk_LowMark (); + + host_initialized = true; + + Con_Printf ("\n========= Quake Initialized =========\n\n"); //johnfitz - was Sys_Printf +} + + +/* +=============== +Host_Shutdown + +FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better +to run quit through here before the final handoff to the sys code. +=============== +*/ +void Host_Shutdown(void) +{ + static qboolean isdown = false; + + if (isdown) + { + printf ("recursive shutdown\n"); + return; + } + isdown = true; + +// keep Con_Printf from trying to update the screen + scr_disabled_for_loading = true; + + Host_WriteConfiguration (); + + CDAudio_Shutdown (); + NET_Shutdown (); + S_Shutdown(); + + if (cls.state != ca_dedicated) + { + IN_Shutdown (); // input is only initialized in Host_Init if we're not dedicated -- kristian + VID_Shutdown(); + } +} + diff --git a/Quake/host_cmd.c b/Quake/host_cmd.c new file mode 100644 index 00000000..f7441aed --- /dev/null +++ b/Quake/host_cmd.c @@ -0,0 +1,2235 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include "quakedef.h" + +extern cvar_t pausable; + +extern int com_nummissionpacks; //johnfitz + +int current_skill; + +void Mod_Print (void); + +/* +================== +Host_Quit_f +================== +*/ + +extern void M_Menu_Quit_f (void); + +void Host_Quit_f (void) +{ + if (key_dest != key_console && cls.state != ca_dedicated) + { + M_Menu_Quit_f (); + return; + } + CL_Disconnect (); + Host_ShutdownServer(false); + + Sys_Quit (); +} + +//============================================================================== +//johnfitz -- dynamic gamedir stuff +//============================================================================== + +// Declarations shared with common.c: +typedef struct +{ + char name[MAX_QPATH]; + int filepos, filelen; +} packfile_t; + +typedef struct pack_s +{ + char filename[MAX_OSPATH]; + int handle; + int numfiles; + packfile_t *files; +} pack_t; + +typedef struct searchpath_s +{ + char filename[MAX_OSPATH]; + pack_t *pack; // only one of filename / pack will be used + struct searchpath_s *next; +} searchpath_t; + +extern qboolean com_modified; +extern searchpath_t *com_searchpaths; +pack_t *COM_LoadPackFile (char *packfile); + +// Kill all the search packs until the game path is found. Kill it, then return +// the next path to it. +void KillGameDir(searchpath_t *search) +{ + searchpath_t *search_killer; + while (search) + { + if (*search->filename) + { + com_searchpaths = search->next; + Z_Free(search); + return; //once you hit the dir, youve already freed the paks + } + Sys_FileClose (search->pack->handle); //johnfitz + search_killer = search->next; + Z_Free(search->pack->files); + Z_Free(search->pack); + Z_Free(search); + search = search_killer; + } +} + +// Return the number of games in memory +int NumGames(searchpath_t *search) +{ + int found = 0; + while (search) + { + if (*search->filename) + found++; + search = search->next; + } + return found; +} + +void ExtraMaps_NewGame (void); + +/* +================== +Host_Game_f +================== +*/ +void Host_Game_f (void) +{ + int i; + searchpath_t *search = com_searchpaths; + pack_t *pak; + char pakfile[MAX_OSPATH]; //FIXME: it's confusing to use this string for two different things + + if (Cmd_Argc() > 1) + { + + if (!registered.value) //disable command for shareware quake + { + Con_Printf("You must have the registered version to use modified games\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + strcpy (pakfile, va("%s/%s", host_parms.basedir, Cmd_Argv(1))); + if (!Q_strcasecmp(pakfile, com_gamedir)) //no change + { + Con_Printf("\"game\" is already \"%s\"\n", COM_SkipPath(com_gamedir)); + return; + } + + com_modified = true; + + //Kill the server + CL_Disconnect (); + Host_ShutdownServer(true); + + //Write config file + Host_WriteConfiguration (); + + //Kill the extra game if it is loaded + if (NumGames(com_searchpaths) > 1 + com_nummissionpacks) + KillGameDir(com_searchpaths); + + strcpy (com_gamedir, pakfile); + + if (Q_strcasecmp(Cmd_Argv(1), GAMENAME)) //game is not id1 + { + search = Z_Malloc(sizeof(searchpath_t)); + strcpy (search->filename, pakfile); + search->next = com_searchpaths; + com_searchpaths = search; + + //Load the paks if any are found: + for (i = 0; ; i++) + { + sprintf (pakfile, "%s/pak%i.pak", com_gamedir, i); + pak = COM_LoadPackFile (pakfile); + if (!pak) + break; + search = Z_Malloc(sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + } + } + + //clear out and reload appropriate data + Cache_Flush (); + if (!isDedicated) + { + TexMgr_NewGame (); + Draw_NewGame (); + R_NewGame (); + } + ExtraMaps_NewGame (); + //Cbuf_InsertText ("exec quake.rc\n"); + + Con_Printf("\"game\" changed to \"%s\"\n", COM_SkipPath(com_gamedir)); + } + else //Diplay the current gamedir + Con_Printf("\"game\" is \"%s\"\n", COM_SkipPath(com_gamedir)); +} + +//============================================================================== +//johnfitz -- extramaps management +//============================================================================== + +typedef struct extralevel_s +{ + char name[32]; + struct extralevel_s *next; +} extralevel_t; + +extralevel_t *extralevels; + +void ExtraMaps_Add (char *name) +{ + extralevel_t *level,*cursor,*prev; + + //ingore duplicate + for (level = extralevels; level; level = level->next) + if (!Q_strcmp (name, level->name)) + return; + + level = Z_Malloc(sizeof(extralevel_t)); + strcpy (level->name, name); + + //insert each entry in alphabetical order + if (extralevels == NULL || Q_strcasecmp(level->name, extralevels->name) > 0) //insert at front + { + level->next = extralevels; + extralevels = level; + } + else //insert later + { + prev = extralevels; + cursor = extralevels->next; + while (cursor && (Q_strcasecmp(level->name, cursor->name) < 0)) + { + prev = cursor; + cursor = cursor->next; + } + level->next = prev->next; + prev->next = level; + } +} + +void ExtraMaps_Init (void) +{ + DIR *dir_p; + struct dirent *dir_t; + char filestring[MAX_OSPATH]; + char mapname[32]; + char ignorepakdir[32]; + searchpath_t *search; + pack_t *pak; + int i; + + //we don't want to list the maps in id1 pakfiles, becuase these are not "add-on" levels + sprintf (ignorepakdir, "/%s/", GAMENAME); + + for (search = com_searchpaths ; search ; search = search->next) + { + if (*search->filename) //directory + { + sprintf (filestring,"%s/maps/",search->filename); + dir_p = opendir(filestring); + + if (dir_p == NULL) + continue; + + while ((dir_t = readdir(dir_p)) != NULL) + { + if (!strstr(dir_t->d_name, ".bsp") && !strstr(dir_t->d_name, ".BSP")) + continue; + + COM_StripExtension(dir_t->d_name, mapname); + ExtraMaps_Add (mapname); + } + + closedir(dir_p); + } + else //pakfile + { + if (!strstr(search->pack->filename, ignorepakdir)) //don't list standard id maps + for (i=0, pak=search->pack; inumfiles ; i++) + if (strstr(pak->files[i].name, ".bsp")) + if (pak->files[i].filelen > 32*1024) // don't list files under 32k (ammo boxes etc) + { + COM_StripExtension(pak->files[i].name + 5, mapname); + ExtraMaps_Add (mapname); + } + } + } +} + +void ExtraMaps_Clear (void) +{ + extralevel_t *blah; + + while (extralevels) + { + blah = extralevels->next; + Z_Free(extralevels); + extralevels = blah; + } +} + +void ExtraMaps_NewGame (void) +{ + ExtraMaps_Clear (); + ExtraMaps_Init (); +} + +/* +================== +Host_Maps_f +================== +*/ +void Host_Maps_f (void) +{ + int i; + extralevel_t *level; + + for (level=extralevels, i=0; level; level=level->next, i++) + Con_SafePrintf (" %s\n", level->name); + + if (i) + Con_SafePrintf ("%i map(s)\n", i); + else + Con_SafePrintf ("no maps found\n"); +} + +//============================================================================== +//johnfitz -- modlist management +//============================================================================== + +typedef struct mod_s +{ + char name[MAX_OSPATH]; + struct mod_s *next; +} mod_t; + +mod_t *modlist; + +void Modlist_Add (char *name) +{ + mod_t *mod,*cursor,*prev; + + //ingore duplicate + for (mod = modlist; mod; mod = mod->next) + if (!Q_strcmp (name, mod->name)) + return; + + mod = Z_Malloc(sizeof(mod_t)); + strcpy (mod->name, name); + + //insert each entry in alphabetical order + if (modlist == NULL || Q_strcasecmp(mod->name, modlist->name) > 0) //insert at front + { + mod->next = modlist; + modlist = mod; + } + else //insert later + { + prev = modlist; + cursor = modlist->next; + while (cursor && (Q_strcasecmp(mod->name, cursor->name) < 0)) + { + prev = cursor; + cursor = cursor->next; + } + mod->next = prev->next; + prev->next = mod; + } +} + +void Modlist_Init (void) +{ + DIR *dir_p, *mod_dir_p; + struct dirent *dir_t, *mod_dir_t; + qboolean progs_found, pak_found; + char dir_string[MAX_OSPATH], mod_dir_string[MAX_OSPATH]; + int i; + + i = COM_CheckParm ("-basedir"); + if (i && i < com_argc-1) + sprintf (dir_string, "%s/", com_argv[i+1]); + else + sprintf (dir_string, "%s/", host_parms.basedir); + + dir_p = opendir(dir_string); + if (dir_p == NULL) + return; + + while ((dir_t = readdir(dir_p)) != NULL) + { + if ((strcmp(dir_t->d_name, ".") == 0) || (strcmp(dir_t->d_name, "..") == 0)) + continue; + + sprintf(mod_dir_string, "%s%s/", dir_string, dir_t->d_name); + mod_dir_p = opendir(mod_dir_string); + + if (mod_dir_p == NULL) + continue; + + progs_found = false; + pak_found = false; + + // find progs.dat and pak file(s) + while ((mod_dir_t = readdir(mod_dir_p)) != NULL) + { + if ((strcmp(mod_dir_t->d_name, ".") == 0) || (strcmp(mod_dir_t->d_name, "..") == 0)) + continue; + + if (Q_strcasecmp(mod_dir_t->d_name, "progs.dat") != -1) + progs_found = true; + + if (strstr(mod_dir_t->d_name, ".pak") || strstr(mod_dir_t->d_name, ".PAK")) + pak_found = true; + + if (progs_found || pak_found) + break; + } + closedir(mod_dir_p); + + if (!progs_found && !pak_found) + continue; + + Modlist_Add(dir_t->d_name); + } + + closedir(dir_p); +} + +/* +================== +Host_Mods_f -- johnfitz + +list all potential mod directories (contain either a pak file or a progs.dat) +================== +*/ +void Host_Mods_f (void) +{ + int i; + mod_t *mod; + + for (mod = modlist, i=0; mod; mod = mod->next, i++) + Con_SafePrintf (" %s\n", mod->name); + + if (i) + Con_SafePrintf ("%i mod(s)\n", i); + else + Con_SafePrintf ("no mods found\n"); +} + +//============================================================================== + +/* +============= +Host_Mapname_f -- johnfitz +============= +*/ +void Host_Mapname_f (void) +{ + char name[MAX_QPATH]; + + if (sv.active) + { + COM_StripExtension (sv.worldmodel->name + 5, name); + Con_Printf ("\"mapname\" is \"%s\"\n", name); + return; + } + + if (cls.state == ca_connected) + { + COM_StripExtension (cl.worldmodel->name + 5, name); + Con_Printf ("\"mapname\" is \"%s\"\n", name); + return; + } + + Con_Printf ("no map loaded\n"); +} + +/* +================== +Host_Status_f +================== +*/ +void Host_Status_f (void) +{ + client_t *client; + int seconds; + int minutes; + int hours = 0; + int j; + void (*print) (char *fmt, ...); + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + print ("host: %s\n", Cvar_VariableString ("hostname")); + print ("version: %4.2f\n", VERSION); + if (tcpipAvailable) + print ("tcp/ip: %s\n", my_tcpip_address); + if (ipxAvailable) + print ("ipx: %s\n", my_ipx_address); + print ("map: %s\n", sv.name); + print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients); + for (j=0, client = svs.clients ; jactive) + continue; + seconds = (int)(net_time - client->netconnection->connecttime); + minutes = seconds / 60; + if (minutes) + { + seconds -= (minutes * 60); + hours = minutes / 60; + if (hours) + minutes -= (hours * 60); + } + else + hours = 0; + print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds); + print (" %s\n", client->netconnection->address); + } +} + +/* +================== +Host_God_f + +Sets client to godmode +================== +*/ +void Host_God_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + //johnfitz -- allow user to explicitly set god mode to on or off + switch (Cmd_Argc()) + { + case 1: + sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE; + if (!((int)sv_player->v.flags & FL_GODMODE) ) + SV_ClientPrintf ("godmode OFF\n"); + else + SV_ClientPrintf ("godmode ON\n"); + break; + case 2: + if (Q_atof(Cmd_Argv(1))) + { + sv_player->v.flags = (int)sv_player->v.flags | FL_GODMODE; + SV_ClientPrintf ("godmode ON\n"); + } + else + { + sv_player->v.flags = (int)sv_player->v.flags & ~FL_GODMODE; + SV_ClientPrintf ("godmode OFF\n"); + } + break; + default: + Con_Printf("god [value] : toggle god mode. values: 0 = off, 1 = on\n"); + break; + } + //johnfitz +} + +/* +================== +Host_Notarget_f +================== +*/ +void Host_Notarget_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + //johnfitz -- allow user to explicitly set notarget to on or off + switch (Cmd_Argc()) + { + case 1: + sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET; + if (!((int)sv_player->v.flags & FL_NOTARGET) ) + SV_ClientPrintf ("notarget OFF\n"); + else + SV_ClientPrintf ("notarget ON\n"); + break; + case 2: + if (Q_atof(Cmd_Argv(1))) + { + sv_player->v.flags = (int)sv_player->v.flags | FL_NOTARGET; + SV_ClientPrintf ("notarget ON\n"); + } + else + { + sv_player->v.flags = (int)sv_player->v.flags & ~FL_NOTARGET; + SV_ClientPrintf ("notarget OFF\n"); + } + break; + default: + Con_Printf("notarget [value] : toggle notarget mode. values: 0 = off, 1 = on\n"); + break; + } + //johnfitz +} + +qboolean noclip_anglehack; + +/* +================== +Host_Noclip_f +================== +*/ +void Host_Noclip_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + //johnfitz -- allow user to explicitly set noclip to on or off + switch (Cmd_Argc()) + { + case 1: + if (sv_player->v.movetype != MOVETYPE_NOCLIP) + { + noclip_anglehack = true; + sv_player->v.movetype = MOVETYPE_NOCLIP; + SV_ClientPrintf ("noclip ON\n"); + } + else + { + noclip_anglehack = false; + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("noclip OFF\n"); + } + break; + case 2: + if (Q_atof(Cmd_Argv(1))) + { + noclip_anglehack = true; + sv_player->v.movetype = MOVETYPE_NOCLIP; + SV_ClientPrintf ("noclip ON\n"); + } + else + { + noclip_anglehack = false; + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("noclip OFF\n"); + } + break; + default: + Con_Printf("noclip [value] : toggle noclip mode. values: 0 = off, 1 = on\n"); + break; + } + //johnfitz +} + +/* +================== +Host_Fly_f + +Sets client to flymode +================== +*/ +void Host_Fly_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + //johnfitz -- allow user to explicitly set noclip to on or off + switch (Cmd_Argc()) + { + case 1: + if (sv_player->v.movetype != MOVETYPE_FLY) + { + sv_player->v.movetype = MOVETYPE_FLY; + SV_ClientPrintf ("flymode ON\n"); + } + else + { + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("flymode OFF\n"); + } + break; + case 2: + if (Q_atof(Cmd_Argv(1))) + { + sv_player->v.movetype = MOVETYPE_FLY; + SV_ClientPrintf ("flymode ON\n"); + } + else + { + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("flymode OFF\n"); + } + break; + default: + Con_Printf("fly [value] : toggle fly mode. values: 0 = off, 1 = on\n"); + break; + } + //johnfitz +} + + +/* +================== +Host_Ping_f + +================== +*/ +void Host_Ping_f (void) +{ + int i, j; + float total; + client_t *client; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + SV_ClientPrintf ("Client ping times:\n"); + for (i=0, client = svs.clients ; iactive) + continue; + total = 0; + for (j=0 ; jping_times[j]; + total /= NUM_PING_TIMES; + SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name); + } +} + +/* +=============================================================================== + +SERVER TRANSITIONS + +=============================================================================== +*/ + + +/* +====================== +Host_Map_f + +handle a +map +command from the console. Active clients are kicked off. +====================== +*/ +void Host_Map_f (void) +{ + int i; + char name[MAX_QPATH]; + + if (cmd_source != src_command) + return; + + cls.demonum = -1; // stop demo loop in case this fails + + CL_Disconnect (); + Host_ShutdownServer(false); + + IN_Activate(); + key_dest = key_game; // remove console or menu + SCR_BeginLoadingPlaque (); + + cls.mapstring[0] = 0; + for (i=0 ; i : continue game on a new level\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + + //johnfitz -- check for client having map before anything else + sprintf (level, "maps/%s.bsp", Cmd_Argv(1)); + if (COM_OpenFile (level, &i) == -1) + Host_Error ("cannot find map %s", level); + //johnfitz + + SV_SaveSpawnparms (); + strcpy (level, Cmd_Argv(1)); + SV_SpawnServer (level); +} + +/* +================== +Host_Restart_f + +Restarts the current server for a dead player +================== +*/ +void Host_Restart_f (void) +{ + char mapname[MAX_QPATH]; + + if (cls.demoplayback || !sv.active) + return; + + if (cmd_source != src_command) + return; + strcpy (mapname, sv.name); // must copy out, because it gets cleared + // in sv_spawnserver + SV_SpawnServer (mapname); +} + +/* +================== +Host_Reconnect_f + +This command causes the client to wait for the signon messages again. +This is sent just before a server changes levels +================== +*/ +void Host_Reconnect_f (void) +{ + SCR_BeginLoadingPlaque (); + cls.signon = 0; // need new connection messages +} + +/* +===================== +Host_Connect_f + +User command to connect to server +===================== +*/ +void Host_Connect_f (void) +{ + char name[MAX_QPATH]; + + cls.demonum = -1; // stop demo loop in case this fails + if (cls.demoplayback) + { + CL_StopPlayback (); + CL_Disconnect (); + } + strcpy (name, Cmd_Argv(1)); + CL_EstablishConnection (name); + Host_Reconnect_f (); +} + + +/* +=============================================================================== + +LOAD / SAVE GAME + +=============================================================================== +*/ + +#define SAVEGAME_VERSION 5 + +/* +=============== +Host_SavegameComment + +Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current +=============== +*/ +void Host_SavegameComment (char *text) +{ + int i; + char kills[20]; + + for (i=0 ; i : save a game\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + for (i=0 ; iv.health <= 0) ) + { + Con_Printf ("Can't savegame with a dead player\n"); + return; + } + } + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + + Con_Printf ("Saving game to %s...\n", name); + f = fopen (name, "w"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fprintf (f, "%i\n", SAVEGAME_VERSION); + Host_SavegameComment (comment); + fprintf (f, "%s\n", comment); + for (i=0 ; ispawn_parms[i]); + fprintf (f, "%d\n", current_skill); + fprintf (f, "%s\n", sv.name); + fprintf (f, "%f\n",sv.time); + +// write the light styles + + for (i=0 ; i : load a game\n"); + return; + } + + cls.demonum = -1; // stop demo loop in case this fails + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + +// we can't call SCR_BeginLoadingPlaque, because too much stack space has +// been used. The menu calls it before stuffing loadgame command +// SCR_BeginLoadingPlaque (); + + Con_Printf ("Loading game from %s...\n", name); + f = fopen (name, "r"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fscanf (f, "%i\n", &version); + if (version != SAVEGAME_VERSION) + { + fclose (f); + Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return; + } + fscanf (f, "%s\n", str); + for (i=0 ; iv, 0, progs->entityfields * 4); + ent->free = false; + ED_ParseEdict (start, ent); + + // link it into the bsp tree + if (!ent->free) + SV_LinkEdict (ent, false); + } + + entnum++; + } + + sv.num_edicts = entnum; + sv.time = time; + + fclose (f); + + for (i=0 ; ispawn_parms[i] = spawn_parms[i]; + + if (cls.state != ca_dedicated) + { + CL_EstablishConnection ("local"); + Host_Reconnect_f (); + } +} + +//============================================================================ + +/* +====================== +Host_Name_f +====================== +*/ +void Host_Name_f (void) +{ + char *newName; + + if (Cmd_Argc () == 1) + { + Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); + return; + } + if (Cmd_Argc () == 2) + newName = Cmd_Argv(1); + else + newName = Cmd_Args(); + newName[15] = 0; + + if (cmd_source == src_command) + { + if (Q_strcmp(cl_name.string, newName) == 0) + return; + Cvar_Set ("_cl_name", newName); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) + if (Q_strcmp(host_client->name, newName) != 0) + Con_Printf ("%s renamed to %s\n", host_client->name, newName); + Q_strcpy (host_client->name, newName); + host_client->edict->v.netname = host_client->name - pr_strings; + +// send notification to all clients + + MSG_WriteByte (&sv.reliable_datagram, svc_updatename); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteString (&sv.reliable_datagram, host_client->name); +} + + +void Host_Version_f (void) +{ + Con_Printf ("Quake Version %1.2f\n", VERSION); //johnfitz + Con_Printf ("FitzQuake (SDL port) Version %1.2f\n", FITZQUAKE_VERSION); //johnfitz + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); +} + +void Host_Say(qboolean teamonly) +{ + client_t *client; + client_t *save; + int j; + char *p; + // removed unsigned keyword -- kristian + char text[64]; + qboolean fromServer = false; + + if (cmd_source == src_command) + { + if (cls.state == ca_dedicated) + { + fromServer = true; + teamonly = false; + } + else + { + Cmd_ForwardToServer (); + return; + } + } + + if (Cmd_Argc () < 2) + return; + + save = host_client; + + p = Cmd_Args(); +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// turn on color set 1 + if (!fromServer) + sprintf (text, "%c%s: ", 1, save->name); + else + sprintf (text, "%c<%s> ", 1, hostname.string); + + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) + { + if (!client || !client->active || !client->spawned) + continue; + if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team) + continue; + host_client = client; + SV_ClientPrintf("%s", text); + } + host_client = save; + + Sys_Printf("%s", &text[1]); +} + + +void Host_Say_f(void) +{ + Host_Say(false); +} + + +void Host_Say_Team_f(void) +{ + Host_Say(true); +} + + +void Host_Tell_f(void) +{ + client_t *client; + client_t *save; + int j; + char *p; + char text[64]; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (Cmd_Argc () < 3) + return; + + Q_strcpy(text, host_client->name); + Q_strcat(text, ": "); + + p = Cmd_Args(); + +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// check length & truncate if necessary + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + save = host_client; + for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) + { + if (!client->active || !client->spawned) + continue; + if (Q_strcasecmp(client->name, Cmd_Argv(1))) + continue; + host_client = client; + SV_ClientPrintf("%s", text); + break; + } + host_client = save; +} + + +/* +================== +Host_Color_f +================== +*/ +void Host_Color_f(void) +{ + int top, bottom; + int playercolor; + + if (Cmd_Argc() == 1) + { + Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f); + Con_Printf ("color <0-13> [0-13]\n"); + return; + } + + if (Cmd_Argc() == 2) + top = bottom = atoi(Cmd_Argv(1)); + else + { + top = atoi(Cmd_Argv(1)); + bottom = atoi(Cmd_Argv(2)); + } + + top &= 15; + if (top > 13) + top = 13; + bottom &= 15; + if (bottom > 13) + bottom = 13; + + playercolor = top*16 + bottom; + + if (cmd_source == src_command) + { + Cvar_SetValue ("_cl_color", playercolor); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + host_client->colors = playercolor; + host_client->edict->v.team = bottom + 1; + +// send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteByte (&sv.reliable_datagram, host_client->colors); +} + +/* +================== +Host_Kill_f +================== +*/ +void Host_Kill_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (sv_player->v.health <= 0) + { + SV_ClientPrintf ("Can't suicide -- allready dead!\n"); + return; + } + + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(sv_player); + PR_ExecuteProgram (pr_global_struct->ClientKill); +} + + +/* +================== +Host_Pause_f +================== +*/ +void Host_Pause_f (void) +{ + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + if (!pausable.value) + SV_ClientPrintf ("Pause not allowed.\n"); + else + { + sv.paused ^= 1; + + if (sv.paused) + { + SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->v.netname); + } + else + { + SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->v.netname); + } + + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_setpause); + MSG_WriteByte (&sv.reliable_datagram, sv.paused); + } +} + +//=========================================================================== + + +/* +================== +Host_PreSpawn_f +================== +*/ +void Host_PreSpawn_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("prespawn is not valid from the console\n"); + return; + } + + if (host_client->spawned) + { + Con_Printf ("prespawn not valid -- allready spawned\n"); + return; + } + + SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize); + MSG_WriteByte (&host_client->message, svc_signonnum); + MSG_WriteByte (&host_client->message, 2); + host_client->sendsignon = true; +} + +/* +================== +Host_Spawn_f +================== +*/ +void Host_Spawn_f (void) +{ + int i; + client_t *client; + edict_t *ent; + + if (cmd_source == src_command) + { + Con_Printf ("spawn is not valid from the console\n"); + return; + } + + if (host_client->spawned) + { + Con_Printf ("Spawn not valid -- allready spawned\n"); + return; + } + +// run the entrance script + if (sv.loadgame) + { // loaded games are fully inited allready + // if this is the last client to be connected, unpause + sv.paused = false; + } + else + { + // set up the edict + ent = host_client->edict; + + memset (&ent->v, 0, progs->entityfields * 4); + ent->v.colormap = NUM_FOR_EDICT(ent); + ent->v.team = (host_client->colors & 15) + 1; + ent->v.netname = host_client->name - pr_strings; + + // copy spawn parms out of the client_t + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; + + // call the spawn function + + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(sv_player); + PR_ExecuteProgram (pr_global_struct->ClientConnect); + + if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time) + Sys_Printf ("%s entered the game\n", host_client->name); + + PR_ExecuteProgram (pr_global_struct->PutClientInServer); + } + + +// send all current names, colors, and frag counts + SZ_Clear (&host_client->message); + +// send time of update + MSG_WriteByte (&host_client->message, svc_time); + MSG_WriteFloat (&host_client->message, sv.time); + + for (i=0, client = svs.clients ; imessage, svc_updatename); + MSG_WriteByte (&host_client->message, i); + MSG_WriteString (&host_client->message, client->name); + MSG_WriteByte (&host_client->message, svc_updatefrags); + MSG_WriteByte (&host_client->message, i); + MSG_WriteShort (&host_client->message, client->old_frags); + MSG_WriteByte (&host_client->message, svc_updatecolors); + MSG_WriteByte (&host_client->message, i); + MSG_WriteByte (&host_client->message, client->colors); + } + +// send all current light styles + for (i=0 ; imessage, svc_lightstyle); + MSG_WriteByte (&host_client->message, (char)i); + MSG_WriteString (&host_client->message, sv.lightstyles[i]); + } + +// +// send some stats +// + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS); + MSG_WriteLong (&host_client->message, pr_global_struct->total_secrets); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS); + MSG_WriteLong (&host_client->message, pr_global_struct->total_monsters); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_SECRETS); + MSG_WriteLong (&host_client->message, pr_global_struct->found_secrets); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_MONSTERS); + MSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters); + + +// +// send a fixangle +// Never send a roll angle, because savegames can catch the server +// in a state where it is expecting the client to correct the angle +// and it won't happen if the game was just loaded, so you wind up +// with a permanent head tilt + ent = EDICT_NUM( 1 + (host_client - svs.clients) ); + MSG_WriteByte (&host_client->message, svc_setangle); + for (i=0 ; i < 2 ; i++) + MSG_WriteAngle (&host_client->message, ent->v.angles[i] ); + MSG_WriteAngle (&host_client->message, 0 ); + + SV_WriteClientdataToMessage (sv_player, &host_client->message); + + MSG_WriteByte (&host_client->message, svc_signonnum); + MSG_WriteByte (&host_client->message, 3); + host_client->sendsignon = true; +} + +/* +================== +Host_Begin_f +================== +*/ +void Host_Begin_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("begin is not valid from the console\n"); + return; + } + + host_client->spawned = true; +} + +//=========================================================================== + + +/* +================== +Host_Kick_f + +Kicks a user off of the server +================== +*/ +void Host_Kick_f (void) +{ + char *who; + char *message = NULL; + client_t *save; + int i; + qboolean byNumber = false; + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + } + else if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + save = host_client; + + if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + i = Q_atof(Cmd_Argv(2)) - 1; + if (i < 0 || i >= svs.maxclients) + return; + if (!svs.clients[i].active) + return; + host_client = &svs.clients[i]; + byNumber = true; + } + else + { + for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) + { + if (!host_client->active) + continue; + if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0) + break; + } + } + + if (i < svs.maxclients) + { + if (cmd_source == src_command) + if (cls.state == ca_dedicated) + who = "Console"; + else + who = cl_name.string; + else + who = save->name; + + // can't kick yourself! + if (host_client == save) + return; + + if (Cmd_Argc() > 2) + { + message = COM_Parse(Cmd_Args()); + if (byNumber) + { + message++; // skip the # + while (*message == ' ') // skip white space + message++; + message += Q_strlen(Cmd_Argv(2)); // skip the number + } + while (*message && *message == ' ') + message++; + } + if (message) + SV_ClientPrintf ("Kicked by %s: %s\n", who, message); + else + SV_ClientPrintf ("Kicked by %s\n", who); + SV_DropClient (false); + } + + host_client = save; +} + +/* +=============================================================================== + +DEBUGGING TOOLS + +=============================================================================== +*/ + +/* +================== +Host_Give_f +================== +*/ +void Host_Give_f (void) +{ + char *t; + int v; + eval_t *val; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + t = Cmd_Argv(1); + v = atoi (Cmd_Argv(2)); + + switch (t[0]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // MED 01/04/97 added hipnotic give stuff + if (hipnotic) + { + if (t[0] == '6') + { + if (t[1] == 'a') + sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN; + else + sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER; + } + else if (t[0] == '9') + sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON; + else if (t[0] == '0') + sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR; + else if (t[0] >= '2') + sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2')); + } + else + { + if (t[0] >= '2') + sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2')); + } + break; + + case 's': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_shells1"); + if (val) + val->_float = v; + } + + sv_player->v.ammo_shells = v; + break; + case 'n': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_nails1"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_nails = v; + } + } + else + { + sv_player->v.ammo_nails = v; + } + break; + case 'l': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_lava_nails"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_nails = v; + } + } + break; + case 'r': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_rockets1"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_rockets = v; + } + } + else + { + sv_player->v.ammo_rockets = v; + } + break; + case 'm': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_multi_rockets"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_rockets = v; + } + } + break; + case 'h': + sv_player->v.health = v; + break; + case 'c': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_cells1"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_cells = v; + } + } + else + { + sv_player->v.ammo_cells = v; + } + break; + case 'p': + if (rogue) + { + val = GetEdictFieldValue(sv_player, "ammo_plasma"); + if (val) + { + val->_float = v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_cells = v; + } + } + break; + //johnfitz -- give armour + case 'a': + if (v > 150) + { + sv_player->v.armortype = 0.8; + sv_player->v.armorvalue = v; + sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR3; + } + else if (v > 100) + { + sv_player->v.armortype = 0.6; + sv_player->v.armorvalue = v; + sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR2; + } + else if (v >= 0) + { + sv_player->v.armortype = 0.3; + sv_player->v.armorvalue = v; + sv_player->v.items = sv_player->v.items - ((int)(sv_player->v.items) & (int)(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + IT_ARMOR1; + } + break; + //johnfitz + } + + //johnfitz -- update currentammo to match new ammo (so statusbar updates correctly) + switch ((int)(sv_player->v.weapon)) + { + case IT_SHOTGUN: + case IT_SUPER_SHOTGUN: + sv_player->v.currentammo = sv_player->v.ammo_shells; + break; + case IT_NAILGUN: + case IT_SUPER_NAILGUN: + case RIT_LAVA_SUPER_NAILGUN: + sv_player->v.currentammo = sv_player->v.ammo_nails; + break; + case IT_GRENADE_LAUNCHER: + case IT_ROCKET_LAUNCHER: + case RIT_MULTI_GRENADE: + case RIT_MULTI_ROCKET: + sv_player->v.currentammo = sv_player->v.ammo_rockets; + break; + case IT_LIGHTNING: + case HIT_LASER_CANNON: + case HIT_MJOLNIR: + sv_player->v.currentammo = sv_player->v.ammo_cells; + break; + case RIT_LAVA_NAILGUN: //same as IT_AXE + if (rogue) + sv_player->v.currentammo = sv_player->v.ammo_nails; + break; + case RIT_PLASMA_GUN: //same as HIT_PROXIMITY_GUN + if (rogue) + sv_player->v.currentammo = sv_player->v.ammo_cells; + if (hipnotic) + sv_player->v.currentammo = sv_player->v.ammo_rockets; + break; + } + //johnfitz +} + +edict_t *FindViewthing (void) +{ + int i; + edict_t *e; + + for (i=0 ; iv.classname, "viewthing") ) + return e; + } + Con_Printf ("No viewthing on map\n"); + return NULL; +} + +/* +================== +Host_Viewmodel_f +================== +*/ +void Host_Viewmodel_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + + m = Mod_ForName (Cmd_Argv(1), false); + if (!m) + { + Con_Printf ("Can't load %s\n", Cmd_Argv(1)); + return; + } + + e->v.frame = 0; + cl.model_precache[(int)e->v.modelindex] = m; +} + +/* +================== +Host_Viewframe_f +================== +*/ +void Host_Viewframe_f (void) +{ + edict_t *e; + int f; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + m = cl.model_precache[(int)e->v.modelindex]; + + f = atoi(Cmd_Argv(1)); + if (f >= m->numframes) + f = m->numframes-1; + + e->v.frame = f; +} + + +void PrintFrameName (model_t *m, int frame) +{ + aliashdr_t *hdr; + maliasframedesc_t *pframedesc; + + hdr = (aliashdr_t *)Mod_Extradata (m); + if (!hdr) + return; + pframedesc = &hdr->frames[frame]; + + Con_Printf ("frame %i: %s\n", frame, pframedesc->name); +} + +/* +================== +Host_Viewnext_f +================== +*/ +void Host_Viewnext_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + m = cl.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame + 1; + if (e->v.frame >= m->numframes) + e->v.frame = m->numframes - 1; + + PrintFrameName (m, e->v.frame); +} + +/* +================== +Host_Viewprev_f +================== +*/ +void Host_Viewprev_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + + m = cl.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame - 1; + if (e->v.frame < 0) + e->v.frame = 0; + + PrintFrameName (m, e->v.frame); +} + +/* +=============================================================================== + +DEMO LOOP CONTROL + +=============================================================================== +*/ + + +/* +================== +Host_Startdemos_f +================== +*/ +void Host_Startdemos_f (void) +{ + int i, c; + + if (cls.state == ca_dedicated) + { + if (!sv.active) + Cbuf_AddText ("map start\n"); + return; + } + + c = Cmd_Argc() - 1; + if (c > MAX_DEMOS) + { + Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS); + c = MAX_DEMOS; + } + Con_Printf ("%i demo(s) in loop\n", c); + + for (i=1 ; i>8; + header[14] = height&255; + header[15] = height>>8; + header[16] = bpp; // pixel size + if (upsidedown) + header[17] = 0x20; //upside-down attribute + + // swap red and blue bytes + bytes = bpp/8; + size = width*height*bytes; + for (i=0; i=0; row--) + { + //johnfitz -- fix for upside-down targas + realrow = upside_down ? row : rows - 1 - row; + pixbuf = targa_rgba + realrow*columns*4; + //johnfitz + for(column=0; column=0; row--) + { + //johnfitz -- fix for upside-down targas + realrow = upside_down ? row : rows - 1 - row; + pixbuf = targa_rgba + realrow*columns*4; + //johnfitz + for(column=0; column0) + row--; + else + goto breakOut; + //johnfitz -- fix for upside-down targas + realrow = upside_down ? row : rows - 1 - row; + pixbuf = targa_rgba + realrow*columns*4; + //johnfitz + } + } + } + else // non run-length packet + { + for(j=0;j0) + row--; + else + goto breakOut; + //johnfitz -- fix for upside-down targas + realrow = upside_down ? row : rows - 1 - row; + pixbuf = targa_rgba + realrow*columns*4; + //johnfitz + } + } + } + } + breakOut:; + } + } + + fclose(fin); + + *width = (int)(targa_header.width); + *height = (int)(targa_header.height); + return targa_rgba; +} + +//============================================================================== +// +// PCX +// +//============================================================================== + +typedef struct +{ + char signature; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hdpi,vdpi; + byte colortable[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; +} pcxheader_t; + +/* +============ +Image_LoadPCX +============ +*/ +byte *Image_LoadPCX (FILE *f, int *width, int *height) +{ + pcxheader_t pcx; + int x, y, w, h, readbyte, runlength, start; + byte *p, *data; + byte palette[768]; + + start = ftell (f); //save start of file (since we might be inside a pak file, SEEK_SET might not be the start of the pcx) + + fread(&pcx, sizeof(pcx), 1, f); + pcx.xmin = (unsigned short)LittleShort (pcx.xmin); + pcx.ymin = (unsigned short)LittleShort (pcx.ymin); + pcx.xmax = (unsigned short)LittleShort (pcx.xmax); + pcx.ymax = (unsigned short)LittleShort (pcx.ymax); + pcx.bytes_per_line = (unsigned short)LittleShort (pcx.bytes_per_line); + + if (pcx.signature != 0x0A) + Sys_Error ("'%s' is not a valid PCX file", loadfilename); + + if (pcx.version != 5) + Sys_Error ("'%s' is version %i, should be 5", loadfilename, pcx.version); + + if (pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.color_planes != 1) + Sys_Error ("'%s' has wrong encoding or bit depth", loadfilename); + + w = pcx.xmax - pcx.xmin + 1; + h = pcx.ymax - pcx.ymin + 1; + + data = Hunk_Alloc((w*h+1)*4); //+1 to allow reading padding byte on last line + + //load palette + fseek (f, start + com_filesize - 768, SEEK_SET); + fread (palette, 1, 768, f); + + //back to start of image data + fseek (f, start + sizeof(pcx), SEEK_SET); + + for (y=0; y= 0xC0) + { + runlength = readbyte & 0x3F; + readbyte = fgetc(f); + } + else + runlength = 1; + + while(runlength--) + { + p[0] = palette[readbyte*3]; + p[1] = palette[readbyte*3+1]; + p[2] = palette[readbyte*3+2]; + p[3] = 255; + p += 4; + x++; + } + } + } + + fclose(f); + + *width = w; + *height = h; + return data; +} diff --git a/Quake/image.h b/Quake/image.h new file mode 100644 index 00000000..9d41f4aa --- /dev/null +++ b/Quake/image.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +//image.h -- image reading / writing + +//be sure to free the hunk after using these loading functions +byte *Image_LoadTGA (FILE *f, int *width, int *height); +byte *Image_LoadPCX (FILE *f, int *width, int *height); +byte *Image_LoadImage (char *name, int *width, int *height); + +qboolean Image_WriteTGA (char *name, byte *data, int width, int height, int bpp, qboolean upsidedown); diff --git a/Quake/in_sdl.c b/Quake/in_sdl.c new file mode 100644 index 00000000..b16cdedd --- /dev/null +++ b/Quake/in_sdl.c @@ -0,0 +1,168 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +// mouse variables +cvar_t m_filter = {"m_filter","0"}; + +// total accumulated mouse movement since last frame +// this gets updated from the main game loop via IN_MouseMove +int total_dx, total_dy = 0; + +int FilterMouseEvents (const SDL_Event *event) +{ + switch (event->type) { + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + return 0; + } + + return 1; +} + +void IN_Activate (void) +{ + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) + { + SDL_WM_GrabInput(SDL_GRAB_ON); + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_ON) + Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_ON) failed.\n"); + } + + if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE) + { + SDL_ShowCursor(SDL_DISABLE); + if (SDL_ShowCursor(SDL_QUERY) != SDL_DISABLE) + Con_Printf("WARNING: SDL_ShowCursor(SDL_DISABLE) failed.\n"); + } + + if (SDL_GetEventFilter() != NULL) + SDL_SetEventFilter(NULL); + + total_dx = 0; + total_dy = 0; +} + +void IN_Deactivate (qboolean free_cursor) +{ + if (free_cursor) + { + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF) + { + SDL_WM_GrabInput(SDL_GRAB_OFF); + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) != SDL_GRAB_OFF) + Con_Printf("WARNING: SDL_WM_GrabInput(SDL_GRAB_OFF) failed.\n"); + } + + if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE) + { + SDL_ShowCursor(SDL_ENABLE); + if (SDL_ShowCursor(SDL_QUERY) != SDL_ENABLE) + Con_Printf("WARNING: SDL_ShowCursor(SDL_ENABLE) failed.\n"); + } + } + + // discard all mouse events when input is deactivated + if (SDL_GetEventFilter() != FilterMouseEvents) + SDL_SetEventFilter(FilterMouseEvents); +} + +void IN_Init (void) +{ + BuildKeyMaps(); + + if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) == -1) + Con_Printf("Warning: SDL_EnableKeyRepeat() failed.\n"); + + IN_Activate(); +} + +void IN_Shutdown (void) +{ + IN_Deactivate(true); +} + +void IN_Commands (void) +{ + // TODO: implement this for joystick support +} + +extern cvar_t cl_maxpitch; //johnfitz -- variable pitch clamping +extern cvar_t cl_minpitch; //johnfitz -- variable pitch clamping + + +void IN_MouseMove(int dx, int dy) +{ + total_dx += dx; + total_dy += dy; +} + +void IN_Move (usercmd_t *cmd) +{ + int dmx, dmy; + + /* TODO: fix this + if (m_filter.value) + { + dmx = (2*mx - dmx) * 0.5; + dmy = (2*my - dmy) * 0.5; + } + */ + + dmx = total_dx * sensitivity.value; + dmy = total_dy * sensitivity.value; + + total_dx = 0; + total_dy = 0; + + if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) + cmd->sidemove += m_side.value * dmx; + else + cl.viewangles[YAW] -= m_yaw.value * dmx; + + if (in_mlook.state & 1) + V_StopPitchDrift (); + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + cl.viewangles[PITCH] += m_pitch.value * dmy; + //johnfitz -- variable pitch clamping + if (cl.viewangles[PITCH] > cl_maxpitch.value) + cl.viewangles[PITCH] = cl_maxpitch.value; + if (cl.viewangles[PITCH] < cl_minpitch.value) + cl.viewangles[PITCH] = cl_minpitch.value; + //johnfitz + } + else + { + if ((in_strafe.state & 1) && noclip_anglehack) + cmd->upmove -= m_forward.value * dmy; + else + cmd->forwardmove -= m_forward.value * dmy; + } +} + +void IN_ClearStates (void) +{ +} diff --git a/Quake/input.h b/Quake/input.h new file mode 100644 index 00000000..a834c94c --- /dev/null +++ b/Quake/input.h @@ -0,0 +1,44 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// input.h -- external (non-keyboard) input devices + +void IN_Init (void); + +void IN_Shutdown (void); + +void IN_Commands (void); +// oportunity for devices to stick commands on the script buffer + +// mouse moved by dx and dy pixels +void IN_MouseMove(int dx, int dy); + +void IN_Move (usercmd_t *cmd); +// add additional movement on top of the keyboard move cmd + +void IN_ClearStates (void); +// restores all button and position states to defaults + +// called when the app becomes active +void IN_Activate (); + +// called when the app becomes inactive +void IN_Deactivate (qboolean free_cursor); diff --git a/Quake/keys.c b/Quake/keys.c new file mode 100644 index 00000000..6a946c0e --- /dev/null +++ b/Quake/keys.c @@ -0,0 +1,1141 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +/* + +key up events are sent even if in console mode + +*/ + +#define MAXCMDLINE 256 +char key_lines[32][MAXCMDLINE]; +int key_linepos; +int shift_down=false; +int key_lastpress; +int key_insert; //johnfitz -- insert key toggle (for editing) +double key_blinktime; //johnfitz -- fudge cursor blinking to make it easier to spot in certain cases + +int edit_line=0; +int history_line=0; + +keydest_t key_dest; + +int key_count; // incremented every key event + +char *keybindings[256]; +int keyshift[256]; // key to map to if shift held down in console +int key_repeats[256]; // if > 1, it is autorepeating +qboolean consolekeys[256]; // if true, can't be rebound while in console +qboolean menubound[256]; // if true, can't be rebound while in menu +qboolean keydown[256]; + +qboolean repeatkeys[256]; //johnfitz -- if true, autorepeat is enabled for this key + +typedef struct +{ + char *name; + int keynum; +} keyname_t; + +keyname_t keynames[] = +{ + {"TAB", K_TAB}, + {"ENTER", K_ENTER}, + {"ESCAPE", K_ESCAPE}, + {"SPACE", K_SPACE}, + {"BACKSPACE", K_BACKSPACE}, + {"UPARROW", K_UPARROW}, + {"DOWNARROW", K_DOWNARROW}, + {"LEFTARROW", K_LEFTARROW}, + {"RIGHTARROW", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"CTRL", K_CTRL}, + {"SHIFT", K_SHIFT}, + + //johnfitz -- keypad + {"KP_NUMLOCK", KP_NUMLOCK}, + {"KP_SLASH", KP_SLASH }, + {"KP_STAR", KP_STAR }, + {"KP_MINUS", KP_MINUS }, + {"KP_HOME", KP_HOME }, + {"KP_UPARROW", KP_UPARROW }, + {"KP_PGUP", KP_PGUP }, + {"KP_PLUS", KP_PLUS }, + {"KP_LEFTARROW", KP_LEFTARROW }, + {"KP_5", KP_5 }, + {"KP_RIGHTARROW", KP_RIGHTARROW }, + {"KP_END", KP_END }, + {"KP_DOWNARROW", KP_DOWNARROW }, + {"KP_PGDN", KP_PGDN }, + {"KP_ENTER", KP_ENTER }, + {"KP_INS", KP_INS }, + {"KP_DEL", KP_DEL }, + //johnfitz + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"INS", K_INS}, + {"DEL", K_DEL}, + {"PGDN", K_PGDN}, + {"PGUP", K_PGUP}, + {"HOME", K_HOME}, + {"END", K_END}, + + {"MOUSE1", K_MOUSE1}, + {"MOUSE2", K_MOUSE2}, + {"MOUSE3", K_MOUSE3}, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + {"AUX17", K_AUX17}, + {"AUX18", K_AUX18}, + {"AUX19", K_AUX19}, + {"AUX20", K_AUX20}, + {"AUX21", K_AUX21}, + {"AUX22", K_AUX22}, + {"AUX23", K_AUX23}, + {"AUX24", K_AUX24}, + {"AUX25", K_AUX25}, + {"AUX26", K_AUX26}, + {"AUX27", K_AUX27}, + {"AUX28", K_AUX28}, + {"AUX29", K_AUX29}, + {"AUX30", K_AUX30}, + {"AUX31", K_AUX31}, + {"AUX32", K_AUX32}, + + {"PAUSE", K_PAUSE}, + + {"MWHEELUP", K_MWHEELUP}, + {"MWHEELDOWN", K_MWHEELDOWN}, + + {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + + {NULL,0} +}; + + // dedicated before exiting +byte key_map[SDLK_LAST]; + +void BuildKeyMaps() +{ + int i; + + for (i = 0; i < SDLK_LAST; i++) + key_map[i] = 0; + + key_map[SDLK_BACKSPACE] = K_BACKSPACE; + key_map[SDLK_TAB] = K_TAB; + key_map[SDLK_RETURN] = K_ENTER; + key_map[SDLK_PAUSE] = K_PAUSE; + key_map[SDLK_ESCAPE] = K_ESCAPE; + key_map[SDLK_SPACE] = K_SPACE; + key_map[SDLK_EXCLAIM] = '!'; + key_map[SDLK_QUOTEDBL] = '"'; + key_map[SDLK_HASH] = '#'; + key_map[SDLK_DOLLAR] = '$'; + key_map[SDLK_AMPERSAND] = '&'; + key_map[SDLK_QUOTE] = '\''; + key_map[SDLK_LEFTPAREN] = '('; + key_map[SDLK_RIGHTPAREN] = ')'; + key_map[SDLK_ASTERISK] = '*'; + key_map[SDLK_PLUS] = '+'; + key_map[SDLK_COMMA] = ','; + key_map[SDLK_MINUS] = '-'; + key_map[SDLK_PERIOD] = '.'; + key_map[SDLK_SLASH] = '/'; + + key_map[SDLK_0] = '0'; + key_map[SDLK_1] = '1'; + key_map[SDLK_2] = '2'; + key_map[SDLK_3] = '3'; + key_map[SDLK_4] = '4'; + key_map[SDLK_5] = '5'; + key_map[SDLK_6] = '6'; + key_map[SDLK_7] = '7'; + key_map[SDLK_8] = '8'; + key_map[SDLK_9] = '9'; + + key_map[SDLK_COLON] = ':'; + key_map[SDLK_SEMICOLON] = ';'; + key_map[SDLK_LESS] = '<'; + key_map[SDLK_EQUALS] = '='; + key_map[SDLK_GREATER] = '>'; + key_map[SDLK_QUESTION] = '?'; + key_map[SDLK_AT] = '@'; + key_map[SDLK_LEFTBRACKET] = '['; + key_map[SDLK_BACKSLASH] = '\\'; + key_map[SDLK_RIGHTBRACKET] = ']'; + key_map[SDLK_CARET] = '^'; + key_map[SDLK_UNDERSCORE] = '_'; + key_map[SDLK_BACKQUOTE] = '`'; + + key_map[SDLK_a] = 'a'; + key_map[SDLK_b] = 'b'; + key_map[SDLK_c] = 'c'; + key_map[SDLK_d] = 'd'; + key_map[SDLK_e] = 'e'; + key_map[SDLK_f] = 'f'; + key_map[SDLK_g] = 'g'; + key_map[SDLK_h] = 'h'; + key_map[SDLK_i] = 'i'; + key_map[SDLK_j] = 'j'; + key_map[SDLK_k] = 'k'; + key_map[SDLK_l] = 'l'; + key_map[SDLK_m] = 'm'; + key_map[SDLK_n] = 'n'; + key_map[SDLK_o] = 'o'; + key_map[SDLK_p] = 'p'; + key_map[SDLK_q] = 'q'; + key_map[SDLK_r] = 'r'; + key_map[SDLK_s] = 's'; + key_map[SDLK_t] = 't'; + key_map[SDLK_u] = 'u'; + key_map[SDLK_v] = 'v'; + key_map[SDLK_w] = 'w'; + key_map[SDLK_x] = 'x'; + key_map[SDLK_y] = 'y'; + key_map[SDLK_z] = 'z'; + + key_map[SDLK_DELETE] = K_DEL; + + key_map[SDLK_KP0] = KP_INS; + key_map[SDLK_KP1] = KP_END; + key_map[SDLK_KP2] = KP_DOWNARROW; + key_map[SDLK_KP3] = KP_PGDN; + key_map[SDLK_KP4] = KP_LEFTARROW; + key_map[SDLK_KP5] = KP_5; + key_map[SDLK_KP6] = KP_RIGHTARROW; + key_map[SDLK_KP7] = KP_HOME; + key_map[SDLK_KP8] = KP_UPARROW; + key_map[SDLK_KP9] = KP_PGUP; + key_map[SDLK_KP_PERIOD] = KP_DEL; + key_map[SDLK_KP_DIVIDE] = KP_SLASH; + key_map[SDLK_KP_MULTIPLY] = KP_STAR; + key_map[SDLK_KP_MINUS] = KP_MINUS; + key_map[SDLK_KP_PLUS] = KP_PLUS; + key_map[SDLK_KP_ENTER] = KP_ENTER; + key_map[SDLK_KP_EQUALS] = 0; + + key_map[SDLK_UP] = K_UPARROW; + key_map[SDLK_DOWN] = K_DOWNARROW; + key_map[SDLK_RIGHT] = K_RIGHTARROW; + key_map[SDLK_LEFT] = K_LEFTARROW; + key_map[SDLK_INSERT] = K_INS; + key_map[SDLK_HOME] = K_HOME; + key_map[SDLK_END] = K_END; + key_map[SDLK_PAGEUP] = K_PGUP; + key_map[SDLK_PAGEDOWN] = K_PGDN; + + key_map[SDLK_F1] = K_F1; + key_map[SDLK_F2] = K_F2; + key_map[SDLK_F3] = K_F3; + key_map[SDLK_F4] = K_F4; + key_map[SDLK_F5] = K_F5; + key_map[SDLK_F6] = K_F6; + key_map[SDLK_F7] = K_F7; + key_map[SDLK_F8] = K_F8; + key_map[SDLK_F9] = K_F9; + key_map[SDLK_F10] = K_F10; + key_map[SDLK_F11] = K_F11; + key_map[SDLK_F12] = K_F12; + key_map[SDLK_F13] = 0; + key_map[SDLK_F14] = 0; + key_map[SDLK_F15] = 0; + + key_map[SDLK_NUMLOCK] = KP_NUMLOCK; + key_map[SDLK_CAPSLOCK] = 0; + key_map[SDLK_SCROLLOCK] = 0; + key_map[SDLK_RSHIFT] = K_SHIFT; + key_map[SDLK_LSHIFT] = K_SHIFT; + key_map[SDLK_RCTRL] = K_CTRL; + key_map[SDLK_LCTRL] = K_CTRL; + key_map[SDLK_RALT] = K_ALT; + key_map[SDLK_LALT] = K_ALT; + key_map[SDLK_RMETA] = 0; + key_map[SDLK_LMETA] = 0; + key_map[SDLK_LSUPER] = 0; + key_map[SDLK_RSUPER] = 0; + key_map[SDLK_MODE] = 0; + key_map[SDLK_COMPOSE] = 0; + key_map[SDLK_HELP] = 0; + key_map[SDLK_PRINT] = 0; + key_map[SDLK_SYSREQ] = 0; + key_map[SDLK_BREAK] = 0; + key_map[SDLK_MENU] = 0; + key_map[SDLK_POWER] = 0; + key_map[SDLK_EURO] = 0; + key_map[SDLK_UNDO] = 0; +} + +/* +======= +MapKey + +Map from SDL to quake keynums +======= +*/ +int Key_Map (SDL_KeyboardEvent *event) +{ + return key_map[(*event).keysym.sym]; + + /* TODO: keypad handling + if (cl_keypad.value) { + if (extended) { + switch (key) { + case K_ENTER: return KP_ENTER; + case '/': return KP_SLASH; + case K_PAUSE: return KP_NUMLOCK; + }; + } else { + switch (key) { + case K_HOME: return KP_HOME; + case K_UPARROW: return KP_UPARROW; + case K_PGUP: return KP_PGUP; + case K_LEFTARROW: return KP_LEFTARROW; + case K_RIGHTARROW: return KP_RIGHTARROW; + case K_END: return KP_END; + case K_DOWNARROW: return KP_DOWNARROW; + case K_PGDN: return KP_PGDN; + case K_INS: return KP_INS; + case K_DEL: return KP_DEL; + } + } + } else { + // cl_keypad 0, compatibility mode + switch (key) { + case KP_STAR: return '*'; + case KP_MINUS: return '-'; + case KP_5: return '5'; + case KP_PLUS: return '+'; + } + } + */ +} + +/* +============================================================================== + + LINE TYPING INTO THE CONSOLE + +============================================================================== +*/ + +/* +==================== +Key_Console -- johnfitz -- heavy revision + +Interactive line editing and console scrollback +==================== +*/ +void Key_Console (int key) +{ + extern int con_vislines; + extern char key_tabpartial[MAXCMDLINE]; + // char *cmd; unused -- kristian + + switch (key) + { + case K_ENTER: + case KP_ENTER: + key_tabpartial[0] = 0; + Cbuf_AddText (key_lines[edit_line]+1); // skip the prompt + Cbuf_AddText ("\n"); + Con_Printf ("%s\n",key_lines[edit_line]); + edit_line = (edit_line + 1) & 31; + history_line = edit_line; + key_lines[edit_line][0] = ']'; + key_lines[edit_line][1] = 0; //johnfitz -- otherwise old history items show up in the new edit line + key_linepos = 1; + if (cls.state == ca_disconnected) + SCR_UpdateScreen (); // force an update, because the command may take some time + return; + + case K_TAB: + Con_TabComplete (); + return; + + case K_BACKSPACE: + + key_tabpartial[0] = 0; + if (key_linepos > 1) + { + strcpy(key_lines[edit_line] + key_linepos - 1, key_lines[edit_line] + key_linepos); + key_linepos--; + } + return; + + case K_INS: + key_insert ^= 1; + return; + + case K_DEL: + key_tabpartial[0] = 0; + if (key_linepos < strlen(key_lines[edit_line])) + strcpy(key_lines[edit_line] + key_linepos, key_lines[edit_line] + key_linepos + 1); + return; + + case K_HOME: + if (keydown[K_CTRL]) + { + //skip initial empty lines + int i, x; + char *line; + extern int con_current, con_linewidth; + extern char *con_text; + //extern float scr_con_current; unused -- kristian + + for (i = con_current - con_totallines + 1 ; i <= con_current ; i++) + { + line = con_text + (i%con_totallines)*con_linewidth; + for (x=0 ; x>3)-1); + } + else + key_linepos = 1; + return; + + case K_END: + if (keydown[K_CTRL]) + con_backscroll = 0; + else + key_linepos = strlen(key_lines[edit_line]); + return; + + case K_PGUP: + //case K_MWHEELUP: + con_backscroll += keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2; + if (con_backscroll > con_totallines - (vid.height>>3) - 1) + con_backscroll = con_totallines - (vid.height>>3) - 1; + return; + + case K_PGDN: + //case K_MWHEELDOWN: + con_backscroll -= keydown[K_CTRL] ? ((con_vislines>>3) - 4) : 2; + if (con_backscroll < 0) + con_backscroll = 0; + return; + + case K_LEFTARROW: + if (key_linepos > 1) + { + key_linepos--; + key_blinktime = realtime; + } + return; + + case K_RIGHTARROW: + if (strlen(key_lines[edit_line]) == key_linepos) + { + if (strlen(key_lines[(edit_line + 31) & 31]) <= key_linepos) + return; // no character to get + + key_lines[edit_line][key_linepos] = key_lines[(edit_line + 31) & 31][key_linepos]; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + } + else + { + key_linepos++; + key_blinktime = realtime; + } + return; + + case K_UPARROW: + key_tabpartial[0] = 0; + do + { + history_line = (history_line - 1) & 31; + } while (history_line != edit_line + && !key_lines[history_line][1]); + if (history_line == edit_line) + history_line = (edit_line+1)&31; + Q_strcpy(key_lines[edit_line], key_lines[history_line]); + key_linepos = Q_strlen(key_lines[edit_line]); + return; + + case K_DOWNARROW: + key_tabpartial[0] = 0; + + if (history_line == edit_line) + { + //clear editline + key_lines[edit_line][1] = 0; + key_linepos = 1; + return; + } + + do { + history_line = (history_line + 1) & 31; + } while (history_line != edit_line + && !key_lines[history_line][1]); + if (history_line == edit_line) + { + key_lines[edit_line][0] = ']'; + key_linepos = 1; + } + else + { + Q_strcpy(key_lines[edit_line], key_lines[history_line]); + key_linepos = Q_strlen(key_lines[edit_line]); + } + return; + } + +//johnfitz -- clipboard pasting, stolen from zquake +/* TODO: make portable or remove + if ((key=='V' || key=='v') && keydown[K_CTRL]) + { + HANDLE th; + char *clipText; + int i; + + if (OpenClipboard(NULL)) { + th = GetClipboardData(CF_TEXT); + if (th) { + clipText = GlobalLock(th); + if (clipText) { + for (i=0; clipText[i]; i++) + if (clipText[i]=='\n' || clipText[i]=='\r' || clipText[i]=='\b') + break; + if (i + strlen(key_lines[edit_line]) > MAXCMDLINE-1) + i = MAXCMDLINE-1 - strlen(key_lines[edit_line]); + if (i > 0) + { // insert the string + memmove (key_lines[edit_line] + key_linepos + i, + key_lines[edit_line] + key_linepos, strlen(key_lines[edit_line]) - key_linepos + 1); + memcpy (key_lines[edit_line] + key_linepos, clipText, i); + key_linepos += i; + } + } + GlobalUnlock(th); + } + CloseClipboard(); + } + return; + } +*/ + if (key < 32 || key > 127) + return; // non printable + + //johnfitz -- stolen from darkplaces + if (key_linepos < MAXCMDLINE-1) + { + int i; + + key_tabpartial[0] = 0; //johnfitz + + if (key_insert) // check insert mode + { + // can't do strcpy to move string to right + i = strlen(key_lines[edit_line]) - 1; + + if (i == 254) + i--; + + for (; i >= key_linepos; i--) + key_lines[edit_line][i + 1] = key_lines[edit_line][i]; + } + + // only null terminate if at the end + i = key_lines[edit_line][key_linepos]; + key_lines[edit_line][key_linepos] = key; + key_linepos++; + + if (!i) + key_lines[edit_line][key_linepos] = 0; + } + //johnfitz +} + +//============================================================================ + +char chat_buffer[32]; +qboolean team_message = false; + +void Key_Message (int key) +{ + static int chat_bufferlen = 0; + + if (key == K_ENTER) + { + if (team_message) + Cbuf_AddText ("say_team \""); + else + Cbuf_AddText ("say \""); + Cbuf_AddText(chat_buffer); + Cbuf_AddText("\"\n"); + + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + if (key == K_ESCAPE) + { + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + if (key < 32 || key > 127) + return; // non printable + + if (key == K_BACKSPACE) + { + if (chat_bufferlen) + { + chat_bufferlen--; + chat_buffer[chat_bufferlen] = 0; + } + return; + } + + if (chat_bufferlen == 31) + return; // all full + + chat_buffer[chat_bufferlen++] = key; + chat_buffer[chat_bufferlen] = 0; +} + +//============================================================================ + + +/* +=================== +Key_StringToKeynum + +Returns a key number to be used to index keybindings[] by looking at +the given string. Single ascii characters return themselves, while +the K_* names are matched up. +=================== +*/ +int Key_StringToKeynum (char *str) +{ + keyname_t *kn; + + if (!str || !str[0]) + return -1; + if (!str[1]) + return str[0]; + + for (kn=keynames ; kn->name ; kn++) + { + if (!Q_strcasecmp(str,kn->name)) + return kn->keynum; + } + return -1; +} + +/* +=================== +Key_KeynumToString + +Returns a string (either a single ascii char, or a K_* name) for the +given keynum. +FIXME: handle quote special (general escape sequence?) +=================== +*/ +char *Key_KeynumToString (int keynum) +{ + keyname_t *kn; + static char tinystr[2]; + + if (keynum == -1) + return ""; + if (keynum > 32 && keynum < 127) + { // printable ascii + tinystr[0] = keynum; + tinystr[1] = 0; + return tinystr; + } + + for (kn=keynames ; kn->name ; kn++) + if (keynum == kn->keynum) + return kn->name; + + return ""; +} + + +/* +=================== +Key_SetBinding +=================== +*/ +void Key_SetBinding (int keynum, char *binding) +{ + char *new; + int l; + + if (keynum == -1) + return; + +// free old bindings + if (keybindings[keynum]) + { + Z_Free (keybindings[keynum]); + keybindings[keynum] = NULL; + } + +// allocate memory for new binding + l = Q_strlen (binding); + new = Z_Malloc (l+1); + Q_strcpy (new, binding); + new[l] = 0; + keybindings[keynum] = new; +} + +/* +=================== +Key_Unbind_f +=================== +*/ +void Key_Unbind_f (void) +{ + int b; + + if (Cmd_Argc() != 2) + { + Con_Printf ("unbind : remove commands from a key\n"); + return; + } + + b = Key_StringToKeynum (Cmd_Argv(1)); + if (b==-1) + { + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + return; + } + + Key_SetBinding (b, ""); +} + +void Key_Unbindall_f (void) +{ + int i; + + for (i=0 ; i<256 ; i++) + if (keybindings[i]) + Key_SetBinding (i, ""); +} + +/* +============ +Key_Bindlist_f -- johnfitz +============ +*/ +void Key_Bindlist_f (void) +{ + int i, count; + + count = 0; + for (i=0 ; i<256 ; i++) + if (keybindings[i]) + if (*keybindings[i]) + { + Con_SafePrintf (" %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]); + count++; + } + Con_SafePrintf ("%i bindings\n", count); +} + +/* +=================== +Key_Bind_f +=================== +*/ +void Key_Bind_f (void) +{ + int i, c, b; + char cmd[1024]; + + c = Cmd_Argc(); + + if (c != 2 && c != 3) + { + Con_Printf ("bind [command] : attach a command to a key\n"); + return; + } + b = Key_StringToKeynum (Cmd_Argv(1)); + if (b==-1) + { + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + return; + } + + if (c == 2) + { + if (keybindings[b]) + Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] ); + else + Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); + return; + } + +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + for (i=2 ; i< c ; i++) + { + if (i > 2) + strcat (cmd, " "); + strcat (cmd, Cmd_Argv(i)); + } + + Key_SetBinding (b, cmd); +} + +/* +============ +Key_WriteBindings + +Writes lines containing "bind key value" +============ +*/ +void Key_WriteBindings (FILE *f) +{ + int i; + + for (i=0 ; i<256 ; i++) + if (keybindings[i]) + if (*keybindings[i]) + fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]); +} + + +/* +=================== +Key_Init +=================== +*/ +void Key_Init (void) +{ + int i; + + BuildKeyMaps(); + + for (i=0 ; i<32 ; i++) + { + key_lines[i][0] = ']'; + key_lines[i][1] = 0; + } + key_linepos = 1; + + key_blinktime = realtime; //johnfitz + +// +// init ascii characters in console mode +// + for (i=32 ; i<128 ; i++) + consolekeys[i] = true; + consolekeys[K_ENTER] = true; + consolekeys[KP_ENTER] = true; //johnfitz + consolekeys[K_TAB] = true; + consolekeys[K_LEFTARROW] = true; + consolekeys[K_RIGHTARROW] = true; + consolekeys[K_UPARROW] = true; + consolekeys[K_DOWNARROW] = true; + consolekeys[K_BACKSPACE] = true; + consolekeys[K_DEL] = true; //johnfitz + consolekeys[K_INS] = true; //johnfitz + consolekeys[K_HOME] = true; //johnfitz + consolekeys[K_END] = true; //johnfitz + consolekeys[K_PGUP] = true; + consolekeys[K_PGDN] = true; + consolekeys[K_SHIFT] = true; + consolekeys[K_MWHEELUP] = true; + consolekeys[K_MWHEELDOWN] = true; + consolekeys['`'] = false; + consolekeys['~'] = false; + + //johnfitz -- repeating keys + for (i=0 ; i<256 ; i++) + repeatkeys[i] = false; + repeatkeys[K_BACKSPACE] = true; + repeatkeys[K_DEL] = true; + repeatkeys[K_PAUSE] = true; + repeatkeys[K_PGUP] = true; + repeatkeys[K_PGDN] = true; + repeatkeys[K_LEFTARROW] = true; + repeatkeys[K_RIGHTARROW] = true; + //johnfitz + + for (i=0 ; i<256 ; i++) + keyshift[i] = i; + for (i='a' ; i<='z' ; i++) + keyshift[i] = i - 'a' + 'A'; + keyshift['1'] = '!'; + keyshift['2'] = '@'; + keyshift['3'] = '#'; + keyshift['4'] = '$'; + keyshift['5'] = '%'; + keyshift['6'] = '^'; + keyshift['7'] = '&'; + keyshift['8'] = '*'; + keyshift['9'] = '('; + keyshift['0'] = ')'; + keyshift['-'] = '_'; + keyshift['='] = '+'; + keyshift[','] = '<'; + keyshift['.'] = '>'; + keyshift['/'] = '?'; + keyshift[';'] = ':'; + keyshift['\''] = '"'; + keyshift['['] = '{'; + keyshift[']'] = '}'; + keyshift['`'] = '~'; + keyshift['\\'] = '|'; + + menubound[K_ESCAPE] = true; + for (i=0 ; i<12 ; i++) + menubound[K_F1+i] = true; + +// +// register our functions +// + Cmd_AddCommand ("bindlist",Key_Bindlist_f); //johnfitz + Cmd_AddCommand ("bind",Key_Bind_f); + Cmd_AddCommand ("unbind",Key_Unbind_f); + Cmd_AddCommand ("unbindall",Key_Unbindall_f); +} + +/* +=================== +Key_Event + +Called by the system between frames for both key up and key down events +Should NOT be called during an interrupt! +=================== +*/ +void Key_Event (int key, qboolean down) +{ + char *kb; + char cmd[1024]; + + keydown[key] = down; + + if (!down) + key_repeats[key] = 0; + + key_lastpress = key; + key_count++; + if (key_count <= 0) + { + return; // just catching keys for Con_NotifyBox + } + +// update auto-repeat status + if (down) + { + key_repeats[key]++; + if (key_dest != key_console && key_repeats[key] > 1 && !repeatkeys[key]) //johnfitz -- use repeatkeys[] + return; // ignore most autorepeats + + if (key >= 200 && !keybindings[key]) + Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) ); + } + + if (key == K_SHIFT) + shift_down = down; + +// +// handle escape specialy, so the user can never unbind it +// + if (key == K_ESCAPE) + { + if (!down) + return; + switch (key_dest) + { + case key_message: + Key_Message (key); + break; + case key_menu: + M_Keydown (key); + break; + case key_game: + case key_console: + M_ToggleMenu_f (); + break; + default: + Sys_Error ("Bad key_dest"); + } + return; + } + +// johnfitz -- alt-enter to toggle fullscreen. FIXME -- this does NOT work +#if 0 + if (!down && (key == K_ENTER) && keydown[K_ALT]) + { + extern cvar_t vid_fullscreen; + if (vid_fullscreen.value) + Cvar_Set ("vid_fullscreen", "0"); + else + Cvar_Set ("vid_fullscreen", "1"); + VID_Restart (); + } +#endif +// johnfitz + +// +// key up events only generate commands if the game key binding is +// a button command (leading + sign). These will occur even in console mode, +// to keep the character from continuing an action started before a console +// switch. Button commands include the kenum as a parameter, so multiple +// downs can be matched with ups +// + if (!down) + { + kb = keybindings[key]; + if (kb && kb[0] == '+') + { + sprintf (cmd, "-%s %i\n", kb+1, key); + Cbuf_AddText (cmd); + } + if (keyshift[key] != key) + { + kb = keybindings[keyshift[key]]; + if (kb && kb[0] == '+') + { + sprintf (cmd, "-%s %i\n", kb+1, key); + Cbuf_AddText (cmd); + } + } + return; + } + +// +// during demo playback, most keys bring up the main menu +// + if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game) + { + M_ToggleMenu_f (); + return; + } + +// +// if not a consolekey, send to the interpreter no matter what mode is +// + if ( (key_dest == key_menu && menubound[key]) + || (key_dest == key_console && !consolekeys[key]) + || (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) ) + { + kb = keybindings[key]; + if (kb) + { + if (kb[0] == '+') + { // button commands add keynum as a parm + sprintf (cmd, "%s %i\n", kb, key); + Cbuf_AddText (cmd); + } + else + { + Cbuf_AddText (kb); + Cbuf_AddText ("\n"); + } + } + return; + } + + if (!down) + return; // other systems only care about key down events + + if (shift_down) + { + key = keyshift[key]; + } + + switch (key_dest) + { + case key_message: + Key_Message (key); + break; + case key_menu: + M_Keydown (key); + break; + + case key_game: + case key_console: + Key_Console (key); + break; + default: + Sys_Error ("Bad key_dest"); + } +} + + +/* +=================== +Key_ClearStates +=================== +*/ +void Key_ClearStates (void) +{ + int i; + + for (i=0 ; i<256 ; i++) + { + keydown[i] = false; + key_repeats[i] = 0; + } +} + diff --git a/Quake/keys.h b/Quake/keys.h new file mode 100644 index 00000000..63282ea2 --- /dev/null +++ b/Quake/keys.h @@ -0,0 +1,154 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +//johnfitz -- keypad +#define KP_NUMLOCK 153 +#define KP_SLASH 154 +#define KP_STAR 155 +#define KP_MINUS 156 +#define KP_HOME 157 +#define KP_UPARROW 158 +#define KP_PGUP 159 +#define KP_PLUS 160 +#define KP_LEFTARROW 161 +#define KP_5 162 +#define KP_RIGHTARROW 163 +#define KP_END 164 +#define KP_DOWNARROW 165 +#define KP_PGDN 166 +#define KP_ENTER 167 +#define KP_INS 168 +#define KP_DEL 169 +//johnfitz + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 200 +#define K_MOUSE2 201 +#define K_MOUSE3 202 + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 + +// JACK: Intellimouse(c) Mouse Wheel Support + +#define K_MWHEELUP 239 +#define K_MWHEELDOWN 240 + + + +typedef enum {key_game, key_console, key_message, key_menu} keydest_t; + +extern keydest_t key_dest; +extern char *keybindings[256]; +extern int key_repeats[256]; +extern int key_count; // incremented every key event +extern int key_lastpress; + +void Key_Event (int key, qboolean down); +void Key_Init (void); +void Key_WriteBindings (FILE *f); +void Key_SetBinding (int keynum, char *binding); +void Key_ClearStates (void); + diff --git a/Quake/main.c b/Quake/main.c new file mode 100644 index 00000000..a0219f17 --- /dev/null +++ b/Quake/main.c @@ -0,0 +1,147 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include +#include "quakedef.h" + +#define DEFAULT_MEMORY 0x2000000 + +int main(int argc, char *argv[]) +{ + SDL_Event event; + quakeparms_t parms; + int t; + int done = 0; + double time, oldtime, newtime; + + parms.basedir = "."; + parms.cachedir = NULL; + + parms.argc = argc; + parms.argv = argv; + + COM_InitArgv(parms.argc, parms.argv); + + isDedicated = (COM_CheckParm("-dedicated") != 0); + + // default memory size + parms.memsize = DEFAULT_MEMORY; + + if (COM_CheckParm("-heapsize")) + { + t = COM_CheckParm("-heapsize") + 1; + if (t < com_argc) + parms.memsize = Q_atoi(com_argv[t]) * 1024; + } + + parms.membase = malloc (parms.memsize); + + if (!parms.membase) + Sys_Error ("Not enough memory free; check disk space\n"); + + // Sys_PageIn (parms.membase, parms.memsize); don't think this is needed -- kristian + + // TODO: dedicated server setup + + // S_BlockSound(); do I need this? + + Con_Printf("Host_Init\n"); + Host_Init(&parms); + + oldtime = Sys_FloatTime(); + while (!done) + { + // TODO: dedicated server loop + + while (!done && SDL_PollEvent (&event)) { + switch (event.type) { + case SDL_ACTIVEEVENT: + if (event.active.state & SDL_APPACTIVE & SDL_APPINPUTFOCUS) + if (event.active.gain) + { + IN_Activate(); + } + else + { + // TODO: handle sound + IN_Deactivate(vid.type == MODE_WINDOWED); + } + break; + case SDL_MOUSEMOTION: + IN_MouseMove(event.motion.xrel, event.motion.yrel); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + + switch (event.button.button) { + case SDL_BUTTON_LEFT: + Key_Event(K_MOUSE1, event.button.type == SDL_MOUSEBUTTONDOWN); + break; + case SDL_BUTTON_RIGHT: + Key_Event(K_MOUSE2, event.button.type == SDL_MOUSEBUTTONDOWN); + break; + case SDL_BUTTON_MIDDLE: + Key_Event(K_MOUSE3, event.button.type == SDL_MOUSEBUTTONDOWN); + break; + case SDL_BUTTON_WHEELUP: + Key_Event(K_MWHEELUP, event.button.type == SDL_MOUSEBUTTONDOWN); + break; + case SDL_BUTTON_WHEELDOWN: + Key_Event(K_MWHEELDOWN, event.button.type == SDL_MOUSEBUTTONDOWN); + break; + } + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + // LSHIFT + ESC and circomflex always opens the console no matter what + if ((event.key.keysym.sym == SDLK_ESCAPE && (event.key.keysym.mod & KMOD_LSHIFT != 0)) || (event.key.keysym.sym == SDLK_CARET)) + { + if (event.key.type == SDL_KEYDOWN) + Con_ToggleConsole_f(); + } + else + { + Key_Event(Key_Map(&(event.key)), event.key.type == SDL_KEYDOWN); + } + break; + case SDL_QUIT: + done = 1; + break; + default: + break; + } + } + + newtime = Sys_FloatTime(); + time = newtime - oldtime; + + Host_Frame(time); + + // throttle the game loop just a little bit - noone needs more than 1000fps, I think + if (newtime - oldtime < 1) + SDL_Delay(1); + + oldtime = newtime; + } + + Sys_Quit(); + return 0; +} diff --git a/Quake/mathlib.c b/Quake/mathlib.c new file mode 100644 index 00000000..6371a487 --- /dev/null +++ b/Quake/mathlib.c @@ -0,0 +1,557 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// mathlib.c -- math primitives + +#include +#include "quakedef.h" + +void Sys_Error (char *error, ...); + +vec3_t vec3_origin = {0,0,0}; +int nanmask = 255<<23; + +/*-----------------------------------------------------------------*/ + + +//#define DEG2RAD( a ) ( a * M_PI ) / 180.0F +#define DEG2RAD( a ) ( (a) * M_PI_DIV_180 ) //johnfitz + +// kristian - missing math functions +#ifndef max +int max (int x, int y) +{ + if (x > y) + return x; + + return y; +} +#endif +#ifndef min +int min (int x, int y) +{ + if (x < y) + return x; + + return y; +} +#endif +// kristian + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct( normal, normal ); + + d = DotProduct( normal, p ) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + int pos; + int i; + float minelem = 1.0F; + vec3_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( fabs( src[i] ) < minelem ) + { + pos = i; + minelem = fabs( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlane( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalize( dst ); +} + +//johnfitz -- removed RotatePointAroundVector() becuase it's no longer used and my compiler fucked it up anyway + +/*-----------------------------------------------------------------*/ + + +float anglemod(float a) +{ +#if 0 + if (a >= 0) + a -= 360*(int)(a/360); + else + a += 360*( 1 + (int)(-a/360) ); +#endif + a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); + return a; +} + +/* +================== +BOPS_Error + +Split out like this for ASM to call. +================== +*/ +void BOPS_Error (void) +{ + Sys_Error ("BoxOnPlaneSide: Bad signbits"); +} + + +/* +================== +BoxOnPlaneSide + +Returns 1, 2, or 1 + 2 +================== +*/ +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) +{ + float dist1, dist2; + int sides; + +#if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this + // function +// fast axial cases + if (p->type < 3) + { + if (p->dist <= emins[p->type]) + return 1; + if (p->dist >= emaxs[p->type]) + return 2; + return 3; + } +#endif + +// general case + switch (p->signbits) + { + case 0: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 1: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 2: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 3: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 4: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 5: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 6: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + case 7: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + default: + dist1 = dist2 = 0; // shut up compiler + BOPS_Error (); + break; + } + +#if 0 + int i; + vec3_t corners[2]; + + for (i=0 ; i<3 ; i++) + { + if (plane->normal[i] < 0) + { + corners[0][i] = emins[i]; + corners[1][i] = emaxs[i]; + } + else + { + corners[1][i] = emins[i]; + corners[0][i] = emaxs[i]; + } + } + dist = DotProduct (plane->normal, corners[0]) - plane->dist; + dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; + sides = 0; + if (dist1 >= 0) + sides = 1; + if (dist2 < 0) + sides |= 2; + +#endif + + sides = 0; + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + +#ifdef PARANOID +if (sides == 0) + Sys_Error ("BoxOnPlaneSide: sides==0"); +#endif + + return sides; +} + +//johnfitz -- the opposite of AngleVectors. this takes forward and generates pitch yaw roll +//TODO: take right and up vectors to properly set yaw and roll +void VectorAngles (const vec3_t forward, vec3_t angles) +{ + vec3_t temp; + + temp[0] = forward[0]; + temp[1] = forward[1]; + temp[2] = 0; + angles[PITCH] = -atan2(forward[2], Length(temp)) / M_PI_DIV_180; + angles[YAW] = atan2(forward[1], forward[0]) / M_PI_DIV_180; + angles[ROLL] = 0; +} + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + right[0] = (-1*sr*sp*cy+-1*cr*-sy); + right[1] = (-1*sr*sp*sy+-1*cr*cy); + right[2] = -1*sr*cp; + up[0] = (cr*sp*cy+-sr*-sy); + up[1] = (cr*sp*sy+-sr*cy); + up[2] = cr*cp; +} + +int VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]-vecb[0]; + out[1] = veca[1]-vecb[1]; + out[2] = veca[2]-vecb[2]; +} + +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]+vecb[0]; + out[1] = veca[1]+vecb[1]; + out[2] = veca[2]+vecb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +double sqrt(double x); + +vec_t Length(vec3_t v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +float VectorNormalize (vec3_t v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = sqrt (length); // FIXME + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (vec3_t in, vec_t scale, vec3_t out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + + +int Q_log2(int val) +{ + int answer=0; + while (val>>=1) + answer++; + return answer; +} + + +/* +================ +R_ConcatRotations +================ +*/ +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + + +/* +================ +R_ConcatTransforms +================ +*/ +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + + +/* +=================== +FloorDivMod + +Returns mathematically correct (floor-based) quotient and remainder for +numer and denom, both of which should contain no fractional part. The +quotient must fit in 32 bits. +==================== +*/ + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem) +{ + int q, r; + double x; + +#ifndef PARANOID + if (denom <= 0.0) + Sys_Error ("FloorDivMod: bad denominator %d\n", denom); + +// if ((floor(numer) != numer) || (floor(denom) != denom)) +// Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n", +// numer, denom); +#endif + + if (numer >= 0.0) + { + + x = floor(numer / denom); + q = (int)x; + r = (int)floor(numer - (x * denom)); + } + else + { + // + // perform operations with positive values, and fix mod to make floor-based + // + x = floor(-numer / denom); + q = -(int)x; + r = (int)floor(-numer - (x * denom)); + if (r != 0) + { + q--; + r = (int)denom - r; + } + } + + *quotient = q; + *rem = r; +} + + +/* +=================== +GreatestCommonDivisor +==================== +*/ +int GreatestCommonDivisor (int i1, int i2) +{ + if (i1 > i2) + { + if (i2 == 0) + return (i1); + return GreatestCommonDivisor (i2, i1 % i2); + } + else + { + if (i1 == 0) + return (i2); + return GreatestCommonDivisor (i1, i2 % i1); + } +} + + +#if !id386 + +// TODO: move to nonintel.c + +/* +=================== +Invert24To16 + +Inverts an 8.24 value to a 16.16 value +==================== +*/ + +fixed16_t Invert24To16(fixed16_t val) +{ + if (val < 256) + return (0xFFFFFFFF); + + return (fixed16_t) + (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5); +} + +#endif diff --git a/Quake/mathlib.h b/Quake/mathlib.h new file mode 100644 index 00000000..8d57a46f --- /dev/null +++ b/Quake/mathlib.h @@ -0,0 +1,122 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// mathlib.h + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#define M_PI_DIV_180 (M_PI / 180.0) //johnfitz + +struct mplane_s; + +extern vec3_t vec3_origin; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +#define CLAMP(min, x, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) //johnfitz + +#define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5)) //johnfitz -- from joequake + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} + +//johnfitz -- courtesy of lordhavoc +#define VectorNormalizeFast(_v)\ +{\ + float _y, _number;\ + _number = DotProduct(_v, _v);\ + if (_number != 0.0)\ + {\ + *((long *)&_y) = 0x5f3759df - ((* (long *) &_number) >> 1);\ + _y = _y * (1.5f - (_number * 0.5f * _y * _y));\ + VectorScale(_v, _y, _v);\ + }\ +} + +// kristian - missing math functions +#if !defined(max) +inline int max (int x, int y); +#endif +#if !defined(min) +inline int min (int x, int y); +#endif +// kristian + +void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle); //johnfitz +void VectorAngles (const vec3_t forward, vec3_t angles); //johnfitz + +void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); + +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +int VectorCompare (vec3_t v1, vec3_t v2); +vec_t Length (vec3_t v); +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +float VectorNormalize (vec3_t v); // returns vector length +void VectorInverse (vec3_t v); +void VectorScale (vec3_t in, vec_t scale, vec3_t out); +int Q_log2(int val); + +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem); +fixed16_t Invert24To16(fixed16_t val); +int GreatestCommonDivisor (int i1, int i2); + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +float anglemod(float a); + + + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) diff --git a/Quake/menu.c b/Quake/menu.c new file mode 100644 index 00000000..03697422 --- /dev/null +++ b/Quake/menu.c @@ -0,0 +1,3155 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +void (*vid_menucmdfn)(void); //johnfitz +void (*vid_menudrawfn)(void); +void (*vid_menukeyfn)(int key); + +enum { + 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; + +void M_Menu_Main_f (void); + void M_Menu_SinglePlayer_f (void); + void M_Menu_Load_f (void); + void M_Menu_Save_f (void); + void M_Menu_MultiPlayer_f (void); + void M_Menu_Setup_f (void); + void M_Menu_Net_f (void); + void M_Menu_LanConfig_f (void); + void M_Menu_SerialConfig_f (void); + void M_Menu_ModemConfig_f (void); + void M_Menu_GameOptions_f (void); + void M_Menu_Search_f (void); + void M_Menu_ServerList_f (void); + void M_Menu_Options_f (void); + void M_Menu_Keys_f (void); + void M_Menu_Video_f (void); + void M_Menu_Help_f (void); + void M_Menu_Quit_f (void); + +void M_Main_Draw (void); + void M_SinglePlayer_Draw (void); + void M_Load_Draw (void); + void M_Save_Draw (void); + void M_MultiPlayer_Draw (void); + void M_Setup_Draw (void); + void M_Net_Draw (void); + void M_SerialConfig_Draw (void); + void M_ModemConfig_Draw (void); + void M_LanConfig_Draw (void); + void M_GameOptions_Draw (void); + void M_Search_Draw (void); + void M_ServerList_Draw (void); + void M_Options_Draw (void); + void M_Keys_Draw (void); + void M_Video_Draw (void); + void M_Help_Draw (void); + void M_Quit_Draw (void); + +void M_Main_Key (int key); + void M_SinglePlayer_Key (int key); + void M_Load_Key (int key); + void M_Save_Key (int key); + void M_MultiPlayer_Key (int key); + void M_Setup_Key (int key); + void M_Net_Key (int key); + void M_SerialConfig_Key (int key); + void M_ModemConfig_Key (int key); + void M_LanConfig_Key (int key); + void M_GameOptions_Key (int key); + void M_Search_Key (int key); + void M_ServerList_Key (int key); + void M_Options_Key (int key); + void M_Keys_Key (int key); + void M_Video_Key (int key); + void M_Help_Key (int key); + void M_Quit_Key (int key); + +qboolean m_entersound; // play after drawing a frame, so caching + // won't disrupt the sound +qboolean m_recursiveDraw; + +int m_return_state; +qboolean m_return_onerror; +char m_return_reason [32]; + +#define StartingGame (m_multiplayer_cursor == 1) +#define JoiningGame (m_multiplayer_cursor == 0) +#define SerialConfig (m_net_cursor == 0) +#define DirectConfig (m_net_cursor == 1) +#define IPXConfig (m_net_cursor == 2) +#define TCPIPConfig (m_net_cursor == 3) + +void M_ConfigureNetSubsystem(void); + +/* +================ +M_DrawCharacter + +Draws one solid graphics character +================ +*/ +void M_DrawCharacter (int cx, int line, int num) +{ + Draw_Character (cx, line, num); +} + +void M_Print (int cx, int cy, char *str) +{ + while (*str) + { + M_DrawCharacter (cx, cy, (*str)+128); + str++; + cx += 8; + } +} + +void M_PrintWhite (int cx, int cy, char *str) +{ + while (*str) + { + M_DrawCharacter (cx, cy, *str); + str++; + cx += 8; + } +} + +void M_DrawTransPic (int x, int y, qpic_t *pic) +{ + Draw_Pic (x, y, pic); //johnfitz -- simplified becuase centering is handled elsewhere +} + +void M_DrawPic (int x, int y, qpic_t *pic) +{ + Draw_Pic (x, y, pic); //johnfitz -- simplified becuase centering is handled elsewhere +} + +void M_DrawTransPicTranslate (int x, int y, qpic_t *pic, int top, int bottom) //johnfitz -- more parameters +{ + Draw_TransPicTranslate (x, y, pic, top, bottom); //johnfitz -- simplified becuase centering is handled elsewhere +} + +void M_DrawTextBox (int x, int y, int width, int lines) +{ + qpic_t *p; + int cx, cy; + int n; + + // draw left side + cx = x; + cy = y; + p = Draw_CachePic ("gfx/box_tl.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_ml.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_bl.lmp"); + M_DrawTransPic (cx, cy+8, p); + + // draw middle + cx += 8; + while (width > 0) + { + cy = y; + p = Draw_CachePic ("gfx/box_tm.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_mm.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + if (n == 1) + p = Draw_CachePic ("gfx/box_mm2.lmp"); + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_bm.lmp"); + M_DrawTransPic (cx, cy+8, p); + width -= 2; + cx += 16; + } + + // draw right side + cy = y; + p = Draw_CachePic ("gfx/box_tr.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_mr.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_br.lmp"); + M_DrawTransPic (cx, cy+8, p); +} + +//============================================================================= + +int m_save_demonum; + +/* +================ +M_ToggleMenu_f +================ +*/ +void M_ToggleMenu_f (void) +{ + m_entersound = true; + + if (key_dest == key_menu) + { + if (m_state != m_main) + { + M_Menu_Main_f (); + return; + } + + IN_Activate(); + key_dest = key_game; + m_state = m_none; + return; + } + if (key_dest == key_console) + { + Con_ToggleConsole_f (); + } + else + { + M_Menu_Main_f (); + } +} + + +//============================================================================= +/* MAIN MENU */ + +int m_main_cursor; +#define MAIN_ITEMS 5 + + +void M_Menu_Main_f (void) +{ + if (key_dest != key_menu) + { + m_save_demonum = cls.demonum; + cls.demonum = -1; + } + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_main; + m_entersound = true; +} + + +void M_Main_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/ttl_main.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") ); + + f = (int)(realtime * 10)%6; //johnfitz -- was host_time + + M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +} + + +void M_Main_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + IN_Activate(); + key_dest = key_game; + m_state = m_none; + cls.demonum = m_save_demonum; + if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected) + CL_NextDemo (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_main_cursor >= MAIN_ITEMS) + m_main_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_main_cursor < 0) + m_main_cursor = MAIN_ITEMS - 1; + break; + + case K_ENTER: + m_entersound = true; + + switch (m_main_cursor) + { + case 0: + M_Menu_SinglePlayer_f (); + break; + + case 1: + M_Menu_MultiPlayer_f (); + break; + + case 2: + M_Menu_Options_f (); + break; + + case 3: + M_Menu_Help_f (); + break; + + case 4: + M_Menu_Quit_f (); + break; + } + } +} + +//============================================================================= +/* SINGLE PLAYER MENU */ + +int m_singleplayer_cursor; +#define SINGLEPLAYER_ITEMS 3 + + +void M_Menu_SinglePlayer_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_singleplayer; + m_entersound = true; +} + + +void M_SinglePlayer_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/ttl_sgl.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") ); + + f = (int)(realtime * 10)%6; //johnfitz -- was host_time + + M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +} + + +void M_SinglePlayer_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS) + m_singleplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_singleplayer_cursor < 0) + m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; + break; + + case K_ENTER: + m_entersound = true; + + switch (m_singleplayer_cursor) + { + case 0: + if (sv.active) + if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n", 0.0f)) + break; + IN_Activate(); + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("maxplayers 1\n"); + Cbuf_AddText ("deathmatch 0\n"); //johnfitz + Cbuf_AddText ("coop 0\n"); //johnfitz + Cbuf_AddText ("map start\n"); + break; + + case 1: + M_Menu_Load_f (); + break; + + case 2: + M_Menu_Save_f (); + break; + } + } +} + +//============================================================================= +/* LOAD/SAVE MENU */ + +int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES + +#define MAX_SAVEGAMES 20 //johnfitz -- increased from 12 +char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1]; +int loadable[MAX_SAVEGAMES]; + +void M_ScanSaves (void) +{ + int i, j; + char name[MAX_OSPATH]; + FILE *f; + int version; + + for (i=0 ; iwidth)/2, 4, p); + + for (i=0 ; i< MAX_SAVEGAMES; i++) + M_Print (16, 32 + 8*i, m_filenames[i]); + +// line cursor + M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1)); +} + + +void M_Save_Draw (void) +{ + int i; + qpic_t *p; + + p = Draw_CachePic ("gfx/p_save.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + for (i=0 ; i= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + + +void M_Save_Key (int k) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_SinglePlayer_f (); + break; + + case K_ENTER: + m_state = m_none; + IN_Activate(); + key_dest = key_game; + Cbuf_AddText (va("save s%i\n", load_cursor)); + return; + + case K_UPARROW: + case K_LEFTARROW: + S_LocalSound ("misc/menu1.wav"); + load_cursor--; + if (load_cursor < 0) + load_cursor = MAX_SAVEGAMES-1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + S_LocalSound ("misc/menu1.wav"); + load_cursor++; + if (load_cursor >= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + +//============================================================================= +/* MULTIPLAYER MENU */ + +int m_multiplayer_cursor; +#define MULTIPLAYER_ITEMS 3 + + +void M_Menu_MultiPlayer_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_multiplayer; + m_entersound = true; +} + + +void M_MultiPlayer_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") ); + + f = (int)(realtime * 10)%6; //johnfitz -- was host_time + + M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); + + if (serialAvailable || ipxAvailable || tcpipAvailable) + return; + M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available"); +} + + +void M_MultiPlayer_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS) + m_multiplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_multiplayer_cursor < 0) + m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; + break; + + case K_ENTER: + m_entersound = true; + switch (m_multiplayer_cursor) + { + case 0: + if (serialAvailable || ipxAvailable || tcpipAvailable) + M_Menu_Net_f (); + break; + + case 1: + if (serialAvailable || ipxAvailable || tcpipAvailable) + M_Menu_Net_f (); + break; + + case 2: + M_Menu_Setup_f (); + break; + } + } +} + +//============================================================================= +/* SETUP MENU */ + +int setup_cursor = 4; +int setup_cursor_table[] = {40, 56, 80, 104, 140}; + +char setup_hostname[16]; +char setup_myname[16]; +int setup_oldtop; +int setup_oldbottom; +int setup_top; +int setup_bottom; + +#define NUM_SETUP_CMDS 5 + +void M_Menu_Setup_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_setup; + m_entersound = true; + Q_strcpy(setup_myname, cl_name.string); + Q_strcpy(setup_hostname, hostname.string); + setup_top = setup_oldtop = ((int)cl_color.value) >> 4; + setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15; +} + + +void M_Setup_Draw (void) +{ + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + M_Print (64, 40, "Hostname"); + M_DrawTextBox (160, 32, 16, 1); + M_Print (168, 40, setup_hostname); + + M_Print (64, 56, "Your name"); + M_DrawTextBox (160, 48, 16, 1); + M_Print (168, 56, setup_myname); + + M_Print (64, 80, "Shirt color"); + M_Print (64, 104, "Pants color"); + + M_DrawTextBox (64, 140-8, 14, 1); + M_Print (72, 140, "Accept Changes"); + + p = Draw_CachePic ("gfx/bigbox.lmp"); + M_DrawTransPic (160, 64, p); + p = Draw_CachePic ("gfx/menuplyr.lmp"); + M_DrawTransPicTranslate (172, 72, p, setup_top, setup_bottom); + + M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1)); + + if (setup_cursor == 0) + M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); + + if (setup_cursor == 1) + M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); +} + + +void M_Setup_Key (int k) +{ + int l; + + switch (k) + { + case K_ESCAPE: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + setup_cursor--; + if (setup_cursor < 0) + setup_cursor = NUM_SETUP_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + setup_cursor++; + if (setup_cursor >= NUM_SETUP_CMDS) + setup_cursor = 0; + break; + + case K_LEFTARROW: + if (setup_cursor < 2) + return; + S_LocalSound ("misc/menu3.wav"); + if (setup_cursor == 2) + setup_top = setup_top - 1; + if (setup_cursor == 3) + setup_bottom = setup_bottom - 1; + break; + case K_RIGHTARROW: + if (setup_cursor < 2) + return; +forward: + S_LocalSound ("misc/menu3.wav"); + if (setup_cursor == 2) + setup_top = setup_top + 1; + if (setup_cursor == 3) + setup_bottom = setup_bottom + 1; + break; + + case K_ENTER: + if (setup_cursor == 0 || setup_cursor == 1) + return; + + if (setup_cursor == 2 || setup_cursor == 3) + goto forward; + + // setup_cursor == 4 (OK) + if (Q_strcmp(cl_name.string, setup_myname) != 0) + Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) ); + if (Q_strcmp(hostname.string, setup_hostname) != 0) + Cvar_Set("hostname", setup_hostname); + if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom) + Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) ); + m_entersound = true; + M_Menu_MultiPlayer_f (); + break; + + case K_BACKSPACE: + if (setup_cursor == 0) + { + if (strlen(setup_hostname)) + setup_hostname[strlen(setup_hostname)-1] = 0; + } + + if (setup_cursor == 1) + { + if (strlen(setup_myname)) + setup_myname[strlen(setup_myname)-1] = 0; + } + break; + + default: + if (k < 32 || k > 127) + break; + if (setup_cursor == 0) + { + l = strlen(setup_hostname); + if (l < 15) + { + setup_hostname[l+1] = 0; + setup_hostname[l] = k; + } + } + if (setup_cursor == 1) + { + l = strlen(setup_myname); + if (l < 15) + { + setup_myname[l+1] = 0; + setup_myname[l] = k; + } + } + } + + if (setup_top > 13) + setup_top = 0; + if (setup_top < 0) + setup_top = 13; + if (setup_bottom > 13) + setup_bottom = 0; + if (setup_bottom < 0) + setup_bottom = 13; +} + +//============================================================================= +/* NET MENU */ + +int m_net_cursor; +int m_net_items; +int m_net_saveHeight; + +char *net_helpMessage [] = +{ +/* .........1.........2.... */ + " ", + " Two computers connected", + " through two modems. ", + " ", + + " ", + " Two computers connected", + " by a null-modem cable. ", + " ", + + " Novell network LANs ", + " or Windows 95 DOS-box. ", + " ", + "(LAN=Local Area Network)", + + " Commonly used to play ", + " over the Internet, but ", + " also used on a Local ", + " Area Network. " +}; + +void M_Menu_Net_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_net; + m_entersound = true; + m_net_items = 4; + + if (m_net_cursor >= m_net_items) + m_net_cursor = 0; + m_net_cursor--; + M_Net_Key (K_DOWNARROW); +} + + +void M_Net_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + f = 32; + + if (serialAvailable) + { + p = Draw_CachePic ("gfx/netmen1.lmp"); + } + else + { +#ifdef _WIN32 + p = NULL; +#else + p = Draw_CachePic ("gfx/dim_modm.lmp"); +#endif + } + + if (p) + M_DrawTransPic (72, f, p); + + f += 19; + + if (serialAvailable) + { + p = Draw_CachePic ("gfx/netmen2.lmp"); + } + else + { +#ifdef _WIN32 + p = NULL; +#else + p = Draw_CachePic ("gfx/dim_drct.lmp"); +#endif + } + + if (p) + M_DrawTransPic (72, f, p); + + f += 19; + if (ipxAvailable) + p = Draw_CachePic ("gfx/netmen3.lmp"); + else + p = Draw_CachePic ("gfx/dim_ipx.lmp"); + M_DrawTransPic (72, f, p); + + f += 19; + if (tcpipAvailable) + p = Draw_CachePic ("gfx/netmen4.lmp"); + else + p = Draw_CachePic ("gfx/dim_tcp.lmp"); + M_DrawTransPic (72, f, p); + + if (m_net_items == 5) // JDC, could just be removed + { + f += 19; + p = Draw_CachePic ("gfx/netmen5.lmp"); + M_DrawTransPic (72, f, p); + } + + f = (320-26*8)/2; + M_DrawTextBox (f, 134, 24, 4); + f += 8; + M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]); + M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]); + M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]); + M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]); + + f = (int)(realtime * 10)%6; //johnfitz -- was host_time + M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +} + + +void M_Net_Key (int k) +{ +again: + switch (k) + { + case K_ESCAPE: + M_Menu_MultiPlayer_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_net_cursor >= m_net_items) + m_net_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_net_cursor < 0) + m_net_cursor = m_net_items - 1; + break; + + case K_ENTER: + m_entersound = true; + + switch (m_net_cursor) + { + case 0: + M_Menu_SerialConfig_f (); + break; + + case 1: + M_Menu_SerialConfig_f (); + break; + + case 2: + M_Menu_LanConfig_f (); + break; + + case 3: + M_Menu_LanConfig_f (); + break; + + case 4: +// multiprotocol + break; + } + } + + if (m_net_cursor == 0 && !serialAvailable) + goto again; + if (m_net_cursor == 1 && !serialAvailable) + goto again; + if (m_net_cursor == 2 && !ipxAvailable) + goto again; + if (m_net_cursor == 3 && !tcpipAvailable) + goto again; +} + +//============================================================================= +/* OPTIONS MENU */ + +#ifdef _WIN32 +#define OPTIONS_ITEMS 14 +#else +#define OPTIONS_ITEMS 13 +#endif + +#define SLIDER_RANGE 10 + +int options_cursor; + +void M_Menu_Options_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_options; + m_entersound = true; +} + + +void M_AdjustSliders (int dir) +{ + S_LocalSound ("misc/menu3.wav"); + + switch (options_cursor) + { + case 3: // screen size + scr_viewsize.value += dir * 10; + if (scr_viewsize.value < 30) + scr_viewsize.value = 30; + if (scr_viewsize.value > 120) + scr_viewsize.value = 120; + Cvar_SetValue ("viewsize", scr_viewsize.value); + break; + case 4: // gamma + vid_gamma.value -= dir * 0.05; + if (vid_gamma.value < 0.5) + vid_gamma.value = 0.5; + if (vid_gamma.value > 1) + vid_gamma.value = 1; + Cvar_SetValue ("gamma", vid_gamma.value); + break; + case 5: // mouse speed + sensitivity.value += dir * 0.5; + if (sensitivity.value < 1) + sensitivity.value = 1; + if (sensitivity.value > 11) + sensitivity.value = 11; + Cvar_SetValue ("sensitivity", sensitivity.value); + break; + case 6: // music volume +#ifdef _WIN32 + bgmvolume.value += dir * 1.0; +#else + bgmvolume.value += dir * 0.1; +#endif + if (bgmvolume.value < 0) + bgmvolume.value = 0; + if (bgmvolume.value > 1) + bgmvolume.value = 1; + Cvar_SetValue ("bgmvolume", bgmvolume.value); + break; + case 7: // sfx volume + volume.value += dir * 0.1; + if (volume.value < 0) + volume.value = 0; + if (volume.value > 1) + volume.value = 1; + Cvar_SetValue ("volume", volume.value); + break; + + case 8: // allways run + if (cl_forwardspeed.value > 200) + { + Cvar_SetValue ("cl_forwardspeed", 200); + Cvar_SetValue ("cl_backspeed", 200); + } + else + { + Cvar_SetValue ("cl_forwardspeed", 400); + Cvar_SetValue ("cl_backspeed", 400); + } + break; + + case 9: // invert mouse + Cvar_SetValue ("m_pitch", -m_pitch.value); + break; + + case 10: // lookspring + Cvar_SetValue ("lookspring", !lookspring.value); + break; + + case 11: // lookstrafe + Cvar_SetValue ("lookstrafe", !lookstrafe.value); + break; + } +} + + +void M_DrawSlider (int x, int y, float range) +{ + int i; + + if (range < 0) + range = 0; + if (range > 1) + range = 1; + M_DrawCharacter (x-8, y, 128); + for (i=0 ; iwidth)/2, 4, p); + + M_Print (16, 32, " Customize controls"); + M_Print (16, 40, " Go to console"); + M_Print (16, 48, " Reset to defaults"); + + M_Print (16, 56, " Screen size"); + r = (scr_viewsize.value - 30) / (120 - 30); + M_DrawSlider (220, 56, r); + + M_Print (16, 64, " Brightness"); + r = (1.0 - vid_gamma.value) / 0.5; + M_DrawSlider (220, 64, r); + + M_Print (16, 72, " Mouse Speed"); + r = (sensitivity.value - 1)/10; + M_DrawSlider (220, 72, r); + + M_Print (16, 80, " CD Music Volume"); + r = bgmvolume.value; + M_DrawSlider (220, 80, r); + + M_Print (16, 88, " Sound Volume"); + r = volume.value; + M_DrawSlider (220, 88, r); + + M_Print (16, 96, " Always Run"); + M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200); + + M_Print (16, 104, " Invert Mouse"); + M_DrawCheckbox (220, 104, m_pitch.value < 0); + + M_Print (16, 112, " Lookspring"); + M_DrawCheckbox (220, 112, lookspring.value); + + M_Print (16, 120, " Lookstrafe"); + M_DrawCheckbox (220, 120, lookstrafe.value); + + if (vid_menudrawfn) + M_Print (16, 128, " Video Options"); + +// cursor + M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1)); +} + + +void M_Options_Key (int k) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_ENTER: + m_entersound = true; + switch (options_cursor) + { + case 0: + M_Menu_Keys_f (); + break; + case 1: + m_state = m_none; + Con_ToggleConsole_f (); + break; + case 2: + Cbuf_AddText ("resetall\n"); //johnfitz + Cbuf_AddText ("exec default.cfg\n"); + break; + case 12: + M_Menu_Video_f (); + break; + default: + M_AdjustSliders (1); + break; + } + return; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + options_cursor--; + if (options_cursor < 0) + options_cursor = OPTIONS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + options_cursor++; + if (options_cursor >= OPTIONS_ITEMS) + options_cursor = 0; + break; + + case K_LEFTARROW: + M_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + M_AdjustSliders (1); + break; + } + + if (options_cursor == 12 && vid_menudrawfn == NULL) + { + if (k == K_UPARROW) + options_cursor = 11; + else + options_cursor = 0; + } + +} + +//============================================================================= +/* KEYS MENU */ + +char *bindnames[][2] = +{ +{"+attack", "attack"}, +{"impulse 10", "change weapon"}, +{"+jump", "jump / swim up"}, +{"+forward", "walk forward"}, +{"+back", "backpedal"}, +{"+left", "turn left"}, +{"+right", "turn right"}, +{"+speed", "run"}, +{"+moveleft", "step left"}, +{"+moveright", "step right"}, +{"+strafe", "sidestep"}, +{"+lookup", "look up"}, +{"+lookdown", "look down"}, +{"centerview", "center view"}, +{"+mlook", "mouse look"}, +{"+klook", "keyboard look"}, +{"+moveup", "swim up"}, +{"+movedown", "swim down"} +}; + +#define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0])) + +int keys_cursor; +int bind_grab; + +void M_Menu_Keys_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_keys; + m_entersound = true; +} + + +void M_FindKeysForCommand (char *command, int *twokeys) +{ + int count; + int j; + int l; + char *b; + + twokeys[0] = twokeys[1] = -1; + l = strlen(command); + count = 0; + + for (j=0 ; j<256 ; j++) + { + b = keybindings[j]; + if (!b) + continue; + if (!strncmp (b, command, l) ) + { + twokeys[count] = j; + count++; + if (count == 2) + break; + } + } +} + +void M_UnbindCommand (char *command) +{ + int j; + int l; + char *b; + + l = strlen(command); + + for (j=0 ; j<256 ; j++) + { + b = keybindings[j]; + if (!b) + continue; + if (!strncmp (b, command, l) ) + Key_SetBinding (j, ""); + } +} + + +void M_Keys_Draw (void) +{ + int i, l; + int keys[2]; + char *name; + int x, y; + qpic_t *p; + + p = Draw_CachePic ("gfx/ttl_cstm.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + if (bind_grab) + M_Print (12, 32, "Press a key or button for this action"); + else + M_Print (18, 32, "Enter to change, backspace to clear"); + +// search for known bindings + for (i=0 ; i= NUMCOMMANDS) + keys_cursor = 0; + break; + + case K_ENTER: // go into bind mode + M_FindKeysForCommand (bindnames[keys_cursor][0], keys); + S_LocalSound ("misc/menu2.wav"); + if (keys[1] != -1) + M_UnbindCommand (bindnames[keys_cursor][0]); + bind_grab = true; + IN_Activate(); // activate to allow mouse key binding + break; + + case K_BACKSPACE: // delete bindings + case K_DEL: // delete bindings + S_LocalSound ("misc/menu2.wav"); + M_UnbindCommand (bindnames[keys_cursor][0]); + break; + } +} + +//============================================================================= +/* VIDEO MENU */ + +void M_Menu_Video_f (void) +{ + (*vid_menucmdfn) (); //johnfitz +} + + +void M_Video_Draw (void) +{ + (*vid_menudrawfn) (); +} + + +void M_Video_Key (int key) +{ + (*vid_menukeyfn) (key); +} + +//============================================================================= +/* HELP MENU */ + +int help_page; +#define NUM_HELP_PAGES 6 + + +void M_Menu_Help_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_help; + m_entersound = true; + help_page = 0; +} + + + +void M_Help_Draw (void) +{ + M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) ); +} + + +void M_Help_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Main_f (); + break; + + case K_UPARROW: + case K_RIGHTARROW: + m_entersound = true; + if (++help_page >= NUM_HELP_PAGES) + help_page = 0; + break; + + case K_DOWNARROW: + case K_LEFTARROW: + m_entersound = true; + if (--help_page < 0) + help_page = NUM_HELP_PAGES-1; + break; + } + +} + +//============================================================================= +/* QUIT MENU */ + +int msgNumber; +int m_quit_prevstate; +qboolean wasInMenus; + +void M_Menu_Quit_f (void) +{ + if (m_state == m_quit) + return; + wasInMenus = (key_dest == key_menu); + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_quit_prevstate = m_state; + m_state = m_quit; + m_entersound = true; + msgNumber = rand()&7; +} + + +void M_Quit_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case 'n': + case 'N': + if (wasInMenus) + { + m_state = m_quit_prevstate; + m_entersound = true; + } + else + { + IN_Activate(); + key_dest = key_game; + m_state = m_none; + } + break; + + case 'Y': + case 'y': + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_console; + Host_Quit_f (); + break; + + default: + break; + } + +} + +void M_Quit_Draw (void) //johnfitz -- modified for new quit message +{ + char msg1[40]; + char msg2[40]; + char msg3[40]; + int boxlen, y; + + if (wasInMenus) + { + m_state = m_quit_prevstate; + m_recursiveDraw = true; + M_Draw (); + m_state = m_quit; + } + + sprintf(msg1, "FitzQuake version %1.2f", (float)FITZQUAKE_VERSION); + sprintf(msg2, "by John Fitzgibbons"); + sprintf(msg3, "Press y to quit"); + + //okay, this is kind of fucked up. M_DrawTextBox will always act as if + //width is even. Also, the width and lines values are for the interior of the box, + //but the x and y values include the border. + boxlen = max(strlen(msg1),max(strlen(msg2),strlen(msg3))) + 1; + if (boxlen & 1) boxlen++; + M_DrawTextBox (160-4*(boxlen+2), 76, boxlen, 4); + + //now do the text + M_Print (160-4*strlen(msg1), 88, msg1); + M_Print (160-4*strlen(msg2), 96, msg2); + M_PrintWhite (160-4*strlen(msg3), 104, msg3); +} + +//============================================================================= + +/* SERIAL CONFIG MENU */ + +int serialConfig_cursor; +int serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132}; +#define NUM_SERIALCONFIG_CMDS 6 + +static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8}; +static int ISA_IRQs[] = {4,3,4,3}; +int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600}; + +int serialConfig_comport; +int serialConfig_irq ; +int serialConfig_baud; +char serialConfig_phone[16]; + +void M_Menu_SerialConfig_f (void) +{ + int n; + int port; + int baudrate; + qboolean useModem; + + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_serialconfig; + m_entersound = true; + if (JoiningGame && SerialConfig) + serialConfig_cursor = 4; + else + serialConfig_cursor = 5; + + (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem); + + // map uart's port to COMx + for (n = 0; n < 4; n++) + if (ISA_uarts[n] == port) + break; + if (n == 4) + { + n = 0; + serialConfig_irq = 4; + } + serialConfig_comport = n + 1; + + // map baudrate to index + for (n = 0; n < 6; n++) + if (serialConfig_baudrate[n] == baudrate) + break; + if (n == 6) + n = 5; + serialConfig_baud = n; + + m_return_onerror = false; + m_return_reason[0] = 0; +} + + +void M_SerialConfig_Draw (void) +{ + qpic_t *p; + int basex; + char *startJoin; + char *directModem; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (320-p->width)/2; + M_DrawPic (basex, 4, p); + + if (StartingGame) + startJoin = "New Game"; + else + startJoin = "Join Game"; + if (SerialConfig) + directModem = "Modem"; + else + directModem = "Direct Connect"; + M_Print (basex, 32, va ("%s - %s", startJoin, directModem)); + basex += 8; + + M_Print (basex, serialConfig_cursor_table[0], "Port"); + M_DrawTextBox (160, 40, 4, 1); + M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport)); + + M_Print (basex, serialConfig_cursor_table[1], "IRQ"); + M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1); + M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq)); + + M_Print (basex, serialConfig_cursor_table[2], "Baud"); + M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1); + M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud])); + + if (SerialConfig) + { + M_Print (basex, serialConfig_cursor_table[3], "Modem Setup..."); + if (JoiningGame) + { + M_Print (basex, serialConfig_cursor_table[4], "Phone number"); + M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1); + M_Print (168, serialConfig_cursor_table[4], serialConfig_phone); + } + } + + if (JoiningGame) + { + M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1); + M_Print (basex+8, serialConfig_cursor_table[5], "Connect"); + } + else + { + M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1); + M_Print (basex+8, serialConfig_cursor_table[5], "OK"); + } + + M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1)); + + if (serialConfig_cursor == 4) + M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_PrintWhite (basex, 148, m_return_reason); +} + + +void M_SerialConfig_Key (int key) +{ + int l; + + switch (key) + { + case K_ESCAPE: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + serialConfig_cursor--; + if (serialConfig_cursor < 0) + serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + serialConfig_cursor++; + if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS) + serialConfig_cursor = 0; + break; + + case K_LEFTARROW: + if (serialConfig_cursor > 2) + break; + S_LocalSound ("misc/menu3.wav"); + + if (serialConfig_cursor == 0) + { + serialConfig_comport--; + if (serialConfig_comport == 0) + serialConfig_comport = 4; + serialConfig_irq = ISA_IRQs[serialConfig_comport-1]; + } + + if (serialConfig_cursor == 1) + { + serialConfig_irq--; + if (serialConfig_irq == 6) + serialConfig_irq = 5; + if (serialConfig_irq == 1) + serialConfig_irq = 7; + } + + if (serialConfig_cursor == 2) + { + serialConfig_baud--; + if (serialConfig_baud < 0) + serialConfig_baud = 5; + } + + break; + + case K_RIGHTARROW: + if (serialConfig_cursor > 2) + break; +forward: + S_LocalSound ("misc/menu3.wav"); + + if (serialConfig_cursor == 0) + { + serialConfig_comport++; + if (serialConfig_comport > 4) + serialConfig_comport = 1; + serialConfig_irq = ISA_IRQs[serialConfig_comport-1]; + } + + if (serialConfig_cursor == 1) + { + serialConfig_irq++; + if (serialConfig_irq == 6) + serialConfig_irq = 7; + if (serialConfig_irq == 8) + serialConfig_irq = 2; + } + + if (serialConfig_cursor == 2) + { + serialConfig_baud++; + if (serialConfig_baud > 5) + serialConfig_baud = 0; + } + + break; + + case K_ENTER: + if (serialConfig_cursor < 3) + goto forward; + + m_entersound = true; + + if (serialConfig_cursor == 3) + { + (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); + + M_Menu_ModemConfig_f (); + break; + } + + if (serialConfig_cursor == 4) + { + serialConfig_cursor = 5; + break; + } + + // serialConfig_cursor == 5 (OK/CONNECT) + (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); + + M_ConfigureNetSubsystem (); + + if (StartingGame) + { + M_Menu_GameOptions_f (); + break; + } + + m_return_state = m_state; + m_return_onerror = true; + IN_Activate(); + key_dest = key_game; + m_state = m_none; + + if (SerialConfig) + Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone)); + else + Cbuf_AddText ("connect\n"); + break; + + case K_BACKSPACE: + if (serialConfig_cursor == 4) + { + if (strlen(serialConfig_phone)) + serialConfig_phone[strlen(serialConfig_phone)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + if (serialConfig_cursor == 4) + { + l = strlen(serialConfig_phone); + if (l < 15) + { + serialConfig_phone[l+1] = 0; + serialConfig_phone[l] = key; + } + } + } + + if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4)) + if (key == K_UPARROW) + serialConfig_cursor = 2; + else + serialConfig_cursor = 5; + + if (SerialConfig && StartingGame && serialConfig_cursor == 4) + if (key == K_UPARROW) + serialConfig_cursor = 3; + else + serialConfig_cursor = 5; +} + +//============================================================================= +/* MODEM CONFIG MENU */ + +int modemConfig_cursor; +int modemConfig_cursor_table [] = {40, 56, 88, 120, 156}; +#define NUM_MODEMCONFIG_CMDS 5 + +char modemConfig_dialing; +char modemConfig_clear [16]; +char modemConfig_init [32]; +char modemConfig_hangup [16]; + +void M_Menu_ModemConfig_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_modemconfig; + m_entersound = true; + (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup); +} + + +void M_ModemConfig_Draw (void) +{ + qpic_t *p; + int basex; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (320-p->width)/2; + M_DrawPic (basex, 4, p); + basex += 8; + + if (modemConfig_dialing == 'P') + M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing"); + else + M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing"); + + M_Print (basex, modemConfig_cursor_table[1], "Clear"); + M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1); + M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear); + if (modemConfig_cursor == 1) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1)); + + M_Print (basex, modemConfig_cursor_table[2], "Init"); + M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1); + M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init); + if (modemConfig_cursor == 2) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1)); + + M_Print (basex, modemConfig_cursor_table[3], "Hangup"); + M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1); + M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup); + if (modemConfig_cursor == 3) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1)); + + M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1); + M_Print (basex+8, modemConfig_cursor_table[4], "OK"); + + M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1)); +} + + +void M_ModemConfig_Key (int key) +{ + int l; + + switch (key) + { + case K_ESCAPE: + M_Menu_SerialConfig_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + modemConfig_cursor--; + if (modemConfig_cursor < 0) + modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + modemConfig_cursor++; + if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS) + modemConfig_cursor = 0; + break; + + case K_LEFTARROW: + case K_RIGHTARROW: + if (modemConfig_cursor == 0) + { + if (modemConfig_dialing == 'P') + modemConfig_dialing = 'T'; + else + modemConfig_dialing = 'P'; + S_LocalSound ("misc/menu1.wav"); + } + break; + + case K_ENTER: + if (modemConfig_cursor == 0) + { + if (modemConfig_dialing == 'P') + modemConfig_dialing = 'T'; + else + modemConfig_dialing = 'P'; + m_entersound = true; + } + + if (modemConfig_cursor == 4) + { + (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup); + m_entersound = true; + M_Menu_SerialConfig_f (); + } + break; + + case K_BACKSPACE: + if (modemConfig_cursor == 1) + { + if (strlen(modemConfig_clear)) + modemConfig_clear[strlen(modemConfig_clear)-1] = 0; + } + + if (modemConfig_cursor == 2) + { + if (strlen(modemConfig_init)) + modemConfig_init[strlen(modemConfig_init)-1] = 0; + } + + if (modemConfig_cursor == 3) + { + if (strlen(modemConfig_hangup)) + modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + + if (modemConfig_cursor == 1) + { + l = strlen(modemConfig_clear); + if (l < 15) + { + modemConfig_clear[l+1] = 0; + modemConfig_clear[l] = key; + } + } + + if (modemConfig_cursor == 2) + { + l = strlen(modemConfig_init); + if (l < 29) + { + modemConfig_init[l+1] = 0; + modemConfig_init[l] = key; + } + } + + if (modemConfig_cursor == 3) + { + l = strlen(modemConfig_hangup); + if (l < 15) + { + modemConfig_hangup[l+1] = 0; + modemConfig_hangup[l] = key; + } + } + } +} + +//============================================================================= +/* LAN CONFIG MENU */ + +int lanConfig_cursor = -1; +int lanConfig_cursor_table [] = {72, 92, 124}; +#define NUM_LANCONFIG_CMDS 3 + +int lanConfig_port; +char lanConfig_portname[6]; +char lanConfig_joinname[22]; + +void M_Menu_LanConfig_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_lanconfig; + m_entersound = true; + if (lanConfig_cursor == -1) + { + if (JoiningGame && TCPIPConfig) + lanConfig_cursor = 2; + else + lanConfig_cursor = 1; + } + if (StartingGame && lanConfig_cursor == 2) + lanConfig_cursor = 1; + lanConfig_port = DEFAULTnet_hostport; + sprintf(lanConfig_portname, "%u", lanConfig_port); + + m_return_onerror = false; + m_return_reason[0] = 0; +} + + +void M_LanConfig_Draw (void) +{ + qpic_t *p; + int basex; + char *startJoin; + char *protocol; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (320-p->width)/2; + M_DrawPic (basex, 4, p); + + if (StartingGame) + startJoin = "New Game"; + else + startJoin = "Join Game"; + if (IPXConfig) + protocol = "IPX"; + else + protocol = "TCP/IP"; + M_Print (basex, 32, va ("%s - %s", startJoin, protocol)); + basex += 8; + + M_Print (basex, 52, "Address:"); + if (IPXConfig) + M_Print (basex+9*8, 52, my_ipx_address); + else + M_Print (basex+9*8, 52, my_tcpip_address); + + M_Print (basex, lanConfig_cursor_table[0], "Port"); + M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1); + M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname); + + if (JoiningGame) + { + M_Print (basex, lanConfig_cursor_table[1], "Search for local games..."); + M_Print (basex, 108, "Join game at:"); + M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1); + M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname); + } + else + { + M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1); + M_Print (basex+8, lanConfig_cursor_table[1], "OK"); + } + + M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1)); + + if (lanConfig_cursor == 0) + M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1)); + + if (lanConfig_cursor == 2) + M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_PrintWhite (basex, 148, m_return_reason); +} + + +void M_LanConfig_Key (int key) +{ + int l; + + switch (key) + { + case K_ESCAPE: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + lanConfig_cursor--; + if (lanConfig_cursor < 0) + lanConfig_cursor = NUM_LANCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + lanConfig_cursor++; + if (lanConfig_cursor >= NUM_LANCONFIG_CMDS) + lanConfig_cursor = 0; + break; + + case K_ENTER: + if (lanConfig_cursor == 0) + break; + + m_entersound = true; + + M_ConfigureNetSubsystem (); + + if (lanConfig_cursor == 1) + { + if (StartingGame) + { + M_Menu_GameOptions_f (); + break; + } + M_Menu_Search_f(); + break; + } + + if (lanConfig_cursor == 2) + { + m_return_state = m_state; + m_return_onerror = true; + IN_Activate(); + key_dest = key_game; + m_state = m_none; + Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) ); + break; + } + + break; + + case K_BACKSPACE: + if (lanConfig_cursor == 0) + { + if (strlen(lanConfig_portname)) + lanConfig_portname[strlen(lanConfig_portname)-1] = 0; + } + + if (lanConfig_cursor == 2) + { + if (strlen(lanConfig_joinname)) + lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + + if (lanConfig_cursor == 2) + { + l = strlen(lanConfig_joinname); + if (l < 21) + { + lanConfig_joinname[l+1] = 0; + lanConfig_joinname[l] = key; + } + } + + if (key < '0' || key > '9') + break; + if (lanConfig_cursor == 0) + { + l = strlen(lanConfig_portname); + if (l < 5) + { + lanConfig_portname[l+1] = 0; + lanConfig_portname[l] = key; + } + } + } + + if (StartingGame && lanConfig_cursor == 2) + if (key == K_UPARROW) + lanConfig_cursor = 1; + else + lanConfig_cursor = 0; + + l = Q_atoi(lanConfig_portname); + if (l > 65535) + l = lanConfig_port; + else + lanConfig_port = l; + sprintf(lanConfig_portname, "%u", lanConfig_port); +} + +//============================================================================= +/* GAME OPTIONS MENU */ + +typedef struct +{ + char *name; + char *description; +} level_t; + +level_t levels[] = +{ + {"start", "Entrance"}, // 0 + + {"e1m1", "Slipgate Complex"}, // 1 + {"e1m2", "Castle of the Damned"}, + {"e1m3", "The Necropolis"}, + {"e1m4", "The Grisly Grotto"}, + {"e1m5", "Gloom Keep"}, + {"e1m6", "The Door To Chthon"}, + {"e1m7", "The House of Chthon"}, + {"e1m8", "Ziggurat Vertigo"}, + + {"e2m1", "The Installation"}, // 9 + {"e2m2", "Ogre Citadel"}, + {"e2m3", "Crypt of Decay"}, + {"e2m4", "The Ebon Fortress"}, + {"e2m5", "The Wizard's Manse"}, + {"e2m6", "The Dismal Oubliette"}, + {"e2m7", "Underearth"}, + + {"e3m1", "Termination Central"}, // 16 + {"e3m2", "The Vaults of Zin"}, + {"e3m3", "The Tomb of Terror"}, + {"e3m4", "Satan's Dark Delight"}, + {"e3m5", "Wind Tunnels"}, + {"e3m6", "Chambers of Torment"}, + {"e3m7", "The Haunted Halls"}, + + {"e4m1", "The Sewage System"}, // 23 + {"e4m2", "The Tower of Despair"}, + {"e4m3", "The Elder God Shrine"}, + {"e4m4", "The Palace of Hate"}, + {"e4m5", "Hell's Atrium"}, + {"e4m6", "The Pain Maze"}, + {"e4m7", "Azure Agony"}, + {"e4m8", "The Nameless City"}, + + {"end", "Shub-Niggurath's Pit"}, // 31 + + {"dm1", "Place of Two Deaths"}, // 32 + {"dm2", "Claustrophobopolis"}, + {"dm3", "The Abandoned Base"}, + {"dm4", "The Bad Place"}, + {"dm5", "The Cistern"}, + {"dm6", "The Dark Zone"} +}; + +//MED 01/06/97 added hipnotic levels +level_t hipnoticlevels[] = +{ + {"start", "Command HQ"}, // 0 + + {"hip1m1", "The Pumping Station"}, // 1 + {"hip1m2", "Storage Facility"}, + {"hip1m3", "The Lost Mine"}, + {"hip1m4", "Research Facility"}, + {"hip1m5", "Military Complex"}, + + {"hip2m1", "Ancient Realms"}, // 6 + {"hip2m2", "The Black Cathedral"}, + {"hip2m3", "The Catacombs"}, + {"hip2m4", "The Crypt"}, + {"hip2m5", "Mortum's Keep"}, + {"hip2m6", "The Gremlin's Domain"}, + + {"hip3m1", "Tur Torment"}, // 12 + {"hip3m2", "Pandemonium"}, + {"hip3m3", "Limbo"}, + {"hip3m4", "The Gauntlet"}, + + {"hipend", "Armagon's Lair"}, // 16 + + {"hipdm1", "The Edge of Oblivion"} // 17 +}; + +//PGM 01/07/97 added rogue levels +//PGM 03/02/97 added dmatch level +level_t roguelevels[] = +{ + {"start", "Split Decision"}, + {"r1m1", "Deviant's Domain"}, + {"r1m2", "Dread Portal"}, + {"r1m3", "Judgement Call"}, + {"r1m4", "Cave of Death"}, + {"r1m5", "Towers of Wrath"}, + {"r1m6", "Temple of Pain"}, + {"r1m7", "Tomb of the Overlord"}, + {"r2m1", "Tempus Fugit"}, + {"r2m2", "Elemental Fury I"}, + {"r2m3", "Elemental Fury II"}, + {"r2m4", "Curse of Osiris"}, + {"r2m5", "Wizard's Keep"}, + {"r2m6", "Blood Sacrifice"}, + {"r2m7", "Last Bastion"}, + {"r2m8", "Source of Evil"}, + {"ctf1", "Division of Change"} +}; + +typedef struct +{ + char *description; + int firstLevel; + int levels; +} episode_t; + +episode_t episodes[] = +{ + {"Welcome to Quake", 0, 1}, + {"Doomed Dimension", 1, 8}, + {"Realm of Black Magic", 9, 7}, + {"Netherworld", 16, 7}, + {"The Elder World", 23, 8}, + {"Final Level", 31, 1}, + {"Deathmatch Arena", 32, 6} +}; + +//MED 01/06/97 added hipnotic episodes +episode_t hipnoticepisodes[] = +{ + {"Scourge of Armagon", 0, 1}, + {"Fortress of the Dead", 1, 5}, + {"Dominion of Darkness", 6, 6}, + {"The Rift", 12, 4}, + {"Final Level", 16, 1}, + {"Deathmatch Arena", 17, 1} +}; + +//PGM 01/07/97 added rogue episodes +//PGM 03/02/97 added dmatch episode +episode_t rogueepisodes[] = +{ + {"Introduction", 0, 1}, + {"Hell's Fortress", 1, 7}, + {"Corridors of Time", 8, 8}, + {"Deathmatch Arena", 16, 1} +}; + +int startepisode; +int startlevel; +int maxplayers; +qboolean m_serverInfoMessage = false; +double m_serverInfoMessageTime; + +void M_Menu_GameOptions_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_gameoptions; + m_entersound = true; + if (maxplayers == 0) + maxplayers = svs.maxclients; + if (maxplayers < 2) + maxplayers = svs.maxclientslimit; +} + + +int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120}; +#define NUM_GAMEOPTIONS 9 +int gameoptions_cursor; + +void M_GameOptions_Draw (void) +{ + qpic_t *p; + int x; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + M_DrawTextBox (152, 32, 10, 1); + M_Print (160, 40, "begin game"); + + M_Print (0, 56, " Max players"); + M_Print (160, 56, va("%i", maxplayers) ); + + M_Print (0, 64, " Game Type"); + if (coop.value) + M_Print (160, 64, "Cooperative"); + else + M_Print (160, 64, "Deathmatch"); + + M_Print (0, 72, " Teamplay"); + if (rogue) + { + char *msg; + + switch((int)teamplay.value) + { + case 1: msg = "No Friendly Fire"; break; + case 2: msg = "Friendly Fire"; break; + case 3: msg = "Tag"; break; + case 4: msg = "Capture the Flag"; break; + case 5: msg = "One Flag CTF"; break; + case 6: msg = "Three Team CTF"; break; + default: msg = "Off"; break; + } + M_Print (160, 72, msg); + } + else + { + char *msg; + + switch((int)teamplay.value) + { + case 1: msg = "No Friendly Fire"; break; + case 2: msg = "Friendly Fire"; break; + default: msg = "Off"; break; + } + M_Print (160, 72, msg); + } + + M_Print (0, 80, " Skill"); + if (skill.value == 0) + M_Print (160, 80, "Easy difficulty"); + else if (skill.value == 1) + M_Print (160, 80, "Normal difficulty"); + else if (skill.value == 2) + M_Print (160, 80, "Hard difficulty"); + else + M_Print (160, 80, "Nightmare difficulty"); + + M_Print (0, 88, " Frag Limit"); + if (fraglimit.value == 0) + M_Print (160, 88, "none"); + else + M_Print (160, 88, va("%i frags", (int)fraglimit.value)); + + M_Print (0, 96, " Time Limit"); + if (timelimit.value == 0) + M_Print (160, 96, "none"); + else + M_Print (160, 96, va("%i minutes", (int)timelimit.value)); + + M_Print (0, 112, " Episode"); + //MED 01/06/97 added hipnotic episodes + if (hipnotic) + M_Print (160, 112, hipnoticepisodes[startepisode].description); + //PGM 01/07/97 added rogue episodes + else if (rogue) + M_Print (160, 112, rogueepisodes[startepisode].description); + else + M_Print (160, 112, episodes[startepisode].description); + + M_Print (0, 120, " Level"); + //MED 01/06/97 added hipnotic episodes + if (hipnotic) + { + M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name); + } + //PGM 01/07/97 added rogue episodes + else if (rogue) + { + M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name); + } + else + { + M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name); + } + +// line cursor + M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1)); + + if (m_serverInfoMessage) + { + if ((realtime - m_serverInfoMessageTime) < 5.0) + { + x = (320-26*8)/2; + M_DrawTextBox (x, 138, 24, 4); + x += 8; + M_Print (x, 146, " More than 4 players "); + M_Print (x, 154, " requires using command "); + M_Print (x, 162, "line parameters; please "); + M_Print (x, 170, " see techinfo.txt. "); + } + else + { + m_serverInfoMessage = false; + } + } +} + + +void M_NetStart_Change (int dir) +{ + int count; + + switch (gameoptions_cursor) + { + case 1: + maxplayers += dir; + if (maxplayers > svs.maxclientslimit) + { + maxplayers = svs.maxclientslimit; + m_serverInfoMessage = true; + m_serverInfoMessageTime = realtime; + } + if (maxplayers < 2) + maxplayers = 2; + break; + + case 2: + Cvar_SetValue ("coop", coop.value ? 0 : 1); + break; + + case 3: + if (rogue) + count = 6; + else + count = 2; + + Cvar_SetValue ("teamplay", teamplay.value + dir); + if (teamplay.value > count) + Cvar_SetValue ("teamplay", 0); + else if (teamplay.value < 0) + Cvar_SetValue ("teamplay", count); + break; + + case 4: + Cvar_SetValue ("skill", skill.value + dir); + if (skill.value > 3) + Cvar_SetValue ("skill", 0); + if (skill.value < 0) + Cvar_SetValue ("skill", 3); + break; + + case 5: + Cvar_SetValue ("fraglimit", fraglimit.value + dir*10); + if (fraglimit.value > 100) + Cvar_SetValue ("fraglimit", 0); + if (fraglimit.value < 0) + Cvar_SetValue ("fraglimit", 100); + break; + + case 6: + Cvar_SetValue ("timelimit", timelimit.value + dir*5); + if (timelimit.value > 60) + Cvar_SetValue ("timelimit", 0); + if (timelimit.value < 0) + Cvar_SetValue ("timelimit", 60); + break; + + case 7: + startepisode += dir; + //MED 01/06/97 added hipnotic count + if (hipnotic) + count = 6; + //PGM 01/07/97 added rogue count + //PGM 03/02/97 added 1 for dmatch episode + else if (rogue) + count = 4; + else if (registered.value) + count = 7; + else + count = 2; + + if (startepisode < 0) + startepisode = count - 1; + + if (startepisode >= count) + startepisode = 0; + + startlevel = 0; + break; + + case 8: + startlevel += dir; + //MED 01/06/97 added hipnotic episodes + if (hipnotic) + count = hipnoticepisodes[startepisode].levels; + //PGM 01/06/97 added hipnotic episodes + else if (rogue) + count = rogueepisodes[startepisode].levels; + else + count = episodes[startepisode].levels; + + if (startlevel < 0) + startlevel = count - 1; + + if (startlevel >= count) + startlevel = 0; + break; + } +} + +void M_GameOptions_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + gameoptions_cursor--; + if (gameoptions_cursor < 0) + gameoptions_cursor = NUM_GAMEOPTIONS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + gameoptions_cursor++; + if (gameoptions_cursor >= NUM_GAMEOPTIONS) + gameoptions_cursor = 0; + break; + + case K_LEFTARROW: + if (gameoptions_cursor == 0) + break; + S_LocalSound ("misc/menu3.wav"); + M_NetStart_Change (-1); + break; + + case K_RIGHTARROW: + if (gameoptions_cursor == 0) + break; + S_LocalSound ("misc/menu3.wav"); + M_NetStart_Change (1); + break; + + case K_ENTER: + S_LocalSound ("misc/menu2.wav"); + if (gameoptions_cursor == 0) + { + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined + Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) ); + SCR_BeginLoadingPlaque (); + + if (hipnotic) + Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) ); + else if (rogue) + Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) ); + else + Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) ); + + return; + } + + M_NetStart_Change (1); + break; + } +} + +//============================================================================= +/* SEARCH MENU */ + +qboolean searchComplete = false; +double searchCompleteTime; + +void M_Menu_Search_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_search; + m_entersound = false; + slistSilent = true; + slistLocal = false; + searchComplete = false; + NET_Slist_f(); + +} + + +void M_Search_Draw (void) +{ + qpic_t *p; + int x; + + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + x = (320/2) - ((12*8)/2) + 4; + M_DrawTextBox (x-8, 32, 12, 1); + M_Print (x, 40, "Searching..."); + + if(slistInProgress) + { + NET_Poll(); + return; + } + + if (! searchComplete) + { + searchComplete = true; + searchCompleteTime = realtime; + } + + if (hostCacheCount) + { + M_Menu_ServerList_f (); + return; + } + + M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found"); + if ((realtime - searchCompleteTime) < 3.0) + return; + + M_Menu_LanConfig_f (); +} + + +void M_Search_Key (int key) +{ +} + +//============================================================================= +/* SLIST MENU */ + +int slist_cursor; +qboolean slist_sorted; + +void M_Menu_ServerList_f (void) +{ + IN_Deactivate(vid.type == MODE_WINDOWED); + key_dest = key_menu; + m_state = m_slist; + m_entersound = true; + slist_cursor = 0; + m_return_onerror = false; + m_return_reason[0] = 0; + slist_sorted = false; +} + + +void M_ServerList_Draw (void) +{ + int n; + char string [64]; + qpic_t *p; + + if (!slist_sorted) + { + if (hostCacheCount > 1) + { + int i,j; + hostcache_t temp; + for (i = 0; i < hostCacheCount; i++) + for (j = i+1; j < hostCacheCount; j++) + if (strcmp(hostcache[j].name, hostcache[i].name) < 0) + { + Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t)); + Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t)); + Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t)); + } + } + slist_sorted = true; + } + + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + for (n = 0; n < hostCacheCount; n++) + { + if (hostcache[n].maxusers) + sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); + else + sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); + M_Print (16, 32 + 8*n, string); + } + M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_PrintWhite (16, 148, m_return_reason); +} + + +void M_ServerList_Key (int k) +{ + switch (k) + { + case K_ESCAPE: + M_Menu_LanConfig_f (); + break; + + case K_SPACE: + M_Menu_Search_f (); + break; + + case K_UPARROW: + case K_LEFTARROW: + S_LocalSound ("misc/menu1.wav"); + slist_cursor--; + if (slist_cursor < 0) + slist_cursor = hostCacheCount - 1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + S_LocalSound ("misc/menu1.wav"); + slist_cursor++; + if (slist_cursor >= hostCacheCount) + slist_cursor = 0; + break; + + case K_ENTER: + S_LocalSound ("misc/menu2.wav"); + m_return_state = m_state; + m_return_onerror = true; + slist_sorted = false; + IN_Activate(); + key_dest = key_game; + m_state = m_none; + Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) ); + break; + + default: + break; + } + +} + +//============================================================================= +/* Menu Subsystem */ + + +void M_Init (void) +{ + Cmd_AddCommand ("togglemenu", M_ToggleMenu_f); + + Cmd_AddCommand ("menu_main", M_Menu_Main_f); + Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f); + Cmd_AddCommand ("menu_load", M_Menu_Load_f); + Cmd_AddCommand ("menu_save", M_Menu_Save_f); + Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f); + Cmd_AddCommand ("menu_setup", M_Menu_Setup_f); + Cmd_AddCommand ("menu_options", M_Menu_Options_f); + Cmd_AddCommand ("menu_keys", M_Menu_Keys_f); + Cmd_AddCommand ("menu_video", M_Menu_Video_f); + Cmd_AddCommand ("help", M_Menu_Help_f); + Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); +} + + +void M_Draw (void) +{ + if (m_state == m_none || key_dest != key_menu) + return; + + if (!m_recursiveDraw) + { + if (scr_con_current) + { + Draw_ConsoleBackground (); + S_ExtraUpdate (); + } + + Draw_FadeScreen (); //johnfitz -- fade even if console fills screen + } + else + { + m_recursiveDraw = false; + } + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + switch (m_state) + { + case m_none: + break; + + case m_main: + M_Main_Draw (); + break; + + case m_singleplayer: + M_SinglePlayer_Draw (); + break; + + case m_load: + M_Load_Draw (); + break; + + case m_save: + M_Save_Draw (); + break; + + case m_multiplayer: + M_MultiPlayer_Draw (); + break; + + case m_setup: + M_Setup_Draw (); + break; + + case m_net: + M_Net_Draw (); + break; + + case m_options: + M_Options_Draw (); + break; + + case m_keys: + M_Keys_Draw (); + break; + + case m_video: + M_Video_Draw (); + break; + + case m_help: + M_Help_Draw (); + break; + + case m_quit: + M_Quit_Draw (); + break; + + case m_serialconfig: + M_SerialConfig_Draw (); + break; + + case m_modemconfig: + M_ModemConfig_Draw (); + break; + + case m_lanconfig: + M_LanConfig_Draw (); + break; + + case m_gameoptions: + M_GameOptions_Draw (); + break; + + case m_search: + M_Search_Draw (); + break; + + case m_slist: + M_ServerList_Draw (); + break; + } + + if (m_entersound) + { + S_LocalSound ("misc/menu2.wav"); + m_entersound = false; + } + + S_ExtraUpdate (); +} + + +void M_Keydown (int key) +{ + switch (m_state) + { + case m_none: + return; + + case m_main: + M_Main_Key (key); + return; + + case m_singleplayer: + M_SinglePlayer_Key (key); + return; + + case m_load: + M_Load_Key (key); + return; + + case m_save: + M_Save_Key (key); + return; + + case m_multiplayer: + M_MultiPlayer_Key (key); + return; + + case m_setup: + M_Setup_Key (key); + return; + + case m_net: + M_Net_Key (key); + return; + + case m_options: + M_Options_Key (key); + return; + + case m_keys: + M_Keys_Key (key); + return; + + case m_video: + M_Video_Key (key); + return; + + case m_help: + M_Help_Key (key); + return; + + case m_quit: + M_Quit_Key (key); + return; + + case m_serialconfig: + M_SerialConfig_Key (key); + return; + + case m_modemconfig: + M_ModemConfig_Key (key); + return; + + case m_lanconfig: + M_LanConfig_Key (key); + return; + + case m_gameoptions: + M_GameOptions_Key (key); + return; + + case m_search: + M_Search_Key (key); + break; + + case m_slist: + M_ServerList_Key (key); + return; + } +} + + +void M_ConfigureNetSubsystem(void) +{ +// enable/disable net systems to match desired config + + Cbuf_AddText ("stopdemo\n"); + if (SerialConfig || DirectConfig) + { + Cbuf_AddText ("com1 enable\n"); + } + + if (IPXConfig || TCPIPConfig) + net_hostport = lanConfig_port; +} diff --git a/Quake/menu.h b/Quake/menu.h new file mode 100644 index 00000000..f2729a7f --- /dev/null +++ b/Quake/menu.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// +// the net drivers should just set the apropriate bits in m_activenet, +// instead of having the menu code look through their internal tables +// +#define MNET_IPX 1 +#define MNET_TCP 2 + +extern int m_activenet; + +// +// menus +// +void M_Init (void); +void M_Keydown (int key); +void M_Draw (void); +void M_ToggleMenu_f (void); + + diff --git a/Quake/modelgen.h b/Quake/modelgen.h new file mode 100644 index 00000000..1d0bacbf --- /dev/null +++ b/Quake/modelgen.h @@ -0,0 +1,135 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// modelgen.h: header file for model generation program +// + +// ********************************************************* +// * This file must be identical in the modelgen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via model files. * +// ********************************************************* + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "mathlib.h" + +#endif + +#define ALIAS_VERSION 6 + +#define ALIAS_ONSEAM 0x0020 + +// must match definition in spritegn.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t; + +typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; + +typedef struct { + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; +} mdl_t; + +// TODO: could be shorts + +typedef struct { + int onseam; + int s; + int t; +} stvert_t; + +typedef struct dtriangle_s { + int facesfront; + int vertindex[3]; +} dtriangle_t; + +#define DT_FACES_FRONT 0x0010 + +// This mirrors trivert_t in trilib.h, is present so Quake knows how to +// load this data + +typedef struct { + byte v[3]; + byte lightnormalindex; +} trivertx_t; + +typedef struct { + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used + char name[16]; // frame name from grabbing +} daliasframe_t; + +typedef struct { + int numframes; + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used +} daliasgroup_t; + +typedef struct { + int numskins; +} daliasskingroup_t; + +typedef struct { + float interval; +} daliasinterval_t; + +typedef struct { + float interval; +} daliasskininterval_t; + +typedef struct { + aliasframetype_t type; +} daliasframetype_t; + +typedef struct { + aliasskintype_t type; +} daliasskintype_t; + +#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I') + // little-endian "IDPO" + diff --git a/Quake/net.h b/Quake/net.h new file mode 100644 index 00000000..ffc066c7 --- /dev/null +++ b/Quake/net.h @@ -0,0 +1,334 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net.h -- quake's interface to the networking layer + +struct qsockaddr +{ + short sa_family; + unsigned char sa_data[14]; +}; + + +#define NET_NAMELEN 64 + +#define NET_MAXMESSAGE 32000 //johnfitz -- was 8192 +#define NET_HEADERSIZE (2 * sizeof(unsigned int)) +#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE) + +// NetHeader flags +#define NETFLAG_LENGTH_MASK 0x0000ffff +#define NETFLAG_DATA 0x00010000 +#define NETFLAG_ACK 0x00020000 +#define NETFLAG_NAK 0x00040000 +#define NETFLAG_EOM 0x00080000 +#define NETFLAG_UNRELIABLE 0x00100000 +#define NETFLAG_CTL 0x80000000 + + +#define NET_PROTOCOL_VERSION 3 + +// This is the network info/connection protocol. It is used to find Quake +// servers, get info about them, and connect to them. Once connected, the +// Quake game protocol (documented elsewhere) is used. +// +// +// General notes: +// game_name is currently always "QUAKE", but is there so this same protocol +// can be used for future games as well; can you say Quake2? +// +// CCREQ_CONNECT +// string game_name "QUAKE" +// byte net_protocol_version NET_PROTOCOL_VERSION +// +// CCREQ_SERVER_INFO +// string game_name "QUAKE" +// byte net_protocol_version NET_PROTOCOL_VERSION +// +// CCREQ_PLAYER_INFO +// byte player_number +// +// CCREQ_RULE_INFO +// string rule +// +// +// +// CCREP_ACCEPT +// long port +// +// CCREP_REJECT +// string reason +// +// CCREP_SERVER_INFO +// string server_address +// string host_name +// string level_name +// byte current_players +// byte max_players +// byte protocol_version NET_PROTOCOL_VERSION +// +// CCREP_PLAYER_INFO +// byte player_number +// string name +// long colors +// long frags +// long connect_time +// string address +// +// CCREP_RULE_INFO +// string rule +// string value + +// note: +// There are two address forms used above. The short form is just a +// port number. The address that goes along with the port is defined as +// "whatever address you receive this reponse from". This lets us use +// the host OS to solve the problem of multiple host addresses (possibly +// with no routing between them); the host will use the right address +// when we reply to the inbound connection request. The long from is +// a full address and port in a string. It is used for returning the +// address of a server that is not running locally. + +#define CCREQ_CONNECT 0x01 +#define CCREQ_SERVER_INFO 0x02 +#define CCREQ_PLAYER_INFO 0x03 +#define CCREQ_RULE_INFO 0x04 + +#define CCREP_ACCEPT 0x81 +#define CCREP_REJECT 0x82 +#define CCREP_SERVER_INFO 0x83 +#define CCREP_PLAYER_INFO 0x84 +#define CCREP_RULE_INFO 0x85 + +typedef struct qsocket_s +{ + struct qsocket_s *next; + double connecttime; + double lastMessageTime; + double lastSendTime; + + qboolean disconnected; + qboolean canSend; + qboolean sendNext; + + int driver; + int landriver; + int socket; + void *driverdata; + + unsigned int ackSequence; + unsigned int sendSequence; + unsigned int unreliableSendSequence; + int sendMessageLength; + byte sendMessage [NET_MAXMESSAGE]; + + unsigned int receiveSequence; + unsigned int unreliableReceiveSequence; + int receiveMessageLength; + byte receiveMessage [NET_MAXMESSAGE]; + + struct qsockaddr addr; + char address[NET_NAMELEN]; + +} qsocket_t; + +extern qsocket_t *net_activeSockets; +extern qsocket_t *net_freeSockets; +extern int net_numsockets; + +typedef struct +{ + char *name; + qboolean initialized; + int controlSock; + int (*Init) (void); + void (*Shutdown) (void); + void (*Listen) (qboolean state); + int (*OpenSocket) (int port); + int (*CloseSocket) (int socket); + int (*Connect) (int socket, struct qsockaddr *addr); + int (*CheckNewConnections) (void); + int (*Read) (int socket, byte *buf, int len, struct qsockaddr *addr); + int (*Write) (int socket, byte *buf, int len, struct qsockaddr *addr); + int (*Broadcast) (int socket, byte *buf, int len); + char * (*AddrToString) (struct qsockaddr *addr); + int (*StringToAddr) (char *string, struct qsockaddr *addr); + int (*GetSocketAddr) (int socket, struct qsockaddr *addr); + int (*GetNameFromAddr) (struct qsockaddr *addr, char *name); + int (*GetAddrFromName) (char *name, struct qsockaddr *addr); + int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2); + int (*GetSocketPort) (struct qsockaddr *addr); + int (*SetSocketPort) (struct qsockaddr *addr, int port); +} net_landriver_t; + +#define MAX_NET_DRIVERS 8 +extern int net_numlandrivers; +extern net_landriver_t net_landrivers[MAX_NET_DRIVERS]; + +typedef struct +{ + char *name; + qboolean initialized; + int (*Init) (void); + void (*Listen) (qboolean state); + void (*SearchForHosts) (qboolean xmit); + qsocket_t *(*Connect) (char *host); + qsocket_t *(*CheckNewConnections) (void); + int (*QGetMessage) (qsocket_t *sock); + int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data); + int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data); + qboolean (*CanSendMessage) (qsocket_t *sock); + qboolean (*CanSendUnreliableMessage) (qsocket_t *sock); + void (*Close) (qsocket_t *sock); + void (*Shutdown) (void); + int controlSock; +} net_driver_t; + +extern int net_numdrivers; +extern net_driver_t net_drivers[MAX_NET_DRIVERS]; + +extern int DEFAULTnet_hostport; +extern int net_hostport; + +extern int net_driverlevel; +extern cvar_t hostname; +extern char playername[]; +extern int playercolor; + +extern int messagesSent; +extern int messagesReceived; +extern int unreliableMessagesSent; +extern int unreliableMessagesReceived; + +qsocket_t *NET_NewQSocket (void); +void NET_FreeQSocket(qsocket_t *); +double SetNetTime(void); + + +#define HOSTCACHESIZE 8 + +typedef struct +{ + char name[16]; + char map[16]; + char cname[32]; + int users; + int maxusers; + int driver; + int ldriver; + struct qsockaddr addr; +} hostcache_t; + +extern int hostCacheCount; +extern hostcache_t hostcache[HOSTCACHESIZE]; + +#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__) +#ifndef htonl +extern unsigned long htonl (unsigned long hostlong); +#endif +#ifndef htons +extern unsigned short htons (unsigned short hostshort); +#endif +#ifndef ntohl +extern unsigned long ntohl (unsigned long netlong); +#endif +#ifndef ntohs +extern unsigned short ntohs (unsigned short netshort); +#endif +#endif + +//============================================================================ +// +// public network functions +// +//============================================================================ + +extern double net_time; +extern sizebuf_t net_message; +extern int net_activeconnections; + +void NET_Init (void); +void NET_Shutdown (void); + +struct qsocket_s *NET_CheckNewConnections (void); +// returns a new connection number if there is one pending, else -1 + +struct qsocket_s *NET_Connect (char *host); +// called by client to connect to a host. Returns -1 if not able to + +qboolean NET_CanSendMessage (qsocket_t *sock); +// Returns true or false if the given qsocket can currently accept a +// message to be transmitted. + +int NET_GetMessage (struct qsocket_s *sock); +// returns data in net_message sizebuf +// returns 0 if no data is waiting +// returns 1 if a message was received +// returns 2 if an unreliable message was received +// returns -1 if the connection died + +int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data); +int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data); +// returns 0 if the message connot be delivered reliably, but the connection +// is still considered valid +// returns 1 if the message was sent properly +// returns -1 if the connection died + +int NET_SendToAll(sizebuf_t *data, int blocktime); +// This is a reliable *blocking* send to all attached clients. + + +void NET_Close (struct qsocket_s *sock); +// if a dead connection is returned by a get or send function, this function +// should be called when it is convenient + +// Server calls when a client is kicked off for a game related misbehavior +// like an illegal protocal conversation. Client calls when disconnecting +// from a server. +// A netcon_t number will not be reused until this function is called for it + +void NET_Poll(void); + + +typedef struct _PollProcedure +{ + struct _PollProcedure *next; + double nextTime; + void (*procedure)(); + void *arg; +} PollProcedure; + +void SchedulePollProcedure(PollProcedure *pp, double timeOffset); + +extern qboolean serialAvailable; +extern qboolean ipxAvailable; +extern qboolean tcpipAvailable; +extern char my_ipx_address[NET_NAMELEN]; +extern char my_tcpip_address[NET_NAMELEN]; +extern void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem); +extern void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem); +extern void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); +extern void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); + +extern qboolean slistInProgress; +extern qboolean slistSilent; +extern qboolean slistLocal; + +void NET_Slist_f (void); diff --git a/Quake/net_dgrm.c b/Quake/net_dgrm.c new file mode 100644 index 00000000..0fc2ca45 --- /dev/null +++ b/Quake/net_dgrm.c @@ -0,0 +1,1384 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_dgrm.c + +// This is enables a simple IP banning mechanism +//#define BAN_TEST disabled --kristian + +#ifdef BAN_TEST +#if defined(_WIN32) +#include +#elif defined (NeXT) +#include +#include +#else +#define AF_INET 2 /* internet */ +struct in_addr +{ + union + { + struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { unsigned short s_w1,s_w2; } S_un_w; + unsigned long S_addr; + } S_un; +}; +#define s_addr S_un.S_addr /* can be used for most tcp & ip code */ +struct sockaddr_in +{ + short sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; +char *inet_ntoa(struct in_addr in); +unsigned long inet_addr(const char *cp); +#endif +#endif // BAN_TEST + +#include "quakedef.h" +#include "net_dgrm.h" + +// these two macros are to make the code more readable +#define sfunc net_landrivers[sock->landriver] +#define dfunc net_landrivers[net_landriverlevel] + +static int net_landriverlevel; + +/* statistic counters */ +int packetsSent = 0; +int packetsReSent = 0; +int packetsReceived = 0; +int receivedDuplicateCount = 0; +int shortPacketCount = 0; +int droppedDatagrams; + +static int myDriverLevel; + +struct +{ + unsigned int length; + unsigned int sequence; + byte data[MAX_DATAGRAM]; +} packetBuffer; + +extern int m_return_state; +extern int m_state; +extern qboolean m_return_onerror; +extern char m_return_reason[32]; + + +char *StrAddr (struct qsockaddr *addr) +{ + static char buf[34]; + byte *p = (byte *)addr; + int n; + + for (n = 0; n < 16; n++) + sprintf (buf + n * 2, "%02x", *p++); + return buf; +} + + +#ifdef BAN_TEST +unsigned long banAddr = 0x00000000; +unsigned long banMask = 0xffffffff; + +void NET_Ban_f (void) +{ + char addrStr [32]; + char maskStr [32]; + void (*print) (char *fmt, ...); + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + { + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + print = SV_ClientPrintf; + } + + switch (Cmd_Argc ()) + { + case 1: + if (((struct in_addr *)&banAddr)->s_addr) + { + Q_strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr)); + Q_strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask)); + print("Banning %s [%s]\n", addrStr, maskStr); + } + else + print("Banning not active\n"); + break; + + case 2: + if (Q_strcasecmp(Cmd_Argv(1), "off") == 0) + banAddr = 0x00000000; + else + banAddr = inet_addr(Cmd_Argv(1)); + banMask = 0xffffffff; + break; + + case 3: + banAddr = inet_addr(Cmd_Argv(1)); + banMask = inet_addr(Cmd_Argv(2)); + break; + + default: + print("BAN ip_address [mask]\n"); + break; + } +} +#endif + + +int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + +#ifdef DEBUG + if (data->cursize == 0) + Sys_Error("Datagram_SendMessage: zero length message\n"); + + if (data->cursize > NET_MAXMESSAGE) + Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize); + + if (sock->canSend == false) + Sys_Error("SendMessage: called with canSend == false\n"); +#endif + + Q_memcpy(sock->sendMessage, data->data, data->cursize); + sock->sendMessageLength = data->cursize; + + if (data->cursize <= MAX_DATAGRAM) + { + dataLen = data->cursize; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence++); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->canSend = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsSent++; + return 1; +} + + +int SendMessageNext (qsocket_t *sock) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + + if (sock->sendMessageLength <= MAX_DATAGRAM) + { + dataLen = sock->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence++); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->sendNext = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsSent++; + return 1; +} + + +int ReSendMessage (qsocket_t *sock) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + + if (sock->sendMessageLength <= MAX_DATAGRAM) + { + dataLen = sock->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence - 1); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->sendNext = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsReSent++; + return 1; +} + + +qboolean Datagram_CanSendMessage (qsocket_t *sock) +{ + if (sock->sendNext) + SendMessageNext (sock); + + return sock->canSend; +} + + +qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock) +{ + return true; +} + + +int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + int packetLen; + +#ifdef DEBUG + if (data->cursize == 0) + Sys_Error("Datagram_SendUnreliableMessage: zero length message\n"); + + if (data->cursize > MAX_DATAGRAM) + Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize); +#endif + + packetLen = NET_HEADERSIZE + data->cursize; + + packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE); + packetBuffer.sequence = BigLong(sock->unreliableSendSequence++); + Q_memcpy (packetBuffer.data, data->data, data->cursize); + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + packetsSent++; + return 1; +} + + +int Datagram_GetMessage (qsocket_t *sock) +{ + unsigned int length; + unsigned int flags; + int ret = 0; + struct qsockaddr readaddr; + unsigned int sequence; + unsigned int count; + + if (!sock->canSend) + if ((net_time - sock->lastSendTime) > 1.0) + ReSendMessage (sock); + + while(1) + { + length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); + +// if ((rand() & 255) > 220) +// continue; + + if (length == 0) + break; + + if (length == -1) + { + Con_Printf("Read error\n"); + return -1; + } + + if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) + { +#ifdef DEBUG + Con_DPrintf("Forged packet received\n"); + Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr)); + Con_DPrintf("Received: %s\n", StrAddr (&readaddr)); +#endif + continue; + } + + if (length < NET_HEADERSIZE) + { + shortPacketCount++; + continue; + } + + length = BigLong(packetBuffer.length); + flags = length & (~NETFLAG_LENGTH_MASK); + length &= NETFLAG_LENGTH_MASK; + + if (flags & NETFLAG_CTL) + continue; + + sequence = BigLong(packetBuffer.sequence); + packetsReceived++; + + if (flags & NETFLAG_UNRELIABLE) + { + if (sequence < sock->unreliableReceiveSequence) + { + Con_DPrintf("Got a stale datagram\n"); + ret = 0; + break; + } + if (sequence != sock->unreliableReceiveSequence) + { + count = sequence - sock->unreliableReceiveSequence; + droppedDatagrams += count; + Con_DPrintf("Dropped %u datagram(s)\n", count); + } + sock->unreliableReceiveSequence = sequence + 1; + + length -= NET_HEADERSIZE; + + SZ_Clear (&net_message); + SZ_Write (&net_message, packetBuffer.data, length); + + ret = 2; + break; + } + + if (flags & NETFLAG_ACK) + { + if (sequence != (sock->sendSequence - 1)) + { + Con_DPrintf("Stale ACK received\n"); + continue; + } + if (sequence == sock->ackSequence) + { + sock->ackSequence++; + if (sock->ackSequence != sock->sendSequence) + Con_DPrintf("ack sequencing error\n"); + } + else + { + Con_DPrintf("Duplicate ACK received\n"); + continue; + } + sock->sendMessageLength -= MAX_DATAGRAM; + if (sock->sendMessageLength > 0) + { + Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength); + sock->sendNext = true; + } + else + { + sock->sendMessageLength = 0; + sock->canSend = true; + } + continue; + } + + if (flags & NETFLAG_DATA) + { + packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); + packetBuffer.sequence = BigLong(sequence); + sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); + + if (sequence != sock->receiveSequence) + { + receivedDuplicateCount++; + continue; + } + sock->receiveSequence++; + + length -= NET_HEADERSIZE; + + if (flags & NETFLAG_EOM) + { + SZ_Clear(&net_message); + SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); + SZ_Write(&net_message, packetBuffer.data, length); + sock->receiveMessageLength = 0; + + ret = 1; + break; + } + + Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); + sock->receiveMessageLength += length; + continue; + } + } + + if (sock->sendNext) + SendMessageNext (sock); + + return ret; +} + + +void PrintStats(qsocket_t *s) +{ + Con_Printf("canSend = %4u \n", s->canSend); + Con_Printf("sendSeq = %4u ", s->sendSequence); + Con_Printf("recvSeq = %4u \n", s->receiveSequence); + Con_Printf("\n"); +} + +void NET_Stats_f (void) +{ + qsocket_t *s; + + if (Cmd_Argc () == 1) + { + Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent); + Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived); + Con_Printf("reliable messages sent = %i\n", messagesSent); + Con_Printf("reliable messages received = %i\n", messagesReceived); + Con_Printf("packetsSent = %i\n", packetsSent); + Con_Printf("packetsReSent = %i\n", packetsReSent); + Con_Printf("packetsReceived = %i\n", packetsReceived); + Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount); + Con_Printf("shortPacketCount = %i\n", shortPacketCount); + Con_Printf("droppedDatagrams = %i\n", droppedDatagrams); + } + else if (Q_strcmp(Cmd_Argv(1), "*") == 0) + { + for (s = net_activeSockets; s; s = s->next) + PrintStats(s); + for (s = net_freeSockets; s; s = s->next) + PrintStats(s); + } + else + { + for (s = net_activeSockets; s; s = s->next) + if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0) + break; + if (s == NULL) + for (s = net_freeSockets; s; s = s->next) + if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0) + break; + if (s == NULL) + return; + PrintStats(s); + } +} + + +static qboolean testInProgress = false; +static int testPollCount; +static int testDriver; +static int testSocket; + +static void Test_Poll(void); +PollProcedure testPollProcedure = {NULL, 0.0, Test_Poll}; + +static void Test_Poll(void) +{ + struct qsockaddr clientaddr; + int control; + int len; + char name[32]; + char address[64]; + int colors; + int frags; + int connectTime; + byte playerNumber; + + net_landriverlevel = testDriver; + + while (1) + { + len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + break; + + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + break; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + break; + if ((control & NETFLAG_LENGTH_MASK) != len) + break; + + if (MSG_ReadByte() != CCREP_PLAYER_INFO) + Sys_Error("Unexpected repsonse to Player Info request\n"); + + playerNumber = MSG_ReadByte(); + Q_strcpy(name, MSG_ReadString()); + colors = MSG_ReadLong(); + frags = MSG_ReadLong(); + connectTime = MSG_ReadLong(); + Q_strcpy(address, MSG_ReadString()); + + Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address); + } + + testPollCount--; + if (testPollCount) + { + SchedulePollProcedure(&testPollProcedure, 0.1); + } + else + { + dfunc.CloseSocket(testSocket); + testInProgress = false; + } +} + +static void Net_Test_f (void) +{ + char *host; + int n; + int max = MAX_SCOREBOARD; + struct qsockaddr sendaddr; + + if (testInProgress) + return; + + host = Cmd_Argv (1); + + if (host && hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + if (hostcache[n].driver != myDriverLevel) + continue; + net_landriverlevel = hostcache[n].ldriver; + max = hostcache[n].maxusers; + Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (!net_landrivers[net_landriverlevel].initialized) + continue; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) != -1) + break; + } + if (net_landriverlevel == net_numlandrivers) + return; + +JustDoIt: + testSocket = dfunc.OpenSocket(0); + if (testSocket == -1) + return; + + testInProgress = true; + testPollCount = 20; + testDriver = net_landriverlevel; + + for (n = 0; n < max; n++) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO); + MSG_WriteByte(&net_message, n); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr); + } + SZ_Clear(&net_message); + SchedulePollProcedure(&testPollProcedure, 0.1); +} + + +static qboolean test2InProgress = false; +static int test2Driver; +static int test2Socket; + +static void Test2_Poll(void); +PollProcedure test2PollProcedure = {NULL, 0.0, Test2_Poll}; + +static void Test2_Poll(void) +{ + struct qsockaddr clientaddr; + int control; + int len; + char name[256]; + char value[256]; + + net_landriverlevel = test2Driver; + name[0] = 0; + + len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + goto Reschedule; + + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + goto Error; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + goto Error; + if ((control & NETFLAG_LENGTH_MASK) != len) + goto Error; + + if (MSG_ReadByte() != CCREP_RULE_INFO) + goto Error; + + Q_strcpy(name, MSG_ReadString()); + if (name[0] == 0) + goto Done; + Q_strcpy(value, MSG_ReadString()); + + Con_Printf("%-16.16s %-16.16s\n", name, value); + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_RULE_INFO); + MSG_WriteString(&net_message, name); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + +Reschedule: + SchedulePollProcedure(&test2PollProcedure, 0.05); + return; + +Error: + Con_Printf("Unexpected repsonse to Rule Info request\n"); +Done: + dfunc.CloseSocket(test2Socket); + test2InProgress = false; + return; +} + +static void Test2_f (void) +{ + char *host; + int n; + struct qsockaddr sendaddr; + + if (test2InProgress) + return; + + host = Cmd_Argv (1); + + if (host && hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + if (hostcache[n].driver != myDriverLevel) + continue; + net_landriverlevel = hostcache[n].ldriver; + Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (!net_landrivers[net_landriverlevel].initialized) + continue; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) != -1) + break; + } + if (net_landriverlevel == net_numlandrivers) + return; + +JustDoIt: + test2Socket = dfunc.OpenSocket(0); + if (test2Socket == -1) + return; + + test2InProgress = true; + test2Driver = net_landriverlevel; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_RULE_INFO); + MSG_WriteString(&net_message, ""); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr); + SZ_Clear(&net_message); + SchedulePollProcedure(&test2PollProcedure, 0.05); +} + + +int Datagram_Init (void) +{ + int i; + int csock; + + myDriverLevel = net_driverlevel; + Cmd_AddCommand ("net_stats", NET_Stats_f); + + if (COM_CheckParm("-nolan")) + return -1; + + for (i = 0; i < net_numlandrivers; i++) + { + csock = net_landrivers[i].Init (); + if (csock == -1) + continue; + net_landrivers[i].initialized = true; + net_landrivers[i].controlSock = csock; + } + + return 0; +} + + +void Datagram_Shutdown (void) +{ + int i; + +// +// shutdown the lan drivers +// + for (i = 0; i < net_numlandrivers; i++) + { + if (net_landrivers[i].initialized) + { + net_landrivers[i].Shutdown (); + net_landrivers[i].initialized = false; + } + } +} + + +void Datagram_Close (qsocket_t *sock) +{ + sfunc.CloseSocket(sock->socket); +} + + +void Datagram_Listen (qboolean state) +{ + int i; + + for (i = 0; i < net_numlandrivers; i++) + if (net_landrivers[i].initialized) + net_landrivers[i].Listen (state); +} + + +static qsocket_t *_Datagram_CheckNewConnections (void) +{ + struct qsockaddr clientaddr; + struct qsockaddr newaddr; + int newsock; + int acceptsock; + qsocket_t *sock; + qsocket_t *s; + int len; + int command; + int control; + int ret; + + acceptsock = dfunc.CheckNewConnections(); + if (acceptsock == -1) + return NULL; + + SZ_Clear(&net_message); + + len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + return NULL; + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + return NULL; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + return NULL; + if ((control & NETFLAG_LENGTH_MASK) != len) + return NULL; + + command = MSG_ReadByte(); + if (command == CCREQ_SERVER_INFO) + { + if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) + return NULL; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_SERVER_INFO); + dfunc.GetSocketAddr(acceptsock, &newaddr); + MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); + MSG_WriteString(&net_message, hostname.string); + MSG_WriteString(&net_message, sv.name); + MSG_WriteByte(&net_message, net_activeconnections); + MSG_WriteByte(&net_message, svs.maxclients); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + + if (command == CCREQ_PLAYER_INFO) + { + int playerNumber; + int activeNumber; + int clientNumber; + client_t *client; + + playerNumber = MSG_ReadByte(); + activeNumber = -1; + for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) + { + if (client->active) + { + activeNumber++; + if (activeNumber == playerNumber) + break; + } + } + if (clientNumber == svs.maxclients) + return NULL; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); + MSG_WriteByte(&net_message, playerNumber); + MSG_WriteString(&net_message, client->name); + MSG_WriteLong(&net_message, client->colors); + MSG_WriteLong(&net_message, (int)client->edict->v.frags); + MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); + MSG_WriteString(&net_message, client->netconnection->address); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return NULL; + } + + if (command == CCREQ_RULE_INFO) + { + char *prevCvarName; + cvar_t *var; + + // find the search start location + prevCvarName = MSG_ReadString(); + if (*prevCvarName) + { + var = Cvar_FindVar (prevCvarName); + if (!var) + return NULL; + var = var->next; + } + else + var = cvar_vars; + + // search for the next server cvar + while (var) + { + if (var->server) + break; + var = var->next; + } + + // send the response + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_RULE_INFO); + if (var) + { + MSG_WriteString(&net_message, var->name); + MSG_WriteString(&net_message, var->string); + } + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return NULL; + } + + if (command != CCREQ_CONNECT) + return NULL; + + if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) + return NULL; + + if (MSG_ReadByte() != NET_PROTOCOL_VERSION) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "Incompatible version.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + +#ifdef BAN_TEST + // check for a ban + if (clientaddr.sa_family == AF_INET) + { + unsigned long testAddr; + testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; + if ((testAddr & banMask) == banAddr) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "You have been banned.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + } +#endif + + // see if this guy is already connected + for (s = net_activeSockets; s; s = s->next) + { + if (s->driver != net_driverlevel) + continue; + ret = dfunc.AddrCompare(&clientaddr, &s->addr); + if (ret >= 0) + { + // is this a duplicate connection reqeust? + if (ret == 0 && net_time - s->connecttime < 2.0) + { + // yes, so send a duplicate reply + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_ACCEPT); + dfunc.GetSocketAddr(s->socket, &newaddr); + MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + // it's somebody coming back in from a crash/disconnect + // so close the old qsocket and let their retry get them back in + NET_Close(s); + return NULL; + } + } + + // allocate a QSocket + sock = NET_NewQSocket (); + if (sock == NULL) + { + // no room; try to let him know + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "Server is full.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + + // allocate a network socket + newsock = dfunc.OpenSocket(0); + if (newsock == -1) + { + NET_FreeQSocket(sock); + return NULL; + } + + // connect to the client + if (dfunc.Connect (newsock, &clientaddr) == -1) + { + dfunc.CloseSocket(newsock); + NET_FreeQSocket(sock); + return NULL; + } + + // everything is allocated, just fill in the details + sock->socket = newsock; + sock->landriver = net_landriverlevel; + sock->addr = clientaddr; + Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr)); + + // send him back the info about the server connection he has been allocated + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_ACCEPT); + dfunc.GetSocketAddr(newsock, &newaddr); + MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); +// MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return sock; +} + +qsocket_t *Datagram_CheckNewConnections (void) +{ + qsocket_t *ret = NULL; + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + if (net_landrivers[net_landriverlevel].initialized) + if ((ret = _Datagram_CheckNewConnections ()) != NULL) + break; + return ret; +} + + +static void _Datagram_SearchForHosts (qboolean xmit) +{ + int ret; + int n; + int i; + struct qsockaddr readaddr; + struct qsockaddr myaddr; + int control; + + dfunc.GetSocketAddr (dfunc.controlSock, &myaddr); + if (xmit) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); + MSG_WriteString(&net_message, "QUAKE"); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); + SZ_Clear(&net_message); + } + + while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) + { + if (ret < sizeof(int)) + continue; + net_message.cursize = ret; + + // don't answer our own query + if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) + continue; + + // is the cache full? + if (hostCacheCount == HOSTCACHESIZE) + continue; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + continue; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + continue; + if ((control & NETFLAG_LENGTH_MASK) != ret) + continue; + + if (MSG_ReadByte() != CCREP_SERVER_INFO) + continue; + + dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); + // search the cache for this server + for (n = 0; n < hostCacheCount; n++) + if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) + break; + + // is it already there? + if (n < hostCacheCount) + continue; + + // add it + hostCacheCount++; + Q_strcpy(hostcache[n].name, MSG_ReadString()); + Q_strcpy(hostcache[n].map, MSG_ReadString()); + hostcache[n].users = MSG_ReadByte(); + hostcache[n].maxusers = MSG_ReadByte(); + if (MSG_ReadByte() != NET_PROTOCOL_VERSION) + { + Q_strcpy(hostcache[n].cname, hostcache[n].name); + hostcache[n].cname[14] = 0; + Q_strcpy(hostcache[n].name, "*"); + Q_strcat(hostcache[n].name, hostcache[n].cname); + } + Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); + hostcache[n].driver = net_driverlevel; + hostcache[n].ldriver = net_landriverlevel; + Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); + + // check for a name conflict + for (i = 0; i < hostCacheCount; i++) + { + if (i == n) + continue; + if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0) + { + i = Q_strlen(hostcache[n].name); + if (i < 15 && hostcache[n].name[i-1] > '8') + { + hostcache[n].name[i] = '0'; + hostcache[n].name[i+1] = 0; + } + else + hostcache[n].name[i-1]++; + i = -1; + } + } + } +} + +void Datagram_SearchForHosts (qboolean xmit) +{ + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (hostCacheCount == HOSTCACHESIZE) + break; + if (net_landrivers[net_landriverlevel].initialized) + _Datagram_SearchForHosts (xmit); + } +} + + +static qsocket_t *_Datagram_Connect (char *host) +{ + struct qsockaddr sendaddr; + struct qsockaddr readaddr; + qsocket_t *sock; + int newsock; + int ret; + int reps; + double start_time; + int control; + char *reason; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) == -1) + return NULL; + + newsock = dfunc.OpenSocket (0); + if (newsock == -1) + return NULL; + + sock = NET_NewQSocket (); + if (sock == NULL) + goto ErrorReturn2; + sock->socket = newsock; + sock->landriver = net_landriverlevel; + + // connect to the host + if (dfunc.Connect (newsock, &sendaddr) == -1) + goto ErrorReturn; + + // send the connection request + Con_Printf("trying...\n"); SCR_UpdateScreen (); + start_time = net_time; + + for (reps = 0; reps < 3; reps++) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_CONNECT); + MSG_WriteString(&net_message, "QUAKE"); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr); + SZ_Clear(&net_message); + do + { + ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr); + // if we got something, validate it + if (ret > 0) + { + // is it from the right place? + if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) + { +//#ifdef DEBUG + Con_Printf("wrong reply address\n"); + Con_Printf("Expected: %s | %s\n", dfunc.AddrToString (&sendaddr), StrAddr(&sendaddr)); + Con_Printf("Received: %s | %s\n", dfunc.AddrToString (&readaddr), StrAddr(&readaddr)); + SCR_UpdateScreen (); +//#endif + ret = 0; + continue; + } + + if (ret < sizeof(int)) + { + ret = 0; + continue; + } + + net_message.cursize = ret; + MSG_BeginReading (); + + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + { + ret = 0; + continue; + } + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + { + ret = 0; + continue; + } + if ((control & NETFLAG_LENGTH_MASK) != ret) + { + ret = 0; + continue; + } + } + } + while (ret == 0 && (SetNetTime() - start_time) < 2.5); + if (ret) + break; + Con_Printf("still trying...\n"); SCR_UpdateScreen (); + start_time = SetNetTime(); + } + + if (ret == 0) + { + reason = "No Response"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + if (ret == -1) + { + reason = "Network Error"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + ret = MSG_ReadByte(); + if (ret == CCREP_REJECT) + { + reason = MSG_ReadString(); + Con_Printf(reason); + Q_strncpy(m_return_reason, reason, 31); + goto ErrorReturn; + } + + if (ret == CCREP_ACCEPT) + { + Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); + dfunc.SetSocketPort (&sock->addr, MSG_ReadLong()); + } + else + { + reason = "Bad Response"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + dfunc.GetNameFromAddr (&sendaddr, sock->address); + + Con_Printf ("Connection accepted\n"); + sock->lastMessageTime = SetNetTime(); + + // switch the connection to the specified address + if (dfunc.Connect (newsock, &sock->addr) == -1) + { + reason = "Connect to Game failed"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + m_return_onerror = false; + return sock; + +ErrorReturn: + NET_FreeQSocket(sock); +ErrorReturn2: + dfunc.CloseSocket(newsock); + if (m_return_onerror) + { + key_dest = key_menu; + m_state = m_return_state; + m_return_onerror = false; + } + return NULL; +} + +qsocket_t *Datagram_Connect (char *host) +{ + qsocket_t *ret = NULL; + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + if (net_landrivers[net_landriverlevel].initialized) + if ((ret = _Datagram_Connect (host)) != NULL) + break; + return ret; +} diff --git a/Quake/net_dgrm.h b/Quake/net_dgrm.h new file mode 100644 index 00000000..e4a4a94d --- /dev/null +++ b/Quake/net_dgrm.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_dgrm.h + + +int Datagram_Init (void); +void Datagram_Listen (qboolean state); +void Datagram_SearchForHosts (qboolean xmit); +qsocket_t *Datagram_Connect (char *host); +qsocket_t *Datagram_CheckNewConnections (void); +int Datagram_GetMessage (qsocket_t *sock); +int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data); +int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); +qboolean Datagram_CanSendMessage (qsocket_t *sock); +qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock); +void Datagram_Close (qsocket_t *sock); +void Datagram_Shutdown (void); diff --git a/Quake/net_loop.c b/Quake/net_loop.c new file mode 100644 index 00000000..a9b3a844 --- /dev/null +++ b/Quake/net_loop.c @@ -0,0 +1,246 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_loop.c + +#include "quakedef.h" +#include "net_loop.h" + +qboolean localconnectpending = false; +qsocket_t *loop_client = NULL; +qsocket_t *loop_server = NULL; + +int Loop_Init (void) +{ + if (cls.state == ca_dedicated) + return -1; + return 0; +} + + +void Loop_Shutdown (void) +{ +} + + +void Loop_Listen (qboolean state) +{ +} + + +void Loop_SearchForHosts (qboolean xmit) +{ + if (!sv.active) + return; + + hostCacheCount = 1; + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + Q_strcpy(hostcache[0].name, "local"); + else + Q_strcpy(hostcache[0].name, hostname.string); + Q_strcpy(hostcache[0].map, sv.name); + hostcache[0].users = net_activeconnections; + hostcache[0].maxusers = svs.maxclients; + hostcache[0].driver = net_driverlevel; + Q_strcpy(hostcache[0].cname, "local"); +} + + +qsocket_t *Loop_Connect (char *host) +{ + if (Q_strcmp(host,"local") != 0) + return NULL; + + localconnectpending = true; + + if (!loop_client) + { + if ((loop_client = NET_NewQSocket ()) == NULL) + { + Con_Printf("Loop_Connect: no qsocket available\n"); + return NULL; + } + Q_strcpy (loop_client->address, "localhost"); + } + loop_client->receiveMessageLength = 0; + loop_client->sendMessageLength = 0; + loop_client->canSend = true; + + if (!loop_server) + { + if ((loop_server = NET_NewQSocket ()) == NULL) + { + Con_Printf("Loop_Connect: no qsocket available\n"); + return NULL; + } + Q_strcpy (loop_server->address, "LOCAL"); + } + loop_server->receiveMessageLength = 0; + loop_server->sendMessageLength = 0; + loop_server->canSend = true; + + loop_client->driverdata = (void *)loop_server; + loop_server->driverdata = (void *)loop_client; + + return loop_client; +} + + +qsocket_t *Loop_CheckNewConnections (void) +{ + if (!localconnectpending) + return NULL; + + localconnectpending = false; + loop_server->sendMessageLength = 0; + loop_server->receiveMessageLength = 0; + loop_server->canSend = true; + loop_client->sendMessageLength = 0; + loop_client->receiveMessageLength = 0; + loop_client->canSend = true; + return loop_server; +} + + +static int IntAlign(int value) +{ + return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1)); +} + + +int Loop_GetMessage (qsocket_t *sock) +{ + int ret; + int length; + + if (sock->receiveMessageLength == 0) + return 0; + + ret = sock->receiveMessage[0]; + length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8); + // alignment byte skipped here + SZ_Clear (&net_message); + SZ_Write (&net_message, &sock->receiveMessage[4], length); + + length = IntAlign(length + 4); + sock->receiveMessageLength -= length; + + if (sock->receiveMessageLength) + Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength); + + if (sock->driverdata && ret == 1) + ((qsocket_t *)sock->driverdata)->canSend = true; + + return ret; +} + + +int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + byte *buffer; + int *bufferLength; + + if (!sock->driverdata) + return -1; + + bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; + + if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE) + Sys_Error("Loop_SendMessage: overflow\n"); + + buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; + + // message type + *buffer++ = 1; + + // length + *buffer++ = data->cursize & 0xff; + *buffer++ = data->cursize >> 8; + + // align + buffer++; + + // message + Q_memcpy(buffer, data->data, data->cursize); + *bufferLength = IntAlign(*bufferLength + data->cursize + 4); + + sock->canSend = false; + return 1; +} + + +int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + byte *buffer; + int *bufferLength; + + if (!sock->driverdata) + return -1; + + bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; + + if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE) + return 0; + + buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; + + // message type + *buffer++ = 2; + + // length + *buffer++ = data->cursize & 0xff; + *buffer++ = data->cursize >> 8; + + // align + buffer++; + + // message + Q_memcpy(buffer, data->data, data->cursize); + *bufferLength = IntAlign(*bufferLength + data->cursize + 4); + return 1; +} + + +qboolean Loop_CanSendMessage (qsocket_t *sock) +{ + if (!sock->driverdata) + return false; + return sock->canSend; +} + + +qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock) +{ + return true; +} + + +void Loop_Close (qsocket_t *sock) +{ + if (sock->driverdata) + ((qsocket_t *)sock->driverdata)->driverdata = NULL; + sock->receiveMessageLength = 0; + sock->sendMessageLength = 0; + sock->canSend = true; + if (sock == loop_client) + loop_client = NULL; + else + loop_server = NULL; +} diff --git a/Quake/net_loop.h b/Quake/net_loop.h new file mode 100644 index 00000000..cfd9f860 --- /dev/null +++ b/Quake/net_loop.h @@ -0,0 +1,34 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_loop.h + +int Loop_Init (void); +void Loop_Listen (qboolean state); +void Loop_SearchForHosts (qboolean xmit); +qsocket_t *Loop_Connect (char *host); +qsocket_t *Loop_CheckNewConnections (void); +int Loop_GetMessage (qsocket_t *sock); +int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data); +int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); +qboolean Loop_CanSendMessage (qsocket_t *sock); +qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock); +void Loop_Close (qsocket_t *sock); +void Loop_Shutdown (void); diff --git a/Quake/net_main.c b/Quake/net_main.c new file mode 100644 index 00000000..f8e15d05 --- /dev/null +++ b/Quake/net_main.c @@ -0,0 +1,865 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_main.c + +#include "quakedef.h" + +qsocket_t *net_activeSockets = NULL; +qsocket_t *net_freeSockets = NULL; +int net_numsockets = 0; + +qboolean serialAvailable = false; +qboolean ipxAvailable = false; +qboolean tcpipAvailable = false; + +int net_hostport; +int DEFAULTnet_hostport = 26000; + +char my_ipx_address[NET_NAMELEN]; +char my_tcpip_address[NET_NAMELEN]; + +void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem); +void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem); +void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); +void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); + +static qboolean listening = false; + +qboolean slistInProgress = false; +qboolean slistSilent = false; +qboolean slistLocal = true; +static double slistStartTime; +static int slistLastShown; + +static void Slist_Send(void); +static void Slist_Poll(void); +PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send}; +PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll}; + + +sizebuf_t net_message; +int net_activeconnections = 0; + +int messagesSent = 0; +int messagesReceived = 0; +int unreliableMessagesSent = 0; +int unreliableMessagesReceived = 0; + +cvar_t net_messagetimeout = {"net_messagetimeout","300"}; +cvar_t hostname = {"hostname", "UNNAMED"}; + +qboolean configRestored = false; +cvar_t config_com_port = {"_config_com_port", "0x3f8", true}; +cvar_t config_com_irq = {"_config_com_irq", "4", true}; +cvar_t config_com_baud = {"_config_com_baud", "57600", true}; +cvar_t config_com_modem = {"_config_com_modem", "1", true}; +cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true}; +cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true}; +cvar_t config_modem_init = {"_config_modem_init", "", true}; +cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true}; + +// these two macros are to make the code more readable +#define sfunc net_drivers[sock->driver] +#define dfunc net_drivers[net_driverlevel] + +int net_driverlevel; + + +double net_time; + +double SetNetTime(void) +{ + net_time = Sys_FloatTime(); + return net_time; +} + + +/* +=================== +NET_NewQSocket + +Called by drivers when a new communications endpoint is required +The sequence and buffer fields will be filled in properly +=================== +*/ +qsocket_t *NET_NewQSocket (void) +{ + qsocket_t *sock; + + if (net_freeSockets == NULL) + return NULL; + + if (net_activeconnections >= svs.maxclients) + return NULL; + + // get one from free list + sock = net_freeSockets; + net_freeSockets = sock->next; + + // add it to active list + sock->next = net_activeSockets; + net_activeSockets = sock; + + sock->disconnected = false; + sock->connecttime = net_time; + Q_strcpy (sock->address,"UNSET ADDRESS"); + sock->driver = net_driverlevel; + sock->socket = 0; + sock->driverdata = NULL; + sock->canSend = true; + sock->sendNext = false; + sock->lastMessageTime = net_time; + sock->ackSequence = 0; + sock->sendSequence = 0; + sock->unreliableSendSequence = 0; + sock->sendMessageLength = 0; + sock->receiveSequence = 0; + sock->unreliableReceiveSequence = 0; + sock->receiveMessageLength = 0; + + return sock; +} + + +void NET_FreeQSocket(qsocket_t *sock) +{ + qsocket_t *s; + + // remove it from active list + if (sock == net_activeSockets) + net_activeSockets = net_activeSockets->next; + else + { + for (s = net_activeSockets; s; s = s->next) + if (s->next == sock) + { + s->next = sock->next; + break; + } + if (!s) + Sys_Error ("NET_FreeQSocket: not active\n"); + } + + // add it to free list + sock->next = net_freeSockets; + net_freeSockets = sock; + sock->disconnected = true; +} + + +static void NET_Listen_f (void) +{ + if (Cmd_Argc () != 2) + { + Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0); + return; + } + + listening = Q_atoi(Cmd_Argv(1)) ? true : false; + + for (net_driverlevel=0 ; net_driverlevel svs.maxclientslimit) + { + n = svs.maxclientslimit; + Con_Printf ("\"maxplayers\" set to \"%u\"\n", n); + } + + if ((n == 1) && listening) + Cbuf_AddText ("listen 0\n"); + + if ((n > 1) && (!listening)) + Cbuf_AddText ("listen 1\n"); + + svs.maxclients = n; + if (n == 1) + Cvar_Set ("deathmatch", "0"); + else + Cvar_Set ("deathmatch", "1"); +} + + +static void NET_Port_f (void) +{ + int n; + + if (Cmd_Argc () != 2) + { + Con_Printf ("\"port\" is \"%u\"\n", net_hostport); + return; + } + + n = Q_atoi(Cmd_Argv(1)); + if (n < 1 || n > 65534) + { + Con_Printf ("Bad value, must be between 1 and 65534\n"); + return; + } + + DEFAULTnet_hostport = n; + net_hostport = n; + + if (listening) + { + // force a change to the new port + Cbuf_AddText ("listen 0\n"); + Cbuf_AddText ("listen 1\n"); + } +} + + +static void PrintSlistHeader(void) +{ + Con_Printf("Server Map Users\n"); + Con_Printf("--------------- --------------- -----\n"); + slistLastShown = 0; +} + + +static void PrintSlist(void) +{ + int n; + + for (n = slistLastShown; n < hostCacheCount; n++) + { + if (hostcache[n].maxusers) + Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); + else + Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); + } + slistLastShown = n; +} + + +static void PrintSlistTrailer(void) +{ + if (hostCacheCount) + Con_Printf("== end list ==\n\n"); + else + Con_Printf("No Quake servers found.\n\n"); +} + + +void NET_Slist_f (void) +{ + if (slistInProgress) + return; + + if (! slistSilent) + { + Con_Printf("Looking for Quake servers...\n"); + PrintSlistHeader(); + } + + slistInProgress = true; + slistStartTime = Sys_FloatTime(); + + SchedulePollProcedure(&slistSendProcedure, 0.0); + SchedulePollProcedure(&slistPollProcedure, 0.1); + + hostCacheCount = 0; +} + + +static void Slist_Send(void) +{ + for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (!slistLocal && net_driverlevel == 0) + continue; + if (net_drivers[net_driverlevel].initialized == false) + continue; + dfunc.SearchForHosts (true); + } + + if ((Sys_FloatTime() - slistStartTime) < 0.5) + SchedulePollProcedure(&slistSendProcedure, 0.75); +} + + +static void Slist_Poll(void) +{ + for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (!slistLocal && net_driverlevel == 0) + continue; + if (net_drivers[net_driverlevel].initialized == false) + continue; + dfunc.SearchForHosts (false); + } + + if (! slistSilent) + PrintSlist(); + + if ((Sys_FloatTime() - slistStartTime) < 1.5) + { + SchedulePollProcedure(&slistPollProcedure, 0.1); + return; + } + + if (! slistSilent) + PrintSlistTrailer(); + slistInProgress = false; + slistSilent = false; + slistLocal = true; +} + + +/* +=================== +NET_Connect +=================== +*/ + +int hostCacheCount = 0; +hostcache_t hostcache[HOSTCACHESIZE]; + +qsocket_t *NET_Connect (char *host) +{ + qsocket_t *ret; + int n; + int numdrivers = net_numdrivers; + + SetNetTime(); + + if (host && *host == 0) + host = NULL; + + if (host) + { + if (Q_strcasecmp (host, "local") == 0) + { + numdrivers = 1; + goto JustDoIt; + } + + if (hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + host = hostcache[n].cname; + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + } + + slistSilent = host ? true : false; + NET_Slist_f (); + + while(slistInProgress) + NET_Poll(); + + if (host == NULL) + { + if (hostCacheCount != 1) + return NULL; + host = hostcache[0].cname; + Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host); + } + + if (hostCacheCount) + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + host = hostcache[n].cname; + break; + } + +JustDoIt: + for (net_driverlevel=0 ; net_driverleveldisconnected) + return; + + SetNetTime(); + + // call the driver_Close function + sfunc.Close (sock); + + NET_FreeQSocket(sock); +} + + +/* +================= +NET_GetMessage + +If there is a complete message, return it in net_message + +returns 0 if no data is waiting +returns 1 if a message was received +returns -1 if connection is invalid +================= +*/ + +extern void PrintStats(qsocket_t *s); + +int NET_GetMessage (qsocket_t *sock) +{ + int ret; + + if (!sock) + return -1; + + if (sock->disconnected) + { + Con_Printf("NET_GetMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + + ret = sfunc.QGetMessage(sock); + + // see if this connection has timed out + if (ret == 0 && sock->driver) + { + if (net_time - sock->lastMessageTime > net_messagetimeout.value) + { + NET_Close(sock); + return -1; + } + } + + + if (ret > 0) + { + if (sock->driver) + { + sock->lastMessageTime = net_time; + if (ret == 1) + messagesReceived++; + else if (ret == 2) + unreliableMessagesReceived++; + } + } + + return ret; +} + + +/* +================== +NET_SendMessage + +Try to send a complete length+message unit over the reliable stream. +returns 0 if the message cannot be delivered reliably, but the connection + is still considered valid +returns 1 if the message was sent properly +returns -1 if the connection died +================== +*/ +int NET_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + int r; + + if (!sock) + return -1; + + if (sock->disconnected) + { + Con_Printf("NET_SendMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + r = sfunc.QSendMessage(sock, data); + if (r == 1 && sock->driver) + messagesSent++; + + return r; +} + + +int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + int r; + + if (!sock) + return -1; + + if (sock->disconnected) + { + Con_Printf("NET_SendMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + r = sfunc.SendUnreliableMessage(sock, data); + if (r == 1 && sock->driver) + unreliableMessagesSent++; + + return r; +} + + +/* +================== +NET_CanSendMessage + +Returns true or false if the given qsocket can currently accept a +message to be transmitted. +================== +*/ +qboolean NET_CanSendMessage (qsocket_t *sock) +{ + int r; + + if (!sock) + return false; + + if (sock->disconnected) + return false; + + SetNetTime(); + + r = sfunc.CanSendMessage(sock); + + return r; +} + + +int NET_SendToAll(sizebuf_t *data, int blocktime) +{ + double start; + int i; + int count = 0; + qboolean state1 [MAX_SCOREBOARD]; + qboolean state2 [MAX_SCOREBOARD]; + + for (i=0, host_client = svs.clients ; inetconnection) + continue; + if (host_client->active) + { + if (host_client->netconnection->driver == 0) + { + NET_SendMessage(host_client->netconnection, data); + state1[i] = true; + state2[i] = true; + continue; + } + count++; + state1[i] = false; + state2[i] = false; + } + else + { + state1[i] = true; + state2[i] = true; + } + } + + start = Sys_FloatTime(); + while (count) + { + count = 0; + for (i=0, host_client = svs.clients ; inetconnection)) + { + state1[i] = true; + NET_SendMessage(host_client->netconnection, data); + } + else + { + NET_GetMessage (host_client->netconnection); + } + count++; + continue; + } + + if (! state2[i]) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + state2[i] = true; + } + else + { + NET_GetMessage (host_client->netconnection); + } + count++; + continue; + } + } + if ((Sys_FloatTime() - start) > blocktime) + break; + } + return count; +} + + +//============================================================================= + +/* +==================== +NET_Init +==================== +*/ + +void NET_Init (void) +{ + int i; + int controlSocket; + qsocket_t *s; + + i = COM_CheckParm ("-port"); + if (!i) + i = COM_CheckParm ("-udpport"); + if (!i) + i = COM_CheckParm ("-ipxport"); + + if (i) + { + if (i < com_argc-1) + DEFAULTnet_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("NET_Init: you must specify a number after -port"); + } + net_hostport = DEFAULTnet_hostport; + + if (COM_CheckParm("-listen") || cls.state == ca_dedicated) + listening = true; + net_numsockets = svs.maxclientslimit; + if (cls.state != ca_dedicated) + net_numsockets++; + + SetNetTime(); + + for (i = 0; i < net_numsockets; i++) + { + s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket"); + s->next = net_freeSockets; + net_freeSockets = s; + s->disconnected = true; + } + + // allocate space for network message buffer + SZ_Alloc (&net_message, NET_MAXMESSAGE); + + Cvar_RegisterVariable (&net_messagetimeout, NULL); + Cvar_RegisterVariable (&hostname, NULL); + Cvar_RegisterVariable (&config_com_port, NULL); + Cvar_RegisterVariable (&config_com_irq, NULL); + Cvar_RegisterVariable (&config_com_baud, NULL); + Cvar_RegisterVariable (&config_com_modem, NULL); + Cvar_RegisterVariable (&config_modem_dialtype, NULL); + Cvar_RegisterVariable (&config_modem_clear, NULL); + Cvar_RegisterVariable (&config_modem_init, NULL); + Cvar_RegisterVariable (&config_modem_hangup, NULL); + + Cmd_AddCommand ("slist", NET_Slist_f); + Cmd_AddCommand ("listen", NET_Listen_f); + Cmd_AddCommand ("maxplayers", MaxPlayers_f); + Cmd_AddCommand ("port", NET_Port_f); + + // initialize all the drivers + for (net_driverlevel=0 ; net_driverlevelnext) + NET_Close(sock); + +// +// shutdown the drivers +// + for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (net_drivers[net_driverlevel].initialized == true) + { + net_drivers[net_driverlevel].Shutdown (); + net_drivers[net_driverlevel].initialized = false; + } + } +} + + +static PollProcedure *pollProcedureList = NULL; + +void NET_Poll(void) +{ + PollProcedure *pp; + qboolean useModem; + + if (!configRestored) + { + if (serialAvailable) + { + if (config_com_modem.value == 1.0) + useModem = true; + else + useModem = false; + SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem); + SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string); + } + configRestored = true; + } + + SetNetTime(); + + for (pp = pollProcedureList; pp; pp = pp->next) + { + if (pp->nextTime > net_time) + break; + pollProcedureList = pp->next; + pp->procedure(pp->arg); + } +} + + +void SchedulePollProcedure(PollProcedure *proc, double timeOffset) +{ + PollProcedure *pp, *prev; + + proc->nextTime = Sys_FloatTime() + timeOffset; + for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) + { + if (pp->nextTime >= proc->nextTime) + break; + prev = pp; + } + + if (prev == NULL) + { + proc->next = pollProcedureList; + pollProcedureList = proc; + return; + } + + proc->next = pp; + prev->next = proc; +} diff --git a/Quake/net_sdl.c b/Quake/net_sdl.c new file mode 100644 index 00000000..91f712bc --- /dev/null +++ b/Quake/net_sdl.c @@ -0,0 +1,112 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +#include "net_loop.h" +#include "net_dgrm.h" +#include "net_sdlnet.h" + +net_driver_t net_drivers[MAX_NET_DRIVERS] = +{ + { + "Loopback", + false, + Loop_Init, + Loop_Listen, + Loop_SearchForHosts, + Loop_Connect, + Loop_CheckNewConnections, + Loop_GetMessage, + Loop_SendMessage, + Loop_SendUnreliableMessage, + Loop_CanSendMessage, + Loop_CanSendUnreliableMessage, + Loop_Close, + Loop_Shutdown + } + , + { + "Datagram", + false, + Datagram_Init, + Datagram_Listen, + Datagram_SearchForHosts, + Datagram_Connect, + Datagram_CheckNewConnections, + Datagram_GetMessage, + Datagram_SendMessage, + Datagram_SendUnreliableMessage, + Datagram_CanSendMessage, + Datagram_CanSendUnreliableMessage, + Datagram_Close, + Datagram_Shutdown + } + , + { + "Datagram", + false, + Datagram_Init, + Datagram_Listen, + Datagram_SearchForHosts, + Datagram_Connect, + Datagram_CheckNewConnections, + Datagram_GetMessage, + Datagram_SendMessage, + Datagram_SendUnreliableMessage, + Datagram_CanSendMessage, + Datagram_CanSendUnreliableMessage, + Datagram_Close, + Datagram_Shutdown + } +}; + +int net_numdrivers = 2; + + +net_landriver_t net_landrivers[MAX_NET_DRIVERS] = +{ + { + "UDP", + false, + 0, + SDLN_Init, + SDLN_Shutdown, + SDLN_Listen, + SDLN_OpenSocket, + SDLN_CloseSocket, + SDLN_Connect, + SDLN_CheckNewConnections, + SDLN_Read, + SDLN_Write, + SDLN_Broadcast, + SDLN_AddrToString, + SDLN_StringToAddr, + SDLN_GetSocketAddr, + SDLN_GetNameFromAddr, + SDLN_GetAddrFromName, + SDLN_AddrCompare, + SDLN_GetSocketPort, + SDLN_SetSocketPort + } +}; + +int net_numlandrivers = 1; diff --git a/Quake/net_sdlnet.c b/Quake/net_sdlnet.c new file mode 100644 index 00000000..14dcb416 --- /dev/null +++ b/Quake/net_sdlnet.c @@ -0,0 +1,565 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundat(&addr->sa_dataion, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +#if defined(_WIN32) +#include +#endif + +#if defined(LINUX) +#include +#else +#include +#endif + +#include "net_sdlnet.h" + +#define MAX_SOCKETS 32 +#define MAXHOSTNAMELEN 255 +#define AF_INET 2 /* internet */ + +static int net_controlsocket; +static int net_broadcastsocket = 0; +static int net_acceptsocket = -1; +static struct qsockaddr broadcastaddr; + +SDLNet_SocketSet acceptsocket_set; + +IPaddress myaddr; + +// contains a map of socket numbers to SDL_net UDP sockets +UDPsocket net_sockets[MAX_SOCKETS]; + +int socket_id(UDPsocket socket) +{ + int i; + int index = -1; + + for (i = 0; i < MAX_SOCKETS; i++) + { + if (net_sockets[i] == socket) + return i; + + if (net_sockets[i] == NULL && index == -1) + { + index = i; + break; + } + } + + if (index == -1) + { + // todo error + } + + net_sockets[index] = socket; + + return index; +} + +char *_AddrToString (int ip, int port) +{ + static char buffer[22]; + + sprintf(buffer, "%d.%d.%d.%d:%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff, port); + return buffer; +} + +char *_IPAddrToString (IPaddress *address) +{ + int ip; + int port; + + ip = SDLNet_Read32(&address->host); + port = SDLNet_Read16(&address->port); + + return _AddrToString(ip, port); +} + +int SDLN_Init (void) +{ + int i; + char buff[MAXHOSTNAMELEN]; + char *p; + IPaddress *ipaddress; + + // init SDL + if (SDLNet_Init() == -1) + { + Con_SafePrintf ("SDL_net initialization failed.\n"); + return -1; + } + + // allocate a socket set for the accept socket + acceptsocket_set = SDLNet_AllocSocketSet(1); + if (acceptsocket_set == NULL) + { + Con_DPrintf ("SDL_net initialization failed: Could not create socket set.\n"); + return -1; + } + + // determine my name + if (gethostname(buff, MAXHOSTNAMELEN) == -1) + { + Con_DPrintf ("SDL_net initialization failed: Could not determine host name.\n"); + return -1; + } + + // if the quake hostname isn't set, set it to the machine name + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } + Cvar_Set ("hostname", buff); + } + + // set my IP address + i = COM_CheckParm ("-ip"); + if (i) + { + if (i < com_argc-1) + { + SDLNet_ResolveHost(&myaddr, com_argv[i+1], 0); + if (myaddr.host == INADDR_NONE) + Sys_Error ("%s is not a valid IP address", com_argv[i+1]); + strcpy(my_tcpip_address, com_argv[i+1]); + } + else + { + Sys_Error ("NET_Init: you must specify an IP address after -ip"); + } + } + else + { + SDLNet_ResolveHost(&myaddr, NULL, 0); + strcpy(my_tcpip_address, "INADDR_ANY"); + } + + // open the control socket + if ((net_controlsocket = SDLN_OpenSocket (0)) == -1) + { + Con_Printf("SDLN_Init: Unable to open control socket\n"); + return -1; + } + + broadcastaddr.sa_family = AF_INET; + ipaddress = (IPaddress *)&(broadcastaddr.sa_data); + SDLNet_Write32(INADDR_BROADCAST, &ipaddress->host); + SDLNet_Write16(net_hostport, &ipaddress->port); + + Con_Printf("SDL_net TCP/IP initialized\n"); + tcpipAvailable = true; + + return net_controlsocket; +} + +void SDLN_Shutdown (void) +{ + SDLN_Listen (false); + SDLN_CloseSocket (net_controlsocket); +} + +void SDLN_GetLocalAddress() +{ + if (myaddr.host != INADDR_ANY) + return; + + SDLNet_ResolveHost(&myaddr, NULL, 0); +} + +void SDLN_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + + SDLN_GetLocalAddress(); + if ((net_acceptsocket = SDLN_OpenSocket (net_hostport)) == -1) + Sys_Error ("SDLN_Listen: Unable to open accept socket\n"); + + SDLNet_UDP_AddSocket(acceptsocket_set, net_sockets[net_acceptsocket]); + } + else + { + // disable listening + if (net_acceptsocket == -1) + return; + + SDLNet_UDP_DelSocket(acceptsocket_set, net_sockets[net_acceptsocket]); + SDLN_CloseSocket(net_acceptsocket); + + net_acceptsocket = -1; + } +} + +int SDLN_OpenSocket (int port) +{ + + UDPsocket newsocket; + static IPaddress address; + + if ((newsocket = SDLNet_UDP_Open(port)) == NULL) + return -1; + +// todo check what this does +// if (pioctlsocket (newsocket, FIONBIO, &_true) == -1) +// goto ErrorReturn; + + address.host = myaddr.host; + address.port = SDLNet_Read16(&port); + + if (SDLNet_UDP_Bind(newsocket, 0, &address) != -1) + return socket_id(newsocket); + + Sys_Error ("Unable to bind to %s", _IPAddrToString(&address)); + + SDLNet_UDP_Close(newsocket); + return -1; +} + +int SDLN_CloseSocket (int socketid) +{ + UDPsocket socket; + + if (socketid == net_broadcastsocket) + net_broadcastsocket = -1; + + socket = net_sockets[socketid]; + + if (socket == NULL) + return -1; + + SDLNet_UDP_Close(socket); + + net_sockets[socketid] = NULL; + return 0; +} + +int SDLN_Connect (int socket, struct qsockaddr *addr) +{ + return 0; +} + +int SDLN_CheckNewConnections (void) +{ + if (net_acceptsocket == -1) + return -1; + + if (SDLNet_CheckSockets(acceptsocket_set, 0) > 0) + return net_acceptsocket; + + return -1; +} + +UDPpacket *init_packet(UDPpacket *packet, int len) +{ + if (packet == NULL) + return SDLNet_AllocPacket(len); + + if (packet->maxlen < len) + SDLNet_ResizePacket(packet, len); + + return packet; +} + +int SDLN_Read (int socketid, byte *buf, int len, struct qsockaddr *addr) +{ + int numrecv; + static UDPpacket *packet; + IPaddress *ipaddress; + + UDPsocket socket = net_sockets[socketid]; + if (socket == NULL) + return -1; + + packet = init_packet(packet, len); + + numrecv = SDLNet_UDP_Recv(socket, packet); + if (numrecv == 1) + { + memcpy(buf, packet->data, packet->len); + + addr->sa_family = AF_INET; + ipaddress = (IPaddress *)&(addr->sa_data); + ipaddress->host = packet->address.host; + ipaddress->port = packet->address.port; + + return packet->len; + } + + return numrecv; + +} + +int SDLN_Write (int socketid, byte *buf, int len, struct qsockaddr *addr) +{ + int numsent; + static UDPpacket *packet; + UDPsocket socket; + IPaddress *ipaddress; + + socket = net_sockets[socketid]; + + if (socket == NULL) + return -1; + + packet = init_packet(packet, len); + memcpy(packet->data, buf, len); + packet->len = len; + + ipaddress = (IPaddress *)&(addr->sa_data); + packet->address.host = ipaddress->host; + packet->address.port = ipaddress->port; + + numsent = SDLNet_UDP_Send(socket, -1, packet); + if (numsent == 0) + return 0; + + return len; +} + +int SDLN_Broadcast (int socketid, byte *buf, int len) +{ + + if (socketid != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + Sys_Error("Attempted to use multiple broadcast sockets\n"); + + // todo make socket broadcast capable + Sys_Error("Unable to make socket broadcast capable\n"); + } + + return SDLN_Write(socketid, buf, len, &broadcastaddr); +} + +char *SDLN_AddrToString (struct qsockaddr *addr) +{ + int ip; + int port; + IPaddress *ipaddress; + + ipaddress = (IPaddress *)&(addr->sa_data); + + ip = SDLNet_Read32(&ipaddress->host); + port = SDLNet_Read16(&ipaddress->port); + + return _AddrToString(ip, port); +} + +int SDLN_StringToAddr (char *string, struct qsockaddr *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int hostaddr; + IPaddress *ipaddress; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + hostaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ipaddress = (IPaddress *)&(addr->sa_data); + + SDLNet_Write32(hostaddr, &ipaddress->host); + SDLNet_Write16(hp, &ipaddress->port); + + return 0; +} + +int SDLN_GetSocketAddr (int socketid, struct qsockaddr *addr) +{ + static UDPsocket socket; + IPaddress *peeraddress; + IPaddress *ipaddress; + + Q_memset(addr, 0, sizeof(struct qsockaddr)); + + socket = net_sockets[socketid]; + if (socket == NULL) + return -1; + + peeraddress = SDLNet_UDP_GetPeerAddress(socket, -1); + if (peeraddress == NULL) + return -1; + + addr->sa_family = AF_INET; + ipaddress = (IPaddress *)&(addr->sa_data); + if (peeraddress->host == 0 || peeraddress->host == inet_addr("127.0.0.1")) + { + ipaddress->host = myaddr.host; + ipaddress->port = myaddr.port; + } + else + { + ipaddress->host = peeraddress->host; + ipaddress->port = peeraddress->port; + } + + return 0; +} + +int SDLN_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + char *buf; + IPaddress *ipaddress; + + ipaddress = (IPaddress *)&(addr->sa_data); + + buf = (char *)SDLNet_ResolveIP(ipaddress); + if (buf != NULL) { + Q_strncpy(name, buf, NET_NAMELEN - 1); + return 0; + } + + Q_strcpy(name, SDLN_AddrToString(addr)); + return 0; +} + +//============================================================================= +/* +============ +PartialIPAddress + +this lets you type only as much of the net address as required, using +the local network components to fill in the rest +============ +*/ +static int PartialIPAddress (char *in, struct qsockaddr *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + int tmp; + int run; + int port; + IPaddress *ipaddress; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') + b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + b++; + num = 0; + run = 0; + while (!( *b < '0' || *b > '9')) + { + num = num*10 + *b++ - '0'; + if (++run > 3) + return -1; + } + if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) + return -1; + if (num < 0 || num > 255) + return -1; + mask<<=8; + addr = (addr<<8) + num; + } + + if (*b++ == ':') + port = Q_atoi(b); + else + port = net_hostport; + + tmp = SDLNet_Read32(&myaddr.host); + tmp = (tmp & mask) | addr; + + hostaddr->sa_family = AF_INET; + ipaddress = (IPaddress *)&(hostaddr->sa_data); + + SDLNet_Write32(tmp, &ipaddress->host); + SDLNet_Write16(port, &ipaddress->port); + + return 0; +} + +int SDLN_GetAddrFromName (char *name, struct qsockaddr *addr) +{ + IPaddress *ipaddress; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + ipaddress = (IPaddress *)&(addr->sa_data); + if (SDLNet_ResolveHost((IPaddress *)(&addr->sa_data), name, 26000) == -1) + return -1; + + addr->sa_family = AF_INET; + return 0; +} + +int SDLN_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + IPaddress *ipaddr1; + IPaddress *ipaddr2; + + if (addr1->sa_family != addr2->sa_family) + return -1; + + ipaddr1 = (IPaddress *)&(addr1->sa_data); + ipaddr2 = (IPaddress *)&(addr2->sa_data); + + if (ipaddr1->host != ipaddr2->host) + return -1; + + if (ipaddr1->port != ipaddr2->port) + return 1; + + return 0; +} + +int SDLN_GetSocketPort (struct qsockaddr *addr) +{ + IPaddress *ipaddress; + + ipaddress = (IPaddress *)&(addr->sa_data); + return SDLNet_Read16(&ipaddress->port); +} + +int SDLN_SetSocketPort (struct qsockaddr *addr, int port) +{ + IPaddress *ipaddress; + + ipaddress = (IPaddress *)&(addr->sa_data); + SDLNet_Write16(port, &ipaddress->port); + + return 0; +} + diff --git a/Quake/net_sdlnet.h b/Quake/net_sdlnet.h new file mode 100644 index 00000000..948853a1 --- /dev/null +++ b/Quake/net_sdlnet.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +int SDLN_Init (void); +void SDLN_Shutdown (void); +void SDLN_Listen (qboolean state); +int SDLN_OpenSocket (int port); +int SDLN_CloseSocket (int socket); +int SDLN_Connect (int socket, struct qsockaddr *addr); +int SDLN_CheckNewConnections (void); +int SDLN_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int SDLN_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int SDLN_Broadcast (int socket, byte *buf, int len); +char *SDLN_AddrToString (struct qsockaddr *addr); +int SDLN_StringToAddr (char *string, struct qsockaddr *addr); +int SDLN_GetSocketAddr (int socket, struct qsockaddr *addr); +int SDLN_GetNameFromAddr (struct qsockaddr *addr, char *name); +int SDLN_GetAddrFromName (char *name, struct qsockaddr *addr); +int SDLN_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int SDLN_GetSocketPort (struct qsockaddr *addr); +int SDLN_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/Quake/net_udp.c b/Quake/net_udp.c new file mode 100644 index 00000000..6445dad7 --- /dev/null +++ b/Quake/net_udp.c @@ -0,0 +1,478 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __sun__ +#include +#endif + +#if defined(NeXT) +#include +#endif + +#if defined (__APPLE__) || defined (MACOSX) +#include +#endif /* __APPLE__ || MACOSX */ + +extern int gethostname (char *, int); +extern int close (int); + +extern cvar_t hostname; + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_broadcastsocket = 0; +static struct qsockaddr broadcastaddr; + +static unsigned long myAddr; + +#include "net_udp.h" + +//============================================================================= + +int UDP_Init (void) +{ + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct qsockaddr addr; + char *colon; + + if (COM_CheckParm ("-noudp")) + return -1; + + // determine my name & address +#if defined (__APPLE__) || defined (MACOSX) + + if (gethostname(buff, MAXHOSTNAMELEN) != 0) + { + Con_Printf ("UDP init failed. Disabling UDP...\n"); + return (-1); + } + + local = gethostbyname(buff); + if (local == NULL) + { + Con_Printf ("UDP init failed. Disabling UDP...\n"); + return (-1); + } + +#else + + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + +#endif /* __APPLE__ ||ÊMACOSX */ + + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + buff[15] = 0; + Cvar_Set ("hostname", buff); + } + + if ((net_controlsocket = UDP_OpenSocket (0)) == -1) + Sys_Error("UDP_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport); + +#if defined (__APPLE__) || defined (MACOSX) + + if (UDP_GetSocketAddr (net_controlsocket, &addr) != 0) + { + Con_Printf ("UDP init failed. Disabling UDP...\n"); + return (-1); + } + +#else + + UDP_GetSocketAddr (net_controlsocket, &addr); + +#endif /* __APPLE__ || MACOSX */ + + Q_strcpy(my_tcpip_address, UDP_AddrToString (&addr)); + colon = Q_strrchr (my_tcpip_address, ':'); + if (colon) + *colon = 0; + + Con_Printf("UDP Initialized\n"); + tcpipAvailable = true; + + return net_controlsocket; +} + +//============================================================================= + +void UDP_Shutdown (void) +{ + UDP_Listen (false); + UDP_CloseSocket (net_controlsocket); +} + +//============================================================================= + +void UDP_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1) + Sys_Error ("UDP_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + UDP_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} + +//============================================================================= + +int UDP_OpenSocket (int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = true; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return -1; + + if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1) + goto ErrorReturn; + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + goto ErrorReturn; + + return newsocket; + +ErrorReturn: + close (newsocket); + return -1; +} + +//============================================================================= + +int UDP_CloseSocket (int socket) +{ + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + return close (socket); +} + + +//============================================================================= +/* +============ +PartialIPAddress + +this lets you type only as much of the net address as required, using +the local network components to fill in the rest +============ +*/ +static int PartialIPAddress (char *in, struct qsockaddr *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + int run; + int port; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') + b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + b++; + num = 0; + run = 0; + while (!( *b < '0' || *b > '9')) + { + num = num*10 + *b++ - '0'; + if (++run > 3) + return -1; + } + if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) + return -1; + if (num < 0 || num > 255) + return -1; + mask<<=8; + addr = (addr<<8) + num; + } + + if (*b++ == ':') + port = Q_atoi(b); + else + port = net_hostport; + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} +//============================================================================= + +int UDP_Connect (int socket, struct qsockaddr *addr) +{ + return 0; +} + +//============================================================================= + +int UDP_CheckNewConnections (void) +{ + unsigned long available; + + if (net_acceptsocket == -1) + return -1; + + if (ioctl (net_acceptsocket, FIONREAD, &available) == -1) + Sys_Error ("UDP: ioctlsocket (FIONREAD) failed\n"); + if (available) + return net_acceptsocket; + return -1; +} + +//============================================================================= + +void get_qsockaddr(struct sockaddr *saddr, struct qsockaddr *qaddr) +{ + qaddr->sa_family = saddr->sa_family; + memcpy(&(qaddr->sa_data), &(saddr->sa_data), sizeof(qaddr->sa_data)); +} + +int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + static struct sockaddr saddr; + unsigned int addrlen = sizeof (struct sockaddr); + int ret; + + ret = recvfrom (socket, buf, len, 0, &saddr, &addrlen); + + if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED)) + return 0; + + get_qsockaddr(&saddr, addr); + return ret; +} + +//============================================================================= + +int UDP_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} + +//============================================================================= + +int UDP_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + Sys_Error("Attempted to use multiple broadcasts sockets\n"); + ret = UDP_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + Con_Printf("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return UDP_Write (socket, buf, len, &broadcastaddr); +} + +//============================================================================= + +int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + int ret; + + ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); + + if (ret == -1 && errno == EWOULDBLOCK) + return 0; + return ret; +} + +//============================================================================= + +char *UDP_AddrToString (struct qsockaddr *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); +#if defined (__APPLE__) || defined (MACOSX) + snprintf(buffer, 22, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); +#else + 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)); +#endif /* __APPLE__ || MACOSX */ + return buffer; +} + +//============================================================================= + +int UDP_StringToAddr (char *string, struct qsockaddr *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons(hp); + return 0; +} + +//============================================================================= + +int UDP_GetSocketAddr (int socket, struct qsockaddr *addr) +{ + unsigned int addrlen = sizeof(struct qsockaddr); + unsigned int a; + + Q_memset(addr, 0, sizeof(struct qsockaddr)); + +#if defined (__APPLE__) || defined (MACOSX) + + if (getsockname(socket, (struct sockaddr *)addr, &addrlen) != 0) + return (-1); + +#else + + getsockname(socket, (struct sockaddr *)addr, &addrlen); + +#endif /* __APPLE__ || MACOSX */ + + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} + +//============================================================================= + +int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + Q_strcpy (name, UDP_AddrToString (addr)); + return 0; +} + +//============================================================================= + +int UDP_GetAddrFromName(char *name, struct qsockaddr *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons(net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} + +//============================================================================= + +int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} + +//============================================================================= + +int UDP_GetSocketPort (struct qsockaddr *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} + + +int UDP_SetSocketPort (struct qsockaddr *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons(port); + return 0; +} + +//============================================================================= diff --git a/Quake/net_udp.h b/Quake/net_udp.h new file mode 100644 index 00000000..75303011 --- /dev/null +++ b/Quake/net_udp.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_udp.h + +int UDP_Init (void); +void UDP_Shutdown (void); +void UDP_Listen (qboolean state); +int UDP_OpenSocket (int port); +int UDP_CloseSocket (int socket); +int UDP_Connect (int socket, struct qsockaddr *addr); +int UDP_CheckNewConnections (void); +int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int UDP_Broadcast (int socket, byte *buf, int len); +char *UDP_AddrToString (struct qsockaddr *addr); +int UDP_StringToAddr (char *string, struct qsockaddr *addr); +int UDP_GetSocketAddr (int socket, struct qsockaddr *addr); +int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name); +int UDP_GetAddrFromName (char *name, struct qsockaddr *addr); +int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int UDP_GetSocketPort (struct qsockaddr *addr); +int UDP_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/Quake/net_win.c b/Quake/net_win.c new file mode 100644 index 00000000..8b700109 --- /dev/null +++ b/Quake/net_win.c @@ -0,0 +1,121 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +#include "net_loop.h" +#include "net_dgrm.h" +#include "net_ser.h" + +net_driver_t net_drivers[MAX_NET_DRIVERS] = +{ + { + "Loopback", + false, + Loop_Init, + Loop_Listen, + Loop_SearchForHosts, + Loop_Connect, + Loop_CheckNewConnections, + Loop_GetMessage, + Loop_SendMessage, + Loop_SendUnreliableMessage, + Loop_CanSendMessage, + Loop_CanSendUnreliableMessage, + Loop_Close, + Loop_Shutdown + } + , + { + "Datagram", + false, + Datagram_Init, + Datagram_Listen, + Datagram_SearchForHosts, + Datagram_Connect, + Datagram_CheckNewConnections, + Datagram_GetMessage, + Datagram_SendMessage, + Datagram_SendUnreliableMessage, + Datagram_CanSendMessage, + Datagram_CanSendUnreliableMessage, + Datagram_Close, + Datagram_Shutdown + } +}; + +int net_numdrivers = 2; + + +#include "net_wins.h" +#include "net_wipx.h" + +net_landriver_t net_landrivers[MAX_NET_DRIVERS] = +{ + { + "Winsock TCPIP", + false, + 0, + WINS_Init, + WINS_Shutdown, + WINS_Listen, + WINS_OpenSocket, + WINS_CloseSocket, + WINS_Connect, + WINS_CheckNewConnections, + WINS_Read, + WINS_Write, + WINS_Broadcast, + WINS_AddrToString, + WINS_StringToAddr, + WINS_GetSocketAddr, + WINS_GetNameFromAddr, + WINS_GetAddrFromName, + WINS_AddrCompare, + WINS_GetSocketPort, + WINS_SetSocketPort + }, + { + "Winsock IPX", + false, + 0, + WIPX_Init, + WIPX_Shutdown, + WIPX_Listen, + WIPX_OpenSocket, + WIPX_CloseSocket, + WIPX_Connect, + WIPX_CheckNewConnections, + WIPX_Read, + WIPX_Write, + WIPX_Broadcast, + WIPX_AddrToString, + WIPX_StringToAddr, + WIPX_GetSocketAddr, + WIPX_GetNameFromAddr, + WIPX_GetAddrFromName, + WIPX_AddrCompare, + WIPX_GetSocketPort, + WIPX_SetSocketPort + } + +}; + +int net_numlandrivers = 2; diff --git a/Quake/net_wins.c b/Quake/net_wins.c new file mode 100644 index 00000000..bb2e8c8e --- /dev/null +++ b/Quake/net_wins.c @@ -0,0 +1,576 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_wins.c + +#include "quakedef.h" +#include "winquake.h" + +extern cvar_t hostname; + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_broadcastsocket = 0; +static struct qsockaddr broadcastaddr; + +static unsigned long myAddr; + +qboolean winsock_lib_initialized; + +int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData); +int (PASCAL FAR *pWSACleanup)(void); +int (PASCAL FAR *pWSAGetLastError)(void); +SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol); +int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp); +int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname, + const char FAR * optval, int optlen); +int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags, + struct sockaddr FAR *from, int FAR * fromlen); +int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags, + const struct sockaddr FAR *to, int tolen); +int (PASCAL FAR *pclosesocket)(SOCKET s); +int (PASCAL FAR *pgethostname)(char FAR * name, int namelen); +struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name); +struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr, + int len, int type); +int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name, + int FAR * namelen); + +#include "net_wins.h" + +int winsock_initialized = 0; +WSADATA winsockdata; + +//============================================================================= + +static double blocktime; + +BOOL PASCAL FAR BlockingHook(void) +{ + MSG msg; + BOOL ret; + + if ((Sys_FloatTime() - blocktime) > 2.0) + { + WSACancelBlockingCall(); + return FALSE; + } + + /* get the next message, if any */ + ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); + + /* if we got one, process it */ + if (ret) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + /* TRUE if we got a message */ + return ret; +} + + +void WINS_GetLocalAddress() +{ + struct hostent *local = NULL; + char buff[MAXHOSTNAMELEN]; + unsigned long addr; + + if (myAddr != INADDR_ANY) + return; + + if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR) + return; + + blocktime = Sys_FloatTime(); + WSASetBlockingHook(BlockingHook); + local = pgethostbyname(buff); + WSAUnhookBlockingHook(); + if (local == NULL) + return; + + myAddr = *(int *)local->h_addr_list[0]; + + addr = ntohl(myAddr); + sprintf(my_tcpip_address, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); +} + + +int WINS_Init (void) +{ + int i; + char buff[MAXHOSTNAMELEN]; + char *p; + int r; + WORD wVersionRequested; + HINSTANCE hInst; + +// initialize the Winsock function vectors (we do this instead of statically linking +// so we can run on Win 3.1, where there isn't necessarily Winsock) + hInst = LoadLibrary("wsock32.dll"); + + if (hInst == NULL) + { + Con_SafePrintf ("Failed to load winsock.dll\n"); + winsock_lib_initialized = false; + return -1; + } + + winsock_lib_initialized = true; + + pWSAStartup = (void *)GetProcAddress(hInst, "WSAStartup"); + pWSACleanup = (void *)GetProcAddress(hInst, "WSACleanup"); + pWSAGetLastError = (void *)GetProcAddress(hInst, "WSAGetLastError"); + psocket = (void *)GetProcAddress(hInst, "socket"); + pioctlsocket = (void *)GetProcAddress(hInst, "ioctlsocket"); + psetsockopt = (void *)GetProcAddress(hInst, "setsockopt"); + precvfrom = (void *)GetProcAddress(hInst, "recvfrom"); + psendto = (void *)GetProcAddress(hInst, "sendto"); + pclosesocket = (void *)GetProcAddress(hInst, "closesocket"); + pgethostname = (void *)GetProcAddress(hInst, "gethostname"); + pgethostbyname = (void *)GetProcAddress(hInst, "gethostbyname"); + pgethostbyaddr = (void *)GetProcAddress(hInst, "gethostbyaddr"); + pgetsockname = (void *)GetProcAddress(hInst, "getsockname"); + + if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError || + !psocket || !pioctlsocket || !psetsockopt || + !precvfrom || !psendto || !pclosesocket || + !pgethostname || !pgethostbyname || !pgethostbyaddr || + !pgetsockname) + { + Con_SafePrintf ("Couldn't GetProcAddress from winsock.dll\n"); + return -1; + } + + if (COM_CheckParm ("-noudp")) + return -1; + + if (winsock_initialized == 0) + { + wVersionRequested = MAKEWORD(1, 1); + + r = pWSAStartup (MAKEWORD(1, 1), &winsockdata); + + if (r) + { + Con_SafePrintf ("Winsock initialization failed.\n"); + return -1; + } + } + winsock_initialized++; + + // determine my name + if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR) + { + Con_DPrintf ("Winsock TCP/IP Initialization failed.\n"); + if (--winsock_initialized == 0) + pWSACleanup (); + return -1; + } + + // if the quake hostname isn't set, set it to the machine name + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } + Cvar_Set ("hostname", buff); + } + + i = COM_CheckParm ("-ip"); + if (i) + { + if (i < com_argc-1) + { + myAddr = inet_addr(com_argv[i+1]); + if (myAddr == INADDR_NONE) + Sys_Error ("%s is not a valid IP address", com_argv[i+1]); + strcpy(my_tcpip_address, com_argv[i+1]); + } + else + { + Sys_Error ("NET_Init: you must specify an IP address after -ip"); + } + } + else + { + myAddr = INADDR_ANY; + strcpy(my_tcpip_address, "INADDR_ANY"); + } + + if ((net_controlsocket = WINS_OpenSocket (0)) == -1) + { + Con_Printf("WINS_Init: Unable to open control socket\n"); + if (--winsock_initialized == 0) + pWSACleanup (); + return -1; + } + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport); + + Con_Printf("Winsock TCP/IP Initialized\n"); + tcpipAvailable = true; + + return net_controlsocket; +} + +//============================================================================= + +void WINS_Shutdown (void) +{ + WINS_Listen (false); + WINS_CloseSocket (net_controlsocket); + if (--winsock_initialized == 0) + pWSACleanup (); +} + +//============================================================================= + +void WINS_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + WINS_GetLocalAddress(); + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + Sys_Error ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} + +//============================================================================= + +int WINS_OpenSocket (int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = psocket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return -1; + + if (pioctlsocket (newsocket, FIONBIO, &_true) == -1) + goto ErrorReturn; + + address.sin_family = AF_INET; + address.sin_addr.s_addr = myAddr; + address.sin_port = htons((unsigned short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == 0) + return newsocket; + + Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address)); +ErrorReturn: + pclosesocket (newsocket); + return -1; +} + +//============================================================================= + +int WINS_CloseSocket (int socket) +{ + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + return pclosesocket (socket); +} + + +//============================================================================= +/* +============ +PartialIPAddress + +this lets you type only as much of the net address as required, using +the local network components to fill in the rest +============ +*/ +static int PartialIPAddress (char *in, struct qsockaddr *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + int run; + int port; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') + b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + b++; + num = 0; + run = 0; + while (!( *b < '0' || *b > '9')) + { + num = num*10 + *b++ - '0'; + if (++run > 3) + return -1; + } + if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) + return -1; + if (num < 0 || num > 255) + return -1; + mask<<=8; + addr = (addr<<8) + num; + } + + if (*b++ == ':') + port = Q_atoi(b); + else + port = net_hostport; + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} +//============================================================================= + +int WINS_Connect (int socket, struct qsockaddr *addr) +{ + return 0; +} + +//============================================================================= + +int WINS_CheckNewConnections (void) +{ + char buf[4096]; + + if (net_acceptsocket == -1) + return -1; + + if (precvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) > 0) + { + return net_acceptsocket; + } + return -1; +} + +//============================================================================= + +int WINS_Read (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + int addrlen = sizeof (struct qsockaddr); + int ret; + + ret = precvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { + int err = pWSAGetLastError(); + + if (err == WSAEWOULDBLOCK || err == WSAECONNREFUSED) + return 0; + + } + return ret; +} + +//============================================================================= + +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (psetsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} + +//============================================================================= + +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + Sys_Error("Attempted to use multiple broadcasts sockets\n"); + WINS_GetLocalAddress(); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + Con_Printf("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} + +//============================================================================= + +int WINS_Write (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + int ret; + + ret = psendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); + if (ret == -1) + if (pWSAGetLastError() == WSAEWOULDBLOCK) + return 0; + + return ret; +} + +//============================================================================= + +char *WINS_AddrToString (struct qsockaddr *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + 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)); + return buffer; +} + +//============================================================================= + +int WINS_StringToAddr (char *string, struct qsockaddr *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp); + return 0; +} + +//============================================================================= + +int WINS_GetSocketAddr (int socket, struct qsockaddr *addr) +{ + int addrlen = sizeof(struct qsockaddr); + unsigned int a; + + Q_memset(addr, 0, sizeof(struct qsockaddr)); + pgetsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} + +//============================================================================= + +int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = pgethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + Q_strcpy (name, WINS_AddrToString (addr)); + return 0; +} + +//============================================================================= + +int WINS_GetAddrFromName(char *name, struct qsockaddr *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = pgethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} + +//============================================================================= + +int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} + +//============================================================================= + +int WINS_GetSocketPort (struct qsockaddr *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} + + +int WINS_SetSocketPort (struct qsockaddr *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port); + return 0; +} + +//============================================================================= diff --git a/Quake/net_wins.h b/Quake/net_wins.h new file mode 100644 index 00000000..09709184 --- /dev/null +++ b/Quake/net_wins.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_wins.h + +int WINS_Init (void); +void WINS_Shutdown (void); +void WINS_Listen (qboolean state); +int WINS_OpenSocket (int port); +int WINS_CloseSocket (int socket); +int WINS_Connect (int socket, struct qsockaddr *addr); +int WINS_CheckNewConnections (void); +int WINS_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int WINS_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int WINS_Broadcast (int socket, byte *buf, int len); +char *WINS_AddrToString (struct qsockaddr *addr); +int WINS_StringToAddr (char *string, struct qsockaddr *addr); +int WINS_GetSocketAddr (int socket, struct qsockaddr *addr); +int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name); +int WINS_GetAddrFromName (char *name, struct qsockaddr *addr); +int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int WINS_GetSocketPort (struct qsockaddr *addr); +int WINS_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/Quake/pl_linux.c b/Quake/pl_linux.c new file mode 100644 index 00000000..86c02571 --- /dev/null +++ b/Quake/pl_linux.c @@ -0,0 +1,38 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +void PL_SetWindowIcon (void) +{ + // TODO: implement this +} + +void PL_VID_Shutdown (void) +{ +} + +void PL_ErrorDialog(char *text) +{ + // TODO: implement this properly + printf(text); +} diff --git a/Quake/pl_osx.m b/Quake/pl_osx.m new file mode 100644 index 00000000..81bf589c --- /dev/null +++ b/Quake/pl_osx.m @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" +#import + +void PL_SetWindowIcon (void) +{ + // nothing to do on OS X +} + +void PL_VID_Shutdown (void) +{ +} + +void PL_ErrorDialog(char *text) +{ + NSString *msg = [NSString stringWithCString:text encoding:NSASCIIStringEncoding]; + NSRunAlertPanel(nil, msg, nil, nil, nil); +} diff --git a/Quake/pl_win.c b/Quake/pl_win.c new file mode 100644 index 00000000..f866f464 --- /dev/null +++ b/Quake/pl_win.c @@ -0,0 +1,58 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" +#include +#include "SDL/SDL_syswm.h" + +HICON icon; + +void PL_SetWindowIcon (void) +{ + HINSTANCE handle; + SDL_SysWMinfo wminfo; + HWND hwnd; + + handle = GetModuleHandle(NULL); + icon = LoadIcon(handle, "icon"); + + if (!icon) + return; // no icon in executable + + SDL_VERSION(&wminfo.version); + + if (SDL_GetWMInfo(&wminfo) != 1) + return; // wrong SDL version + + hwnd = wminfo.window; + SetClassLong(hwnd, GCL_HICON, (LONG) icon); +} + +void PL_VID_Shutdown (void) +{ + DestroyIcon(icon); +} + +void PL_ErrorDialog(char *text) +{ + MessageBox(NULL, text, "Quake Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP); +} diff --git a/Quake/platform.h b/Quake/platform.h new file mode 100644 index 00000000..6f40e77d --- /dev/null +++ b/Quake/platform.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// platform dependent way to set the window icon +void PL_SetWindowIcon(void); + +// platform dependent cleanup +void PL_VID_Shutdown (void); + +// show an error dialog +void PL_ErrorDialog(char *text); diff --git a/Quake/pr_cmds.c b/Quake/pr_cmds.c new file mode 100644 index 00000000..b4a98a12 --- /dev/null +++ b/Quake/pr_cmds.c @@ -0,0 +1,1691 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e)) + +/* +=============================================================================== + + BUILT-IN FUNCTIONS + +=============================================================================== +*/ + +char *PF_VarString (int first) +{ + int i; + static char out[256]; + + out[0] = 0; + for (i=first ; is_name,s); + ed = PROG_TO_EDICT(pr_global_struct->self); + ED_Print (ed); + + Host_Error ("Program error"); +} + +/* +================= +PF_objerror + +Dumps out self, then an error message. The program is aborted and self is +removed, but the level can continue. + +objerror(value) +================= +*/ +void PF_objerror (void) +{ + char *s; + edict_t *ed; + + s = PF_VarString(0); + Con_Printf ("======OBJECT ERROR in %s:\n%s\n" + ,pr_strings + pr_xfunction->s_name,s); + ed = PROG_TO_EDICT(pr_global_struct->self); + ED_Print (ed); + ED_Free (ed); + + //Host_Error ("Program error"); //johnfitz -- by design, this should not be fatal +} + + + +/* +============== +PF_makevectors + +Writes new values for v_forward, v_up, and v_right based on angles +makevectors(vector) +============== +*/ +void PF_makevectors (void) +{ + AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up); +} + +/* +================= +PF_setorigin + +This 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. + +setorigin (entity, origin) +================= +*/ +void PF_setorigin (void) +{ + edict_t *e; + float *org; + + e = G_EDICT(OFS_PARM0); + org = G_VECTOR(OFS_PARM1); + VectorCopy (org, e->v.origin); + SV_LinkEdict (e, false); +} + + +void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate) +{ + float *angles; + vec3_t rmin, rmax; + float bounds[2][3]; + float xvector[2], yvector[2]; + float a; + vec3_t base, transformed; + int i, j, k, l; + + for (i=0 ; i<3 ; i++) + if (min[i] > max[i]) + PR_RunError ("backwards mins/maxs"); + + rotate = false; // FIXME: implement rotation properly again + + if (!rotate) + { + VectorCopy (min, rmin); + VectorCopy (max, rmax); + } + else + { + // find min / max for rotations + angles = e->v.angles; + + a = angles[1]/180 * M_PI; + + xvector[0] = cos(a); + xvector[1] = sin(a); + yvector[0] = -sin(a); + yvector[1] = cos(a); + + VectorCopy (min, bounds[0]); + VectorCopy (max, bounds[1]); + + rmin[0] = rmin[1] = rmin[2] = 9999; + rmax[0] = rmax[1] = rmax[2] = -9999; + + for (i=0 ; i<= 1 ; i++) + { + base[0] = bounds[i][0]; + for (j=0 ; j<= 1 ; j++) + { + base[1] = bounds[j][1]; + for (k=0 ; k<= 1 ; k++) + { + base[2] = bounds[k][2]; + + // transform the point + transformed[0] = xvector[0]*base[0] + yvector[0]*base[1]; + transformed[1] = xvector[1]*base[0] + yvector[1]*base[1]; + transformed[2] = base[2]; + + for (l=0 ; l<3 ; l++) + { + if (transformed[l] < rmin[l]) + rmin[l] = transformed[l]; + if (transformed[l] > rmax[l]) + rmax[l] = transformed[l]; + } + } + } + } + } + +// set derived values + VectorCopy (rmin, e->v.mins); + VectorCopy (rmax, e->v.maxs); + VectorSubtract (max, min, e->v.size); + + SV_LinkEdict (e, false); +} + +/* +================= +PF_setsize + +the size box is rotated by the current angle + +setsize (entity, minvector, maxvector) +================= +*/ +void PF_setsize (void) +{ + edict_t *e; + float *min, *max; + + e = G_EDICT(OFS_PARM0); + min = G_VECTOR(OFS_PARM1); + max = G_VECTOR(OFS_PARM2); + SetMinMaxSize (e, min, max, false); +} + + +/* +================= +PF_setmodel + +setmodel(entity, model) +================= +*/ +void PF_setmodel (void) +{ + edict_t *e; + char *m, **check; + model_t *mod; + int i; + + e = G_EDICT(OFS_PARM0); + m = G_STRING(OFS_PARM1); + +// check to see if model was properly precached + for (i=0, check = sv.model_precache ; *check ; i++, check++) + if (!strcmp(*check, m)) + break; + + if (!*check) + PR_RunError ("no precache: %s\n", m); + + e->v.model = m - pr_strings; + e->v.modelindex = i; //SV_ModelIndex (m); + + mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true); + + if (mod) + //johnfitz -- correct physics cullboxes for bmodels + { + if (mod->type == mod_brush) + SetMinMaxSize (e, mod->clipmins, mod->clipmaxs, true); + else + SetMinMaxSize (e, mod->mins, mod->maxs, true); + } + //johnfitz + else + SetMinMaxSize (e, vec3_origin, vec3_origin, true); +} + +/* +================= +PF_bprint + +broadcast print to everyone on server + +bprint(value) +================= +*/ +void PF_bprint (void) +{ + char *s; + + s = PF_VarString(0); + SV_BroadcastPrintf ("%s", s); +} + +/* +================= +PF_sprint + +single print to a specific client + +sprint(clientent, value) +================= +*/ +void PF_sprint (void) +{ + char *s; + client_t *client; + int entnum; + + entnum = G_EDICTNUM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svs.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svs.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_print); + MSG_WriteString (&client->message, s ); +} + + +/* +================= +PF_centerprint + +single print to a specific client + +centerprint(clientent, value) +================= +*/ +void PF_centerprint (void) +{ + char *s; + client_t *client; + int entnum; + + entnum = G_EDICTNUM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svs.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svs.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_centerprint); + MSG_WriteString (&client->message, s ); +} + + +/* +================= +PF_normalize + +vector normalize(vector) +================= +*/ +void PF_normalize (void) +{ + float *value1; + vec3_t newvalue; + float new; + + value1 = G_VECTOR(OFS_PARM0); + + new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; + new = sqrt(new); + + if (new == 0) + newvalue[0] = newvalue[1] = newvalue[2] = 0; + else + { + new = 1/new; + newvalue[0] = value1[0] * new; + newvalue[1] = value1[1] * new; + newvalue[2] = value1[2] * new; + } + + VectorCopy (newvalue, G_VECTOR(OFS_RETURN)); +} + +/* +================= +PF_vlen + +scalar vlen(vector) +================= +*/ +void PF_vlen (void) +{ + float *value1; + float new; + + value1 = G_VECTOR(OFS_PARM0); + + new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; + new = sqrt(new); + + G_FLOAT(OFS_RETURN) = new; +} + +/* +================= +PF_vectoyaw + +float vectoyaw(vector) +================= +*/ +void PF_vectoyaw (void) +{ + float *value1; + float yaw; + + value1 = G_VECTOR(OFS_PARM0); + + if (value1[1] == 0 && value1[0] == 0) + yaw = 0; + else + { + yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + } + + G_FLOAT(OFS_RETURN) = yaw; +} + + +/* +================= +PF_vectoangles + +vector vectoangles(vector) +================= +*/ +void PF_vectoangles (void) +{ + float *value1; + float forward; + float yaw, pitch; + + value1 = G_VECTOR(OFS_PARM0); + + if (value1[1] == 0 && value1[0] == 0) + { + yaw = 0; + if (value1[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]); + pitch = (int) (atan2(value1[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + G_FLOAT(OFS_RETURN+0) = pitch; + G_FLOAT(OFS_RETURN+1) = yaw; + G_FLOAT(OFS_RETURN+2) = 0; +} + +/* +================= +PF_Random + +Returns a number from 0<= num < 1 + +random() +================= +*/ +void PF_random (void) +{ + float num; + + num = (rand ()&0x7fff) / ((float)0x7fff); + + G_FLOAT(OFS_RETURN) = num; +} + +/* +================= +PF_particle + +particle(origin, color, count) +================= +*/ +void PF_particle (void) +{ + float *org, *dir; + float color; + float count; + + org = G_VECTOR(OFS_PARM0); + dir = G_VECTOR(OFS_PARM1); + color = G_FLOAT(OFS_PARM2); + count = G_FLOAT(OFS_PARM3); + SV_StartParticle (org, dir, color, count); +} + + +/* +================= +PF_ambientsound + +================= +*/ +void PF_ambientsound (void) +{ + char **check; + char *samp; + float *pos; + float vol, attenuation; + int i, soundnum; + int large=false; //johnfitz -- PROTOCOL_FITZQUAKE + + pos = G_VECTOR (OFS_PARM0); + samp = G_STRING(OFS_PARM1); + vol = G_FLOAT(OFS_PARM2); + attenuation = G_FLOAT(OFS_PARM3); + +// check to see if samp was properly precached + for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++) + if (!strcmp(*check,samp)) + break; + + if (!*check) + { + Con_Printf ("no precache: %s\n", samp); + return; + } + + //johnfitz -- PROTOCOL_FITZQUAKE + if (soundnum > 255) + if (sv.protocol == PROTOCOL_NETQUAKE) + return; //don't send any info protocol can't support + else + large = true; + //johnfitz + +// add an svc_spawnambient command to the level signon packet + + //johnfitz -- PROTOCOL_FITZQUAKE + if (large) + MSG_WriteByte (&sv.signon,svc_spawnstaticsound2); + else + MSG_WriteByte (&sv.signon,svc_spawnstaticsound); + //johnfitz + + for (i=0 ; i<3 ; i++) + MSG_WriteCoord(&sv.signon, pos[i]); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (large) + MSG_WriteShort (&sv.signon, soundnum); + else + MSG_WriteByte (&sv.signon, soundnum); + //johnfitz + + MSG_WriteByte (&sv.signon, vol*255); + MSG_WriteByte (&sv.signon, attenuation*64); + +} + +/* +================= +PF_sound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +allready running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. + +================= +*/ +void PF_sound (void) +{ + char *sample; + int channel; + edict_t *entity; + int volume; + float attenuation; + + entity = G_EDICT(OFS_PARM0); + channel = G_FLOAT(OFS_PARM1); + sample = G_STRING(OFS_PARM2); + volume = G_FLOAT(OFS_PARM3) * 255; + attenuation = G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + SV_StartSound (entity, channel, sample, volume, attenuation); +} + +/* +================= +PF_break + +break() +================= +*/ +void PF_break (void) +{ +Con_Printf ("break statement\n"); +*(int *)-4 = 0; // dump to debugger +// PR_RunError ("break statement"); +} + +/* +================= +PF_traceline + +Used for use tracing and shot targeting +Traces are blocked by bbox and exact bsp entityes, and also slide box entities +if the tryents flag is set. + +traceline (vector1, vector2, tryents) +================= +*/ +void PF_traceline (void) +{ + float *v1, *v2; + trace_t trace; + int nomonsters; + edict_t *ent; + + v1 = G_VECTOR(OFS_PARM0); + v2 = G_VECTOR(OFS_PARM1); + nomonsters = G_FLOAT(OFS_PARM2); + ent = G_EDICT(OFS_PARM3); + + trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent); + + pr_global_struct->trace_allsolid = trace.allsolid; + pr_global_struct->trace_startsolid = trace.startsolid; + pr_global_struct->trace_fraction = trace.fraction; + pr_global_struct->trace_inwater = trace.inwater; + pr_global_struct->trace_inopen = trace.inopen; + VectorCopy (trace.endpos, pr_global_struct->trace_endpos); + VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal); + pr_global_struct->trace_plane_dist = trace.plane.dist; + if (trace.ent) + pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent); + else + pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts); +} + +/* +================= +PF_checkpos + +Returns true if the given entity can move to the given position from it's +current position by walking or rolling. +FIXME: make work... +scalar checkpos (entity, vector) +================= +*/ +void PF_checkpos (void) +{ +} + +//============================================================================ + +byte checkpvs[MAX_MAP_LEAFS/8]; + +int PF_newcheckclient (int check) +{ + int i; + byte *pvs; + edict_t *ent; + mleaf_t *leaf; + vec3_t org; + +// cycle to the next one + + if (check < 1) + check = 1; + if (check > svs.maxclients) + check = svs.maxclients; + + if (check == svs.maxclients) + i = 1; + else + i = check + 1; + + for ( ; ; i++) + { + if (i == svs.maxclients+1) + i = 1; + + ent = EDICT_NUM(i); + + if (i == check) + break; // didn't find anything else + + if (ent->free) + continue; + if (ent->v.health <= 0) + continue; + if ((int)ent->v.flags & FL_NOTARGET) + continue; + + // anything that is a client, or has a client as an enemy + break; + } + +// get the PVS for the entity + VectorAdd (ent->v.origin, ent->v.view_ofs, org); + leaf = Mod_PointInLeaf (org, sv.worldmodel); + pvs = Mod_LeafPVS (leaf, sv.worldmodel); + memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 ); + + return i; +} + +/* +================= +PF_checkclient + +Returns a client (or object that has a client enemy) that would be a +valid target. + +If there are more than one valid options, they are cycled each frame + +If (self.origin + self.viewofs) is not in the PVS of the current target, +it is not returned at all. + +name checkclient () +================= +*/ +#define MAX_CHECK 16 +int c_invis, c_notvis; +void PF_checkclient (void) +{ + edict_t *ent, *self; + mleaf_t *leaf; + int l; + vec3_t view; + +// find a new check if on a new frame + if (sv.time - sv.lastchecktime >= 0.1) + { + sv.lastcheck = PF_newcheckclient (sv.lastcheck); + sv.lastchecktime = sv.time; + } + +// return check if it might be visible + ent = EDICT_NUM(sv.lastcheck); + if (ent->free || ent->v.health <= 0) + { + RETURN_EDICT(sv.edicts); + return; + } + +// if current entity can't possibly see the check entity, return 0 + self = PROG_TO_EDICT(pr_global_struct->self); + VectorAdd (self->v.origin, self->v.view_ofs, view); + leaf = Mod_PointInLeaf (view, sv.worldmodel); + l = (leaf - sv.worldmodel->leafs) - 1; + if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) ) + { +c_notvis++; + RETURN_EDICT(sv.edicts); + return; + } + +// might be able to see it +c_invis++; + RETURN_EDICT(ent); +} + +//============================================================================ + + +/* +================= +PF_stuffcmd + +Sends text over to the client's execution buffer + +stuffcmd (clientent, value) +================= +*/ +void PF_stuffcmd (void) +{ + int entnum; + char *str; + client_t *old; + + entnum = G_EDICTNUM(OFS_PARM0); + if (entnum < 1 || entnum > svs.maxclients) + PR_RunError ("Parm 0 not a client"); + str = G_STRING(OFS_PARM1); + + old = host_client; + host_client = &svs.clients[entnum-1]; + Host_ClientCommands ("%s", str); + host_client = old; +} + +/* +================= +PF_localcmd + +Sends text over to the client's execution buffer + +localcmd (string) +================= +*/ +void PF_localcmd (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + Cbuf_AddText (str); +} + +/* +================= +PF_cvar + +float cvar (string) +================= +*/ +void PF_cvar (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str); +} + +/* +================= +PF_cvar_set + +float cvar (string) +================= +*/ +void PF_cvar_set (void) +{ + char *var, *val; + + var = G_STRING(OFS_PARM0); + val = G_STRING(OFS_PARM1); + + Cvar_Set (var, val); +} + +/* +================= +PF_findradius + +Returns a chain of entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +void PF_findradius (void) +{ + edict_t *ent, *chain; + float rad; + float *org; + vec3_t eorg; + int i, j; + + chain = (edict_t *)sv.edicts; + + org = G_VECTOR(OFS_PARM0); + rad = G_FLOAT(OFS_PARM1); + + ent = NEXT_EDICT(sv.edicts); + for (i=1 ; ifree) + continue; + if (ent->v.solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5); + if (Length(eorg) > rad) + continue; + + ent->v.chain = EDICT_TO_PROG(chain); + chain = ent; + } + + RETURN_EDICT(chain); +} + + +/* +========= +PF_dprint +========= +*/ +void PF_dprint (void) +{ + Con_DPrintf ("%s",PF_VarString(0)); +} + +char pr_string_temp[128]; + +void PF_ftos (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + + if (v == (int)v) + sprintf (pr_string_temp, "%d",(int)v); + else + sprintf (pr_string_temp, "%5.1f",v); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} + +void PF_fabs (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + G_FLOAT(OFS_RETURN) = fabs(v); +} + +void PF_vtos (void) +{ + 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]); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} + +void PF_Spawn (void) +{ + edict_t *ed; + ed = ED_Alloc(); + RETURN_EDICT(ed); +} + +void PF_Remove (void) +{ + edict_t *ed; + + ed = G_EDICT(OFS_PARM0); + ED_Free (ed); +} + + +// entity (entity start, .string field, string match) find = #5; +void PF_Find (void) +{ + int e; + int f; + char *s, *t; + edict_t *ed; + + e = G_EDICTNUM(OFS_PARM0); + f = G_INT(OFS_PARM1); + s = G_STRING(OFS_PARM2); + if (!s) + PR_RunError ("PF_Find: bad search string"); + + for (e++ ; e < sv.num_edicts ; e++) + { + ed = EDICT_NUM(e); + if (ed->free) + continue; + t = E_STRING(ed,f); + if (!t) + continue; + if (!strcmp(t,s)) + { + RETURN_EDICT(ed); + return; + } + } + + RETURN_EDICT(sv.edicts); +} + +void PR_CheckEmptyString (char *s) +{ + if (s[0] <= ' ') + PR_RunError ("Bad string"); +} + +void PF_precache_file (void) +{ // precache_file is only used to copy files with qcc, it does nothing + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); +} + +void PF_precache_sound (void) +{ + char *s; + int i; + + if (sv.state != ss_loading) + PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions"); + + s = G_STRING(OFS_PARM0); + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); + PR_CheckEmptyString (s); + + for (i=0 ; iself); + yaw = G_FLOAT(OFS_PARM0); + dist = G_FLOAT(OFS_PARM1); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + + yaw = yaw*M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + +// save program state, because SV_movestep may call other progs + oldf = pr_xfunction; + oldself = pr_global_struct->self; + + G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true); + + +// restore program state + pr_xfunction = oldf; + pr_global_struct->self = oldself; +} + +/* +=============== +PF_droptofloor + +void() droptofloor +=============== +*/ +void PF_droptofloor (void) +{ + edict_t *ent; + vec3_t end; + trace_t trace; + + ent = PROG_TO_EDICT(pr_global_struct->self); + + VectorCopy (ent->v.origin, end); + end[2] -= 256; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.fraction == 1 || trace.allsolid) + G_FLOAT(OFS_RETURN) = 0; + else + { + VectorCopy (trace.endpos, ent->v.origin); + SV_LinkEdict (ent, false); + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + G_FLOAT(OFS_RETURN) = 1; + } +} + +/* +=============== +PF_lightstyle + +void(float style, string value) lightstyle +=============== +*/ +void PF_lightstyle (void) +{ + int style; + char *val; + client_t *client; + int j; + + style = G_FLOAT(OFS_PARM0); + val = G_STRING(OFS_PARM1); + +// change the string in sv + sv.lightstyles[style] = val; + +// send message to all clients on this server + if (sv.state != ss_active) + return; + + for (j=0, client = svs.clients ; jactive || client->spawned) + { + MSG_WriteChar (&client->message, svc_lightstyle); + MSG_WriteChar (&client->message,style); + MSG_WriteString (&client->message, val); + } +} + +void PF_rint (void) +{ + float f; + f = G_FLOAT(OFS_PARM0); + if (f > 0) + G_FLOAT(OFS_RETURN) = (int)(f + 0.5); + else + G_FLOAT(OFS_RETURN) = (int)(f - 0.5); +} +void PF_floor (void) +{ + G_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0)); +} +void PF_ceil (void) +{ + G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0)); +} + + +/* +============= +PF_checkbottom +============= +*/ +void PF_checkbottom (void) +{ + edict_t *ent; + + ent = G_EDICT(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = SV_CheckBottom (ent); +} + +/* +============= +PF_pointcontents +============= +*/ +void PF_pointcontents (void) +{ + float *v; + + v = G_VECTOR(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = SV_PointContents (v); +} + +/* +============= +PF_nextent + +entity nextent(entity) +============= +*/ +void PF_nextent (void) +{ + int i; + edict_t *ent; + + i = G_EDICTNUM(OFS_PARM0); + while (1) + { + i++; + if (i == sv.num_edicts) + { + RETURN_EDICT(sv.edicts); + return; + } + ent = EDICT_NUM(i); + if (!ent->free) + { + RETURN_EDICT(ent); + return; + } + } +} + +/* +============= +PF_aim + +Pick a vector for the player to shoot along +vector aim(entity, missilespeed) +============= +*/ +cvar_t sv_aim = {"sv_aim", "0.93"}; +void PF_aim (void) +{ + edict_t *ent, *check, *bestent; + vec3_t start, dir, end, bestdir; + int i, j; + trace_t tr; + float dist, bestdist; + float speed; + + ent = G_EDICT(OFS_PARM0); + speed = G_FLOAT(OFS_PARM1); + + VectorCopy (ent->v.origin, start); + start[2] += 20; + +// try sending a trace straight + VectorCopy (pr_global_struct->v_forward, dir); + VectorMA (start, 2048, dir, end); + tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); + if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM + && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) ) + { + VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN)); + return; + } + + +// try all possible entities + VectorCopy (dir, bestdir); + bestdist = sv_aim.value; + bestent = NULL; + + check = NEXT_EDICT(sv.edicts); + for (i=1 ; iv.takedamage != DAMAGE_AIM) + continue; + if (check == ent) + continue; + if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team) + continue; // don't aim at teammate + for (j=0 ; j<3 ; j++) + end[j] = check->v.origin[j] + + 0.5*(check->v.mins[j] + check->v.maxs[j]); + VectorSubtract (end, start, dir); + VectorNormalize (dir); + dist = DotProduct (dir, pr_global_struct->v_forward); + if (dist < bestdist) + continue; // to far to turn + tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); + if (tr.ent == check) + { // can shoot at this one + bestdist = dist; + bestent = check; + } + } + + if (bestent) + { + VectorSubtract (bestent->v.origin, ent->v.origin, dir); + dist = DotProduct (dir, pr_global_struct->v_forward); + VectorScale (pr_global_struct->v_forward, dist, end); + end[2] = dir[2]; + VectorNormalize (end); + VectorCopy (end, G_VECTOR(OFS_RETURN)); + } + else + { + VectorCopy (bestdir, G_VECTOR(OFS_RETURN)); + } +} + +/* +============== +PF_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void PF_changeyaw (void) +{ + edict_t *ent; + float ideal, current, move, speed; + + ent = PROG_TO_EDICT(pr_global_struct->self); + current = anglemod( ent->v.angles[1] ); + ideal = ent->v.ideal_yaw; + speed = ent->v.yaw_speed; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->v.angles[1] = anglemod (current + move); +} + +/* +=============================================================================== + +MESSAGE WRITING + +=============================================================================== +*/ + +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string + +sizebuf_t *WriteDest (void) +{ + int entnum; + int dest; + edict_t *ent; + + dest = G_FLOAT(OFS_PARM0); + switch (dest) + { + case MSG_BROADCAST: + return &sv.datagram; + + case MSG_ONE: + ent = PROG_TO_EDICT(pr_global_struct->msg_entity); + entnum = NUM_FOR_EDICT(ent); + if (entnum < 1 || entnum > svs.maxclients) + PR_RunError ("WriteDest: not a client"); + return &svs.clients[entnum-1].message; + + case MSG_ALL: + return &sv.reliable_datagram; + + case MSG_INIT: + return &sv.signon; + + default: + PR_RunError ("WriteDest: bad destination"); + break; + } + + return NULL; +} + +void PF_WriteByte (void) +{ + MSG_WriteByte (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteChar (void) +{ + MSG_WriteChar (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteShort (void) +{ + MSG_WriteShort (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteLong (void) +{ + MSG_WriteLong (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteAngle (void) +{ + MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteCoord (void) +{ + MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteString (void) +{ + MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1)); +} + + +void PF_WriteEntity (void) +{ + MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1)); +} + +//============================================================================= + +int SV_ModelIndex (char *name); + +void PF_makestatic (void) +{ + edict_t *ent; + int i; + int bits=0; //johnfitz -- PROTOCOL_FITZQUAKE + + ent = G_EDICT(OFS_PARM0); + + //johnfitz -- don't send invisible static entities + if (ent->alpha == ENTALPHA_ZERO) { + ED_Free (ent); + return; + } + //johnfitz + + //johnfitz -- PROTOCOL_FITZQUAKE + if (sv.protocol == PROTOCOL_NETQUAKE) + { + if (SV_ModelIndex(pr_strings + ent->v.model) & 0xFF00 || (int)(ent->v.frame) & 0xFF00) + { + ED_Free (ent); + return; //can't display the correct model & frame, so don't show it at all + } + } + else + { + if (SV_ModelIndex(pr_strings + ent->v.model) & 0xFF00) + bits |= B_LARGEMODEL; + if ((int)(ent->v.frame) & 0xFF00) + bits |= B_LARGEFRAME; + if (ent->alpha != ENTALPHA_DEFAULT) + bits |= B_ALPHA; + } + + if (bits) + { + MSG_WriteByte (&sv.signon, svc_spawnstatic2); + MSG_WriteByte (&sv.signon, bits); + } + else + MSG_WriteByte (&sv.signon, svc_spawnstatic); + + if (bits & B_LARGEMODEL) + MSG_WriteShort (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model)); + else + MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model)); + + if (bits & B_LARGEFRAME) + MSG_WriteShort (&sv.signon, ent->v.frame); + else + MSG_WriteByte (&sv.signon, ent->v.frame); + //johnfitz + + MSG_WriteByte (&sv.signon, ent->v.colormap); + MSG_WriteByte (&sv.signon, ent->v.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, ent->v.origin[i]); + MSG_WriteAngle(&sv.signon, ent->v.angles[i]); + } + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & B_ALPHA) + MSG_WriteByte (&sv.signon, ent->alpha); + //johnfitz + +// throw the entity away now + ED_Free (ent); +} + +//============================================================================= + +/* +============== +PF_setspawnparms +============== +*/ +void PF_setspawnparms (void) +{ + edict_t *ent; + int i; + client_t *client; + + ent = G_EDICT(OFS_PARM0); + i = NUM_FOR_EDICT(ent); + if (i < 1 || i > svs.maxclients) + PR_RunError ("Entity is not a client"); + + // copy spawn parms out of the client_t + client = svs.clients + (i-1); + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; +} + +/* +============== +PF_changelevel +============== +*/ +void PF_changelevel (void) +{ + char *s; + +// make sure we don't issue two changelevels + if (svs.changelevel_issued) + return; + svs.changelevel_issued = true; + + s = G_STRING(OFS_PARM0); + Cbuf_AddText (va("changelevel %s\n",s)); +} + +void PF_Fixme (void) +{ + PR_RunError ("unimplemented bulitin"); +} + + + +builtin_t pr_builtin[] = +{ +PF_Fixme, +PF_makevectors, // void(entity e) makevectors = #1; +PF_setorigin, // void(entity e, vector o) setorigin = #2; +PF_setmodel, // void(entity e, string m) setmodel = #3; +PF_setsize, // void(entity e, vector min, vector max) setsize = #4; +PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5; +PF_break, // void() break = #6; +PF_random, // float() random = #7; +PF_sound, // void(entity e, float chan, string samp) sound = #8; +PF_normalize, // vector(vector v) normalize = #9; +PF_error, // void(string e) error = #10; +PF_objerror, // void(string e) objerror = #11; +PF_vlen, // float(vector v) vlen = #12; +PF_vectoyaw, // float(vector v) vectoyaw = #13; +PF_Spawn, // entity() spawn = #14; +PF_Remove, // void(entity e) remove = #15; +PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16; +PF_checkclient, // entity() clientlist = #17; +PF_Find, // entity(entity start, .string fld, string match) find = #18; +PF_precache_sound, // void(string s) precache_sound = #19; +PF_precache_model, // void(string s) precache_model = #20; +PF_stuffcmd, // void(entity client, string s)stuffcmd = #21; +PF_findradius, // entity(vector org, float rad) findradius = #22; +PF_bprint, // void(string s) bprint = #23; +PF_sprint, // void(entity client, string s) sprint = #24; +PF_dprint, // void(string s) dprint = #25; +PF_ftos, // void(string s) ftos = #26; +PF_vtos, // void(string s) vtos = #27; +PF_coredump, +PF_traceon, +PF_traceoff, +PF_eprint, // void(entity e) debug print an entire entity +PF_walkmove, // float(float yaw, float dist) walkmove +PF_Fixme, // float(float yaw, float dist) walkmove +PF_droptofloor, +PF_lightstyle, +PF_rint, +PF_floor, +PF_ceil, +PF_Fixme, +PF_checkbottom, +PF_pointcontents, +PF_Fixme, +PF_fabs, +PF_aim, +PF_cvar, +PF_localcmd, +PF_nextent, +PF_particle, +PF_changeyaw, +PF_Fixme, +PF_vectoangles, + +PF_WriteByte, +PF_WriteChar, +PF_WriteShort, +PF_WriteLong, +PF_WriteCoord, +PF_WriteAngle, +PF_WriteString, +PF_WriteEntity, + +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, + +SV_MoveToGoal, +PF_precache_file, +PF_makestatic, + +PF_changelevel, +PF_Fixme, + +PF_cvar_set, +PF_centerprint, + +PF_ambientsound, + +PF_precache_model, +PF_precache_sound, // precache_sound2 is different only for qcc +PF_precache_file, + +PF_setspawnparms +}; + +builtin_t *pr_builtins = pr_builtin; +int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]); + diff --git a/Quake/pr_comp.h b/Quake/pr_comp.h new file mode 100644 index 00000000..0e4d12fd --- /dev/null +++ b/Quake/pr_comp.h @@ -0,0 +1,181 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// this file is shared by quake and qcc + +typedef int func_t; +typedef int string_t; + +typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t; + + +#define OFS_NULL 0 +#define OFS_RETURN 1 +#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors +#define OFS_PARM1 7 +#define OFS_PARM2 10 +#define OFS_PARM3 13 +#define OFS_PARM4 16 +#define OFS_PARM5 19 +#define OFS_PARM6 22 +#define OFS_PARM7 25 +#define RESERVED_OFS 28 + + +enum { + OP_DONE, + OP_MUL_F, + OP_MUL_V, + OP_MUL_FV, + OP_MUL_VF, + OP_DIV_F, + OP_ADD_F, + OP_ADD_V, + OP_SUB_F, + OP_SUB_V, + + OP_EQ_F, + OP_EQ_V, + OP_EQ_S, + OP_EQ_E, + OP_EQ_FNC, + + OP_NE_F, + OP_NE_V, + OP_NE_S, + OP_NE_E, + OP_NE_FNC, + + OP_LE, + OP_GE, + OP_LT, + OP_GT, + + OP_LOAD_F, + OP_LOAD_V, + OP_LOAD_S, + OP_LOAD_ENT, + OP_LOAD_FLD, + OP_LOAD_FNC, + + OP_ADDRESS, + + OP_STORE_F, + OP_STORE_V, + OP_STORE_S, + OP_STORE_ENT, + OP_STORE_FLD, + OP_STORE_FNC, + + OP_STOREP_F, + OP_STOREP_V, + OP_STOREP_S, + OP_STOREP_ENT, + OP_STOREP_FLD, + OP_STOREP_FNC, + + OP_RETURN, + OP_NOT_F, + OP_NOT_V, + OP_NOT_S, + OP_NOT_ENT, + OP_NOT_FNC, + OP_IF, + OP_IFNOT, + OP_CALL0, + OP_CALL1, + OP_CALL2, + OP_CALL3, + OP_CALL4, + OP_CALL5, + OP_CALL6, + OP_CALL7, + OP_CALL8, + OP_STATE, + OP_GOTO, + OP_AND, + OP_OR, + + OP_BITAND, + OP_BITOR +}; + + +typedef struct statement_s +{ + unsigned short op; + short a,b,c; +} dstatement_t; + +typedef struct +{ + unsigned short type; // if DEF_SAVEGLOBGAL bit is set + // the variable needs to be saved in savegames + unsigned short ofs; + int s_name; +} ddef_t; +#define DEF_SAVEGLOBAL (1<<15) + +#define MAX_PARMS 8 + +typedef struct +{ + int first_statement; // negative numbers are builtins + int parm_start; + int locals; // total ints of parms + locals + + int profile; // runtime + + int s_name; + int s_file; // source file defined in + + int numparms; + byte parm_size[MAX_PARMS]; +} dfunction_t; + + +#define PROG_VERSION 6 +typedef struct +{ + int version; + int crc; // check of header file + + int ofs_statements; + int numstatements; // statement 0 is an error + + int ofs_globaldefs; + int numglobaldefs; + + int ofs_fielddefs; + int numfielddefs; + + int ofs_functions; + int numfunctions; // function 0 is an empty + + int ofs_strings; + int numstrings; // first string is a null string + + int ofs_globals; + int numglobals; + + int entityfields; +} dprograms_t; + diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c new file mode 100644 index 00000000..faf4b922 --- /dev/null +++ b/Quake/pr_edict.c @@ -0,0 +1,1135 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_edict.c -- entity dictionary + +#include "quakedef.h" + +qboolean pr_alpha_supported; //johnfitz + +dprograms_t *progs; +dfunction_t *pr_functions; +char *pr_strings; +ddef_t *pr_fielddefs; +ddef_t *pr_globaldefs; +dstatement_t *pr_statements; +globalvars_t *pr_global_struct; +float *pr_globals; // same as pr_global_struct +int pr_edict_size; // in bytes + +unsigned short pr_crc; + +int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4}; + +ddef_t *ED_FieldAtOfs (int ofs); +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s); + +cvar_t nomonsters = {"nomonsters", "0"}; +cvar_t gamecfg = {"gamecfg", "0"}; +cvar_t scratch1 = {"scratch1", "0"}; +cvar_t scratch2 = {"scratch2", "0"}; +cvar_t scratch3 = {"scratch3", "0"}; +cvar_t scratch4 = {"scratch4", "0"}; +cvar_t savedgamecfg = {"savedgamecfg", "0", true}; +cvar_t saved1 = {"saved1", "0", true}; +cvar_t saved2 = {"saved2", "0", true}; +cvar_t saved3 = {"saved3", "0", true}; +cvar_t saved4 = {"saved4", "0", true}; + +#define MAX_FIELD_LEN 64 +#define GEFV_CACHESIZE 2 + +typedef struct { + ddef_t *pcache; + char field[MAX_FIELD_LEN]; +} gefv_cache; + +static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}}; + +/* +================= +ED_ClearEdict + +Sets everything to NULL +================= +*/ +void ED_ClearEdict (edict_t *e) +{ + memset (&e->v, 0, progs->entityfields * 4); + e->free = false; +} + +/* +================= +ED_Alloc + +Either finds a free edict, or allocates a new one. +Try to avoid reusing an entity that was recently freed, because it +can cause the client to think the entity morphed into something else +instead of being removed and recreated, which can cause interpolated +angles and bad trails. +================= +*/ +edict_t *ED_Alloc (void) +{ + int i; + edict_t *e; + + for ( i=svs.maxclients+1 ; ifree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) ) + { + ED_ClearEdict (e); + return e; + } + } + + if (i == sv.max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS + Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", sv.max_edicts); //johnfitz -- was Sys_Error + + sv.num_edicts++; + e = EDICT_NUM(i); + ED_ClearEdict (e); + + return e; +} + +/* +================= +ED_Free + +Marks the edict as free +FIXME: walk all entities and NULL out references to this entity +================= +*/ +void ED_Free (edict_t *ed) +{ + SV_UnlinkEdict (ed); // unlink from world bsp + + ed->free = true; + ed->v.model = 0; + ed->v.takedamage = 0; + ed->v.modelindex = 0; + ed->v.colormap = 0; + ed->v.skin = 0; + ed->v.frame = 0; + VectorCopy (vec3_origin, ed->v.origin); + VectorCopy (vec3_origin, ed->v.angles); + ed->v.nextthink = -1; + ed->v.solid = 0; + ed->alpha = ENTALPHA_DEFAULT; //johnfitz -- reset alpha for next entity + + ed->freetime = sv.time; +} + +//=========================================================================== + +/* +============ +ED_GlobalAtOfs +============ +*/ +ddef_t *ED_GlobalAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FieldAtOfs +============ +*/ +ddef_t *ED_FieldAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FindField +============ +*/ +ddef_t *ED_FindField (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindGlobal +============ +*/ +ddef_t *ED_FindGlobal (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindFunction +============ +*/ +dfunction_t *ED_FindFunction (char *name) +{ + dfunction_t *func; + int i; + + for (i=0 ; inumfunctions ; i++) + { + func = &pr_functions[i]; + if (!strcmp(pr_strings + func->s_name,name) ) + return func; + } + return NULL; +} + +/* +============ +GetEdictFieldValue +============ +*/ +eval_t *GetEdictFieldValue(edict_t *ed, char *field) +{ + ddef_t *def = NULL; + int i; + static int rep = 0; + + for (i=0 ; iv + def->ofs*4); +} + + +/* +============ +PR_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *PR_ValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) ); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s()", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, ".%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%5.1f", val->_float); + break; + case ev_vector: + sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_UglyValueString + +Returns a string describing *data in a type specific manner +Easier to parse than PR_ValueString +============= +*/ +char *PR_UglyValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, "%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%f", val->_float); + break; + case ev_vector: + sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PR_GlobalString (int ofs) +{ + char *s; + int i; + ddef_t *def; + void *val; + static char line[128]; + + val = (void *)&pr_globals[ofs]; + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + { + s = PR_ValueString (def->type, val); + sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s); + } + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +char *PR_GlobalStringNoContents (int ofs) +{ + int i; + ddef_t *def; + static char line[128]; + + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name); + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + + +/* +============= +ED_Print + +For debugging +============= +*/ +void ED_Print (edict_t *ed) +{ + int l; + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + if (ed->free) + { + Con_Printf ("FREE\n"); + return; + } + + Con_SafePrintf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); //johnfitz -- was Con_Printf + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; jtype, (eval_t *)v)); //johnfitz -- was Con_Printf + } +} + +/* +============= +ED_Write + +For savegames +============= +*/ +void ED_Write (FILE *f, edict_t *ed) +{ + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + fprintf (f, "{\n"); + + if (ed->free) + { + fprintf (f, "}\n"); + return; + } + + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (eval_t *)v)); + } + + //johnfitz -- save entity alpha manually when progs.dat doesn't know about alpha + if (!pr_alpha_supported && ed->alpha != ENTALPHA_DEFAULT) + fprintf (f,"\"alpha\" \"%f\"\n", ENTALPHA_TOSAVE(ed->alpha)); + //johnfitz + + fprintf (f, "}\n"); +} + +void ED_PrintNum (int ent) +{ + ED_Print (EDICT_NUM(ent)); +} + +/* +============= +ED_PrintEdicts + +For debugging, prints all the entities in the current server +============= +*/ +void ED_PrintEdicts (void) +{ + int i; + + Con_Printf ("%i entities\n", sv.num_edicts); + for (i=0 ; i= sv.num_edicts) + { + Con_Printf("Bad edict number\n"); + return; + } + ED_PrintNum (i); +} + +/* +============= +ED_Count + +For debugging +============= +*/ +void ED_Count (void) +{ + int i; + edict_t *ent; + int active, models, solid, step; + + active = models = solid = step = 0; + for (i=0 ; ifree) + continue; + active++; + if (ent->v.solid) + solid++; + if (ent->v.model) + models++; + if (ent->v.movetype == MOVETYPE_STEP) + step++; + } + + Con_Printf ("num_edicts:%3i\n", sv.num_edicts); + Con_Printf ("active :%3i\n", active); + Con_Printf ("view :%3i\n", models); + Con_Printf ("touch :%3i\n", solid); + Con_Printf ("step :%3i\n", step); + +} + +/* +============================================================================== + + ARCHIVING GLOBALS + +FIXME: need to tag constants, doesn't really work +============================================================================== +*/ + +/* +============= +ED_WriteGlobals +============= +*/ +void ED_WriteGlobals (FILE *f) +{ + ddef_t *def; + int i; + char *name; + int type; + + fprintf (f,"{\n"); + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + type = def->type; + if ( !(def->type & DEF_SAVEGLOBAL) ) + continue; + type &= ~DEF_SAVEGLOBAL; + + if (type != ev_string + && type != ev_float + && type != ev_entity) + continue; + + name = pr_strings + def->s_name; + fprintf (f,"\"%s\" ", name); + fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs])); + } + fprintf (f,"}\n"); +} + +/* +============= +ED_ParseGlobals +============= +*/ +void ED_ParseGlobals (char *data) +{ + char keyname[64]; + ddef_t *key; + + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + strcpy (keyname, com_token); + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + key = ED_FindGlobal (keyname); + if (!key) + { + Con_Printf ("'%s' is not a global\n", keyname); + continue; + } + + if (!ED_ParseEpair ((void *)pr_globals, key, com_token)) + Host_Error ("ED_ParseGlobals: parse error"); + } +} + +//============================================================================ + + +/* +============= +ED_NewString +============= +*/ +char *ED_NewString (char *string) +{ + char *new, *new_p; + int i,l; + + l = strlen(string) + 1; + new = Hunk_Alloc (l); + new_p = new; + + for (i=0 ; i< l ; i++) + { + if (string[i] == '\\' && i < l-1) + { + i++; + if (string[i] == 'n') + *new_p++ = '\n'; + else + *new_p++ = '\\'; + } + else + *new_p++ = string[i]; + } + + return new; +} + + +/* +============= +ED_ParseEval + +Can parse either fields or globals +returns false if error +============= +*/ +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s) +{ + int i; + char string[128]; + ddef_t *def; + char *v, *w; + void *d; + dfunction_t *func; + + d = (void *)((int *)base + key->ofs); + + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + *(string_t *)d = ED_NewString (s) - pr_strings; + break; + + case ev_float: + *(float *)d = atof (s); + break; + + case ev_vector: + strcpy (string, s); + v = string; + w = string; + for (i=0 ; i<3 ; i++) + { + while (*v && *v != ' ') + v++; + *v = 0; + ((float *)d)[i] = atof (w); + w = v = v+1; + } + break; + + case ev_entity: + *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s))); + break; + + case ev_field: + def = ED_FindField (s); + if (!def) + { + //johnfitz -- HACK -- suppress error becuase fog/sky fields might not be mentioned in defs.qc + if (strncmp(s, "sky", 3) && strcmp(s, "fog")) + Con_DPrintf ("Can't find field %s\n", s); + return false; + } + *(int *)d = G_INT(def->ofs); + break; + + case ev_function: + func = ED_FindFunction (s); + if (!func) + { + Con_Printf ("Can't find function %s\n", s); + return false; + } + *(func_t *)d = func - pr_functions; + break; + + default: + break; + } + return true; +} + +/* +==================== +ED_ParseEdict + +Parses an edict out of the given string, returning the new position +ed should be a properly initialized empty edict. +Used for initial level load and for savegames. +==================== +*/ +char *ED_ParseEdict (char *data, edict_t *ent) +{ + ddef_t *key; + qboolean anglehack; + qboolean init; + char keyname[256]; + int n; + + init = false; + +// clear it + if (ent != sv.edicts) // hack + memset (&ent->v, 0, progs->entityfields * 4); + +// go through all the dictionary pairs + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + // anglehack is to allow QuakeEd to write single scalar angles + // and allow them to be turned into vectors. (FIXME...) + if (!strcmp(com_token, "angle")) + { + strcpy (com_token, "angles"); + anglehack = true; + } + else + anglehack = false; + + // FIXME: change light to _light to get rid of this hack + if (!strcmp(com_token, "light")) + strcpy (com_token, "light_lev"); // hack for single light def + + strcpy (keyname, com_token); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + init = true; + + // keynames with a leading underscore are used for utility comments, + // and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + //johnfitz -- hack to support .alpha even when progs.dat doesn't know about it + if (!strcmp(keyname, "alpha")) + ent->alpha = ENTALPHA_ENCODE(atof(com_token)); + //johnfitz + + key = ED_FindField (keyname); + if (!key) + { + //johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc + if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha")) + Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf + continue; + } + + if (anglehack) + { + char temp[32]; + strcpy (temp, com_token); + sprintf (com_token, "0 %s 0", temp); + } + + if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) + Host_Error ("ED_ParseEdict: parse error"); + } + + if (!init) + ent->free = true; + + return data; +} + + +/* +================ +ED_LoadFromFile + +The entities are directly placed in the array, rather than allocated with +ED_Alloc, because otherwise an error loading the map would have entity +number references out of order. + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. + +Used for both fresh maps and savegame loads. A fresh map would also need +to call ED_CallSpawnFunctions () to let the objects initialize themselves. +================ +*/ +void ED_LoadFromFile (char *data) +{ + edict_t *ent; + int inhibit; + dfunction_t *func; + + ent = NULL; + inhibit = 0; + pr_global_struct->time = sv.time; + +// parse ents + while (1) + { +// parse the opening brace + data = COM_Parse (data); + if (!data) + break; + if (com_token[0] != '{') + Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); + + if (!ent) + ent = EDICT_NUM(0); + else + ent = ED_Alloc (); + data = ED_ParseEdict (data, ent); + +// remove things from different skill levels or deathmatch + if (deathmatch.value) + { + if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) + { + ED_Free (ent); + inhibit++; + continue; + } + } + else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) + || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) + || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) + { + ED_Free (ent); + inhibit++; + continue; + } + +// +// immediately call spawn function +// + if (!ent->v.classname) + { + Con_SafePrintf ("No classname for:\n"); //johnfitz -- was Con_Printf + ED_Print (ent); + ED_Free (ent); + continue; + } + + // look for the spawn function + func = ED_FindFunction ( pr_strings + ent->v.classname ); + + if (!func) + { + Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf + ED_Print (ent); + ED_Free (ent); + continue; + } + + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (func - pr_functions); + } + + Con_DPrintf ("%i entities inhibited\n", inhibit); +} + + +/* +=============== +PR_LoadProgs +=============== +*/ +void PR_LoadProgs (void) +{ + int i; + +// flush the non-C variable lookup cache + for (i=0 ; iversion != PROG_VERSION) + Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); + if (progs->crc != PROGHEADER_CRC) + Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); + + pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); + pr_strings = (char *)progs + progs->ofs_strings; + pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); + pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); + pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); + + pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); + pr_globals = (float *)pr_global_struct; + + pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); + +// byte swap the lumps + for (i=0 ; inumstatements ; i++) + { + pr_statements[i].op = LittleShort(pr_statements[i].op); + pr_statements[i].a = LittleShort(pr_statements[i].a); + pr_statements[i].b = LittleShort(pr_statements[i].b); + pr_statements[i].c = LittleShort(pr_statements[i].c); + } + + for (i=0 ; inumfunctions; i++) + { + pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); + pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); + pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); + pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); + pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); + pr_functions[i].locals = LittleLong (pr_functions[i].locals); + } + + for (i=0 ; inumglobaldefs ; i++) + { + pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); + pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); + pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); + } + + pr_alpha_supported = false; //johnfitz + + for (i=0 ; inumfielddefs ; i++) + { + pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); + if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) + Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); + pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); + pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); + + //johnfitz -- detect alpha support in progs.dat + if (!strcmp(pr_strings + pr_fielddefs[i].s_name,"alpha")) + pr_alpha_supported = true; + //johnfitz + } + + for (i=0 ; inumglobals ; i++) + ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); +} + + +/* +=============== +PR_Init +=============== +*/ +void PR_Init (void) +{ + Cmd_AddCommand ("edict", ED_PrintEdict_f); + Cmd_AddCommand ("edicts", ED_PrintEdicts); + Cmd_AddCommand ("edictcount", ED_Count); + Cmd_AddCommand ("profile", PR_Profile_f); + Cvar_RegisterVariable (&nomonsters, NULL); + Cvar_RegisterVariable (&gamecfg, NULL); + Cvar_RegisterVariable (&scratch1, NULL); + Cvar_RegisterVariable (&scratch2, NULL); + Cvar_RegisterVariable (&scratch3, NULL); + Cvar_RegisterVariable (&scratch4, NULL); + Cvar_RegisterVariable (&savedgamecfg, NULL); + Cvar_RegisterVariable (&saved1, NULL); + Cvar_RegisterVariable (&saved2, NULL); + Cvar_RegisterVariable (&saved3, NULL); + Cvar_RegisterVariable (&saved4, NULL); +} + + + +edict_t *EDICT_NUM(int n) +{ + if (n < 0 || n >= sv.max_edicts) + Sys_Error ("EDICT_NUM: bad number %i", n); + return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size); +} + +int NUM_FOR_EDICT(edict_t *e) +{ + int b; + + b = (byte *)e - (byte *)sv.edicts; + b = b / pr_edict_size; + + if (b < 0 || b >= sv.num_edicts) + Sys_Error ("NUM_FOR_EDICT: bad pointer"); + return b; +} diff --git a/Quake/pr_exec.c b/Quake/pr_exec.c new file mode 100644 index 00000000..fe6133e7 --- /dev/null +++ b/Quake/pr_exec.c @@ -0,0 +1,665 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + + +/* + +*/ + +typedef struct +{ + int s; + dfunction_t *f; +} prstack_t; + +#define MAX_STACK_DEPTH 32 +prstack_t pr_stack[MAX_STACK_DEPTH]; +int pr_depth; + +#define LOCALSTACK_SIZE 2048 +int localstack[LOCALSTACK_SIZE]; +int localstack_used; + + +qboolean pr_trace; +dfunction_t *pr_xfunction; +int pr_xstatement; + + +int pr_argc; + +char *pr_opnames[] = +{ +"DONE", + +"MUL_F", +"MUL_V", +"MUL_FV", +"MUL_VF", + +"DIV", + +"ADD_F", +"ADD_V", + +"SUB_F", +"SUB_V", + +"EQ_F", +"EQ_V", +"EQ_S", +"EQ_E", +"EQ_FNC", + +"NE_F", +"NE_V", +"NE_S", +"NE_E", +"NE_FNC", + +"LE", +"GE", +"LT", +"GT", + +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", + +"ADDRESS", + +"STORE_F", +"STORE_V", +"STORE_S", +"STORE_ENT", +"STORE_FLD", +"STORE_FNC", + +"STOREP_F", +"STOREP_V", +"STOREP_S", +"STOREP_ENT", +"STOREP_FLD", +"STOREP_FNC", + +"RETURN", + +"NOT_F", +"NOT_V", +"NOT_S", +"NOT_ENT", +"NOT_FNC", + +"IF", +"IFNOT", + +"CALL0", +"CALL1", +"CALL2", +"CALL3", +"CALL4", +"CALL5", +"CALL6", +"CALL7", +"CALL8", + +"STATE", + +"GOTO", + +"AND", +"OR", + +"BITAND", +"BITOR" +}; + +char *PR_GlobalString (int ofs); +char *PR_GlobalStringNoContents (int ofs); + + +//============================================================================= + +/* +================= +PR_PrintStatement +================= +*/ +void PR_PrintStatement (dstatement_t *s) +{ + int i; + + if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0])) + { + Con_Printf ("%s ", pr_opnames[s->op]); + i = strlen(pr_opnames[s->op]); + for ( ; i<10 ; i++) + Con_Printf (" "); + } + + if (s->op == OP_IF || s->op == OP_IFNOT) + Con_Printf ("%sbranch %i",PR_GlobalString(s->a),s->b); + else if (s->op == OP_GOTO) + { + Con_Printf ("branch %i",s->a); + } + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + Con_Printf ("%s",PR_GlobalString(s->a)); + Con_Printf ("%s", PR_GlobalStringNoContents(s->b)); + } + else + { + if (s->a) + Con_Printf ("%s",PR_GlobalString(s->a)); + if (s->b) + Con_Printf ("%s",PR_GlobalString(s->b)); + if (s->c) + Con_Printf ("%s", PR_GlobalStringNoContents(s->c)); + } + Con_Printf ("\n"); +} + +/* +============ +PR_StackTrace +============ +*/ +void PR_StackTrace (void) +{ + dfunction_t *f; + int i; + + if (pr_depth == 0) + { + Con_Printf ("\n"); + return; + } + + pr_stack[pr_depth].f = pr_xfunction; + for (i=pr_depth ; i>=0 ; i--) + { + f = pr_stack[i].f; + + if (!f) + { + Con_Printf ("\n"); + } + else + Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name); + } +} + + +/* +============ +PR_Profile_f + +============ +*/ +void PR_Profile_f (void) +{ + dfunction_t *f, *best; + int max; + int num; + int i; + + num = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; inumfunctions ; i++) + { + f = &pr_functions[i]; + if (f->profile > max) + { + max = f->profile; + best = f; + } + } + if (best) + { + if (num < 10) + Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name); + num++; + best->profile = 0; + } + } while (best); +} + + +/* +============ +PR_RunError + +Aborts the currently executing function +============ +*/ +void PR_RunError (char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + + PR_PrintStatement (pr_statements + pr_xstatement); + PR_StackTrace (); + Con_Printf ("%s\n", string); + + pr_depth = 0; // dump the stack so host_error can shutdown functions + + Host_Error ("Program error"); +} + +/* +============================================================================ +PR_ExecuteProgram + +The interpretation main loop +============================================================================ +*/ + +/* +==================== +PR_EnterFunction + +Returns the new program statement counter +==================== +*/ +int PR_EnterFunction (dfunction_t *f) +{ + int i, j, c, o; + + pr_stack[pr_depth].s = pr_xstatement; + pr_stack[pr_depth].f = pr_xfunction; + pr_depth++; + if (pr_depth >= MAX_STACK_DEPTH) + PR_RunError ("stack overflow"); + +// save off any locals that the new function steps on + c = f->locals; + if (localstack_used + c > LOCALSTACK_SIZE) + PR_RunError ("PR_ExecuteProgram: locals stack overflow\n"); + + for (i=0 ; i < c ; i++) + localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i]; + localstack_used += c; + +// copy parameters + o = f->parm_start; + for (i=0 ; inumparms ; i++) + { + for (j=0 ; jparm_size[i] ; j++) + { + ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j]; + o++; + } + } + + pr_xfunction = f; + return f->first_statement - 1; // offset the s++ +} + +/* +==================== +PR_LeaveFunction +==================== +*/ +int PR_LeaveFunction (void) +{ + int i, c; + + if (pr_depth <= 0) + Sys_Error ("prog stack underflow"); + +// restore locals from the stack + c = pr_xfunction->locals; + localstack_used -= c; + if (localstack_used < 0) + PR_RunError ("PR_ExecuteProgram: locals stack underflow\n"); + + for (i=0 ; i < c ; i++) + ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i]; + +// up stack + pr_depth--; + pr_xfunction = pr_stack[pr_depth].f; + return pr_stack[pr_depth].s; +} + + +/* +==================== +PR_ExecuteProgram +==================== +*/ +void PR_ExecuteProgram (func_t fnum) +{ + eval_t *a, *b, *c; + int s; + dstatement_t *st; + dfunction_t *f, *newf; + int runaway; + int i; + edict_t *ed; + int exitdepth; + eval_t *ptr; + + if (!fnum || fnum >= progs->numfunctions) + { + if (pr_global_struct->self) + ED_Print (PROG_TO_EDICT(pr_global_struct->self)); + Host_Error ("PR_ExecuteProgram: NULL function"); + } + + f = &pr_functions[fnum]; + + runaway = 100000; + pr_trace = false; + +// make a stack frame + exitdepth = pr_depth; + + s = PR_EnterFunction (f); + +while (1) +{ + s++; // next statement + + st = &pr_statements[s]; + a = (eval_t *)&pr_globals[st->a]; + b = (eval_t *)&pr_globals[st->b]; + c = (eval_t *)&pr_globals[st->c]; + + if (!--runaway) + PR_RunError ("runaway loop error"); + + pr_xfunction->profile++; + pr_xstatement = s; + + if (pr_trace) + PR_PrintStatement (st); + + switch (st->op) + { + case OP_ADD_F: + c->_float = a->_float + b->_float; + break; + case OP_ADD_V: + c->vector[0] = a->vector[0] + b->vector[0]; + c->vector[1] = a->vector[1] + b->vector[1]; + c->vector[2] = a->vector[2] + b->vector[2]; + break; + + case OP_SUB_F: + c->_float = a->_float - b->_float; + break; + case OP_SUB_V: + c->vector[0] = a->vector[0] - b->vector[0]; + c->vector[1] = a->vector[1] - b->vector[1]; + c->vector[2] = a->vector[2] - b->vector[2]; + break; + + case OP_MUL_F: + c->_float = a->_float * b->_float; + break; + case OP_MUL_V: + c->_float = a->vector[0]*b->vector[0] + + a->vector[1]*b->vector[1] + + a->vector[2]*b->vector[2]; + break; + case OP_MUL_FV: + c->vector[0] = a->_float * b->vector[0]; + c->vector[1] = a->_float * b->vector[1]; + c->vector[2] = a->_float * b->vector[2]; + break; + case OP_MUL_VF: + c->vector[0] = b->_float * a->vector[0]; + c->vector[1] = b->_float * a->vector[1]; + c->vector[2] = b->_float * a->vector[2]; + break; + + case OP_DIV_F: + c->_float = a->_float / b->_float; + break; + + case OP_BITAND: + c->_float = (int)a->_float & (int)b->_float; + break; + + case OP_BITOR: + c->_float = (int)a->_float | (int)b->_float; + break; + + + case OP_GE: + c->_float = a->_float >= b->_float; + break; + case OP_LE: + c->_float = a->_float <= b->_float; + break; + case OP_GT: + c->_float = a->_float > b->_float; + break; + case OP_LT: + c->_float = a->_float < b->_float; + break; + case OP_AND: + c->_float = a->_float && b->_float; + break; + case OP_OR: + c->_float = a->_float || b->_float; + break; + + case OP_NOT_F: + c->_float = !a->_float; + break; + case OP_NOT_V: + c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; + break; + case OP_NOT_S: + c->_float = !a->string || !pr_strings[a->string]; + break; + case OP_NOT_FNC: + c->_float = !a->function; + break; + case OP_NOT_ENT: + c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); + break; + + case OP_EQ_F: + c->_float = a->_float == b->_float; + break; + case OP_EQ_V: + c->_float = (a->vector[0] == b->vector[0]) && + (a->vector[1] == b->vector[1]) && + (a->vector[2] == b->vector[2]); + break; + case OP_EQ_S: + c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_EQ_E: + c->_float = a->_int == b->_int; + break; + case OP_EQ_FNC: + c->_float = a->function == b->function; + break; + + + case OP_NE_F: + c->_float = a->_float != b->_float; + break; + case OP_NE_V: + c->_float = (a->vector[0] != b->vector[0]) || + (a->vector[1] != b->vector[1]) || + (a->vector[2] != b->vector[2]); + break; + case OP_NE_S: + c->_float = strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_NE_E: + c->_float = a->_int != b->_int; + break; + case OP_NE_FNC: + c->_float = a->function != b->function; + break; + +//================== + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: // integers + case OP_STORE_S: + case OP_STORE_FNC: // pointers + b->_int = a->_int; + break; + case OP_STORE_V: + b->vector[0] = a->vector[0]; + b->vector[1] = a->vector[1]; + b->vector[2] = a->vector[2]; + break; + + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: // integers + case OP_STOREP_S: + case OP_STOREP_FNC: // pointers + ptr = (eval_t *)((byte *)sv.edicts + b->_int); + ptr->_int = a->_int; + break; + case OP_STOREP_V: + ptr = (eval_t *)((byte *)sv.edicts + b->_int); + ptr->vector[0] = a->vector[0]; + ptr->vector[1] = a->vector[1]; + ptr->vector[2] = a->vector[2]; + break; + + case OP_ADDRESS: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + if (ed == (edict_t *)sv.edicts && sv.state == ss_active) + PR_RunError ("assignment to world entity"); + c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; + break; + + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->_int = a->_int; + break; + + case OP_LOAD_V: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->vector[0] = a->vector[0]; + c->vector[1] = a->vector[1]; + c->vector[2] = a->vector[2]; + break; + +//================== + + case OP_IFNOT: + if (!a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_IF: + if (a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_GOTO: + s += st->a - 1; // offset the s++ + break; + + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + pr_argc = st->op - OP_CALL0; + if (!a->function) + PR_RunError ("NULL function"); + + newf = &pr_functions[a->function]; + + if (newf->first_statement < 0) + { // negative statements are built in functions + i = -newf->first_statement; + if (i >= pr_numbuiltins) + PR_RunError ("Bad builtin call number"); + pr_builtins[i] (); + break; + } + + s = PR_EnterFunction (newf); + break; + + case OP_DONE: + case OP_RETURN: + pr_globals[OFS_RETURN] = pr_globals[st->a]; + pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; + pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; + + s = PR_LeaveFunction (); + if (pr_depth == exitdepth) + return; // all done + break; + + case OP_STATE: + ed = PROG_TO_EDICT(pr_global_struct->self); + ed->v.nextthink = pr_global_struct->time + 0.1; + if (a->_float != ed->v.frame) + { + ed->v.frame = a->_float; + } + ed->v.think = b->function; + break; + + default: + PR_RunError ("Bad opcode %i", st->op); + } +} + +} diff --git a/Quake/progdefs.h b/Quake/progdefs.h new file mode 100644 index 00000000..790152be --- /dev/null +++ b/Quake/progdefs.h @@ -0,0 +1,21 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "progdefs.q1" diff --git a/Quake/progdefs.q1 b/Quake/progdefs.q1 new file mode 100644 index 00000000..eb15c45c --- /dev/null +++ b/Quake/progdefs.q1 @@ -0,0 +1,143 @@ + +/* file generated by qcc, do not modify */ + +typedef struct +{ int pad[28]; + int self; + int other; + int world; + float time; + float frametime; + float force_retouch; + string_t mapname; + float deathmatch; + float coop; + float teamplay; + float serverflags; + float total_secrets; + float total_monsters; + float found_secrets; + float killed_monsters; + float parm1; + float parm2; + float parm3; + float parm4; + float parm5; + float parm6; + float parm7; + float parm8; + float parm9; + float parm10; + float parm11; + float parm12; + float parm13; + float parm14; + float parm15; + float parm16; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + int trace_ent; + float trace_inopen; + float trace_inwater; + int msg_entity; + func_t main; + func_t StartFrame; + func_t PlayerPreThink; + func_t PlayerPostThink; + func_t ClientKill; + func_t ClientConnect; + func_t PutClientInServer; + func_t ClientDisconnect; + func_t SetNewParms; + func_t SetChangeParms; +} globalvars_t; + +typedef struct +{ + float modelindex; + vec3_t absmin; + vec3_t absmax; + float ltime; + float movetype; + float solid; + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t angles; + vec3_t avelocity; + vec3_t punchangle; + string_t classname; + string_t model; + float frame; + float skin; + float effects; + vec3_t mins; + vec3_t maxs; + vec3_t size; + func_t touch; + func_t use; + func_t think; + func_t blocked; + float nextthink; + int groundentity; + float health; + float frags; + float weapon; + string_t weaponmodel; + float weaponframe; + float currentammo; + float ammo_shells; + float ammo_nails; + float ammo_rockets; + float ammo_cells; + float items; + float takedamage; + int chain; + float deadflag; + vec3_t view_ofs; + float button0; + float button1; + float button2; + float impulse; + float fixangle; + vec3_t v_angle; + float idealpitch; + string_t netname; + int enemy; + float flags; + float colormap; + float team; + float max_health; + float teleport_time; + float armortype; + float armorvalue; + float waterlevel; + float watertype; + float ideal_yaw; + float yaw_speed; + int aiment; + int goalentity; + float spawnflags; + string_t target; + string_t targetname; + float dmg_take; + float dmg_save; + int dmg_inflictor; + int owner; + vec3_t movedir; + string_t message; + float sounds; + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; +} entvars_t; + +#define PROGHEADER_CRC 5927 diff --git a/Quake/progs.h b/Quake/progs.h new file mode 100644 index 00000000..c3b6abc3 --- /dev/null +++ b/Quake/progs.h @@ -0,0 +1,134 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "pr_comp.h" // defs shared with qcc +#include "progdefs.h" // generated by program cdefs + +typedef union eval_s +{ + string_t string; + float _float; + float vector[3]; + func_t function; + int _int; + int edict; +} eval_t; + +#define MAX_ENT_LEAFS 16 +typedef struct edict_s +{ + qboolean free; + link_t area; // linked to a division node or leaf + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + entity_state_t baseline; + unsigned char alpha; // johnfitz -- hack to support alpha since it's not part of entvars_t + qboolean sendinterval; // johnfitz -- send time until nextthink to client for better lerp timing + float freetime; // sv.time when the object was freed + entvars_t v; // C exported fields from progs +// other fields from progs come immediately after +} edict_t; +#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) + +//============================================================================ + +extern dprograms_t *progs; +extern dfunction_t *pr_functions; +extern char *pr_strings; +extern ddef_t *pr_globaldefs; +extern ddef_t *pr_fielddefs; +extern dstatement_t *pr_statements; +extern globalvars_t *pr_global_struct; +extern float *pr_globals; // same as pr_global_struct + +extern int pr_edict_size; // in bytes + +//============================================================================ + +void PR_Init (void); + +void PR_ExecuteProgram (func_t fnum); +void PR_LoadProgs (void); + +void PR_Profile_f (void); + +edict_t *ED_Alloc (void); +void ED_Free (edict_t *ed); + +char *ED_NewString (char *string); +// returns a copy of the string allocated from the server's string heap + +void ED_Print (edict_t *ed); +void ED_Write (FILE *f, edict_t *ed); +char *ED_ParseEdict (char *data, edict_t *ent); + +void ED_WriteGlobals (FILE *f); +void ED_ParseGlobals (char *data); + +void ED_LoadFromFile (char *data); + +//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size)) +//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size) + +edict_t *EDICT_NUM(int n); +int NUM_FOR_EDICT(edict_t *e); + +#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size)) + +#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts) +#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) + +//============================================================================ + +#define G_FLOAT(o) (pr_globals[o]) +#define G_INT(o) (*(int *)&pr_globals[o]) +#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o])) +#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o)) +#define G_VECTOR(o) (&pr_globals[o]) +#define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o]) +#define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) + +#define E_FLOAT(e,o) (((float*)&e->v)[o]) +#define E_INT(e,o) (*(int *)&((float*)&e->v)[o]) +#define E_VECTOR(e,o) (&((float*)&e->v)[o]) +#define E_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o]) + +extern int type_size[8]; + +typedef void (*builtin_t) (void); +extern builtin_t *pr_builtins; +extern int pr_numbuiltins; + +extern int pr_argc; + +extern qboolean pr_trace; +extern dfunction_t *pr_xfunction; +extern int pr_xstatement; + +extern unsigned short pr_crc; + +void PR_RunError (char *error, ...); + +void ED_PrintEdicts (void); +void ED_PrintNum (int ent); + +eval_t *GetEdictFieldValue(edict_t *ed, char *field); + diff --git a/Quake/protocol.h b/Quake/protocol.h new file mode 100644 index 00000000..3e0848b9 --- /dev/null +++ b/Quake/protocol.h @@ -0,0 +1,213 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// protocol.h -- communications protocols + +#define PROTOCOL_NETQUAKE 15 //johnfitz -- standard quake protocol +#define PROTOCOL_FITZQUAKE 666 //johnfitz -- added new protocol for fitzquake 0.85 + +// if the high bit of the servercmd is set, the low bits are fast update flags: +#define U_MOREBITS (1<<0) +#define U_ORIGIN1 (1<<1) +#define U_ORIGIN2 (1<<2) +#define U_ORIGIN3 (1<<3) +#define U_ANGLE2 (1<<4) +#define U_STEP (1<<5) //johnfitz -- was U_NOLERP, renamed since it's only used for MOVETYPE_STEP +#define U_FRAME (1<<6) +#define U_SIGNAL (1<<7) // just differentiates from other updates + +// svc_update can pass all of the fast update bits, plus more +#define U_ANGLE1 (1<<8) +#define U_ANGLE3 (1<<9) +#define U_MODEL (1<<10) +#define U_COLORMAP (1<<11) +#define U_SKIN (1<<12) +#define U_EFFECTS (1<<13) +#define U_LONGENTITY (1<<14) +//johnfitz -- PROTOCOL_FITZQUAKE -- new bits +#define U_EXTEND1 (1<<15) +#define U_ALPHA (1<<16) // 1 byte, uses ENTALPHA_ENCODE, not sent if equal to baseline +#define U_FRAME2 (1<<17) // 1 byte, this is .frame & 0xFF00 (second byte) +#define U_MODEL2 (1<<18) // 1 byte, this is .modelindex & 0xFF00 (second byte) +#define U_LERPFINISH (1<<19) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 0.1, this is ent->v.nextthink - sv.time, used for lerping +#define U_UNUSED20 (1<<20) +#define U_UNUSED21 (1<<21) +#define U_UNUSED22 (1<<22) +#define U_EXTEND2 (1<<23) // another byte to follow, future expansion +//johnfitz + +//johnfitz -- PROTOCOL_NEHAHRA transparency +#define U_TRANS (1<<15) +//johnfitz + +#define SU_VIEWHEIGHT (1<<0) +#define SU_IDEALPITCH (1<<1) +#define SU_PUNCH1 (1<<2) +#define SU_PUNCH2 (1<<3) +#define SU_PUNCH3 (1<<4) +#define SU_VELOCITY1 (1<<5) +#define SU_VELOCITY2 (1<<6) +#define SU_VELOCITY3 (1<<7) +#define SU_UNUSED8 (1<<8) //AVAILABLE BIT +#define SU_ITEMS (1<<9) +#define SU_ONGROUND (1<<10) // no data follows, the bit is it +#define SU_INWATER (1<<11) // no data follows, the bit is it +#define SU_WEAPONFRAME (1<<12) +#define SU_ARMOR (1<<13) +#define SU_WEAPON (1<<14) +//johnfitz -- PROTOCOL_FITZQUAKE -- new bits +#define SU_EXTEND1 (1<<15) // another byte to follow +#define SU_WEAPON2 (1<<16) // 1 byte, this is .weaponmodel & 0xFF00 (second byte) +#define SU_ARMOR2 (1<<17) // 1 byte, this is .armorvalue & 0xFF00 (second byte) +#define SU_AMMO2 (1<<18) // 1 byte, this is .currentammo & 0xFF00 (second byte) +#define SU_SHELLS2 (1<<19) // 1 byte, this is .ammo_shells & 0xFF00 (second byte) +#define SU_NAILS2 (1<<20) // 1 byte, this is .ammo_nails & 0xFF00 (second byte) +#define SU_ROCKETS2 (1<<21) // 1 byte, this is .ammo_rockets & 0xFF00 (second byte) +#define SU_CELLS2 (1<<22) // 1 byte, this is .ammo_cells & 0xFF00 (second byte) +#define SU_EXTEND2 (1<<23) // another byte to follow +#define SU_WEAPONFRAME2 (1<<24) // 1 byte, this is .weaponframe & 0xFF00 (second byte) +#define SU_WEAPONALPHA (1<<25) // 1 byte, this is alpha for weaponmodel, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT +#define SU_UNUSED26 (1<<26) +#define SU_UNUSED27 (1<<27) +#define SU_UNUSED28 (1<<28) +#define SU_UNUSED29 (1<<29) +#define SU_UNUSED30 (1<<30) +#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion +//johnfitz + +// a sound with no channel is a local only sound +#define SND_VOLUME (1<<0) // a byte +#define SND_ATTENUATION (1<<1) // a byte +#define SND_LOOPING (1<<2) // a long +//johnfitz -- PROTOCOL_FITZQUAKE -- new bits +#define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short) +#define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte) +//johnfitz + +//johnfitz -- PROTOCOL_FITZQUAKE -- flags for entity baseline messages +#define B_LARGEMODEL (1<<0) // modelindex is short instead of byte +#define B_LARGEFRAME (1<<1) // frame is short instead of byte +#define B_ALPHA (1<<2) // 1 byte, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT +//johnfitz + +//johnfitz -- PROTOCOL_FITZQUAKE -- alpha encoding +#define ENTALPHA_DEFAULT 0 //entity's alpha is "default" (i.e. water obeys r_wateralpha) -- must be zero so zeroed out memory works +#define ENTALPHA_ZERO 1 //entity is invisible (lowest possible alpha) +#define ENTALPHA_ONE 255 //entity is fully opaque (highest possible alpha) +#define ENTALPHA_ENCODE(a) (((a)==0)?ENTALPHA_DEFAULT:Q_rint(CLAMP(1,(a)*254.0f+1,255))) //server convert to byte to send to client +#define ENTALPHA_DECODE(a) (((a)==ENTALPHA_DEFAULT)?1.0f:((float)(a)-1)/(254)) //client convert to float for rendering +#define ENTALPHA_TOSAVE(a) (((a)==ENTALPHA_DEFAULT)?0.0f:(((a)==ENTALPHA_ZERO)?-1.0f:((float)(a)-1)/(254))) //server convert to float for savegame +//johnfitz + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 22 + +// game types sent by serverinfo +// these determine which intermission screen plays +#define GAME_COOP 0 +#define GAME_DEATHMATCH 1 + +//================== +// note that there are some defs.qc that mirror to these numbers +// also related to svc_strings[] in cl_parse +//================== + +// +// server to client +// +#define svc_bad 0 +#define svc_nop 1 +#define svc_disconnect 2 +#define svc_updatestat 3 // [byte] [long] +#define svc_version 4 // [long] server version +#define svc_setview 5 // [short] entity number +#define svc_sound 6 // +#define svc_time 7 // [float] server time +#define svc_print 8 // [string] null terminated string +#define svc_stufftext 9 // [string] stuffed into client's console buffer + // the string should be \n terminated +#define svc_setangle 10 // [angle3] set the view angle to this absolute value +#define svc_serverinfo 11 // [long] version + // [string] signon string + // [string]..[0]model cache + // [string]...[0]sounds cache +#define svc_lightstyle 12 // [byte] [string] +#define svc_updatename 13 // [byte] [string] +#define svc_updatefrags 14 // [byte] [short] +#define svc_clientdata 15 // +#define svc_stopsound 16 // +#define svc_updatecolors 17 // [byte] [byte] +#define svc_particle 18 // [vec3] +#define svc_damage 19 +#define svc_spawnstatic 20 +//#define svc_spawnbinary 21 +#define svc_spawnbaseline 22 +#define svc_temp_entity 23 +#define svc_setpause 24 // [byte] on / off +#define svc_signonnum 25 // [byte] used for the signon sequence +#define svc_centerprint 26 // [string] to put in center of the screen +#define svc_killedmonster 27 +#define svc_foundsecret 28 +#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten +#define svc_intermission 30 // [string] music +#define svc_finale 31 // [string] music [string] text +#define svc_cdtrack 32 // [byte] track [byte] looptrack +#define svc_sellscreen 33 +#define svc_cutscene 34 + +//johnfitz -- PROTOCOL_FITZQUAKE -- new server messages +#define svc_skybox 37 // [string] name +#define svc_bf 40 +#define svc_fog 41 // [byte] density [byte] red [byte] green [byte] blue [float] time +#define svc_spawnbaseline2 42 // support for large modelindex, large framenum, alpha, using flags +#define svc_spawnstatic2 43 // support for large modelindex, large framenum, alpha, using flags +#define svc_spawnstaticsound2 44 // [coord3] [short] samp [byte] vol [byte] aten +//johnfitz + +// +// client to server +// +#define clc_bad 0 +#define clc_nop 1 +#define clc_disconnect 2 +#define clc_move 3 // [usercmd_t] +#define clc_stringcmd 4 // [string] message + +// +// temp entity events +// +#define TE_SPIKE 0 +#define TE_SUPERSPIKE 1 +#define TE_GUNSHOT 2 +#define TE_EXPLOSION 3 +#define TE_TAREXPLOSION 4 +#define TE_LIGHTNING1 5 +#define TE_LIGHTNING2 6 +#define TE_WIZSPIKE 7 +#define TE_KNIGHTSPIKE 8 +#define TE_LIGHTNING3 9 +#define TE_LAVASPLASH 10 +#define TE_TELEPORT 11 +#define TE_EXPLOSION2 12 + +// PGM 01/21/97 +#define TE_BEAM 13 +// PGM 01/21/97 + diff --git a/Quake/quakedef.h b/Quake/quakedef.h new file mode 100644 index 00000000..8384bcf3 --- /dev/null +++ b/Quake/quakedef.h @@ -0,0 +1,330 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// quakedef.h -- primary header for client + +//#define GLTEST // experimental stuff + +#define QUAKE_GAME // as opposed to utilities + +#define VERSION 1.09 +#define GLQUAKE_VERSION 1.00 +#define D3DQUAKE_VERSION 0.01 +#define WINQUAKE_VERSION 0.996 +#define LINUX_VERSION 1.30 +#define X11_VERSION 1.10 + +#define FITZQUAKE_VERSION 0.85 //johnfitz + +//define PARANOID // speed sapping error checking + +#define GAMENAME "id1" // directory to look in by default + +#include +#include +#include +#include +#include +#include +#include //johnfitz + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#endif + +#if defined __i386__ // && !defined __sun__ +#define id386 1 +#else +#define id386 0 +#endif + +#if id386 +#define UNALIGNED_OK 1 // set to 0 if unaligned accesses are not supported +#else +#define UNALIGNED_OK 0 +#endif + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define CACHE_SIZE 32 // used to align key data structures + +#define UNUSED(x) (x = x) // for pesky compiler / lint warnings + +#define MINIMUM_MEMORY 0x550000 +#define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000) + +#define MAX_NUM_ARGVS 50 + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + + +#define MAX_QPATH 64 // max length of a quake game pathname +#define MAX_OSPATH 128 // max length of a filesystem pathname + +#define ON_EPSILON 0.1 // point on plane side epsilon + +#define MAX_MSGLEN 32000 // max length of a reliable message //johnfitz -- was 8000 +#define MAX_DATAGRAM 32000 // max length of unreliable message //johnfitz -- was 1024 + +#define DATAGRAM_MTU 1400 // johnfitz -- actual limit for unreliable messages to nonlocal clients + +// +// per-level limits +// + +#define MIN_EDICTS 256 // johnfitz -- lowest allowed value for max_edicts cvar +#define MAX_EDICTS 32000 // johnfitz -- highest allowed value for max_edicts cvar + // ents past 8192 can't play sounds in the standard protocol +#define MAX_LIGHTSTYLES 64 +#define MAX_MODELS 2048 // johnfitz -- was 256 +#define MAX_SOUNDS 2048 // johnfitz -- was 256 + +#define SAVEGAME_COMMENT_LENGTH 39 + +#define MAX_STYLESTRING 64 + +// +// stats are integers communicated to the client by the server +// +#define MAX_CL_STATS 32 +#define STAT_HEALTH 0 +#define STAT_FRAGS 1 +#define STAT_WEAPON 2 +#define STAT_AMMO 3 +#define STAT_ARMOR 4 +#define STAT_WEAPONFRAME 5 +#define STAT_SHELLS 6 +#define STAT_NAILS 7 +#define STAT_ROCKETS 8 +#define STAT_CELLS 9 +#define STAT_ACTIVEWEAPON 10 +#define STAT_TOTALSECRETS 11 +#define STAT_TOTALMONSTERS 12 +#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret +#define STAT_MONSTERS 14 // bumped by svc_killedmonster + +// stock defines + +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_SUPER_LIGHTNING 128 +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 +#define IT_AXE 4096 +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 +#define IT_KEY1 131072 +#define IT_KEY2 262144 +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_SIGIL1 (1<<28) +#define IT_SIGIL2 (1<<29) +#define IT_SIGIL3 (1<<30) +#define IT_SIGIL4 (1<<31) + +//=========================================== +//rogue changed and added defines + +#define RIT_SHELLS 128 +#define RIT_NAILS 256 +#define RIT_ROCKETS 512 +#define RIT_CELLS 1024 +#define RIT_AXE 2048 +#define RIT_LAVA_NAILGUN 4096 +#define RIT_LAVA_SUPER_NAILGUN 8192 +#define RIT_MULTI_GRENADE 16384 +#define RIT_MULTI_ROCKET 32768 +#define RIT_PLASMA_GUN 65536 +#define RIT_ARMOR1 8388608 +#define RIT_ARMOR2 16777216 +#define RIT_ARMOR3 33554432 +#define RIT_LAVA_NAILS 67108864 +#define RIT_PLASMA_AMMO 134217728 +#define RIT_MULTI_ROCKETS 268435456 +#define RIT_SHIELD 536870912 +#define RIT_ANTIGRAV 1073741824 +#define RIT_SUPERHEALTH 2147483648 + +//MED 01/04/97 added hipnotic defines +//=========================================== +//hipnotic added defines +#define HIT_PROXIMITY_GUN_BIT 16 +#define HIT_MJOLNIR_BIT 7 +#define HIT_LASER_CANNON_BIT 23 +#define HIT_PROXIMITY_GUN (1<posedata); + verts2 = verts1; + verts1 += lerpdata.pose1 * paliashdr->poseverts; + verts2 += lerpdata.pose2 * paliashdr->poseverts; + blend = lerpdata.blend; + iblend = 1.0f - blend; + } + else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled + { + lerping = false; + verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); + verts1 += lerpdata.pose1 * paliashdr->poseverts; + } + + commands = (int *)((byte *)paliashdr + paliashdr->commands); + + vertcolor[3] = entalpha; //never changes, so there's no need to put this inside the loop + + while (1) + { + // get the vertex count and primitive type + count = *commands++; + if (!count) + break; // done + + if (count < 0) + { + count = -count; + glBegin (GL_TRIANGLE_FAN); + } + else + glBegin (GL_TRIANGLE_STRIP); + + do + { + u = ((float *)commands)[0]; + v = ((float *)commands)[1]; + if (mtexenabled) + { + GL_MTexCoord2fFunc (TEXTURE0, u, v); + GL_MTexCoord2fFunc (TEXTURE1, u, v); + } + else + glTexCoord2f (u, v); + + commands += 2; + + if (shading) + { + if (r_drawflat_cheatsafe) + { + srand(count * (unsigned int) commands); + glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); + } + else if (lerping) + { + vertcolor[0] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[0]; + vertcolor[1] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[1]; + vertcolor[2] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[2]; + glColor4fv (vertcolor); + } + else + { + vertcolor[0] = shadedots[verts1->lightnormalindex] * lightcolor[0]; + vertcolor[1] = shadedots[verts1->lightnormalindex] * lightcolor[1]; + vertcolor[2] = shadedots[verts1->lightnormalindex] * lightcolor[2]; + glColor4fv (vertcolor); + } + } + + if (lerping) + { + glVertex3f (verts1->v[0]*iblend + verts2->v[0]*blend, + verts1->v[1]*iblend + verts2->v[1]*blend, + verts1->v[2]*iblend + verts2->v[2]*blend); + verts1++; + verts2++; + } + else + { + glVertex3f (verts1->v[0], verts1->v[1], verts1->v[2]); + verts1++; + } + } while (--count); + + glEnd (); + } + + rs_aliaspasses += paliashdr->numtris; +} + +/* +================= +R_SetupAliasFrame -- johnfitz -- rewritten to support lerping +================= +*/ +void R_SetupAliasFrame (aliashdr_t *paliashdr, int frame, lerpdata_t *lerpdata) +{ + entity_t *e = currententity; + int posenum, numposes; + + if ((frame >= paliashdr->numframes) || (frame < 0)) + { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + + posenum = paliashdr->frames[frame].firstpose; + numposes = paliashdr->frames[frame].numposes; + + if (numposes > 1) + { + e->lerptime = paliashdr->frames[frame].interval; + posenum += (int)(cl.time / e->lerptime) % numposes; + } + else + e->lerptime = 0.1; + + if (e->lerpflags & LERP_RESETANIM) //kill any lerp in progress + { + e->lerpstart = 0; + e->previouspose = posenum; + e->currentpose = posenum; + e->lerpflags -= LERP_RESETANIM; + } + else if (e->currentpose != posenum) // pose changed, start new lerp + { + if (e->lerpflags & LERP_RESETANIM2) //defer lerping one more time + { + e->lerpstart = 0; + e->previouspose = posenum; + e->currentpose = posenum; + e->lerpflags -= LERP_RESETANIM2; + } + else + { + e->lerpstart = cl.time; + e->previouspose = e->currentpose; + e->currentpose = posenum; + } + } + + //set up values + if (r_lerpmodels.value && !(e->model->flags & MOD_NOLERP && r_lerpmodels.value != 2)) + { + if (e->lerpflags & LERP_FINISH && numposes == 1) + lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / (e->lerpfinish - e->lerpstart), 1); + else + lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / e->lerptime, 1); + lerpdata->pose1 = e->previouspose; + lerpdata->pose2 = e->currentpose; + } + else //don't lerp + { + lerpdata->blend = 1; + lerpdata->pose1 = posenum; + lerpdata->pose2 = posenum; + } +} + +/* +================= +R_SetupEntityTransform -- johnfitz -- set up transform part of lerpdata +================= +*/ +void R_SetupEntityTransform (entity_t *e, lerpdata_t *lerpdata) +{ + float blend; + vec3_t d; + int i; + + // if LERP_RESETMOVE, kill any lerps in progress + if (e->lerpflags & LERP_RESETMOVE) + { + e->movelerpstart = 0; + VectorCopy (e->origin, e->previousorigin); + VectorCopy (e->origin, e->currentorigin); + VectorCopy (e->angles, e->previousangles); + VectorCopy (e->angles, e->currentangles); + e->lerpflags -= LERP_RESETMOVE; + } + else if (!VectorCompare (e->origin, e->currentorigin) || !VectorCompare (e->angles, e->currentangles)) // origin/angles changed, start new lerp + { + e->movelerpstart = cl.time; + VectorCopy (e->currentorigin, e->previousorigin); + VectorCopy (e->origin, e->currentorigin); + VectorCopy (e->currentangles, e->previousangles); + VectorCopy (e->angles, e->currentangles); + } + + //set up values + if (r_lerpmove.value && e != &cl.viewent && e->lerpflags & LERP_MOVESTEP) + { + if (e->lerpflags & LERP_FINISH) + blend = CLAMP (0, (cl.time - e->movelerpstart) / (e->lerpfinish - e->movelerpstart), 1); + else + blend = CLAMP (0, (cl.time - e->movelerpstart) / 0.1, 1); + + //translation + VectorSubtract (e->currentorigin, e->previousorigin, d); + lerpdata->origin[0] = e->previousorigin[0] + d[0] * blend; + lerpdata->origin[1] = e->previousorigin[1] + d[1] * blend; + lerpdata->origin[2] = e->previousorigin[2] + d[2] * blend; + + //rotation + VectorSubtract (e->currentangles, e->previousangles, d); + for (i = 0; i < 3; i++) + { + if (d[i] > 180) d[i] -= 360; + if (d[i] < -180) d[i] += 360; + } + lerpdata->angles[0] = e->previousangles[0] + d[0] * blend; + lerpdata->angles[1] = e->previousangles[1] + d[1] * blend; + lerpdata->angles[2] = e->previousangles[2] + d[2] * blend; + } + else //don't lerp + { + VectorCopy (e->origin, lerpdata->origin); + VectorCopy (e->angles, lerpdata->angles); + } +} + +/* +================= +R_SetupAliasLighting -- johnfitz -- broken out from R_DrawAliasModel and rewritten +================= +*/ +void R_SetupAliasLighting (entity_t *e) +{ + vec3_t dist; + float add; + int i; + + R_LightPoint (e->origin); + + //add dlights + for (i=0 ; i= cl.time) + { + VectorSubtract (currententity->origin, cl_dlights[i].origin, dist); + add = cl_dlights[i].radius - Length(dist); + if (add > 0) + VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor); + } + } + + // minimum light value on gun (24) + if (e == &cl.viewent) + { + add = 72.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]); + if (add > 0.0f) + { + lightcolor[0] += add / 3.0f; + lightcolor[1] += add / 3.0f; + lightcolor[2] += add / 3.0f; + } + } + + // minimum light value on players (8) + if (currententity > cl_entities && currententity <= cl_entities + cl.maxclients) + { + add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]); + if (add > 0.0f) + { + lightcolor[0] += add / 3.0f; + lightcolor[1] += add / 3.0f; + lightcolor[2] += add / 3.0f; + } + } + + // clamp lighting so it doesn't overbright as much (96) + if (overbright) + { + add = 288.0f / (lightcolor[0] + lightcolor[1] + lightcolor[2]); + if (add < 1.0f) + VectorScale(lightcolor, add, lightcolor); + } + + //hack up the brightness when fullbrights but no overbrights (256) + if (gl_fullbrights.value && !gl_overbright_models.value) + if (e->model->flags & MOD_FBRIGHTHACK) + { + lightcolor[0] = 256.0f; + lightcolor[1] = 256.0f; + lightcolor[2] = 256.0f; + } + + shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; + VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); +} + +/* +================= +R_DrawAliasModel -- johnfitz -- almost completely rewritten +================= +*/ +void R_DrawAliasModel (entity_t *e) +{ + aliashdr_t *paliashdr; + vec3_t mins, maxs; + int i, anim; + gltexture_t *tx, *fb; + lerpdata_t lerpdata; + + // + // setup pose/lerp data -- do it first so we don't miss updates due to culling + // + paliashdr = (aliashdr_t *)Mod_Extradata (e->model); + R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); + R_SetupEntityTransform (e, &lerpdata); + + // + // cull it + // + if (R_CullModelForEntity(e)) + return; + + // + // transform it + // + glPushMatrix (); + R_RotateForEntity (lerpdata.origin, lerpdata.angles); + glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); + glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); + + // + // random stuff + // + if (gl_smoothmodels.value && !r_drawflat_cheatsafe) + glShadeModel (GL_SMOOTH); + if (gl_affinemodels.value) + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + overbright = gl_overbright_models.value; + shading = true; + + // + // set up for alpha blending + // + if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) //no alpha in drawflat or lightmap mode + entalpha = 1; + else + entalpha = ENTALPHA_DECODE(e->alpha); + if (entalpha == 0) + goto cleanup; + if (entalpha < 1) + { + if (!gl_texture_env_combine) overbright = false; //overbright can't be done in a single pass without combiners + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + } + + // + // set up lighting + // + rs_aliaspolys += paliashdr->numtris; + R_SetupAliasLighting (e); + + // + // set up textures + // + GL_DisableMultitexture(); + anim = (int)(cl.time*10) & 3; + tx = paliashdr->gltextures[e->skinnum][anim]; + fb = paliashdr->fbtextures[e->skinnum][anim]; + if (e->colormap != vid.colormap && !gl_nocolors.value) + { + i = e - cl_entities; + if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) + tx = playertextures[i - 1]; + } + if (!gl_fullbrights.value) + fb = NULL; + + // + // draw it + // + if (r_drawflat_cheatsafe) + { + glDisable (GL_TEXTURE_2D); + GL_DrawAliasFrame (paliashdr, lerpdata); + glEnable (GL_TEXTURE_2D); + srand((int) (cl.time * 1000)); //restore randomness + } + else if (r_fullbright_cheatsafe) + { + GL_Bind (tx); + shading = false; + glColor4f(1,1,1,entalpha); + GL_DrawAliasFrame (paliashdr, lerpdata); + if (fb) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_Bind(fb); + glEnable(GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthMask(GL_FALSE); + glColor3f(entalpha,entalpha,entalpha); + Fog_StartAdditive (); + GL_DrawAliasFrame (paliashdr, lerpdata); + Fog_StopAdditive (); + glDepthMask(GL_TRUE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + } + } + else if (r_lightmap_cheatsafe) + { + glDisable (GL_TEXTURE_2D); + shading = false; + glColor3f(1,1,1); + GL_DrawAliasFrame (paliashdr, lerpdata); + glEnable (GL_TEXTURE_2D); + } + else if (overbright) + { + if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass + { + GL_Bind (tx); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); + GL_EnableMultitexture(); // selects TEXTURE1 + GL_Bind (fb); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); + glEnable(GL_BLEND); + GL_DrawAliasFrame (paliashdr, lerpdata); + glDisable(GL_BLEND); + GL_DisableMultitexture(); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass + { + // first pass + GL_Bind(tx); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); + GL_DrawAliasFrame (paliashdr, lerpdata); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + // second pass + if (fb) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_Bind(fb); + glEnable(GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthMask(GL_FALSE); + shading = false; + glColor3f(entalpha,entalpha,entalpha); + Fog_StartAdditive (); + GL_DrawAliasFrame (paliashdr, lerpdata); + Fog_StopAdditive (); + glDepthMask(GL_TRUE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + } + else //case 3: overbright in two passes, then fullbright pass + { + // first pass + GL_Bind(tx); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_DrawAliasFrame (paliashdr, lerpdata); + // second pass -- additive with black fog, to double the object colors but not the fog color + glEnable(GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthMask(GL_FALSE); + Fog_StartAdditive (); + GL_DrawAliasFrame (paliashdr, lerpdata); + Fog_StopAdditive (); + glDepthMask(GL_TRUE); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + // third pass + if (fb) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_Bind(fb); + glEnable(GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthMask(GL_FALSE); + shading = false; + glColor3f(entalpha,entalpha,entalpha); + Fog_StartAdditive (); + GL_DrawAliasFrame (paliashdr, lerpdata); + Fog_StopAdditive (); + glDepthMask(GL_TRUE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + } + } + else + { + if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture + { + GL_DisableMultitexture(); // selects TEXTURE0 + GL_Bind (tx); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_EnableMultitexture(); // selects TEXTURE1 + GL_Bind (fb); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); + glEnable(GL_BLEND); + GL_DrawAliasFrame (paliashdr, lerpdata); + glDisable(GL_BLEND); + GL_DisableMultitexture(); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + else //case 5: fullbright mask without multitexture + { + // first pass + GL_Bind(tx); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_DrawAliasFrame (paliashdr, lerpdata); + // second pass + if (fb) + { + GL_Bind(fb); + glEnable(GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glDepthMask(GL_FALSE); + shading = false; + glColor3f(entalpha,entalpha,entalpha); + Fog_StartAdditive (); + GL_DrawAliasFrame (paliashdr, lerpdata); + Fog_StopAdditive (); + glDepthMask(GL_TRUE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + } + } + } + +cleanup: + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glShadeModel (GL_FLAT); + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glColor3f(1,1,1); + glPopMatrix (); +} + +//johnfitz -- values for shadow matrix +#define SHADOW_SKEW_X -0.7 //skew along x axis. -0.7 to mimic glquake shadows +#define SHADOW_SKEW_Y 0 //skew along y axis. 0 to mimic glquake shadows +#define SHADOW_VSCALE 0 //0=completely flat +#define SHADOW_HEIGHT 0.1 //how far above the floor to render the shadow +//johnfitz + +/* +============= +GL_DrawAliasShadow -- johnfitz -- rewritten + +TODO: orient shadow onto "lightplane" (a global mplane_t*) +============= +*/ +void GL_DrawAliasShadow (entity_t *e) +{ + float shadowmatrix[16] = {1, 0, 0, 0, + 0, 1, 0, 0, + SHADOW_SKEW_X, SHADOW_SKEW_Y, SHADOW_VSCALE, 0, + 0, 0, SHADOW_HEIGHT, 1}; + float lheight; + aliashdr_t *paliashdr; + vec3_t mins, maxs; + lerpdata_t lerpdata; + + if (R_CullModelForEntity(e)) + return; + + if (e == &cl.viewent || e->model->flags & MOD_NOSHADOW) + return; + + entalpha = ENTALPHA_DECODE(e->alpha); + if (entalpha == 0) return; + + paliashdr = (aliashdr_t *)Mod_Extradata (e->model); + R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); + R_SetupEntityTransform (e, &lerpdata); + R_LightPoint (e->origin); + lheight = currententity->origin[2] - lightspot[2]; + +// set up matrix + glPushMatrix (); + glTranslatef (lerpdata.origin[0], lerpdata.origin[1], lerpdata.origin[2]); + glTranslatef (0,0,-lheight); + glMultMatrixf (shadowmatrix); + glTranslatef (0,0,lheight); + glRotatef (lerpdata.angles[1], 0, 0, 1); + glRotatef (-lerpdata.angles[0], 0, 1, 0); + glRotatef (lerpdata.angles[2], 1, 0, 0); + glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); + glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); + +// draw it + glDepthMask(GL_FALSE); + glEnable (GL_BLEND); + GL_DisableMultitexture (); + glDisable (GL_TEXTURE_2D); + shading = false; + glColor4f(0,0,0,entalpha * 0.5); + GL_DrawAliasFrame (paliashdr, lerpdata); + glEnable (GL_TEXTURE_2D); + glDisable (GL_BLEND); + glDepthMask(GL_TRUE); + +//clean up + glPopMatrix (); +} + +/* +================= +R_DrawAliasModel_ShowTris -- johnfitz +================= +*/ +void R_DrawAliasModel_ShowTris (entity_t *e) +{ + aliashdr_t *paliashdr; + vec3_t mins, maxs; + lerpdata_t lerpdata; + + if (R_CullModelForEntity(e)) + return; + + paliashdr = (aliashdr_t *)Mod_Extradata (e->model); + R_SetupAliasFrame (paliashdr, e->frame, &lerpdata); + R_SetupEntityTransform (e, &lerpdata); + + glPushMatrix (); + R_RotateForEntity (lerpdata.origin,lerpdata.angles); + glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); + glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); + + shading = false; + glColor3f(1,1,1); + GL_DrawAliasFrame (paliashdr, lerpdata); + + glPopMatrix (); +} \ No newline at end of file diff --git a/Quake/r_brush.c b/Quake/r_brush.c new file mode 100644 index 00000000..05b406b0 --- /dev/null +++ b/Quake/r_brush.c @@ -0,0 +1,1197 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_brush.c: brush model rendering. renamed from r_surf.c + +#include "quakedef.h" + +extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater; //johnfitz + +int gl_lightmap_format; +int lightmap_bytes; + +#define BLOCK_WIDTH 128 //johnfitz -- was 128 +#define BLOCK_HEIGHT 128 //johnfitz -- was 128 + +unsigned blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (BLOCK_WIDTH*BLOCK_HEIGHT) + +typedef struct glRect_s { + unsigned char l,t,w,h; +} glRect_t; + +glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; +qboolean lightmap_modified[MAX_LIGHTMAPS]; +glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; + +int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; + +// the lightmap texture data needs to be kept in +// main memory so texsubimage can update properly +byte lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT]; + +void R_RenderDynamicLightmaps (msurface_t *fa); +void R_BuildLightMap (msurface_t *surf, byte *dest, int stride); +void R_UploadLightmap (int lmap); + +/* +=============== +R_TextureAnimation -- johnfitz -- added "frame" param to eliminate use of "currententity" global + +Returns the proper texture for a given time and base texture +=============== +*/ +texture_t *R_TextureAnimation (texture_t *base, int frame) +{ + int relative; + int count; + + if (frame) + if (base->alternate_anims) + base = base->alternate_anims; + + if (!base->anim_total) + return base; + + relative = (int)(cl.time*10) % base->anim_total; + + count = 0; + while (base->anim_min > relative || base->anim_max <= relative) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + if (++count > 100) + Sys_Error ("R_TextureAnimation: infinite cycle"); + } + + return base; +} + +/* +================ +DrawGLPoly +================ +*/ +void DrawGLPoly (glpoly_t *p) +{ + float *v; + int i; + + glBegin (GL_POLYGON); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[3], v[4]); + glVertex3fv (v); + } + glEnd (); +} + +/* +================ +DrawGLTriangleFan -- johnfitz -- like DrawGLPoly but for r_showtris +================ +*/ +void DrawGLTriangleFan (glpoly_t *p) +{ + float *v; + int i; + + glBegin (GL_TRIANGLE_FAN); + v = p->verts[0]; + for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) + { + glVertex3fv (v); + } + glEnd (); +} + +/* +============================================================= + + BRUSH MODELS + +============================================================= +*/ + +/* +================ +R_DrawSequentialPoly -- johnfitz -- rewritten +================ +*/ +void R_DrawSequentialPoly (msurface_t *s) +{ + glpoly_t *p; + texture_t *t; + float *v; + float entalpha; + int i; + + t = R_TextureAnimation (s->texinfo->texture, currententity->frame); + entalpha = ENTALPHA_DECODE(currententity->alpha); + +// drawflat + if (r_drawflat_cheatsafe) + { + if ((s->flags & SURF_DRAWTURB) && r_oldwater.value) + { + for (p = s->polys->next; p; p = p->next) + { + srand((unsigned int) p); + glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); + DrawGLPoly (p); + rs_brushpasses++; + } + return; + } + + srand((unsigned int) s->polys); + glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); + DrawGLPoly (s->polys); + rs_brushpasses++; + return; + } + +// fullbright + if ((r_fullbright_cheatsafe) && !(s->flags & SURF_DRAWTILED)) + { + if (entalpha < 1) + { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1, 1, 1, entalpha); + } + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + rs_brushpasses++; + if (entalpha < 1) + { + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f(1, 1, 1); + } + goto fullbrights; + } + +// r_lightmap + if (r_lightmap_cheatsafe) + { + if (s->flags & SURF_DRAWTILED) + { + glDisable (GL_TEXTURE_2D); + DrawGLPoly (s->polys); + glEnable (GL_TEXTURE_2D); + rs_brushpasses++; + return; + } + + R_RenderDynamicLightmaps (s); + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_UploadLightmap(s->lightmaptexturenum); + if (!gl_overbright.value) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0.5, 0.5, 0.5); + } + glBegin (GL_POLYGON); + v = s->polys->verts[0]; + for (i=0 ; ipolys->numverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + if (!gl_overbright.value) + { + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + rs_brushpasses++; + return; + } + +// sky poly -- skip it, already handled in gl_sky.c + if (s->flags & SURF_DRAWSKY) + return; + +// water poly + if (s->flags & SURF_DRAWTURB) + { + if (currententity->alpha == ENTALPHA_DEFAULT) + entalpha = CLAMP(0.0,r_wateralpha.value,1.0); + + if (entalpha < 1) + { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1, 1, 1, entalpha); + } + if (r_oldwater.value) + { + GL_Bind (s->texinfo->texture->gltexture); + for (p = s->polys->next; p; p = p->next) + { + DrawWaterPoly (p); + rs_brushpasses++; + } + rs_brushpasses++; + } + else + { + GL_Bind (s->texinfo->texture->warpimage); + s->texinfo->texture->update_warp = true; // FIXME: one frame too late! + DrawGLPoly (s->polys); + rs_brushpasses++; + } + if (entalpha < 1) + { + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f(1, 1, 1); + } + return; + } + +// missing texture + if (s->flags & SURF_NOTEXTURE) + { + if (entalpha < 1) + { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1, 1, 1, entalpha); + } + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + rs_brushpasses++; + if (entalpha < 1) + { + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f(1, 1, 1); + } + return; + } + +// lightmapped poly + if (entalpha < 1) + { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f(1, 1, 1, entalpha); + } + else + glColor3f(1, 1, 1); + if (gl_overbright.value) + { + if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners + { + GL_DisableMultitexture(); // selects TEXTURE0 + GL_Bind (t->gltexture); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_EnableMultitexture(); // selects TEXTURE1 + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_RenderDynamicLightmaps (s); + R_UploadLightmap(s->lightmaptexturenum); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); + glBegin(GL_POLYGON); + v = s->polys->verts[0]; + for (i=0 ; ipolys->numverts ; i++, v+= VERTEXSIZE) + { + GL_MTexCoord2fFunc (TEXTURE0, v[3], v[4]); + GL_MTexCoord2fFunc (TEXTURE1, v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_DisableMultitexture (); + rs_brushpasses++; + } + else if (entalpha < 1) //case 2: can't do multipass if entity has alpha, so just draw the texture + { + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + rs_brushpasses++; + } + else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass + { + //first pass -- texture with no fog + Fog_DisableGFog (); + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + Fog_EnableGFog (); + rs_brushpasses++; + + //second pass -- lightmap with black fog, modulate blended + R_RenderDynamicLightmaps (s); + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_UploadLightmap(s->lightmaptexturenum); + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); //2x modulate + Fog_StartAdditive (); + glBegin (GL_POLYGON); + v = s->polys->verts[0]; + for (i=0 ; ipolys->numverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + Fog_StopAdditive (); + rs_brushpasses++; + + //third pass -- black geo with normal fog, additive blended + if (Fog_GetDensity() > 0) + { + glBlendFunc(GL_ONE, GL_ONE); //add + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0,0,0); + DrawGLPoly (s->polys); + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + rs_brushpasses++; + } + + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + } + } + else + { + if (gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation + { + GL_DisableMultitexture(); // selects TEXTURE0 + GL_Bind (t->gltexture); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_EnableMultitexture(); // selects TEXTURE1 + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_RenderDynamicLightmaps (s); + R_UploadLightmap(s->lightmaptexturenum); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin(GL_POLYGON); + v = s->polys->verts[0]; + for (i=0 ; ipolys->numverts ; i++, v+= VERTEXSIZE) + { + GL_MTexCoord2fFunc (TEXTURE0, v[3], v[4]); + GL_MTexCoord2fFunc (TEXTURE1, v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + GL_DisableMultitexture (); + rs_brushpasses++; + } + else if (entalpha < 1) //case 5: can't do multipass if entity has alpha, so just draw the texture + { + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + rs_brushpasses++; + } + else //case 6: texture in one pass, lightmap in a second pass, fog in third pass + { + //first pass -- texture with no fog + Fog_DisableGFog (); + GL_Bind (t->gltexture); + DrawGLPoly (s->polys); + Fog_EnableGFog (); + rs_brushpasses++; + + //second pass -- lightmap with black fog, modulate blended + R_RenderDynamicLightmaps (s); + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_UploadLightmap(s->lightmaptexturenum); + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc (GL_ZERO, GL_SRC_COLOR); //modulate + Fog_StartAdditive (); + glBegin (GL_POLYGON); + v = s->polys->verts[0]; + for (i=0 ; ipolys->numverts ; i++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + Fog_StopAdditive (); + rs_brushpasses++; + + //third pass -- black geo with normal fog, additive blended + if (Fog_GetDensity() > 0) + { + glBlendFunc(GL_ONE, GL_ONE); //add + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0,0,0); + DrawGLPoly (s->polys); + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + rs_brushpasses++; + } + + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + + } + } + if (entalpha < 1) + { + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f(1, 1, 1); + } + +fullbrights: + if (gl_fullbrights.value && t->fullbright) + { + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f (entalpha, entalpha, entalpha); + GL_Bind (t->fullbright); + Fog_StartAdditive (); + DrawGLPoly (s->polys); + Fog_StopAdditive (); + glColor3f(1, 1, 1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + rs_brushpasses++; + } +} + +/* +================= +R_DrawBrushModel +================= +*/ +void R_DrawBrushModel (entity_t *e) +{ + int j, k; + int i, numsurfaces; + msurface_t *psurf; + float dot; + mplane_t *pplane; + model_t *clmodel; + + if (R_CullModelForEntity(e)) + return; + + currententity = e; + clmodel = e->model; + + VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + vec3_t temp; + vec3_t forward, right, up; + + VectorCopy (modelorg, temp); + AngleVectors (e->angles, forward, right, up); + modelorg[0] = DotProduct (temp, forward); + modelorg[1] = -DotProduct (temp, right); + modelorg[2] = DotProduct (temp, up); + } + + psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; + +// calculate dynamic lighting for bmodel if it's not an +// instanced model + if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value) + { + for (k=0 ; knodes + clmodel->hulls[0].firstclipnode); + } + } + + glPushMatrix (); + e->angles[0] = -e->angles[0]; // stupid quake bug + R_RotateForEntity (e->origin, e->angles); + e->angles[0] = -e->angles[0]; // stupid quake bug + + // + // draw it + // + + if (r_drawflat_cheatsafe) //johnfitz + glDisable(GL_TEXTURE_2D); + + for (i=0 ; inummodelsurfaces ; i++, psurf++) + { + pplane = psurf->plane; + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + R_DrawSequentialPoly (psurf); + rs_brushpolys++; + } + } + + if (r_drawflat_cheatsafe) //johnfitz + glEnable(GL_TEXTURE_2D); + + GL_DisableMultitexture(); // selects TEXTURE0 + + glPopMatrix (); +} + +/* +================= +R_DrawBrushModel_ShowTris -- johnfitz +================= +*/ +void R_DrawBrushModel_ShowTris (entity_t *e) +{ + int i, j, k, numsurfaces; + msurface_t *psurf; + float dot; + mplane_t *pplane; + model_t *clmodel; + glpoly_t *p; + + if (R_CullModelForEntity(e)) + return; + + currententity = e; + clmodel = e->model; + + VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + if (e->angles[0] || e->angles[1] || e->angles[2]) + { + vec3_t temp; + vec3_t forward, right, up; + + VectorCopy (modelorg, temp); + AngleVectors (e->angles, forward, right, up); + modelorg[0] = DotProduct (temp, forward); + modelorg[1] = -DotProduct (temp, right); + modelorg[2] = DotProduct (temp, up); + } + + psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; + + glPushMatrix (); + e->angles[0] = -e->angles[0]; // stupid quake bug + R_RotateForEntity (e->origin, e->angles); + e->angles[0] = -e->angles[0]; // stupid quake bug + + // + // draw it + // + + for (i=0 ; inummodelsurfaces ; i++, psurf++) + { + pplane = psurf->plane; + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + if ((psurf->flags & SURF_DRAWTURB) && r_oldwater.value) + for (p = psurf->polys->next; p; p = p->next) + DrawGLTriangleFan (p); + else + DrawGLTriangleFan (psurf->polys); + } + } + + glPopMatrix (); +} + +/* +============================================================= + + LIGHTMAPS + +============================================================= +*/ + +/* +================ +R_RenderDynamicLightmaps +called during rendering +================ +*/ +void R_RenderDynamicLightmaps (msurface_t *fa) +{ + byte *base; + int maps; + glRect_t *theRect; + int smax, tmax; + + if (fa->flags & SURF_DRAWTILED) //johnfitz -- not a lightmapped surface + return; + + // add to lightmap chain + fa->polys->chain = lightmap_polys[fa->lightmaptexturenum]; + lightmap_polys[fa->lightmaptexturenum] = fa->polys; + + // check for lightmap modification + for (maps=0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++) + if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps]) + goto dynamic; + + if (fa->dlightframe == r_framecount // dynamic this frame + || fa->cached_dlight) // dynamic previously + { +dynamic: + if (r_dynamic.value) + { + lightmap_modified[fa->lightmaptexturenum] = true; + theRect = &lightmap_rectchange[fa->lightmaptexturenum]; + if (fa->light_t < theRect->t) { + if (theRect->h) + theRect->h += theRect->t - fa->light_t; + theRect->t = fa->light_t; + } + if (fa->light_s < theRect->l) { + if (theRect->w) + theRect->w += theRect->l - fa->light_s; + theRect->l = fa->light_s; + } + smax = (fa->extents[0]>>4)+1; + tmax = (fa->extents[1]>>4)+1; + if ((theRect->w + theRect->l) < (fa->light_s + smax)) + theRect->w = (fa->light_s-theRect->l)+smax; + if ((theRect->h + theRect->t) < (fa->light_t + tmax)) + theRect->h = (fa->light_t-theRect->t)+tmax; + base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; + base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; + R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes); + } + } +} + +/* +======================== +AllocBlock -- returns a texture number and the position inside it +======================== +*/ +int AllocBlock (int w, int h, int *x, int *y) +{ + int i, j; + int best, best2; + int texnum; + /* unused -- kristian + int bestx; + */ + + for (texnum=0 ; texnum= best) + break; + if (allocated[texnum][i+j] > best2) + best2 = allocated[texnum][i+j]; + } + if (j == w) + { // this is a valid spot + *x = i; + *y = best = best2; + } + } + + if (best + h > BLOCK_HEIGHT) + continue; + + for (i=0 ; iextents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + + surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); + base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; + base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; + R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes); +} + +/* +================ +BuildSurfaceDisplayList -- called at level load time +================ +*/ +void BuildSurfaceDisplayList (msurface_t *fa) +{ + int i, lindex, lnumverts; + medge_t *pedges, *r_pedge; + int vertpage; + float *vec; + float s, t; + glpoly_t *poly; + /* unused -- kristian + int s_axis, t_axis; + float dist, lastdist, lzi, scale, u, v, frac; + unsigned mask; + vec3_t local, transformed; + mplane_t *pplane; + int newverts, newpage, lastvert; + qboolean visible; + */ + +// reconstruct the polygon + pedges = currentmodel->edges; + lnumverts = fa->numedges; + vertpage = 0; + + // + // draw texture + // + poly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float)); + poly->next = fa->polys; + fa->polys = poly; + poly->numverts = lnumverts; + + for (i=0 ; isurfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + vec = r_pcurrentvertbase[r_pedge->v[0]].position; + } + else + { + r_pedge = &pedges[-lindex]; + vec = r_pcurrentvertbase[r_pedge->v[1]].position; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s /= fa->texinfo->texture->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t /= fa->texinfo->texture->height; + + VectorCopy (vec, poly->verts[i]); + poly->verts[i][3] = s; + poly->verts[i][4] = t; + + // + // lightmap texture coordinates + // + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + s -= fa->texturemins[0]; + s += fa->light_s*16; + s += 8; + s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width; + + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + t -= fa->texturemins[1]; + t += fa->light_t*16; + t += 8; + t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height; + + poly->verts[i][5] = s; + poly->verts[i][6] = t; + } + + //johnfitz -- removed gl_keeptjunctions code + + poly->numverts = lnumverts; + +} + +/* +================== +GL_BuildLightmaps -- called at level load time + +Builds the lightmap texture +with all the surfaces from all brush models +================== +*/ +void GL_BuildLightmaps (void) +{ + char name[16]; + byte *data; + int i, j; + model_t *m; + + memset (allocated, 0, sizeof(allocated)); + + r_framecount = 1; // no dlightcache + + //johnfitz -- null out array (the gltexture objects themselves were already freed by Mod_ClearAll) + for (i=0; i < MAX_LIGHTMAPS; i++) + lightmap_textures[i] = NULL; + //johnfitz + + gl_lightmap_format = GL_RGB; //johnfitz + + //johnfitz -- only support GL_RGB lightmaps + switch (gl_lightmap_format) + { + case GL_RGB: + lightmap_bytes = 3; + break; + default: + Sys_Error ("GL_BuildLightmaps: bad lightmap format"); + } + //johnfitz + + for (j=1 ; jname[0] == '*') + continue; + r_pcurrentvertbase = m->vertexes; + currentmodel = m; + for (i=0 ; inumsurfaces ; i++) + { + //johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags + if (m->surfaces[i].flags & SURF_DRAWTILED) + continue; + GL_CreateSurfaceLightmap (m->surfaces + i); + BuildSurfaceDisplayList (m->surfaces + i); + //johnfitz + } + } + + // + // upload all lightmaps that were filled + // + for (i=0; i= 64) + Con_Warning ("%i lightmaps exceeds standard limit of 64.\n", i); + //johnfitz +} + +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights (msurface_t *surf) +{ + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + //johnfitz -- lit support via lordhavoc + float cred, cgreen, cblue, brightness; + unsigned *bl; + //johnfitz + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + //johnfitz -- lit support via lordhavoc + bl = blocklights; + cred = cl_dlights[lnum].color[0] * 256.0f; + cgreen = cl_dlights[lnum].color[1] * 256.0f; + cblue = cl_dlights[lnum].color[2] * 256.0f; + //johnfitz + for (t = 0 ; t td) + dist = sd + (td>>1); + else + dist = td + (sd>>1); + if (dist < minlight) + //johnfitz -- lit support via lordhavoc + { + brightness = rad - dist; + bl[0] += (int) (brightness * cred); + bl[1] += (int) (brightness * cgreen); + bl[2] += (int) (brightness * cblue); + } + bl += 3; + //johnfitz + } + } + } +} + + +/* +=============== +R_BuildLightMap -- johnfitz -- revised for lit support via lordhavoc + +Combine and scale multiple lightmaps into the 8.8 format in blocklights +=============== +*/ +void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) +{ + int smax, tmax; + int t; + int i, j, size; + byte *lightmap; + unsigned scale; + int maps; + unsigned *bl; + /* unused -- kristian + int lightadj[4]; + */ + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + if (cl.worldmodel->lightdata) + { + // clear to no light + memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc + + // add all the lightmaps + if (lightmap) + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + //johnfitz -- lit support via lordhavoc + bl = blocklights; + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (surf); + } + else + { + // set to full bright if no light data + memset (&blocklights[0], 255, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc + } + +// bound, invert, and shift +store: + + //johnfitz -- only support GL_RGB lightmaps + switch (gl_lightmap_format) + { + case GL_RGB: + stride -= smax * 3; + bl = blocklights; + for (i=0 ; i> 8;if (t > 255) t = 255;*dest++ = t; + t = *bl++ >> 8;if (t > 255) t = 255;*dest++ = t; + t = *bl++ >> 8;if (t > 255) t = 255;*dest++ = t; + } + else + { + t = *bl++ >> 7;if (t > 255) t = 255;*dest++ = t; + t = *bl++ >> 7;if (t > 255) t = 255;*dest++ = t; + t = *bl++ >> 7;if (t > 255) t = 255;*dest++ = t; + } + } + } + break; + default: + Sys_Error ("R_BuildLightMap: bad lightmap format"); + } + //johnfitz +} + +/* +=============== +R_UploadLightmap -- johnfitz -- uploads the modified lightmap to opengl if necessary + +assumes lightmap texture is already bound +=============== +*/ +void R_UploadLightmap(int lmap) +{ + glRect_t *theRect; + + if (!lightmap_modified[lmap]) + return; + + lightmap_modified[lmap] = false; + + theRect = &lightmap_rectchange[lmap]; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, BLOCK_WIDTH, theRect->h, gl_lightmap_format, + GL_UNSIGNED_BYTE, lightmaps+(lmap* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes); + theRect->l = BLOCK_WIDTH; + theRect->t = BLOCK_HEIGHT; + theRect->h = 0; + theRect->w = 0; + + rs_dynamiclightmaps++; +} + +/* +================ +R_RebuildAllLightmaps -- johnfitz -- called when gl_overbright gets toggled +================ +*/ +void R_RebuildAllLightmaps (void) +{ + int i, j; + model_t *mod; + msurface_t *fa; + byte *base; + + if (!cl.worldmodel) // is this the correct test? + return; + + //for each surface in each model, rebuild lightmap with new scale + for (i=1; isurfaces[mod->firstmodelsurface]; + for (j=0; jnummodelsurfaces; j++, fa++) + { + if (fa->flags & SURF_DRAWTILED) + continue; + base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT; + base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes; + R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes); + } + } + + //for each lightmap, upload it + for (i=0; i 255 ? 255 : r; + a = sharpness * (255 - r); + a = min(a,255); + return a; +} + +/* +=============== +R_InitParticleTextures -- johnfitz -- rewritten +=============== +*/ +void R_InitParticleTextures (void) +{ + int x,y; + static byte particle1_data[64*64*4]; + static byte particle2_data[2*2*4]; + static byte particle3_data[64*64*4]; + byte *dst; + + // particle texture 1 -- circle + dst = particle1_data; + for (x=0 ; x<64 ; x++) + for (y=0 ; y<64 ; y++) + { + *dst++ = 255; + *dst++ = 255; + *dst++ = 255; + *dst++ = R_ParticleTextureLookup(x, y, 8); + } + particletexture1 = TexMgr_LoadImage (NULL, "particle1", 64, 64, SRC_RGBA, particle1_data, "", (unsigned)particle1_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_LINEAR); + + // particle texture 2 -- square + dst = particle2_data; + for (x=0 ; x<2 ; x++) + for (y=0 ; y<2 ; y++) + { + *dst++ = 255; + *dst++ = 255; + *dst++ = 255; + *dst++ = x || y ? 0 : 255; + } + particletexture2 = TexMgr_LoadImage (NULL, "particle2", 2, 2, SRC_RGBA, particle2_data, "", (unsigned)particle2_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_NEAREST); + + // particle texture 3 -- blob + dst = particle3_data; + for (x=0 ; x<64 ; x++) + for (y=0 ; y<64 ; y++) + { + *dst++ = 255; + *dst++ = 255; + *dst++ = 255; + *dst++ = R_ParticleTextureLookup(x, y, 2); + } + particletexture3 = TexMgr_LoadImage (NULL, "particle3", 64, 64, SRC_RGBA, particle3_data, "", (unsigned)particle3_data, TEXPREF_PERSIST | TEXPREF_ALPHA | TEXPREF_LINEAR); + + + //set default + particletexture = particletexture1; + texturescalefactor = 1.27; +} + +/* +=============== +R_SetParticleTexture_f -- johnfitz +=============== +*/ +void R_SetParticleTexture_f (void) +{ + switch ((int)(r_particles.value)) + { + case 1: + particletexture = particletexture1; + texturescalefactor = 1.27; + break; + case 2: + particletexture = particletexture2; + texturescalefactor = 1.0; + break; +// case 3: +// particletexture = particletexture3; +// texturescalefactor = 1.5; +// break; + } +} + +/* +=============== +R_InitParticles +=============== +*/ +void R_InitParticles (void) +{ + int i; + + i = COM_CheckParm ("-particles"); + + if (i) + { + r_numparticles = (int)(Q_atoi(com_argv[i+1])); + if (r_numparticles < ABSOLUTE_MIN_PARTICLES) + r_numparticles = ABSOLUTE_MIN_PARTICLES; + } + else + { + r_numparticles = MAX_PARTICLES; + } + + particles = (particle_t *) + Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles"); + + Cvar_RegisterVariable (&r_particles, R_SetParticleTexture_f); //johnfitz + Cvar_RegisterVariable (&r_quadparticles, NULL); //johnfitz + + R_InitParticleTextures (); //johnfitz +} + +/* +=============== +R_EntityParticles +=============== +*/ +#define NUMVERTEXNORMALS 162 +extern float r_avertexnormals[NUMVERTEXNORMALS][3]; +vec3_t avelocities[NUMVERTEXNORMALS]; +float beamlength = 16; +vec3_t avelocity = {23, 7, 3}; +float partstep = 0.01; +float timescale = 0.01; + +void R_EntityParticles (entity_t *ent) +{ + int count; + int i; + particle_t *p; + float angle; + float sr, sp, sy, cr, cp, cy; + vec3_t forward; + float dist; + + dist = 64; + count = 50; + + if (!avelocities[0][0]) + { + for (i=0 ; inext; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.01; + p->color = 0x6f; + p->type = pt_explode; + + p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength; + p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength; + p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength; + } +} + +/* +=============== +R_ClearParticles +=============== +*/ +void R_ClearParticles (void) +{ + int i; + + free_particles = &particles[0]; + active_particles = NULL; + + for (i=0 ;inext; + p->next = active_particles; + active_particles = p; + + p->die = 99999; + p->color = (-c)&15; + p->type = pt_static; + VectorCopy (vec3_origin, p->vel); + VectorCopy (org, p->org); + } + + fclose (f); + Con_Printf ("%i points read\n", c); +} + +/* +=============== +R_ParseParticleEffect + +Parse an effect out of the server message +=============== +*/ +void R_ParseParticleEffect (void) +{ + vec3_t org, dir; + int i, count, msgcount, color; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + for (i=0 ; i<3 ; i++) + dir[i] = MSG_ReadChar () * (1.0/16); + msgcount = MSG_ReadByte (); + color = MSG_ReadByte (); + +if (msgcount == 255) + count = 1024; +else + count = msgcount; + + R_RunParticleEffect (org, dir, color, count); +} + +/* +=============== +R_ParticleExplosion +=============== +*/ +void R_ParticleExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 5; + p->color = ramp1[0]; + p->ramp = rand()&3; + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + } +} + +/* +=============== +R_ParticleExplosion2 +=============== +*/ +void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) +{ + int i, j; + particle_t *p; + int colorMod = 0; + + for (i=0; i<512; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.3; + p->color = colorStart + (colorMod % colorLength); + colorMod++; + + p->type = pt_blob; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } +} + +/* +=============== +R_BlobExplosion +=============== +*/ +void R_BlobExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 1 + (rand()&8)*0.05; + + if (i & 1) + { + p->type = pt_blob; + p->color = 66 + rand()%6; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + else + { + p->type = pt_blob2; + p->color = 150 + rand()%6; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + } +} + +/* +=============== +R_RunParticleEffect +=============== +*/ +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) +{ + int i, j; + particle_t *p; + + for (i=0 ; inext; + p->next = active_particles; + active_particles = p; + + if (count == 1024) + { // rocket explosion + p->die = cl.time + 5; + p->color = ramp1[0]; + p->ramp = rand()&3; + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (rand()%512)-256; + } + } + } + else + { + p->die = cl.time + 0.1*(rand()%5); + p->color = (color&~7) + (rand()&7); + p->type = pt_slowgrav; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()&15)-8); + p->vel[j] = dir[j]*15;// + (rand()%300)-150; + } + } + } +} + +/* +=============== +R_LavaSplash +=============== +*/ +void R_LavaSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i=-16 ; i<16 ; i++) + for (j=-16 ; j<16 ; j++) + for (k=0 ; k<1 ; k++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 2 + (rand()&31) * 0.02; + p->color = 224 + (rand()&7); + p->type = pt_slowgrav; + + dir[0] = j*8 + (rand()&7); + dir[1] = i*8 + (rand()&7); + dir[2] = 256; + + p->org[0] = org[0] + dir[0]; + p->org[1] = org[1] + dir[1]; + p->org[2] = org[2] + (rand()&63); + + VectorNormalize (dir); + vel = 50 + (rand()&63); + VectorScale (dir, vel, p->vel); + } +} + +/* +=============== +R_TeleportSplash +=============== +*/ +void R_TeleportSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i=-16 ; i<16 ; i+=4) + for (j=-16 ; j<16 ; j+=4) + for (k=-24 ; k<32 ; k+=4) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.2 + (rand()&7) * 0.02; + p->color = 7 + (rand()&7); + p->type = pt_slowgrav; + + dir[0] = j*8; + dir[1] = i*8; + dir[2] = k*8; + + p->org[0] = org[0] + i + (rand()&3); + p->org[1] = org[1] + j + (rand()&3); + p->org[2] = org[2] + k + (rand()&3); + + VectorNormalize (dir); + vel = 50 + (rand()&63); + VectorScale (dir, vel, p->vel); + } +} + +/* +=============== +R_RocketTrail + +FIXME -- rename function and use #defined types instead of numbers +=============== +*/ +void R_RocketTrail (vec3_t start, vec3_t end, int type) +{ + vec3_t vec; + float len; + int j; + particle_t *p; + int dec; + static int tracercount; + + VectorSubtract (end, start, vec); + len = VectorNormalize (vec); + if (type < 128) + dec = 3; + else + { + dec = 1; + type -= 128; + } + + while (len > 0) + { + len -= dec; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (vec3_origin, p->vel); + p->die = cl.time + 2; + + switch (type) + { + case 0: // rocket trail + p->ramp = (rand()&3); + p->color = ramp3[(int)p->ramp]; + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 1: // smoke smoke + p->ramp = (rand()&3) + 2; + p->color = ramp3[(int)p->ramp]; + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 2: // blood + p->type = pt_grav; + p->color = 67 + (rand()&3); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 3: + case 5: // tracer + p->die = cl.time + 0.5; + p->type = pt_static; + if (type == 3) + p->color = 52 + ((tracercount&4)<<1); + else + p->color = 230 + ((tracercount&4)<<1); + + tracercount++; + + VectorCopy (start, p->org); + if (tracercount & 1) + { + p->vel[0] = 30*vec[1]; + p->vel[1] = 30*-vec[0]; + } + else + { + p->vel[0] = 30*-vec[1]; + p->vel[1] = 30*vec[0]; + } + break; + + case 4: // slight blood + p->type = pt_grav; + p->color = 67 + (rand()&3); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + len -= 3; + break; + + case 6: // voor trail + p->color = 9*16 + 8 + (rand()&3); + p->type = pt_static; + p->die = cl.time + 0.3; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()&15)-8); + break; + } + + + VectorAdd (start, vec, start); + } +} + +/* +=============== +CL_RunParticles -- johnfitz -- all the particle behavior, separated from R_DrawParticles +=============== +*/ +void CL_RunParticles (void) +{ + particle_t *p, *kill; + int i; + float time1, time2, time3, dvel, frametime, grav; + extern cvar_t sv_gravity; + /* unused -- kristian + float scale; + */ + + frametime = cl.time - cl.oldtime; + time3 = frametime * 15; + time2 = frametime * 10; + time1 = frametime * 5; + grav = frametime * sv_gravity.value * 0.05; + dvel = 4*frametime; + + for ( ;; ) + { + kill = active_particles; + if (kill && kill->die < cl.time) + { + active_particles = kill->next; + kill->next = free_particles; + free_particles = kill; + continue; + } + break; + } + + for (p=active_particles ; p ; p=p->next) + { + for ( ;; ) + { + kill = p->next; + if (kill && kill->die < cl.time) + { + p->next = kill->next; + kill->next = free_particles; + free_particles = kill; + continue; + } + break; + } + + p->org[0] += p->vel[0]*frametime; + p->org[1] += p->vel[1]*frametime; + p->org[2] += p->vel[2]*frametime; + + switch (p->type) + { + case pt_static: + break; + case pt_fire: + p->ramp += time1; + if (p->ramp >= 6) + p->die = -1; + else + p->color = ramp3[(int)p->ramp]; + p->vel[2] += grav; + break; + + case pt_explode: + p->ramp += time2; + if (p->ramp >=8) + p->die = -1; + else + p->color = ramp1[(int)p->ramp]; + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_explode2: + p->ramp += time3; + if (p->ramp >=8) + p->die = -1; + else + p->color = ramp2[(int)p->ramp]; + for (i=0 ; i<3 ; i++) + p->vel[i] -= p->vel[i]*frametime; + p->vel[2] -= grav; + break; + + case pt_blob: + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_blob2: + for (i=0 ; i<2 ; i++) + p->vel[i] -= p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_grav: + case pt_slowgrav: + p->vel[2] -= grav; + break; + } + } +} + +/* +=============== +R_DrawParticles -- johnfitz -- moved all non-drawing code to CL_RunParticles +=============== +*/ +void R_DrawParticles (void) +{ + particle_t *p; + float scale; + vec3_t up, right, p_up, p_right, p_upright; //johnfitz -- p_ vectors + byte color[4]; //johnfitz -- particle transparency + extern cvar_t r_particles; //johnfitz + /* unused -- kristian + float alpha; //johnfitz -- particle transparency + */ + + if (!r_particles.value) + return; + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); + + GL_Bind(particletexture); + glEnable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glDepthMask (GL_FALSE); //johnfitz -- fix for particle z-buffer bug + + if (r_quadparticles.value) //johnitz -- quads save fillrate + { + glBegin (GL_QUADS); + for (p=active_particles ; p ; p=p->next) + { + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0]) * vpn[0] + + (p->org[1] - r_origin[1]) * vpn[1] + + (p->org[2] - r_origin[2]) * vpn[2]; + if (scale < 20) + scale = 1 + 0.08; //johnfitz -- added .08 to be consistent + else + scale = 1 + scale * 0.004; + + scale /= 2.0; //quad is half the size of triangle + + scale *= texturescalefactor; //johnfitz -- compensate for apparent size of different particle textures + + //johnfitz -- particle transparency and fade out + *(int *)color = d_8to24table[(int)p->color]; + //alpha = CLAMP(0, p->die + 0.5 - cl.time, 1); + color[3] = 255; //(int)(alpha * 255); + glColor4ubv(color); + //johnfitz + + glTexCoord2f (0,0); + glVertex3fv (p->org); + + glTexCoord2f (0.5,0); + VectorMA (p->org, scale, up, p_up); + glVertex3fv (p_up); + + glTexCoord2f (0.5,0.5); + VectorMA (p_up, scale, right, p_upright); + glVertex3fv (p_upright); + + glTexCoord2f (0,0.5); + VectorMA (p->org, scale, right, p_right); + glVertex3fv (p_right); + + rs_particles++; //johnfitz //FIXME: just use r_numparticles + } + glEnd (); + } + else //johnitz -- triangles save verts + { + glBegin (GL_TRIANGLES); + for (p=active_particles ; p ; p=p->next) + { + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0]) * vpn[0] + + (p->org[1] - r_origin[1]) * vpn[1] + + (p->org[2] - r_origin[2]) * vpn[2]; + if (scale < 20) + scale = 1 + 0.08; //johnfitz -- added .08 to be consistent + else + scale = 1 + scale * 0.004; + + scale *= texturescalefactor; //johnfitz -- compensate for apparent size of different particle textures + + //johnfitz -- particle transparency and fade out + *(int *)color = d_8to24table[(int)p->color]; + //alpha = CLAMP(0, p->die + 0.5 - cl.time, 1); + color[3] = 255; //(int)(alpha * 255); + glColor4ubv(color); + //johnfitz + + glTexCoord2f (0,0); + glVertex3fv (p->org); + + glTexCoord2f (1,0); + VectorMA (p->org, scale, up, p_up); + glVertex3fv (p_up); + + glTexCoord2f (0,1); + VectorMA (p->org, scale, right, p_right); + glVertex3fv (p_right); + + rs_particles++; //johnfitz //FIXME: just use r_numparticles + } + glEnd (); + } + + glDepthMask (GL_TRUE); //johnfitz -- fix for particle z-buffer bug + glDisable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f(1,1,1); +} + + +/* +=============== +R_DrawParticles_ShowTris -- johnfitz +=============== +*/ +void R_DrawParticles_ShowTris (void) +{ + particle_t *p; + float scale; + vec3_t up, right, p_up, p_right, p_upright; + extern cvar_t r_particles; + + if (!r_particles.value) + return; + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); + + if (r_quadparticles.value) + { + for (p=active_particles ; p ; p=p->next) + { + glBegin (GL_TRIANGLE_FAN); + + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0]) * vpn[0] + + (p->org[1] - r_origin[1]) * vpn[1] + + (p->org[2] - r_origin[2]) * vpn[2]; + if (scale < 20) + scale = 1 + 0.08; //johnfitz -- added .08 to be consistent + else + scale = 1 + scale * 0.004; + + scale /= 2.0; //quad is half the size of triangle + + scale *= texturescalefactor; //compensate for apparent size of different particle textures + + glVertex3fv (p->org); + + VectorMA (p->org, scale, up, p_up); + glVertex3fv (p_up); + + VectorMA (p_up, scale, right, p_upright); + glVertex3fv (p_upright); + + VectorMA (p->org, scale, right, p_right); + glVertex3fv (p_right); + + glEnd (); + } + } + else + { + glBegin (GL_TRIANGLES); + for (p=active_particles ; p ; p=p->next) + { + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0]) * vpn[0] + + (p->org[1] - r_origin[1]) * vpn[1] + + (p->org[2] - r_origin[2]) * vpn[2]; + if (scale < 20) + scale = 1 + 0.08; //johnfitz -- added .08 to be consistent + else + scale = 1 + scale * 0.004; + + scale *= texturescalefactor; //compensate for apparent size of different particle textures + + glVertex3fv (p->org); + + VectorMA (p->org, scale, up, p_up); + glVertex3fv (p_up); + + VectorMA (p->org, scale, right, p_right); + glVertex3fv (p_right); + } + glEnd (); + } +} \ No newline at end of file diff --git a/Quake/r_sprite.c b/Quake/r_sprite.c new file mode 100644 index 00000000..70ed36f3 --- /dev/null +++ b/Quake/r_sprite.c @@ -0,0 +1,184 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +//r_sprite.c -- sprite model rendering + +#include "quakedef.h" + +/* +================ +R_GetSpriteFrame +================ +*/ +mspriteframe_t *R_GetSpriteFrame (entity_t *currententity) +{ + msprite_t *psprite; + mspritegroup_t *pspritegroup; + mspriteframe_t *pspriteframe; + int i, numframes, frame; + float *pintervals, fullinterval, targettime, time; + + psprite = currententity->model->cache.data; + frame = currententity->frame; + + if ((frame >= psprite->numframes) || (frame < 0)) + { + Con_Printf ("R_DrawSprite: no such frame %d\n", frame); + frame = 0; + } + + if (psprite->frames[frame].type == SPR_SINGLE) + { + pspriteframe = psprite->frames[frame].frameptr; + } + else + { + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = cl.time + currententity->syncbase; + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + pspriteframe = pspritegroup->frames[i]; + } + + return pspriteframe; +} + +/* +================= +R_DrawSpriteModel -- johnfitz -- rewritten: now supports all orientations +================= +*/ +void R_DrawSpriteModel (entity_t *e) +{ + vec3_t point, v_forward, v_right, v_up; + msprite_t *psprite; + mspriteframe_t *frame; + float *s_up, *s_right; + float angle, sr, cr; + /* unused -- kristian + float len; + */ + + //TODO: frustum cull it? + + frame = R_GetSpriteFrame (e); + psprite = currententity->model->cache.data; + + switch(psprite->type) + { + case SPR_VP_PARALLEL_UPRIGHT: //faces view plane, up is towards the heavens + v_up[0] = 0; + v_up[1] = 0; + v_up[2] = 1; + s_up = v_up; + s_right = vright; + break; + case SPR_FACING_UPRIGHT: //faces camera origin, up is towards the heavens + VectorSubtract(currententity->origin, r_origin, v_forward); + v_forward[2] = 0; + VectorNormalizeFast(v_forward); + v_right[0] = v_forward[1]; + v_right[1] = -v_forward[0]; + v_right[2] = 0; + v_up[0] = 0; + v_up[1] = 0; + v_up[2] = 1; + s_up = v_up; + s_right = v_right; + break; + case SPR_VP_PARALLEL: //faces view plane, up is towards the top of the screen + s_up = vup; + s_right = vright; + break; + case SPR_ORIENTED: //pitch yaw roll are independent of camera + AngleVectors (currententity->angles, v_forward, v_right, v_up); + s_up = v_up; + s_right = v_right; + break; + case SPR_VP_PARALLEL_ORIENTED: //faces view plane, but obeys roll value + angle = currententity->angles[ROLL] * M_PI_DIV_180; + sr = sin(angle); + cr = cos(angle); + v_right[0] = vright[0] * cr + vup[0] * sr; + v_right[1] = vright[1] * cr + vup[1] * sr; + v_right[2] = vright[2] * cr + vup[2] * sr; + v_up[0] = vright[0] * -sr + vup[0] * cr; + v_up[1] = vright[1] * -sr + vup[1] * cr; + v_up[2] = vright[2] * -sr + vup[2] * cr; + s_up = v_up; + s_right = v_right; + break; + default: + return; + } + + //johnfitz: offset decals + if (psprite->type == SPR_ORIENTED) + GL_PolygonOffset (OFFSET_DECAL); + + glColor3f (1,1,1); + + GL_DisableMultitexture(); + + GL_Bind(frame->gltexture); + + glEnable (GL_ALPHA_TEST); + glBegin (GL_TRIANGLE_FAN); //was GL_QUADS, but changed to support r_showtris + + glTexCoord2f (0, frame->tmax); + VectorMA (e->origin, frame->down, s_up, point); + VectorMA (point, frame->left, s_right, point); + glVertex3fv (point); + + glTexCoord2f (0, 0); + VectorMA (e->origin, frame->up, s_up, point); + VectorMA (point, frame->left, s_right, point); + glVertex3fv (point); + + glTexCoord2f (frame->smax, 0); + VectorMA (e->origin, frame->up, s_up, point); + VectorMA (point, frame->right, s_right, point); + glVertex3fv (point); + + glTexCoord2f (frame->smax, frame->tmax); + VectorMA (e->origin, frame->down, s_up, point); + VectorMA (point, frame->right, s_right, point); + glVertex3fv (point); + + glEnd (); + glDisable (GL_ALPHA_TEST); + + //johnfitz: offset decals + if (psprite->type == SPR_ORIENTED) + GL_PolygonOffset (OFFSET_NONE); +} diff --git a/Quake/r_world.c b/Quake/r_world.c new file mode 100644 index 00000000..8b6c3553 --- /dev/null +++ b/Quake/r_world.c @@ -0,0 +1,751 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_world.c: world model rendering + +#include "quakedef.h" + +extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskyleaf, r_showtris; //johnfitz + +extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; + +byte *SV_FatPVS (vec3_t org, model_t *worldmodel); +extern byte mod_novis[MAX_MAP_LEAFS/8]; +int vis_changed; //if true, force pvs to be refreshed + +//============================================================================== +// +// SETUP CHAINS +// +//============================================================================== + +/* +=============== +R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains +=============== +*/ +void R_MarkSurfaces (void) +{ + byte *vis; + mleaf_t *leaf; + mnode_t *node; + msurface_t *surf, **mark; + int i, j; + qboolean nearwaterportal; + + // clear lightmap chains + memset (lightmap_polys, 0, sizeof(lightmap_polys)); + + // check this leaf for water portals + // TODO: loop through all water surfs and use distance to leaf cullbox + nearwaterportal = false; + for (i=0, mark = r_viewleaf->firstmarksurface; i < r_viewleaf->nummarksurfaces; i++, mark++) + if ((*mark)->flags & SURF_DRAWTURB) + nearwaterportal = true; + + // choose vis data + if (r_novis.value || r_viewleaf->contents == CONTENTS_SOLID || r_viewleaf->contents == CONTENTS_SKY) + vis = &mod_novis[0]; + else if (nearwaterportal) + vis = SV_FatPVS (r_origin, cl.worldmodel); + else + vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); + + // if surface chains don't need regenerating, just add static entities and return + if (r_oldviewleaf == r_viewleaf && !vis_changed && !nearwaterportal) + { + leaf = &cl.worldmodel->leafs[1]; + for (i=0 ; inumleafs ; i++, leaf++) + if (vis[i>>3] & (1<<(i&7))) + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); + return; + } + + r_visframecount++; + r_oldviewleaf = r_viewleaf; + + // iterate through leaves, marking surfaces + leaf = &cl.worldmodel->leafs[1]; + for (i=0 ; inumleafs ; i++, leaf++) + { + if (vis[i>>3] & (1<<(i&7))) + { + if (r_oldskyleaf.value || leaf->contents != CONTENTS_SKY) + for (j=0, mark = leaf->firstmarksurface; jnummarksurfaces; j++, mark++) + (*mark)->visframe = r_visframecount; + + // add static models + if (leaf->efrags) + R_StoreEfrags (&leaf->efrags); + } + } + + // set all chains to null + for (i=0 ; inumtextures ; i++) + if (cl.worldmodel->textures[i]) + cl.worldmodel->textures[i]->texturechain = NULL; + + // rebuild chains + +#if 1 + //iterate through surfaces one node at a time to rebuild chains + //need to do it this way if we want to work with tyrann's skip removal tool + //becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump + //nor does it remove references to them in each leaf's marksurfaces list + for (i=0, node = cl.worldmodel->nodes ; inumnodes ; i++, node++) + for (j=0, surf=&cl.worldmodel->surfaces[node->firstsurface] ; jnumsurfaces ; j++, surf++) + if (surf->visframe == r_visframecount) + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } +#else + //the old way + surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface]; + for (i=0 ; inummodelsurfaces ; i++, surf++) + { + if (surf->visframe == r_visframecount) + { + surf->texturechain = surf->texinfo->texture->texturechain; + surf->texinfo->texture->texturechain = surf; + } + } +#endif +} + +/* +================ +R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg +================ +*/ +qboolean R_BackFaceCull (msurface_t *surf) +{ + double dot; + + switch (surf->plane->type) + { + case PLANE_X: + dot = r_refdef.vieworg[0] - surf->plane->dist; + break; + case PLANE_Y: + dot = r_refdef.vieworg[1] - surf->plane->dist; + break; + case PLANE_Z: + dot = r_refdef.vieworg[2] - surf->plane->dist; + break; + default: + dot = DotProduct (r_refdef.vieworg, surf->plane->normal) - surf->plane->dist; + break; + } + + if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) + return true; + + return false; +} + +/* +================ +R_CullSurfaces -- johnfitz +================ +*/ +void R_CullSurfaces (void) +{ + msurface_t *s; + int i; + + if (!r_drawworld_cheatsafe) + return; + + s = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface]; + for (i=0 ; inummodelsurfaces ; i++, s++) + { + if (s->visframe == r_visframecount) + { + if (R_CullBox(s->mins, s->maxs) || R_BackFaceCull (s)) + s->culled = true; + else + { + s->culled = false; + rs_brushpolys++; //count wpolys here + if (s->texinfo->texture->warpimage) + s->texinfo->texture->update_warp = true; + } + } + } +} + +/* +================ +R_BuildLightmapChains -- johnfitz -- used for r_lightmap 1 +================ +*/ +void R_BuildLightmapChains (void) +{ + msurface_t *s; + int i; + + // clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo) + memset (lightmap_polys, 0, sizeof(lightmap_polys)); + + // now rebuild them + s = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface]; + for (i=0 ; inummodelsurfaces ; i++, s++) + if (s->visframe == r_visframecount && !R_CullBox(s->mins, s->maxs) && !R_BackFaceCull (s)) + R_RenderDynamicLightmaps (s); +} + +//============================================================================== +// +// DRAW CHAINS +// +//============================================================================== + +/* +================ +R_DrawTextureChains_ShowTris -- johnfitz +================ +*/ +void R_DrawTextureChains_ShowTris (void) +{ + int i; + msurface_t *s; + texture_t *t; + glpoly_t *p; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t) + continue; + + if (r_oldwater.value && t->texturechain && (t->texturechain->flags & SURF_DRAWTURB)) + { + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + for (p = s->polys->next; p; p = p->next) + { + DrawGLTriangleFan (p); + } + } + else + { + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + DrawGLTriangleFan (s->polys); + } + } + } +} + +/* +================ +R_DrawTextureChains_Drawflat -- johnfitz +================ +*/ +void R_DrawTextureChains_Drawflat (void) +{ + int i; + msurface_t *s; + texture_t *t; + glpoly_t *p; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t) + continue; + + if (r_oldwater.value && t->texturechain && (t->texturechain->flags & SURF_DRAWTURB)) + { + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + for (p = s->polys->next; p; p = p->next) + { + srand((unsigned int) p); + glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); + DrawGLPoly (p); + rs_brushpasses++; + } + } + else + { + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + srand((unsigned int) s->polys); + glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0); + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } + } + glColor3f (1,1,1); + srand ((int) (cl.time * 1000)); +} + +/* +================ +R_DrawTextureChains_Glow -- johnfitz +================ +*/ +void R_DrawTextureChains_Glow (void) +{ + int i; + msurface_t *s; + texture_t *t; + gltexture_t *glt; + qboolean bound; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || !(glt = R_TextureAnimation(t,0)->fullbright)) + continue; + + bound = false; + + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind (glt); + bound = true; + } + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } +} + +/* +================ +R_DrawTextureChains_Multitexture -- johnfitz +================ +*/ +void R_DrawTextureChains_Multitexture (void) +{ + int i, j; + msurface_t *s; + texture_t *t; + float *v; + qboolean bound; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || t->texturechain->flags & (SURF_DRAWTILED | SURF_NOTEXTURE)) + continue; + + bound = false; + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind ((R_TextureAnimation(t,0))->gltexture); + GL_EnableMultitexture(); // selects TEXTURE1 + bound = true; + } + R_RenderDynamicLightmaps (s); + GL_Bind (lightmap_textures[s->lightmaptexturenum]); + R_UploadLightmap(s->lightmaptexturenum); + glBegin(GL_POLYGON); + v = s->polys->verts[0]; + for (j=0 ; jpolys->numverts ; j++, v+= VERTEXSIZE) + { + GL_MTexCoord2fFunc (TEXTURE0, v[3], v[4]); + GL_MTexCoord2fFunc (TEXTURE1, v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + rs_brushpasses++; + } + GL_DisableMultitexture(); // selects TEXTURE0 + } +} + +/* +================ +R_DrawTextureChains_NoTexture -- johnfitz + +draws surfs whose textures were missing from the BSP +================ +*/ +void R_DrawTextureChains_NoTexture (void) +{ + int i; + msurface_t *s; + texture_t *t; + qboolean bound; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || !(t->texturechain->flags & SURF_NOTEXTURE)) + continue; + + bound = false; + + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind (t->gltexture); + bound = true; + } + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } +} + +/* +================ +R_DrawTextureChains_TextureOnly -- johnfitz +================ +*/ +void R_DrawTextureChains_TextureOnly (void) +{ + int i; + msurface_t *s; + texture_t *t; + qboolean bound; + + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || t->texturechain->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) + continue; + + bound = false; + + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind ((R_TextureAnimation(t,0))->gltexture); + bound = true; + } + R_RenderDynamicLightmaps (s); //adds to lightmap chain + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } +} + +/* +================ +R_DrawTextureChains_Water -- johnfitz +================ +*/ +void R_DrawTextureChains_Water (void) +{ + int i; + msurface_t *s; + texture_t *t; + glpoly_t *p; + qboolean bound; + /* unused -- kristian + int j; + float *v; + */ + + if (r_drawflat_cheatsafe || r_lightmap_cheatsafe || !r_drawworld_cheatsafe) + return; + + if (r_wateralpha.value < 1.0) + { + glDepthMask(GL_FALSE); + glEnable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor4f (1,1,1,r_wateralpha.value); + } + + if (r_oldwater.value) + { + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t || !t->texturechain || !(t->texturechain->flags & SURF_DRAWTURB)) + continue; + bound = false; + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind (t->gltexture); + bound = true; + } + for (p = s->polys->next; p; p = p->next) + { + DrawWaterPoly (p); + rs_brushpasses++; + } + } + } + } + else + { + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + if (!t || !t->texturechain || !(t->texturechain->flags & SURF_DRAWTURB)) + continue; + bound = false; + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + if (!bound) //only bind once we are sure we need this texture + { + GL_Bind (t->warpimage); + bound = true; + } + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } + } + + if (r_wateralpha.value < 1.0) + { + glDepthMask(GL_TRUE); + glDisable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glColor3f (1,1,1); + } +} + +/* +================ +R_DrawTextureChains_White -- johnfitz -- draw sky and water as white polys when r_lightmap is 1 +================ +*/ +void R_DrawTextureChains_White (void) +{ + int i; + msurface_t *s; + texture_t *t; + + glDisable (GL_TEXTURE_2D); + for (i=0 ; inumtextures ; i++) + { + t = cl.worldmodel->textures[i]; + + if (!t || !t->texturechain || !(t->texturechain->flags & SURF_DRAWTILED)) + continue; + + for (s = t->texturechain; s; s = s->texturechain) + if (!s->culled) + { + DrawGLPoly (s->polys); + rs_brushpasses++; + } + } + glEnable (GL_TEXTURE_2D); +} + +/* +================ +R_DrawLightmapChains -- johnfitz -- R_BlendLightmaps stripped down to almost nothing +================ +*/ +void R_DrawLightmapChains (void) +{ + int i, j; + glpoly_t *p; + float *v; + + for (i=0 ; ichain) + { + glBegin (GL_POLYGON); + v = p->verts[0]; + for (j=0 ; jnumverts ; j++, v+= VERTEXSIZE) + { + glTexCoord2f (v[5], v[6]); + glVertex3fv (v); + } + glEnd (); + rs_brushpasses++; + } + } +} + +/* +============= +R_DrawWorld -- johnfitz -- rewritten +============= +*/ +void R_DrawWorld (void) +{ + if (!r_drawworld_cheatsafe) + return; + + if (r_drawflat_cheatsafe) + { + glDisable (GL_TEXTURE_2D); + R_DrawTextureChains_Drawflat (); + glEnable (GL_TEXTURE_2D); + return; + } + + if (r_fullbright_cheatsafe) + { + R_DrawTextureChains_TextureOnly (); + goto fullbrights; + } + + if (r_lightmap_cheatsafe) + { + R_BuildLightmapChains (); + if (!gl_overbright.value) + { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0.5, 0.5, 0.5); + } + R_DrawLightmapChains (); + if (!gl_overbright.value) + { + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + R_DrawTextureChains_White (); + return; + } + + R_DrawTextureChains_NoTexture (); + + if (gl_overbright.value) + { + if (gl_texture_env_combine && gl_mtexable) + { + GL_EnableMultitexture (); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); + GL_DisableMultitexture (); + R_DrawTextureChains_Multitexture (); + GL_EnableMultitexture (); + glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_DisableMultitexture (); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + else + { + //to make fog work with multipass lightmapping, need to do one pass + //with no fog, one modulate pass with black fog, and one additive + //pass with black geometry and normal fog + Fog_DisableGFog (); + R_DrawTextureChains_TextureOnly (); + Fog_EnableGFog (); + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc (GL_DST_COLOR, GL_SRC_COLOR); //2x modulate + Fog_StartAdditive (); + R_DrawLightmapChains (); + Fog_StopAdditive (); + if (Fog_GetDensity() > 0) + { + glBlendFunc(GL_ONE, GL_ONE); //add + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0,0,0); + R_DrawTextureChains_TextureOnly (); + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + } + } + else + { + if (gl_mtexable) + { + GL_EnableMultitexture (); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + GL_DisableMultitexture (); + R_DrawTextureChains_Multitexture (); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + else + { + //to make fog work with multipass lightmapping, need to do one pass + //with no fog, one modulate pass with black fog, and one additive + //pass with black geometry and normal fog + Fog_DisableGFog (); + R_DrawTextureChains_TextureOnly (); + Fog_EnableGFog (); + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc(GL_ZERO, GL_SRC_COLOR); //modulate + Fog_StartAdditive (); + R_DrawLightmapChains (); + Fog_StopAdditive (); + if (Fog_GetDensity() > 0) + { + glBlendFunc(GL_ONE, GL_ONE); //add + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glColor3f(0,0,0); + R_DrawTextureChains_TextureOnly (); + glColor3f(1,1,1); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + } + } + +fullbrights: + if (gl_fullbrights.value) + { + glDepthMask (GL_FALSE); + glEnable (GL_BLEND); + glBlendFunc (GL_ONE, GL_ONE); + Fog_StartAdditive (); + R_DrawTextureChains_Glow (); + Fog_StopAdditive (); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_BLEND); + glDepthMask (GL_TRUE); + } +} \ No newline at end of file diff --git a/Quake/render.h b/Quake/render.h new file mode 100644 index 00000000..dd6f9e15 --- /dev/null +++ b/Quake/render.h @@ -0,0 +1,175 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// refresh.h -- public interface to refresh functions + +#define MAXCLIPPLANES 11 + +#define TOP_RANGE 16 // soldier uniform colors +#define BOTTOM_RANGE 96 + +//============================================================================= + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +//johnfitz -- for lerping +#define LERP_MOVESTEP (1<<0) //this is a MOVETYPE_STEP entity, enable movement lerp +#define LERP_RESETANIM (1<<1) //disable anim lerping until next anim frame +#define LERP_RESETANIM2 (1<<2) //set this and previous flag to disable anim lerping for two anim frames +#define LERP_RESETMOVE (1<<3) //disable movement lerping until next origin/angles change +#define LERP_FINISH (1<<4) //use lerpfinish time from server update instead of assuming interval of 0.1 +//johnfitz + +typedef struct entity_s +{ + qboolean forcelink; // model changed + + int update_type; + + entity_state_t baseline; // to fill in defaults in updates + + double msgtime; // time of last update + vec3_t msg_origins[2]; // last two updates (0 is newest) + vec3_t origin; + vec3_t msg_angles[2]; // last two updates (0 is newest) + vec3_t angles; + struct model_s *model; // NULL = no model + struct efrag_s *efrag; // linked list of efrags + int frame; + float syncbase; // for client-side animations + byte *colormap; + int effects; // light, particles, etc + int skinnum; // for Alias models + int visframe; // last frame this entity was + // found in an active leaf + + int dlightframe; // dynamic lighting + int dlightbits; + +// FIXME: could turn these into a union + int trivial_accept; + struct mnode_s *topnode; // for bmodels, first world node + // that splits bmodel, or NULL if + // not split + + byte alpha; //johnfitz -- alpha + byte lerpflags; //johnfitz -- lerping + float lerpstart; //johnfitz -- animation lerping + float lerptime; //johnfitz -- animation lerping + float lerpfinish; //johnfitz -- lerping -- server sent us a more accurate interval, use it instead of 0.1 + short previouspose; //johnfitz -- animation lerping + short currentpose; //johnfitz -- animation lerping +// short futurepose; //johnfitz -- animation lerping + float movelerpstart; //johnfitz -- transform lerping + vec3_t previousorigin; //johnfitz -- transform lerping + vec3_t currentorigin; //johnfitz -- transform lerping + vec3_t previousangles; //johnfitz -- transform lerping + vec3_t currentangles; //johnfitz -- transform lerping +} entity_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + vrect_t vrect; // subwindow in video for refresh + // FIXME: not need vrect next field here? + vrect_t aliasvrect; // scaled Alias version + int vrectright, vrectbottom; // right & bottom screen coords + int aliasvrectright, aliasvrectbottom; // scaled Alias versions + float vrectrightedge; // rightmost right edge we care about, + // for use in edge list + float fvrectx, fvrecty; // for floating-point compares + float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping + int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20 + int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20 + float fvrectright_adj, fvrectbottom_adj; + // right and bottom edges, for clamping + float fvrectright; // rightmost edge, for Alias clamping + float fvrectbottom; // bottommost edge, for Alias clamping + float horizontalFieldOfView; // at Z = 1.0, this many X is visible + // 2.0 = 90 degrees + float xOrigin; // should probably allways be 0.5 + float yOrigin; // between be around 0.3 to 0.5 + + vec3_t vieworg; + vec3_t viewangles; + + float fov_x, fov_y; + + int ambientlight; +} refdef_t; + + +// +// refresh +// +extern int reinit_surfcache; + + +extern refdef_t r_refdef; +extern vec3_t r_origin, vpn, vright, vup; + + +void R_Init (void); +void R_InitTextures (void); +void R_InitEfrags (void); +void R_RenderView (void); // must set r_refdef first +void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect); + // called whenever r_refdef or vid change +//void R_InitSky (struct texture_s *mt); // called at level load + +void R_CheckEfrags (void); //johnfitz +void R_AddEfrags (entity_t *ent); +void R_RemoveEfrags (entity_t *ent); + +void R_NewMap (void); + + +void R_ParseParticleEffect (void); +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count); +void R_RocketTrail (vec3_t start, vec3_t end, int type); +void R_EntityParticles (entity_t *ent); +void R_BlobExplosion (vec3_t org); +void R_ParticleExplosion (vec3_t org); +void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength); +void R_LavaSplash (vec3_t org); +void R_TeleportSplash (vec3_t org); + +void R_PushDlights (void); + + +// +// surface cache related +// +extern int reinit_surfcache; // if 1, surface cache is currently empty and +extern qboolean r_cache_thrash; // set if thrashing the surface cache + +int D_SurfaceCacheForRes (int width, int height); +void D_FlushCaches (void); +void D_DeleteSurfaceCache (void); +void D_InitCaches (void *buffer, int size); +void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); + diff --git a/Quake/resource.h b/Quake/resource.h new file mode 100644 index 00000000..d2004d4e --- /dev/null +++ b/Quake/resource.h @@ -0,0 +1,20 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by winquake.rc +// +#define IDS_STRING1 1 +#define IDI_ICON2 1 +#define IDD_DIALOG1 108 +#define IDD_PROGRESS 109 +#define IDC_PROGRESS 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 113 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1004 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Quake/sbar.c b/Quake/sbar.c new file mode 100644 index 00000000..c8265e53 --- /dev/null +++ b/Quake/sbar.c @@ -0,0 +1,1286 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sbar.c -- status bar code + +#include "quakedef.h" + +int sb_updates; // if >= vid.numpages, no update needed + +#define STAT_MINUS 10 // num frame for '-' stats digit +qpic_t *sb_nums[2][11]; +qpic_t *sb_colon, *sb_slash; +qpic_t *sb_ibar; +qpic_t *sb_sbar; +qpic_t *sb_scorebar; + +qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes +qpic_t *sb_ammo[4]; +qpic_t *sb_sigil[4]; +qpic_t *sb_armor[3]; +qpic_t *sb_items[32]; + +qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive + // 0 is static, 1 is temporary animation +qpic_t *sb_face_invis; +qpic_t *sb_face_quad; +qpic_t *sb_face_invuln; +qpic_t *sb_face_invis_invuln; + +qboolean sb_showscores; + +int sb_lines; // scan lines to draw + +qpic_t *rsb_invbar[2]; +qpic_t *rsb_weapons[5]; +qpic_t *rsb_items[2]; +qpic_t *rsb_ammo[3]; +qpic_t *rsb_teambord; // PGM 01/19/97 - team color border + +//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher +qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes +//MED 01/04/97 added array to simplify weapon parsing +int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT}; +//MED 01/04/97 added hipnotic items array +qpic_t *hsb_items[2]; + +void Sbar_MiniDeathmatchOverlay (void); +void Sbar_DeathmatchOverlay (void); +void M_DrawPic (int x, int y, qpic_t *pic); + +/* +=============== +Sbar_ShowScores + +Tab key down +=============== +*/ +void Sbar_ShowScores (void) +{ + if (sb_showscores) + return; + sb_showscores = true; + sb_updates = 0; +} + +/* +=============== +Sbar_DontShowScores + +Tab key up +=============== +*/ +void Sbar_DontShowScores (void) +{ + sb_showscores = false; + sb_updates = 0; +} + +/* +=============== +Sbar_Changed +=============== +*/ +void Sbar_Changed (void) +{ + sb_updates = 0; // update next frame +} + +/* +=============== +Sbar_LoadPics -- johnfitz -- load all the sbar pics +=============== +*/ +void Sbar_LoadPics (void) +{ + int i; + + for (i=0 ; i<10 ; i++) + { + sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i)); + sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i)); + } + + sb_nums[0][10] = Draw_PicFromWad ("num_minus"); + sb_nums[1][10] = Draw_PicFromWad ("anum_minus"); + + sb_colon = Draw_PicFromWad ("num_colon"); + sb_slash = Draw_PicFromWad ("num_slash"); + + sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun"); + sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun"); + sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun"); + sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun"); + sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch"); + sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch"); + sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng"); + + sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun"); + sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun"); + sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun"); + sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun"); + sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch"); + sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch"); + sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng"); + + for (i=0 ; i<5 ; i++) + { + sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1)); + sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1)); + sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1)); + sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1)); + sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1)); + sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1)); + sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1)); + } + + sb_ammo[0] = Draw_PicFromWad ("sb_shells"); + sb_ammo[1] = Draw_PicFromWad ("sb_nails"); + sb_ammo[2] = Draw_PicFromWad ("sb_rocket"); + sb_ammo[3] = Draw_PicFromWad ("sb_cells"); + + sb_armor[0] = Draw_PicFromWad ("sb_armor1"); + sb_armor[1] = Draw_PicFromWad ("sb_armor2"); + sb_armor[2] = Draw_PicFromWad ("sb_armor3"); + + sb_items[0] = Draw_PicFromWad ("sb_key1"); + sb_items[1] = Draw_PicFromWad ("sb_key2"); + sb_items[2] = Draw_PicFromWad ("sb_invis"); + sb_items[3] = Draw_PicFromWad ("sb_invuln"); + sb_items[4] = Draw_PicFromWad ("sb_suit"); + sb_items[5] = Draw_PicFromWad ("sb_quad"); + + sb_sigil[0] = Draw_PicFromWad ("sb_sigil1"); + sb_sigil[1] = Draw_PicFromWad ("sb_sigil2"); + sb_sigil[2] = Draw_PicFromWad ("sb_sigil3"); + sb_sigil[3] = Draw_PicFromWad ("sb_sigil4"); + + sb_faces[4][0] = Draw_PicFromWad ("face1"); + sb_faces[4][1] = Draw_PicFromWad ("face_p1"); + sb_faces[3][0] = Draw_PicFromWad ("face2"); + sb_faces[3][1] = Draw_PicFromWad ("face_p2"); + sb_faces[2][0] = Draw_PicFromWad ("face3"); + sb_faces[2][1] = Draw_PicFromWad ("face_p3"); + sb_faces[1][0] = Draw_PicFromWad ("face4"); + sb_faces[1][1] = Draw_PicFromWad ("face_p4"); + sb_faces[0][0] = Draw_PicFromWad ("face5"); + sb_faces[0][1] = Draw_PicFromWad ("face_p5"); + + sb_face_invis = Draw_PicFromWad ("face_invis"); + sb_face_invuln = Draw_PicFromWad ("face_invul2"); + sb_face_invis_invuln = Draw_PicFromWad ("face_inv2"); + sb_face_quad = Draw_PicFromWad ("face_quad"); + + sb_sbar = Draw_PicFromWad ("sbar"); + sb_ibar = Draw_PicFromWad ("ibar"); + sb_scorebar = Draw_PicFromWad ("scorebar"); + +//MED 01/04/97 added new hipnotic weapons + if (hipnotic) + { + hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser"); + hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir"); + hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox"); + hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren"); + hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox"); + + hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser"); + hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir"); + hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox"); + hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren"); + hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox"); + + for (i=0 ; i<5 ; i++) + { + hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1)); + hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1)); + hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1)); + hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1)); + hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1)); + } + + hsb_items[0] = Draw_PicFromWad ("sb_wsuit"); + hsb_items[1] = Draw_PicFromWad ("sb_eshld"); + } + + if (rogue) + { + rsb_invbar[0] = Draw_PicFromWad ("r_invbar1"); + rsb_invbar[1] = Draw_PicFromWad ("r_invbar2"); + + rsb_weapons[0] = Draw_PicFromWad ("r_lava"); + rsb_weapons[1] = Draw_PicFromWad ("r_superlava"); + rsb_weapons[2] = Draw_PicFromWad ("r_gren"); + rsb_weapons[3] = Draw_PicFromWad ("r_multirock"); + rsb_weapons[4] = Draw_PicFromWad ("r_plasma"); + + rsb_items[0] = Draw_PicFromWad ("r_shield1"); + rsb_items[1] = Draw_PicFromWad ("r_agrav1"); + +// PGM 01/19/97 - team color border + rsb_teambord = Draw_PicFromWad ("r_teambord"); +// PGM 01/19/97 - team color border + + rsb_ammo[0] = Draw_PicFromWad ("r_ammolava"); + rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti"); + rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma"); + } +} + +/* +=============== +Sbar_Init -- johnfitz -- rewritten +=============== +*/ +void Sbar_Init (void) +{ + Cmd_AddCommand ("+showscores", Sbar_ShowScores); + Cmd_AddCommand ("-showscores", Sbar_DontShowScores); + + Sbar_LoadPics (); +} + + +//============================================================================= + +// drawing routines are relative to the status bar location + +/* +============= +Sbar_DrawPic -- johnfitz -- rewritten now that GL_SetCanvas is doing the work +============= +*/ +void Sbar_DrawPic (int x, int y, qpic_t *pic) +{ + Draw_Pic (x, y + 24, pic); +} + +/* +============= +Sbar_DrawPicAlpha -- johnfitz +============= +*/ +Sbar_DrawPicAlpha (int x, int y, qpic_t *pic, float alpha) +{ + glDisable (GL_ALPHA_TEST); + glEnable (GL_BLEND); + glColor4f(1,1,1,alpha); + Draw_Pic (x, y + 24, pic); + glColor3f(1,1,1); + glDisable (GL_BLEND); + glEnable (GL_ALPHA_TEST); +} + +/* +================ +Sbar_DrawCharacter -- johnfitz -- rewritten now that GL_SetCanvas is doing the work +================ +*/ +void Sbar_DrawCharacter (int x, int y, int num) +{ + Draw_Character (x, y + 24, num); +} + +/* +================ +Sbar_DrawString -- johnfitz -- rewritten now that GL_SetCanvas is doing the work +================ +*/ +void Sbar_DrawString (int x, int y, char *str) +{ + Draw_String (x, y + 24, str); +} + +/* +=============== +Sbar_DrawScrollString -- johnfitz + +scroll the string inside a glscissor region +=============== +*/ +void Sbar_DrawScrollString (int x, int y, int width, char* str) +{ + float scale; + int len, ofs, left; + + scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); + left = x * scale; + if (cl.gametype != GAME_DEATHMATCH) + left += (((float)glwidth - 320.0 * scale) / 2); + + glEnable (GL_SCISSOR_TEST); + glScissor (left, 0, width * scale, glheight); + + len = strlen(str)*8 + 40; + ofs = ((int)(realtime*30))%len; + Sbar_DrawString (x - ofs, y, str); + Sbar_DrawCharacter (x - ofs + len - 32, y, '/'); + Sbar_DrawCharacter (x - ofs + len - 24, y, '/'); + Sbar_DrawCharacter (x - ofs + len - 16, y, '/'); + Sbar_DrawString (x - ofs + len, y, str); + + glDisable (GL_SCISSOR_TEST); +} + +/* +============= +Sbar_itoa +============= +*/ +int Sbar_itoa (int num, char *buf) +{ + char *str; + int pow10; + int dig; + + str = buf; + + if (num < 0) + { + *str++ = '-'; + num = -num; + } + + for (pow10 = 10 ; num >= pow10 ; pow10 *= 10) + ; + + do + { + pow10 /= 10; + dig = num/pow10; + *str++ = '0'+dig; + num -= dig*pow10; + } while (pow10 != 1); + + *str = 0; + + return str-buf; +} + + +/* +============= +Sbar_DrawNum +============= +*/ +void Sbar_DrawNum (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + num = min(999,num); //johnfitz -- cap high values rather than truncating number + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Sbar_DrawPic (x,y,sb_nums[color][frame]); //johnfitz -- DrawTransPic is obsolete + x += 24; + ptr++; + } +} + +//============================================================================= + +int fragsort[MAX_SCOREBOARD]; + +char scoreboardtext[MAX_SCOREBOARD][20]; +int scoreboardtop[MAX_SCOREBOARD]; +int scoreboardbottom[MAX_SCOREBOARD]; +int scoreboardcount[MAX_SCOREBOARD]; +int scoreboardlines; + +/* +=============== +Sbar_SortFrags +=============== +*/ +void Sbar_SortFrags (void) +{ + int i, j, k; + +// sort by frags + scoreboardlines = 0; + for (i=0 ; ifrags, s->name); + + top = s->colors & 0xf0; + bottom = (s->colors & 15) <<4; + scoreboardtop[i] = Sbar_ColorForMap (top); + scoreboardbottom[i] = Sbar_ColorForMap (bottom); + } +} + +/* +=============== +Sbar_SoloScoreboard -- johnfitz -- new layout +=============== +*/ +void Sbar_SoloScoreboard (void) +{ + char str[80]; + int minutes, seconds, tens, units; + int len; + + sprintf (str,"Kills: %i/%i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); + Sbar_DrawString (8, 12, str); + + sprintf (str,"Secrets: %i/%i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]); + Sbar_DrawString (312 - strlen(str)*8, 12, str); + + minutes = cl.time / 60; + seconds = cl.time - 60*minutes; + tens = seconds / 10; + units = seconds - 10*tens; + sprintf (str,"%i:%i%i", minutes, tens, units); + Sbar_DrawString (160 - strlen(str)*4, 12, str); + + len = strlen (cl.levelname); + if (len > 40) + Sbar_DrawScrollString (0, 4, 320, cl.levelname); + else + Sbar_DrawString (160 - len*4, 4, cl.levelname); +} + +/* +=============== +Sbar_DrawScoreboard +=============== +*/ +void Sbar_DrawScoreboard (void) +{ + Sbar_SoloScoreboard (); + if (cl.gametype == GAME_DEATHMATCH) + Sbar_DeathmatchOverlay (); +} + +//============================================================================= + +/* +=============== +Sbar_DrawInventory +=============== +*/ +void Sbar_DrawInventory (void) +{ + int i; + char num[6]; + float time; + int flashon; + + if (rogue) + { + if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + Sbar_DrawPicAlpha (0, -24, rsb_invbar[0], scr_sbaralpha.value); //johnfitz -- scr_sbaralpha + else + Sbar_DrawPicAlpha (0, -24, rsb_invbar[1], scr_sbaralpha.value); //johnfitz -- scr_sbaralpha + } + else + { + Sbar_DrawPicAlpha (0, -24, sb_ibar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha + } + +// weapons + for (i=0 ; i<7 ; i++) + { + if (cl.items & (IT_SHOTGUN<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN< 1) + sb_updates = 0; // force update to remove flash + } + } + +// MED 01/04/97 +// hipnotic weapons + if (hipnotic) + { + int grenadeflashing=0; + for (i=0 ; i<4 ; i++) + { + if (cl.items & (1<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (1< 1) + sb_updates = 0; // force update to remove flash + } + } + } + + if (rogue) + { + // check for powered up weapon. + if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + { + for (i=0;i<5;i++) + { + if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) + { + Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]); + } + } + } + } + +// ammo counts + for (i=0 ; i<4 ; i++) + { + sprintf (num, "%3i", min(999,cl.stats[STAT_SHELLS+i])); //johnfitz -- cap displayed value to 999 + if (num[0] != ' ') + Sbar_DrawCharacter ( (6*i+1)*8 + 2, -24, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter ( (6*i+2)*8 + 2, -24, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter ( (6*i+3)*8 + 2, -24, 18 + num[2] - '0'); + } + + flashon = 0; + // items + for (i=0 ; i<6 ; i++) + if (cl.items & (1<<(17+i))) + { + time = cl.item_gettime[17+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + //MED 01/04/97 changed keys + if (!hipnotic || (i>1)) + { + Sbar_DrawPic (192 + i*16, -16, sb_items[i]); + } + } + if (time && time > cl.time - 2) + sb_updates = 0; + } + //MED 01/04/97 added hipnotic items + // hipnotic items + if (hipnotic) + { + for (i=0 ; i<2 ; i++) + if (cl.items & (1<<(24+i))) + { + time = cl.item_gettime[24+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPic (288 + i*16, -16, hsb_items[i]); + } + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + + if (rogue) + { + // new rogue items + for (i=0 ; i<2 ; i++) + { + if (cl.items & (1<<(29+i))) + { + time = cl.item_gettime[29+i]; + + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); + } + + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + } + else + { + // sigils + for (i=0 ; i<4 ; i++) + { + if (cl.items & (1<<(28+i))) + { + time = cl.item_gettime[28+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + Sbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]); + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + } +} + +//============================================================================= + +/* +=============== +Sbar_DrawFrags -- johnfitz -- heavy revision +=============== +*/ +void Sbar_DrawFrags (void) +{ + int numscores, i, x, color; + char num[12]; + scoreboard_t *s; + + Sbar_SortFrags (); + +// draw the text + numscores = min (scoreboardlines, 4); + + for (i=0, x=184; iname[0]) + continue; + + // top color + color = s->colors & 0xf0; + color = Sbar_ColorForMap (color); + Draw_Fill (x + 10, 1, 28, 4, color, 1); + + // bottom color + color = (s->colors & 15)<<4; + color = Sbar_ColorForMap (color); + Draw_Fill (x + 10, 5, 28, 3, color, 1); + + // number + sprintf (num, "%3i", s->frags); + Sbar_DrawCharacter (x + 12, -24, num[0]); + Sbar_DrawCharacter (x + 20, -24, num[1]); + Sbar_DrawCharacter (x + 28, -24, num[2]); + + // brackets + if (fragsort[i] == cl.viewentity - 1) + { + Sbar_DrawCharacter (x + 6, -24, 16); + Sbar_DrawCharacter (x + 32, -24, 17); + } + } +} + +//============================================================================= + + +/* +=============== +Sbar_DrawFace +=============== +*/ +void Sbar_DrawFace (void) +{ + int f, anim; + +// PGM 01/19/97 - team color drawing +// PGM 03/02/97 - fixed so color swatch only appears in CTF modes + if (rogue && (cl.maxclients != 1) && (teamplay.value>3) && (teamplay.value<7)) + { + int top, bottom; + int xofs; + char num[12]; + scoreboard_t *s; + + s = &cl.scores[cl.viewentity - 1]; + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + if (cl.gametype == GAME_DEATHMATCH) + xofs = 113; + else + xofs = ((vid.width - 320)>>1) + 113; + + Sbar_DrawPic (112, 0, rsb_teambord); + Draw_Fill (xofs, /*vid.height-*/24+3, 22, 9, top, 1); //johnfitz -- sbar coords are now relative + Draw_Fill (xofs, /*vid.height-*/24+12, 22, 9, bottom, 1); //johnfitz -- sbar coords are now relative + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + if (top==8) + { + if (num[0] != ' ') + Sbar_DrawCharacter(113, 3, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter(120, 3, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter(127, 3, 18 + num[2] - '0'); + } + else + { + Sbar_DrawCharacter ( 113, 3, num[0]); + Sbar_DrawCharacter ( 120, 3, num[1]); + Sbar_DrawCharacter ( 127, 3, num[2]); + } + + return; + } +// PGM 01/19/97 - team color drawing + + if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) ) + == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + { + Sbar_DrawPic (112, 0, sb_face_invis_invuln); + return; + } + if (cl.items & IT_QUAD) + { + Sbar_DrawPic (112, 0, sb_face_quad ); + return; + } + if (cl.items & IT_INVISIBILITY) + { + Sbar_DrawPic (112, 0, sb_face_invis ); + return; + } + if (cl.items & IT_INVULNERABILITY) + { + Sbar_DrawPic (112, 0, sb_face_invuln); + return; + } + + if (cl.stats[STAT_HEALTH] >= 100) + f = 4; + else + f = cl.stats[STAT_HEALTH] / 20; + + if (cl.time <= cl.faceanimtime) + { + anim = 1; + sb_updates = 0; // make sure the anim gets drawn over + } + else + anim = 0; + Sbar_DrawPic (112, 0, sb_faces[f][anim]); +} + +/* +=============== +Sbar_Draw +=============== +*/ +void Sbar_Draw (void) +{ + float w; //johnfitz + + if (scr_con_current == vid.height) + return; // console is full screen + + if (cl.intermission) + return; //johnfitz -- never draw sbar during intermission + + if (sb_updates >= vid.numpages && !gl_clear.value && scr_sbaralpha.value >= 1 && !isIntelVideo) //johnfitz -- gl_clear, scr_sbaralpha, intel workarounds from baker + return; + + sb_updates++; + + GL_SetCanvas (CANVAS_DEFAULT); //johnfitz + + //johnfitz -- don't waste fillrate by clearing the area behind the sbar + w = CLAMP (320.0f, scr_sbarscale.value * 320.0f, (float)glwidth); + if (sb_lines && glwidth > w) + { + if (scr_sbaralpha.value < 1) + Draw_TileClear (0, glheight - sb_lines, glwidth, sb_lines); + if (cl.gametype == GAME_DEATHMATCH) + Draw_TileClear (w, glheight - sb_lines, glwidth - w, sb_lines); + else + { + Draw_TileClear (0, glheight - sb_lines, (glwidth - w) / 2.0f, sb_lines); + Draw_TileClear ((glwidth - w) / 2.0f + w, glheight - sb_lines, (glwidth - w) / 2.0f, sb_lines); + } + } + //johnfitz + + GL_SetCanvas (CANVAS_SBAR); //johnfitz + + if (scr_viewsize.value < 110) //johnfitz -- check viewsize instead of sb_lines + { + Sbar_DrawInventory (); + if (cl.maxclients != 1) + Sbar_DrawFrags (); + } + + if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) + { + Sbar_DrawPicAlpha (0, 0, sb_scorebar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha + Sbar_DrawScoreboard (); + sb_updates = 0; + } + else if (scr_viewsize.value < 120) //johnfitz -- check viewsize instead of sb_lines + { + Sbar_DrawPicAlpha (0, 0, sb_sbar, scr_sbaralpha.value); //johnfitz -- scr_sbaralpha + + // keys (hipnotic only) + //MED 01/04/97 moved keys here so they would not be overwritten + if (hipnotic) + { + if (cl.items & IT_KEY1) + Sbar_DrawPic (209, 3, sb_items[0]); + if (cl.items & IT_KEY2) + Sbar_DrawPic (209, 12, sb_items[1]); + } + // armor + if (cl.items & IT_INVULNERABILITY) + { + Sbar_DrawNum (24, 0, 666, 3, 1); + Sbar_DrawPic (0, 0, draw_disc); + } + else + { + if (rogue) + { + Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, + cl.stats[STAT_ARMOR] <= 25); + if (cl.items & RIT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.items & RIT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.items & RIT_ARMOR1) + Sbar_DrawPic (0, 0, sb_armor[0]); + } + else + { + Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3 + , cl.stats[STAT_ARMOR] <= 25); + if (cl.items & IT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.items & IT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.items & IT_ARMOR1) + Sbar_DrawPic (0, 0, sb_armor[0]); + } + } + + // face + Sbar_DrawFace (); + + // health + Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3 + , cl.stats[STAT_HEALTH] <= 25); + + // ammo icon + if (rogue) + { + if (cl.items & RIT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.items & RIT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.items & RIT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.items & RIT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + else if (cl.items & RIT_LAVA_NAILS) + Sbar_DrawPic (224, 0, rsb_ammo[0]); + else if (cl.items & RIT_PLASMA_AMMO) + Sbar_DrawPic (224, 0, rsb_ammo[1]); + else if (cl.items & RIT_MULTI_ROCKETS) + Sbar_DrawPic (224, 0, rsb_ammo[2]); + } + else + { + if (cl.items & IT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.items & IT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.items & IT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.items & IT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + } + + Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, + cl.stats[STAT_AMMO] <= 10); + } + + //johnfitz -- removed the vid.width > 320 check here + if (cl.gametype == GAME_DEATHMATCH) + Sbar_MiniDeathmatchOverlay (); +} + +//============================================================================= + +/* +================== +Sbar_IntermissionNumber + +================== +*/ +void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Draw_Pic (x,y,sb_nums[color][frame]); //johnfitz -- stretched menus + x += 24; + ptr++; + } +} + +/* +================== +Sbar_DeathmatchOverlay + +================== +*/ +void Sbar_DeathmatchOverlay (void) +{ + qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + pic = Draw_CachePic ("gfx/ranking.lmp"); + M_DrawPic ((320-pic->width)/2, 8, pic); + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + + x = 80; //johnfitz -- simplified becuase some positioning is handled elsewhere + y = 40; + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y, 40, 4, top, 1); //johnfitz -- stretched overlays + Draw_Fill ( x, y+4, 40, 4, bottom, 1); //johnfitz -- stretched overlays + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Draw_Character ( x+8 , y, num[0]); //johnfitz -- stretched overlays + Draw_Character ( x+16 , y, num[1]); //johnfitz -- stretched overlays + Draw_Character ( x+24 , y, num[2]); //johnfitz -- stretched overlays + + if (k == cl.viewentity - 1) + Draw_Character ( x - 8, y, 12); //johnfitz -- stretched overlays + +#if 0 +{ + int total; + int n, minutes, tens, units; + + // draw time + total = cl.completed_time - s->entertime; + minutes = (int)total/60; + n = total - minutes*60; + tens = n/10; + units = n%10; + + sprintf (num, "%3i:%i%i", minutes, tens, units); + + M_Print ( x+48 , y, num); //johnfitz -- was Draw_String, changed for stretched overlays +} +#endif + + // draw name + M_Print (x+64, y, s->name); //johnfitz -- was Draw_String, changed for stretched overlays + + y += 10; + } + + GL_SetCanvas (CANVAS_SBAR); //johnfitz +} + +/* +================== +Sbar_MiniDeathmatchOverlay +================== +*/ +void Sbar_MiniDeathmatchOverlay (void) +{ + int i, k, l, top, bottom, x, y, f, numlines; + char num[12]; + float scale; //johnfitz + qpic_t *pic; + scoreboard_t *s; + + scale = CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); //johnfitz + + //MAX_SCOREBOARDNAME = 32, so total width for this overlay plus sbar is 632, but we can cut off some i guess + if (glwidth/scale < 512 || scr_viewsize.value >= 120) //johnfitz -- test should consider scr_sbarscale + return; + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + numlines = (scr_viewsize.value >= 110) ? 3 : 6; //johnfitz + + //find us + for (i = 0; i < scoreboardlines; i++) + if (fragsort[i] == cl.viewentity - 1) + break; + if (i == scoreboardlines) // we're not there + i = 0; + else // figure out start + i = i - numlines/2; + if (i > scoreboardlines - numlines) + i = scoreboardlines - numlines; + if (i < 0) + i = 0; + + x = 324; + y = (scr_viewsize.value >= 110) ? 24 : 0; //johnfitz -- start at the right place + for ( ; i < scoreboardlines && y <= 48; i++, y+=8) //johnfitz -- change y init, test, inc + { + k = fragsort[i]; + s = &cl.scores[k]; + if (!s->name[0]) + continue; + + // colors + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y+1, 40, 4, top, 1); + Draw_Fill ( x, y+5, 40, 3, bottom, 1); + + // number + f = s->frags; + sprintf (num, "%3i",f); + Draw_Character ( x+8 , y, num[0]); + Draw_Character ( x+16 , y, num[1]); + Draw_Character ( x+24 , y, num[2]); + + // brackets + if (k == cl.viewentity - 1) + { + Draw_Character ( x, y, 16); + Draw_Character ( x+32, y, 17); + } + + // name + Draw_String (x+48, y, s->name); + } +} + +/* +================== +Sbar_IntermissionOverlay +================== +*/ +void Sbar_IntermissionOverlay (void) +{ + qpic_t *pic; + int dig; + int num; + + if (cl.gametype == GAME_DEATHMATCH) + { + Sbar_DeathmatchOverlay (); + return; + } + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + pic = Draw_CachePic ("gfx/complete.lmp"); + Draw_Pic (64, 24, pic); + + pic = Draw_CachePic ("gfx/inter.lmp"); + Draw_Pic (0, 56, pic); + + dig = cl.completed_time/60; + Sbar_IntermissionNumber (152, 64, dig, 3, 0); //johnfitz -- was 160 + num = cl.completed_time - dig*60; + Draw_Pic (224,64,sb_colon); //johnfitz -- was 234 + Draw_Pic (240,64,sb_nums[0][num/10]); //johnfitz -- was 246 + Draw_Pic (264,64,sb_nums[0][num%10]); //johnfitz -- was 266 + + Sbar_IntermissionNumber (152, 104, cl.stats[STAT_SECRETS], 3, 0); //johnfitz -- was 160 + Draw_Pic (224,104,sb_slash); //johnfitz -- was 232 + Sbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); //johnfitz -- was 248 + + Sbar_IntermissionNumber (152, 144, cl.stats[STAT_MONSTERS], 3, 0); //johnfitz -- was 160 + Draw_Pic (224,144,sb_slash); //johnfitz -- was 232 + Sbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0); //johnfitz -- was 248 +} + + +/* +================== +Sbar_FinaleOverlay +================== +*/ +void Sbar_FinaleOverlay (void) +{ + qpic_t *pic; + + GL_SetCanvas (CANVAS_MENU); //johnfitz + + pic = Draw_CachePic ("gfx/finale.lmp"); + Draw_Pic ( (320 - pic->width)/2, 16, pic); //johnfitz -- stretched menus +} diff --git a/Quake/sbar.h b/Quake/sbar.h new file mode 100644 index 00000000..819552fd --- /dev/null +++ b/Quake/sbar.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// the status bar is only redrawn if something has changed, but if anything +// does, the entire thing will be redrawn for the next vid.numpages frames. + +extern int sb_lines; // scan lines to draw + +void Sbar_Init (void); + +void Sbar_Changed (void); +// call whenever any of the client stats represented on the sbar changes + +void Sbar_Draw (void); +// called every frame by screen + +void Sbar_IntermissionOverlay (void); +// called each frame after the level has been completed + +void Sbar_FinaleOverlay (void); diff --git a/Quake/screen.h b/Quake/screen.h new file mode 100644 index 00000000..e4c1872f --- /dev/null +++ b/Quake/screen.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// screen.h + +void SCR_Init (void); + +void SCR_UpdateScreen (void); + + +void SCR_SizeUp (void); +void SCR_SizeDown (void); +void SCR_BringDownConsole (void); +void SCR_CenterPrint (char *str); + +void SCR_BeginLoadingPlaque (void); +void SCR_EndLoadingPlaque (void); + +int SCR_ModalMessage (char *text, float timeout); //johnfitz -- added timeout + +extern float scr_con_current; +extern float scr_conlines; // lines of console to display + +extern int sb_lines; + +extern int clearnotify; // set to 0 whenever notify text is drawn +extern qboolean scr_disabled_for_loading; +extern qboolean scr_skipupdate; + +extern cvar_t scr_viewsize; + +extern cvar_t scr_sbaralpha; //johnfitz + +extern qboolean block_drawing; + +void SCR_UpdateWholeScreen (void); + +//johnfitz -- stuff for 2d drawing control +typedef enum { + CANVAS_NONE, + CANVAS_DEFAULT, + CANVAS_CONSOLE, + CANVAS_MENU, + CANVAS_SBAR, + CANVAS_WARPIMAGE, + CANVAS_CROSSHAIR, + CANVAS_BOTTOMLEFT, + CANVAS_BOTTOMRIGHT, + CANVAS_TOPRIGHT, +} canvastype; +extern cvar_t scr_menuscale; +extern cvar_t scr_sbarscale; +extern cvar_t scr_conwidth; +extern cvar_t scr_conscale; +extern cvar_t scr_crosshaircale; +//johnfitz + +extern int scr_tileclear_updates; //johnfitz diff --git a/Quake/server.h b/Quake/server.h new file mode 100644 index 00000000..143104b5 --- /dev/null +++ b/Quake/server.h @@ -0,0 +1,228 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// server.h + +typedef struct +{ + int maxclients; + int maxclientslimit; + struct client_s *clients; // [maxclients] + int serverflags; // episode completion information + qboolean changelevel_issued; // cleared when at SV_SpawnServer +} server_static_t; + +//============================================================================= + +typedef enum {ss_loading, ss_active} server_state_t; + +typedef struct +{ + qboolean active; // false if only a net client + + qboolean paused; + qboolean loadgame; // handle connections specially + + double time; + + int lastcheck; // used by PF_checkclient + double lastchecktime; + + char name[64]; // map name + char modelname[64]; // maps/.bsp, for model_precache[0] + struct model_s *worldmodel; + char *model_precache[MAX_MODELS]; // NULL terminated + struct model_s *models[MAX_MODELS]; + char *sound_precache[MAX_SOUNDS]; // NULL terminated + char *lightstyles[MAX_LIGHTSTYLES]; + int num_edicts; + int max_edicts; + edict_t *edicts; // can NOT be array indexed, because + // edict_t is variable sized, but can + // be used to reference the world ent + server_state_t state; // some actions are only valid during load + + sizebuf_t datagram; + byte datagram_buf[MAX_DATAGRAM]; + + sizebuf_t reliable_datagram; // copied to all clients at end of frame + byte reliable_datagram_buf[MAX_DATAGRAM]; + + sizebuf_t signon; + byte signon_buf[MAX_MSGLEN-2]; //johnfitz -- was 8192, now uses MAX_MSGLEN + + unsigned protocol; //johnfitz +} server_t; + + +#define NUM_PING_TIMES 16 +#define NUM_SPAWN_PARMS 16 + +typedef struct client_s +{ + qboolean active; // false = client is free + qboolean spawned; // false = don't send datagrams + qboolean dropasap; // has been told to go to another level + qboolean privileged; // can execute any host command + qboolean sendsignon; // only valid before spawned + + double last_message; // reliable messages must be sent + // periodically + + struct qsocket_s *netconnection; // communications handle + + usercmd_t cmd; // movement + vec3_t wishdir; // intended motion calced from cmd + + sizebuf_t message; // can be added to at any time, + // copied and clear once per frame + byte msgbuf[MAX_MSGLEN]; + edict_t *edict; // EDICT_NUM(clientnum+1) + char name[32]; // for printing to other people + int colors; + + float ping_times[NUM_PING_TIMES]; + int num_pings; // ping_times[num_pings%NUM_PING_TIMES] + +// spawn parms are carried from level to level + float spawn_parms[NUM_SPAWN_PARMS]; + +// client known data for deltas + int old_frags; +} client_t; + + +//============================================================================= + +// edict->movetype values +#define MOVETYPE_NONE 0 // never moves +#define MOVETYPE_ANGLENOCLIP 1 +#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // gravity +#define MOVETYPE_STEP 4 // gravity, special edge handling +#define MOVETYPE_FLY 5 +#define MOVETYPE_TOSS 6 // gravity +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 + +// edict->solid values +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block + +// edict->deadflag values +#define DEAD_NO 0 +#define DEAD_DYING 1 +#define DEAD_DEAD 2 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// edict->flags +#define FL_FLY 1 +#define FL_SWIM 2 +//#define FL_GLIMPSE 4 +#define FL_CONVEYOR 4 +#define FL_CLIENT 8 +#define FL_INWATER 16 +#define FL_MONSTER 32 +#define FL_GODMODE 64 +#define FL_NOTARGET 128 +#define FL_ITEM 256 +#define FL_ONGROUND 512 +#define FL_PARTIALGROUND 1024 // not all corners are valid +#define FL_WATERJUMP 2048 // player jumping out of water +#define FL_JUMPRELEASED 4096 // for jump debouncing + +// entity effects + +#define EF_BRIGHTFIELD 1 +#define EF_MUZZLEFLASH 2 +#define EF_BRIGHTLIGHT 4 +#define EF_DIMLIGHT 8 + +#define SPAWNFLAG_NOT_EASY 256 +#define SPAWNFLAG_NOT_MEDIUM 512 +#define SPAWNFLAG_NOT_HARD 1024 +#define SPAWNFLAG_NOT_DEATHMATCH 2048 + +//============================================================================ + +extern cvar_t teamplay; +extern cvar_t skill; +extern cvar_t deathmatch; +extern cvar_t coop; +extern cvar_t fraglimit; +extern cvar_t timelimit; + +extern server_static_t svs; // persistant server info +extern server_t sv; // local server + +extern client_t *host_client; + +extern jmp_buf host_abortserver; + +extern double host_time; + +extern edict_t *sv_player; + +//=========================================================== + +void SV_Init (void); + +void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); +void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, + float attenuation); + +void SV_DropClient (qboolean crash); + +void SV_SendClientMessages (void); +void SV_ClearDatagram (void); + +int SV_ModelIndex (char *name); + +void SV_SetIdealPitch (void); + +void SV_AddUpdates (void); + +void SV_ClientThink (void); +void SV_AddClientToServer (struct qsocket_s *ret); + +void SV_ClientPrintf (char *fmt, ...); +void SV_BroadcastPrintf (char *fmt, ...); + +void SV_Physics (void); + +qboolean SV_CheckBottom (edict_t *ent); +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); + +void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg); + +void SV_MoveToGoal (void); + +void SV_CheckForNewClients (void); +void SV_RunClients (void); +void SV_SaveSpawnparms (); +void SV_SpawnServer (char *server); diff --git a/Quake/snd_dma.c b/Quake/snd_dma.c new file mode 100644 index 00000000..072de83c --- /dev/null +++ b/Quake/snd_dma.c @@ -0,0 +1,967 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_dma.c -- main control for any streaming sound output device + +#include "quakedef.h" + +void S_Play(void); +void S_PlayVol(void); +void S_SoundList(void); +void S_Update_(); +void S_StopAllSounds(qboolean clear); +void S_StopAllSoundsC(void); + +// ======================================================================= +// Internal sound data & structures +// ======================================================================= + +channel_t channels[MAX_CHANNELS]; +int total_channels; + +int snd_blocked = 0; +static qboolean snd_ambient = 1; +qboolean snd_initialized = false; + +// pointer should go away +volatile dma_t *shm = 0; +volatile dma_t sn; + +vec3_t listener_origin; +vec3_t listener_forward; +vec3_t listener_right; +vec3_t listener_up; +vec_t sound_nominal_clip_dist=1000.0; + +int soundtime; // sample PAIRS +int paintedtime; // sample PAIRS + + +#define MAX_SFX 512 +sfx_t *known_sfx; // hunk allocated [MAX_SFX] +int num_sfx; + +sfx_t *ambient_sfx[NUM_AMBIENTS]; + +int sound_started=0; + +cvar_t bgmvolume = {"bgmvolume", "1", true}; +cvar_t volume = {"volume", "0.7", true}; + +cvar_t nosound = {"nosound", "0"}; +cvar_t precache = {"precache", "1"}; +cvar_t loadas8bit = {"loadas8bit", "0"}; +cvar_t bgmbuffer = {"bgmbuffer", "4096"}; +cvar_t ambient_level = {"ambient_level", "0.3"}; +cvar_t ambient_fade = {"ambient_fade", "100"}; +cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"}; +cvar_t snd_show = {"snd_show", "0"}; +cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true}; +cvar_t sndspeed = {"sndspeed", "11025"}; + + +// ==================================================================== +// User-setable variables +// ==================================================================== + + +// +// Fake dma is a synchronous faking of the DMA progress used for +// isolating performance in the renderer. The fakedma_updates is +// number of times S_Update() is called per second. +// + +qboolean fakedma = false; +int fakedma_updates = 15; + + +void S_AmbientOff (void) +{ + snd_ambient = false; +} + + +void S_AmbientOn (void) +{ + snd_ambient = true; +} + + +void S_SoundInfo_f(void) +{ + if (!sound_started || !shm) + { + Con_Printf ("sound system not started\n"); + return; + } + + Con_Printf("%5d stereo\n", shm->channels - 1); + Con_Printf("%5d samples\n", shm->samples); + Con_Printf("%5d samplepos\n", shm->samplepos); + Con_Printf("%5d samplebits\n", shm->samplebits); + Con_Printf("%5d submission_chunk\n", shm->submission_chunk); + Con_Printf("%5d speed\n", shm->speed); + Con_Printf("0x%x dma buffer\n", shm->buffer); + Con_Printf("%5d total_channels\n", total_channels); +} + + +/* +================ +S_Startup +================ +*/ + +void S_Startup (void) +{ + int rc; + + if (!snd_initialized) + return; + + if (!fakedma) + { + rc = SNDDMA_Init(); + + if (!rc) + { +#ifndef _WIN32 + Con_Printf("S_Startup: SNDDMA_Init failed.\n"); +#endif + sound_started = 0; + return; + } + } + + sound_started = 1; +} + + +/* +================ +S_Init +================ +*/ +void S_Init (void) +{ + if (COM_CheckParm("-nosound")) + return; + + //johnfitz -- clean up init readouts + Con_Printf("Sound Initialization\n"); + //Con_Printf("------------- Init Sound -------------\n"); + //Con_Printf("%cSound Init\n", 2); + //johnfitz + + if (COM_CheckParm("-simsound")) + fakedma = true; + + Cmd_AddCommand("play", S_Play); + Cmd_AddCommand("playvol", S_PlayVol); + Cmd_AddCommand("stopsound", S_StopAllSoundsC); + Cmd_AddCommand("soundlist", S_SoundList); + Cmd_AddCommand("soundinfo", S_SoundInfo_f); + + Cvar_RegisterVariable(&nosound, NULL); + Cvar_RegisterVariable(&volume, NULL); + Cvar_RegisterVariable(&precache, NULL); + Cvar_RegisterVariable(&loadas8bit, NULL); + Cvar_RegisterVariable(&bgmvolume, NULL); + Cvar_RegisterVariable(&bgmbuffer, NULL); + Cvar_RegisterVariable(&ambient_level, NULL); + Cvar_RegisterVariable(&ambient_fade, NULL); + Cvar_RegisterVariable(&snd_noextraupdate, NULL); + Cvar_RegisterVariable(&snd_show, NULL); + Cvar_RegisterVariable(&_snd_mixahead, NULL); + Cvar_RegisterVariable(&sndspeed, NULL); + + if (COM_CheckParm("-sndspeed")) + { + sndspeed.value = Q_atoi(com_argv[COM_CheckParm("-sndspeed")+1]); + } + + if (host_parms.memsize < 0x800000) + { + Cvar_Set ("loadas8bit", "1"); + Con_Printf ("loading all sounds as 8bit\n"); + } + + + + snd_initialized = true; + + S_Startup (); + + SND_InitScaletable (); + + known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t"); + num_sfx = 0; + +// create a piece of DMA memory + + if (fakedma) + { + shm = (void *) Hunk_AllocName(sizeof(*shm), "shm"); + shm->splitbuffer = 0; + shm->samplebits = 16; + shm->speed = 22050; + shm->channels = 2; + shm->samples = 32768; + shm->samplepos = 0; + shm->soundalive = true; + shm->gamealive = true; + shm->submission_chunk = 1; + shm->buffer = Hunk_AllocName(1<<16, "shmbuf"); + } + + Con_Printf ("Sound sampling rate: %i\n", shm->speed); + + // provides a tick sound until washed clean + +// if (shm->buffer) +// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging + + ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav"); + ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav"); + + S_StopAllSounds (true); +} + + +// ======================================================================= +// Shutdown sound engine +// ======================================================================= + +void S_Shutdown(void) +{ + + if (!sound_started) + return; + + if (shm) + shm->gamealive = 0; + + shm = 0; + sound_started = 0; + + if (!fakedma) + { + SNDDMA_Shutdown(); + } +} + + +// ======================================================================= +// Load a sound +// ======================================================================= + +/* +================== +S_FindName + +================== +*/ +sfx_t *S_FindName (char *name) +{ + int i; + sfx_t *sfx; + + if (!name) + Sys_Error ("S_FindName: NULL\n"); + + if (Q_strlen(name) >= MAX_QPATH) + Sys_Error ("Sound name too long: %s", name); + +// see if already loaded + for (i=0 ; i < num_sfx ; i++) + if (!Q_strcmp(known_sfx[i].name, name)) + { + return &known_sfx[i]; + } + + if (num_sfx == MAX_SFX) + Sys_Error ("S_FindName: out of sfx_t"); + + sfx = &known_sfx[i]; + strcpy (sfx->name, name); + + num_sfx++; + + return sfx; +} + + +/* +================== +S_TouchSound + +================== +*/ +void S_TouchSound (char *name) +{ + sfx_t *sfx; + + if (!sound_started) + return; + + sfx = S_FindName (name); + Cache_Check (&sfx->cache); +} + +/* +================== +S_PrecacheSound + +================== +*/ +sfx_t *S_PrecacheSound (char *name) +{ + sfx_t *sfx; + + if (!sound_started || nosound.value) + return NULL; + + sfx = S_FindName (name); + +// cache it in + if (precache.value) + S_LoadSound (sfx); + + return sfx; +} + + +//============================================================================= + +/* +================= +SND_PickChannel +================= +*/ +channel_t *SND_PickChannel(int entnum, int entchannel) +{ + int ch_idx; + int first_to_die; + int life_left; + +// Check for replacement sound, or find the best one to replace + first_to_die = -1; + life_left = 0x7fffffff; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + if (entchannel != 0 // channel 0 never overrides + && channels[ch_idx].entnum == entnum + && (channels[ch_idx].entchannel == entchannel || entchannel == -1) ) + { // allways override sound from same entity + first_to_die = ch_idx; + break; + } + + // don't let monster sounds override player sounds + if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx) + continue; + + if (channels[ch_idx].end - paintedtime < life_left) + { + life_left = channels[ch_idx].end - paintedtime; + first_to_die = ch_idx; + } + } + + if (first_to_die == -1) + return NULL; + + if (channels[first_to_die].sfx) + channels[first_to_die].sfx = NULL; + + return &channels[first_to_die]; +} + +/* +================= +SND_Spatialize +================= +*/ +void SND_Spatialize(channel_t *ch) +{ + vec_t dot; + vec_t dist; + vec_t lscale, rscale, scale; + vec3_t source_vec; + sfx_t *snd; + /* unused -- kristian + vec_t ldist, rdist; + */ + +// anything coming from the view entity will allways be full volume + if (ch->entnum == cl.viewentity) + { + ch->leftvol = ch->master_vol; + ch->rightvol = ch->master_vol; + return; + } + +// calculate stereo seperation and distance attenuation + + snd = ch->sfx; + VectorSubtract(ch->origin, listener_origin, source_vec); + + dist = VectorNormalize(source_vec) * ch->dist_mult; + + dot = DotProduct(listener_right, source_vec); + + if (shm->channels == 1) + { + rscale = 1.0; + lscale = 1.0; + } + else + { + rscale = 1.0 + dot; + lscale = 1.0 - dot; + } + +// add in distance effect + scale = (1.0 - dist) * rscale; + ch->rightvol = (int) (ch->master_vol * scale); + if (ch->rightvol < 0) + ch->rightvol = 0; + + scale = (1.0 - dist) * lscale; + ch->leftvol = (int) (ch->master_vol * scale); + if (ch->leftvol < 0) + ch->leftvol = 0; +} + + +// ======================================================================= +// Start a sound effect +// ======================================================================= + +void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) +{ + channel_t *target_chan, *check; + sfxcache_t *sc; + int vol; + int ch_idx; + int skip; + + if (!sound_started) + return; + + if (!sfx) + return; + + if (nosound.value) + return; + + vol = fvol*255; + +// pick a channel to play on + target_chan = SND_PickChannel(entnum, entchannel); + if (!target_chan) + return; + +// spatialize + memset (target_chan, 0, sizeof(*target_chan)); + VectorCopy(origin, target_chan->origin); + target_chan->dist_mult = attenuation / sound_nominal_clip_dist; + target_chan->master_vol = vol; + target_chan->entnum = entnum; + target_chan->entchannel = entchannel; + SND_Spatialize(target_chan); + + if (!target_chan->leftvol && !target_chan->rightvol) + return; // not audible at all + +// new channel + sc = S_LoadSound (sfx); + if (!sc) + { + target_chan->sfx = NULL; + return; // couldn't load the sound's data + } + + target_chan->sfx = sfx; + target_chan->pos = 0.0; + target_chan->end = paintedtime + sc->length; + +// if an identical sound has also been started this frame, offset the pos +// a bit to keep it from just making the first one louder + check = &channels[NUM_AMBIENTS]; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++) + { + if (check == target_chan) + continue; + if (check->sfx == sfx && !check->pos) + { + skip = rand () % (int)(0.1*shm->speed); + if (skip >= target_chan->end) + skip = target_chan->end - 1; + target_chan->pos += skip; + target_chan->end -= skip; + break; + } + + } +} + +void S_StopSound(int entnum, int entchannel) +{ + int i; + + for (i=0 ; ibuffer) + return; + + if (shm->samplebits == 8) + clear = 0x80; + else + clear = 0; + + Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8); +} + + +/* +================= +S_StaticSound +================= +*/ +void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) +{ + channel_t *ss; + sfxcache_t *sc; + + if (!sfx) + return; + + if (total_channels == MAX_CHANNELS) + { + Con_Printf ("total_channels == MAX_CHANNELS\n"); + return; + } + + ss = &channels[total_channels]; + total_channels++; + + sc = S_LoadSound (sfx); + if (!sc) + return; + + if (sc->loopstart == -1) + { + Con_Printf ("Sound %s not looped\n", sfx->name); + return; + } + + ss->sfx = sfx; + VectorCopy (origin, ss->origin); + ss->master_vol = vol; + ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; + ss->end = paintedtime + sc->length; + + SND_Spatialize (ss); +} + + +//============================================================================= + +/* +=================== +S_UpdateAmbientSounds +=================== +*/ +void S_UpdateAmbientSounds (void) +{ + mleaf_t *l; + float vol; + int ambient_channel; + channel_t *chan; + + if (!snd_ambient) + return; + + //johnfitz -- no ambients when disconnected + if (cls.state != ca_connected) + return; + //johnfitz + +// calc ambient sound levels + if (!cl.worldmodel) + return; + + l = Mod_PointInLeaf (listener_origin, cl.worldmodel); + if (!l || !ambient_level.value) + { + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) + channels[ambient_channel].sfx = NULL; + return; + } + + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) + { + chan = &channels[ambient_channel]; + chan->sfx = ambient_sfx[ambient_channel]; + + vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; + if (vol < 8) + vol = 0; + + // don't adjust volume too fast + if (chan->master_vol < vol) + { + chan->master_vol += host_frametime * ambient_fade.value; + if (chan->master_vol > vol) + chan->master_vol = vol; + } + else if (chan->master_vol > vol) + { + chan->master_vol -= host_frametime * ambient_fade.value; + if (chan->master_vol < vol) + chan->master_vol = vol; + } + + chan->leftvol = chan->rightvol = chan->master_vol; + } +} + + +/* +============ +S_Update + +Called once each time through the main loop +============ +*/ +void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) +{ + int i, j; + int total; + channel_t *ch; + channel_t *combine; + + if (!sound_started || (snd_blocked > 0)) + return; + + VectorCopy(origin, listener_origin); + VectorCopy(forward, listener_forward); + VectorCopy(right, listener_right); + VectorCopy(up, listener_up); + +// update general area ambient sound sources + S_UpdateAmbientSounds (); + + combine = NULL; + +// update spatialization for static and dynamic sounds + ch = channels+NUM_AMBIENTS; + for (i=NUM_AMBIENTS ; isfx) + continue; + SND_Spatialize(ch); // respatialize channel + if (!ch->leftvol && !ch->rightvol) + continue; + + // try to combine static sounds with a previous channel of the same + // sound effect so we don't mix five torches every frame + + if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) + { + // see if it can just use the last one + if (combine && combine->sfx == ch->sfx) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + continue; + } + // search for one + combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; + for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; jsfx == ch->sfx) + break; + + if (j == total_channels) + { + combine = NULL; + } + else + { + if (combine != ch) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + } + continue; + } + } + + + } + +// +// debugging output +// + if (snd_show.value) + { + total = 0; + ch = channels; + for (i=0 ; isfx && (ch->leftvol || ch->rightvol) ) + { + //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); + total++; + } + + Con_Printf ("----(%i)----\n", total); + } + +// mix some sound + S_Update_(); +} + +void GetSoundtime(void) +{ + int samplepos; + static int buffers; + static int oldsamplepos; + int fullsamples; + + fullsamples = shm->samples / shm->channels; + +// it is possible to miscount buffers if it has wrapped twice between +// calls to S_Update. Oh well. +#ifdef __sun__ + soundtime = SNDDMA_GetSamples(); +#else + samplepos = SNDDMA_GetDMAPos(); + + + if (samplepos < oldsamplepos) + { + buffers++; // buffer wrapped + + if (paintedtime > 0x40000000) + { // time to chop things off to avoid 32 bit limits + buffers = 0; + paintedtime = fullsamples; + S_StopAllSounds (true); + } + } + oldsamplepos = samplepos; + + soundtime = buffers*fullsamples + samplepos/shm->channels; +#endif +} + +void S_ExtraUpdate (void) +{ + + if (snd_noextraupdate.value) + return; // don't pollute timings + S_Update_(); +} + +void S_Update_(void) +{ + unsigned endtime; + int samps; + + if (!sound_started || (snd_blocked > 0)) + return; + +// Updates DMA time + GetSoundtime(); + +// check to make sure that we haven't overshot + if (paintedtime < soundtime) + { + //Con_Printf ("S_Update_ : overflow\n"); + paintedtime = soundtime; + } + +// mix ahead of current position + endtime = soundtime + _snd_mixahead.value * shm->speed; + samps = shm->samples >> (shm->channels-1); + if (endtime - soundtime > samps) + endtime = soundtime + samps; + + S_PaintChannels (endtime); + +// SNDDMA_Submit (); +} + +/* +=============================================================================== + +console functions + +=============================================================================== +*/ + +void S_Play(void) +{ + static int hash=345; + int i; + char name[256]; + sfx_t *sfx; + + i = 1; + while (icache); + if (!sc) + continue; + size = sc->length*sc->width*(sc->stereo+1); + total += size; + if (sc->loopstart >= 0) + Con_SafePrintf ("L"); //johnfitz -- was Con_Printf + else + Con_SafePrintf (" "); //johnfitz -- was Con_Printf + Con_SafePrintf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); //johnfitz -- was Con_Printf + } + Con_Printf ("%i sounds, %i bytes\n", num_sfx, total); //johnfitz -- added count +} + + +void S_LocalSound (char *sound) +{ + sfx_t *sfx; + + if (nosound.value) + return; + if (!sound_started) + return; + + sfx = S_PrecacheSound (sound); + if (!sfx) + { + Con_Printf ("S_LocalSound: can't cache %s\n", sound); + return; + } + S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1); +} + + +void S_ClearPrecache (void) +{ +} + + +void S_BeginPrecaching (void) +{ +} + + +void S_EndPrecaching (void) +{ +} + diff --git a/Quake/snd_mem.c b/Quake/snd_mem.c new file mode 100644 index 00000000..098ac5ab --- /dev/null +++ b/Quake/snd_mem.c @@ -0,0 +1,341 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_mem.c: sound caching + +#include "quakedef.h" + +int cache_full_cycle; + +byte *S_Alloc (int size); + +/* +================ +ResampleSfx +================ +*/ +void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data) +{ + int outcount; + int srcsample; + float stepscale; + int i; + int sample, samplefrac, fracstep; + sfxcache_t *sc; + + sc = Cache_Check (&sfx->cache); + if (!sc) + return; + + stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2 + + outcount = sc->length / stepscale; + sc->length = outcount; + if (sc->loopstart != -1) + sc->loopstart = sc->loopstart / stepscale; + + sc->speed = shm->speed; + if (loadas8bit.value) + sc->width = 1; + else + sc->width = inwidth; + sc->stereo = 0; + +// resample / decimate to the current source rate + + if (stepscale == 1 && inwidth == 1 && sc->width == 1) + { +// fast special case + for (i=0 ; idata)[i] + = (int)( (unsigned char)(data[i]) - 128); + } + else + { +// general case + samplefrac = 0; + fracstep = stepscale*256; + for (i=0 ; i> 8; + samplefrac += fracstep; + if (inwidth == 2) + sample = LittleShort ( ((short *)data)[srcsample] ); + else + sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; + if (sc->width == 2) + ((short *)sc->data)[i] = sample; + else + ((signed char *)sc->data)[i] = sample >> 8; + } + } +} + +//============================================================================= + +/* +============== +S_LoadSound +============== +*/ +sfxcache_t *S_LoadSound (sfx_t *s) +{ + char namebuffer[256]; + byte *data; + wavinfo_t info; + int len; + float stepscale; + sfxcache_t *sc; + byte stackbuf[1*1024]; // avoid dirtying the cache heap + +// see if still in memory + sc = Cache_Check (&s->cache); + if (sc) + return sc; + +//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); +// load it in + Q_strcpy(namebuffer, "sound/"); + Q_strcat(namebuffer, s->name); + +// Con_Printf ("loading %s\n",namebuffer); + + data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); + + if (!data) + { + Con_Printf ("Couldn't load %s\n", namebuffer); + return NULL; + } + + info = GetWavinfo (s->name, data, com_filesize); + if (info.channels != 1) + { + Con_Printf ("%s is a stereo sample\n",s->name); + return NULL; + } + + stepscale = (float)info.rate / shm->speed; + len = info.samples / stepscale; + + len = len * info.width * info.channels; + + sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); + if (!sc) + return NULL; + + sc->length = info.samples; + sc->loopstart = info.loopstart; + sc->speed = info.rate; + sc->width = info.width; + sc->stereo = info.channels; + + ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); + + return sc; +} + + + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + + +short GetLittleShort(void) +{ + short val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + data_p += 2; + return val; +} + +int GetLittleLong(void) +{ + int val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + val = val + (*(data_p+2)<<16); + val = val + (*(data_p+3)<<24); + data_p += 4; + return val; +} + +void FindNextChunk(char *name) +{ + while (1) + { + data_p=last_chunk; + + if (data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = GetLittleLong(); + if (iff_chunk_len < 0) + { + data_p = NULL; + return; + } +// if (iff_chunk_len > 1024*1024) +// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!Q_strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p=iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = GetLittleLong(); + Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset (&info, 0, sizeof(info)); + + if (!wav) + return info; + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4))) + { + Con_Printf("Missing RIFF/WAVE chunks\n"); + return info; + } + +// get "fmt " chunk + iff_data = data_p + 12; +// DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + Con_Printf("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + Con_Printf("Microsoft PCM format only\n"); + return info; + } + + info.channels = GetLittleShort(); + info.rate = GetLittleLong(); + data_p += 4+2; + info.width = GetLittleShort() / 8; + +// get cue chunk + FindChunk("cue "); + if (data_p) + { + data_p += 32; + info.loopstart = GetLittleLong(); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp (data_p + 28, "mark", 4)) + { // this is not a proper parse, but it works with cooledit... + data_p += 24; + i = GetLittleLong (); // samples in loop + info.samples = info.loopstart + i; +// Con_Printf("looped length: %i\n", i); + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + Con_Printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong () / info.width; + + if (info.samples) + { + if (samples < info.samples) + Sys_Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + diff --git a/Quake/snd_mix.c b/Quake/snd_mix.c new file mode 100644 index 00000000..2e4c0c85 --- /dev/null +++ b/Quake/snd_mix.c @@ -0,0 +1,295 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_mix.c -- portable code to mix sounds for snd_dma.c + +#include "quakedef.h" + +#define DWORD unsigned long + +#define PAINTBUFFER_SIZE 512 +portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; +int snd_scaletable[32][256]; +int *snd_p, snd_linear_count, snd_vol; +short *snd_out; + +void Snd_WriteLinearBlastStereo16 (void); + +void Snd_WriteLinearBlastStereo16 (void) +{ + int i; + int val; + + for (i=0 ; i>8; + if (val > 0x7fff) + snd_out[i] = 0x7fff; + else if (val < (short)0x8000) + snd_out[i] = (short)0x8000; + else + snd_out[i] = val; + + val = (snd_p[i+1]*snd_vol)>>8; + if (val > 0x7fff) + snd_out[i+1] = 0x7fff; + else if (val < (short)0x8000) + snd_out[i+1] = (short)0x8000; + else + snd_out[i+1] = val; + } +} + +void S_TransferStereo16 (int endtime) +{ + int lpos; + int lpaintedtime; + DWORD *pbuf; + + snd_vol = volume.value*256; + + snd_p = (int *) paintbuffer; + lpaintedtime = paintedtime; + pbuf = (DWORD *)shm->buffer; + + while (lpaintedtime < endtime) + { + // handle recirculating buffer issues + lpos = lpaintedtime & ((shm->samples>>1)-1); + + snd_out = (short *) pbuf + (lpos<<1); + + snd_linear_count = (shm->samples>>1) - lpos; + if (lpaintedtime + snd_linear_count > endtime) + snd_linear_count = endtime - lpaintedtime; + + snd_linear_count <<= 1; + + // write a linear blast of samples + Snd_WriteLinearBlastStereo16 (); + + snd_p += snd_linear_count; + lpaintedtime += (snd_linear_count>>1); + } +} + +void S_TransferPaintBuffer(int endtime) +{ + int out_idx; + int count; + int out_mask; + int *p; + int step; + int val; + int snd_vol; + DWORD *pbuf; + + if (shm->samplebits == 16 && shm->channels == 2) + { + S_TransferStereo16 (endtime); + return; + } + + p = (int *) paintbuffer; + count = (endtime - paintedtime) * shm->channels; + out_mask = shm->samples - 1; + out_idx = paintedtime * shm->channels & out_mask; + step = 3 - shm->channels; + snd_vol = volume.value*256; + pbuf = (DWORD *)shm->buffer; + + if (shm->samplebits == 16) + { + short *out = (short *) pbuf; + while (count--) + { + val = (*p * snd_vol) >> 8; + p+= step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short)0x8000) + val = (short)0x8000; + out[out_idx] = val; + out_idx = (out_idx + 1) & out_mask; + } + } + else if (shm->samplebits == 8) + { + unsigned char *out = (unsigned char *) pbuf; + while (count--) + { + val = (*p * snd_vol) >> 8; + p+= step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short)0x8000) + val = (short)0x8000; + out[out_idx] = (val>>8) + 128; + out_idx = (out_idx + 1) & out_mask; + } + } +} + + +/* +=============================================================================== + +CHANNEL MIXING + +=============================================================================== +*/ + +void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime); +void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime); + +void S_PaintChannels(int endtime) +{ + int i; + int end; + channel_t *ch; + sfxcache_t *sc; + int ltime, count; + + while (paintedtime < endtime) + { + // if paintbuffer is smaller than DMA buffer + end = endtime; + if (endtime - paintedtime > PAINTBUFFER_SIZE) + end = paintedtime + PAINTBUFFER_SIZE; + + // clear the paint buffer + Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t)); + + // paint in the channels. + ch = channels; + for (i=0; isfx) + continue; + if (!ch->leftvol && !ch->rightvol) + continue; + sc = S_LoadSound (ch->sfx); + if (!sc) + continue; + + ltime = paintedtime; + + while (ltime < end) + { // paint up to end + if (ch->end < end) + count = ch->end - ltime; + else + count = end - ltime; + + if (count > 0) + { + if (sc->width == 1) + SND_PaintChannelFrom8(ch, sc, count); + else + SND_PaintChannelFrom16(ch, sc, count); + + ltime += count; + } + + // if at end of loop, restart + if (ltime >= ch->end) + { + if (sc->loopstart >= 0) + { + ch->pos = sc->loopstart; + ch->end = ltime + sc->length - ch->pos; + } + else + { // channel just stopped + ch->sfx = NULL; + break; + } + } + } + + } + + // transfer out according to DMA format + S_TransferPaintBuffer(end); + paintedtime = end; + } +} + +void SND_InitScaletable (void) +{ + int i, j; + + for (i=0 ; i<32 ; i++) + for (j=0 ; j<256 ; j++) + snd_scaletable[i][j] = ((signed char)j) * i * 8; +} + + +void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) +{ + int data; + int *lscale, *rscale; + unsigned char *sfx; + int i; + + if (ch->leftvol > 255) + ch->leftvol = 255; + if (ch->rightvol > 255) + ch->rightvol = 255; + + lscale = snd_scaletable[ch->leftvol >> 3]; + rscale = snd_scaletable[ch->rightvol >> 3]; + sfx = (signed char *)sc->data + ch->pos; + + for (i=0 ; ipos += count; +} + +void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) +{ + int data; + int left, right; + int leftvol, rightvol; + signed short *sfx; + int i; + + leftvol = ch->leftvol; + rightvol = ch->rightvol; + sfx = (signed short *)sc->data + ch->pos; + + for (i=0 ; i> 8; + right = (data * rightvol) >> 8; + paintbuffer[i].left += left; + paintbuffer[i].right += right; + } + + ch->pos += count; +} + diff --git a/Quake/snd_sdl.c b/Quake/snd_sdl.c new file mode 100644 index 00000000..619cf876 --- /dev/null +++ b/Quake/snd_sdl.c @@ -0,0 +1,125 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// stolen from http://www.libsdl.org/projects/quake/ -- apologies, I don't know the author's name + +#include +#include "quakedef.h" + +static dma_t the_shm; +static int snd_inited; + +#define BUF_SIZE 512 + +static void paint_audio(void *unused, Uint8 *stream, int len) +{ + if ( shm ) { + shm->buffer = stream; + shm->samplepos += len/(shm->samplebits/8)/2; + // Check for samplepos overflow? + S_PaintChannels (shm->samplepos); + } +} + +qboolean SNDDMA_Init(void) +{ + SDL_AudioSpec desired, obtained; + + snd_inited = 0; + + /* Set up the desired format */ + desired.freq = sndspeed.value; + if (loadas8bit.value) { + desired.format = AUDIO_U8; + } else { + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + desired.format = AUDIO_S16MSB; + else + desired.format = AUDIO_S16LSB; + } + desired.channels = 2; + desired.samples = BUF_SIZE; + desired.callback = paint_audio; + + /* Open the audio device */ + if ( SDL_OpenAudio(&desired, &obtained) < 0 ) { + Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError()); + return 0; + } + + /* Make sure we can support the audio format */ + switch (obtained.format) { + case AUDIO_U8: + /* Supported */ + break; + case AUDIO_S16LSB: + case AUDIO_S16MSB: + if ( ((obtained.format == AUDIO_S16LSB) && + (SDL_BYTEORDER == SDL_LIL_ENDIAN)) || + ((obtained.format == AUDIO_S16MSB) && + (SDL_BYTEORDER == SDL_BIG_ENDIAN)) ) { + /* Supported */ + break; + } + /* Unsupported, fall through */; + default: + /* Not supported -- force SDL to do our bidding */ + SDL_CloseAudio(); + if ( SDL_OpenAudio(&desired, NULL) < 0 ) { + Con_Printf("Couldn't open SDL audio: %s\n", + SDL_GetError()); + return 0; + } + memcpy(&obtained, &desired, sizeof(desired)); + break; + } + SDL_PauseAudio(0); + + /* Fill the audio DMA information block */ + shm = &the_shm; + shm->splitbuffer = 0; + shm->samplebits = (obtained.format & 0xFF); + shm->speed = obtained.freq; + shm->channels = obtained.channels; + shm->samples = obtained.samples*shm->channels; + shm->samplepos = 0; + shm->submission_chunk = 1; + shm->buffer = NULL; + + snd_inited = 1; + return 1; +} + +int SNDDMA_GetDMAPos(void) +{ + return shm->samplepos; +} + +void SNDDMA_Shutdown(void) +{ + if (snd_inited) + { + SDL_CloseAudio(); + snd_inited = 0; + } +} + diff --git a/Quake/sound.h b/Quake/sound.h new file mode 100644 index 00000000..964162e7 --- /dev/null +++ b/Quake/sound.h @@ -0,0 +1,180 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sound.h -- client sound i/o functions + +#ifndef __SOUND__ +#define __SOUND__ + +#define DEFAULT_SOUND_PACKET_VOLUME 255 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + int left; + int right; +} portable_samplepair_t; + +typedef struct sfx_s +{ + char name[MAX_QPATH]; + cache_user_t cache; +} sfx_t; + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + int length; + int loopstart; + int speed; + int width; + int stereo; + byte data[1]; // variable sized +} sfxcache_t; + +typedef struct +{ + qboolean gamealive; + qboolean soundalive; + qboolean splitbuffer; + int channels; + int samples; // mono samples in buffer + int submission_chunk; // don't mix less than this # + int samplepos; // in mono samples + int samplebits; + int speed; + unsigned char *buffer; +} dma_t; + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + sfx_t *sfx; // sfx number + int leftvol; // 0-255 volume + int rightvol; // 0-255 volume + int end; // end time in global paintsamples + int pos; // sample position in sfx + int looping; // where to loop, -1 = no looping + int entnum; // to allow overriding a specific sound + int entchannel; // + vec3_t origin; // origin of sound effect + vec_t dist_mult; // distance multiplier (attenuation/clipK) + int master_vol; // 0-255 master volume +} channel_t; + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + +void S_Init (void); +void S_Startup (void); +void S_Shutdown (void); +void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); +void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation); +void S_StopSound (int entnum, int entchannel); +void S_StopAllSounds(qboolean clear); +void S_ClearBuffer (void); +void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up); +void S_ExtraUpdate (void); + +sfx_t *S_PrecacheSound (char *sample); +void S_TouchSound (char *sample); +void S_ClearPrecache (void); +void S_BeginPrecaching (void); +void S_EndPrecaching (void); +void S_PaintChannels(int endtime); +void S_InitPaintChannels (void); + +// picks a channel based on priorities, empty slots, number of channels +channel_t *SND_PickChannel(int entnum, int entchannel); + +// spatializes a channel +void SND_Spatialize(channel_t *ch); + +// initializes cycling through a DMA buffer and returns information on it +qboolean SNDDMA_Init(void); + +// gets the current DMA position +int SNDDMA_GetDMAPos(void); + +// shutdown the DMA xfer. +void SNDDMA_Shutdown(void); + +// ==================================================================== +// User-setable variables +// ==================================================================== + +#define MAX_CHANNELS 512 //johnfitz -- was 128 +#define MAX_DYNAMIC_CHANNELS 128 //johnfitz -- was 8 + + +extern channel_t channels[MAX_CHANNELS]; +// 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds +// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc +// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds + +extern int total_channels; + +// +// Fake dma is a synchronous faking of the DMA progress used for +// isolating performance in the renderer. The fakedma_updates is +// number of times S_Update() is called per second. +// + +extern qboolean fakedma; +extern int fakedma_updates; +extern int paintedtime; +extern vec3_t listener_origin; +extern vec3_t listener_forward; +extern vec3_t listener_right; +extern vec3_t listener_up; +extern volatile dma_t *shm; +extern volatile dma_t sn; +extern vec_t sound_nominal_clip_dist; + +extern cvar_t loadas8bit; +extern cvar_t bgmvolume; +extern cvar_t volume; +extern cvar_t sndspeed; + +extern qboolean snd_initialized; + +extern int snd_blocked; + +void S_LocalSound (char *s); +sfxcache_t *S_LoadSound (sfx_t *s); + +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength); + +void SND_InitScaletable (void); +void SNDDMA_Submit(void); + +void S_AmbientOff (void); +void S_AmbientOn (void); + +#endif diff --git a/Quake/spritegn.h b/Quake/spritegn.h new file mode 100644 index 00000000..b5bb9651 --- /dev/null +++ b/Quake/spritegn.h @@ -0,0 +1,111 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// spritegn.h: header file for sprite generation program +// + +// ********************************************************** +// * This file must be identical in the spritegen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via .spr files. * +// ********************************************************** + +//------------------------------------------------------- +// This program generates .spr sprite package files. +// The format of the files is as follows: +// +// dsprite_t file header structure +// +// +// dspriteframe_t frame header structure +// sprite bitmap +// +// dspriteframe_t frame header structure +// sprite bitmap +// +//------------------------------------------------------- + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "dictlib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "mathlib.h" + +#endif + +#define SPRITE_VERSION 1 + +// must match definition in modelgen.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +// TODO: shorten these? +typedef struct { + int ident; + int version; + int type; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +#define SPR_VP_PARALLEL_UPRIGHT 0 +#define SPR_FACING_UPRIGHT 1 +#define SPR_VP_PARALLEL 2 +#define SPR_ORIENTED 3 +#define SPR_VP_PARALLEL_ORIENTED 4 + +typedef struct { + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct { + int numframes; +} dspritegroup_t; + +typedef struct { + float interval; +} dspriteinterval_t; + +typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; + +typedef struct { + spriteframetype_t type; +} dspriteframetype_t; + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDSP" + diff --git a/Quake/sv_main.c b/Quake/sv_main.c new file mode 100644 index 00000000..5b9adf95 --- /dev/null +++ b/Quake/sv_main.c @@ -0,0 +1,1424 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_main.c -- server main program + +#include "quakedef.h" + +server_t sv; +server_static_t svs; + +char localmodels[MAX_MODELS][5]; // inline model names for precache + +int sv_protocol = PROTOCOL_FITZQUAKE; //johnfitz + +extern qboolean pr_alpha_supported; //johnfitz + +//============================================================================ + +/* +=============== +SV_Protocol_f +=============== +*/ +void SV_Protocol_f (void) +{ + int i; + + switch (Cmd_Argc()) + { + case 1: + Con_Printf ("\"sv_protocol\" is \"%i\"\n", sv_protocol); + break; + case 2: + i = atoi(Cmd_Argv(1)); + if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) + Con_Printf ("sv_protocol must be %i or %i\n", PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); + else + { + sv_protocol = i; + if (sv.active) + Con_Printf ("changes will not take effect until the next level load.\n"); + } + break; + default: + Con_SafePrintf ("usage: sv_protocol \n"); + break; + } +} +/* +=============== +SV_Init +=============== +*/ +void SV_Init (void) +{ + int i; + extern cvar_t sv_maxvelocity; + extern cvar_t sv_gravity; + extern cvar_t sv_nostep; + extern cvar_t sv_friction; + extern cvar_t sv_edgefriction; + extern cvar_t sv_stopspeed; + extern cvar_t sv_maxspeed; + extern cvar_t sv_accelerate; + extern cvar_t sv_idealpitchscale; + extern cvar_t sv_aim; + extern cvar_t sv_altnoclip; //johnfitz + + Cvar_RegisterVariable (&sv_maxvelocity, NULL); + Cvar_RegisterVariable (&sv_gravity, NULL); + Cvar_RegisterVariable (&sv_friction, NULL); + Cvar_RegisterVariable (&sv_edgefriction, NULL); + Cvar_RegisterVariable (&sv_stopspeed, NULL); + Cvar_RegisterVariable (&sv_maxspeed, NULL); + Cvar_RegisterVariable (&sv_accelerate, NULL); + Cvar_RegisterVariable (&sv_idealpitchscale, NULL); + Cvar_RegisterVariable (&sv_aim, NULL); + Cvar_RegisterVariable (&sv_nostep, NULL); + Cvar_RegisterVariable (&sv_altnoclip, NULL); //johnfitz + + Cmd_AddCommand ("sv_protocol", &SV_Protocol_f); //johnfitz + + for (i=0 ; i MAX_DATAGRAM-16) + return; + MSG_WriteByte (&sv.datagram, svc_particle); + MSG_WriteCoord (&sv.datagram, org[0]); + MSG_WriteCoord (&sv.datagram, org[1]); + MSG_WriteCoord (&sv.datagram, org[2]); + for (i=0 ; i<3 ; i++) + { + v = dir[i]*16; + if (v > 127) + v = 127; + else if (v < -128) + v = -128; + MSG_WriteChar (&sv.datagram, v); + } + MSG_WriteByte (&sv.datagram, count); + MSG_WriteByte (&sv.datagram, color); +} + +/* +================== +SV_StartSound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +allready running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. (max 4 attenuation) + +================== +*/ +void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, + float attenuation) +{ + int sound_num; + int field_mask; + int i; + int ent; + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + if (sv.datagram.cursize > MAX_DATAGRAM-16) + return; + +// find precache number for sound + for (sound_num=1 ; sound_num= 8192) + if (sv.protocol == PROTOCOL_NETQUAKE) + return; //don't send any info protocol can't support + else + field_mask |= SND_LARGEENTITY; + if (sound_num >= 256 || channel >= 8) + if (sv.protocol == PROTOCOL_NETQUAKE) + return; //don't send any info protocol can't support + else + field_mask |= SND_LARGESOUND; + //johnfitz + +// directed messages go only to the entity the are targeted on + MSG_WriteByte (&sv.datagram, svc_sound); + MSG_WriteByte (&sv.datagram, field_mask); + if (field_mask & SND_VOLUME) + MSG_WriteByte (&sv.datagram, volume); + if (field_mask & SND_ATTENUATION) + MSG_WriteByte (&sv.datagram, attenuation*64); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (field_mask & SND_LARGEENTITY) + { + MSG_WriteShort (&sv.datagram, ent); + MSG_WriteByte (&sv.datagram, channel); + } + else + MSG_WriteShort (&sv.datagram, (ent<<3) | channel); + if (field_mask & SND_LARGESOUND) + MSG_WriteShort (&sv.datagram, sound_num); + else + MSG_WriteByte (&sv.datagram, sound_num); + //johnfitz + + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i])); +} + +/* +============================================================================== + +CLIENT SPAWNING + +============================================================================== +*/ + +/* +================ +SV_SendServerinfo + +Sends the first message from the server to a connected client. +This will be sent on the initial connection and upon each server load. +================ +*/ +void SV_SendServerinfo (client_t *client) +{ + char **s; + char message[2048]; + int i; //johnfitz + + MSG_WriteByte (&client->message, svc_print); + sprintf (message, "%c\nFITZQUAKE %1.2f SERVER (%i CRC)\n", 2, FITZQUAKE_VERSION, pr_crc); //johnfitz -- include fitzquake version + MSG_WriteString (&client->message,message); + + MSG_WriteByte (&client->message, svc_serverinfo); + MSG_WriteLong (&client->message, sv.protocol); //johnfitz -- sv.protocol instead of PROTOCOL_VERSION + MSG_WriteByte (&client->message, svs.maxclients); + + if (!coop.value && deathmatch.value) + MSG_WriteByte (&client->message, GAME_DEATHMATCH); + else + MSG_WriteByte (&client->message, GAME_COOP); + + sprintf (message, pr_strings+sv.edicts->v.message); + + MSG_WriteString (&client->message,message); + + //johnfitz -- only send the first 256 model and sound precaches if protocol is 15 + for (i=0,s = sv.model_precache+1 ; *s; s++,i++) + if (sv.protocol != PROTOCOL_NETQUAKE || i < 256) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + + for (i=0,s = sv.sound_precache+1 ; *s ; s++,i++) + if (sv.protocol != PROTOCOL_NETQUAKE || i < 256) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + //johnfitz + +// send music + MSG_WriteByte (&client->message, svc_cdtrack); + MSG_WriteByte (&client->message, sv.edicts->v.sounds); + MSG_WriteByte (&client->message, sv.edicts->v.sounds); + +// set view + MSG_WriteByte (&client->message, svc_setview); + MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); + + MSG_WriteByte (&client->message, svc_signonnum); + MSG_WriteByte (&client->message, 1); + + client->sendsignon = true; + client->spawned = false; // need prespawn, spawn, etc +} + +/* +================ +SV_ConnectClient + +Initializes a client_t for a new net connection. This will only be called +once for a player each game, not once for each level change. +================ +*/ +void SV_ConnectClient (int clientnum) +{ + edict_t *ent; + client_t *client; + int edictnum; + struct qsocket_s *netconnection; + int i; + float spawn_parms[NUM_SPAWN_PARMS]; + + client = svs.clients + clientnum; + + Con_DPrintf ("Client %s connected\n", client->netconnection->address); + + edictnum = clientnum+1; + + ent = EDICT_NUM(edictnum); + +// set up the client_t + netconnection = client->netconnection; + + if (sv.loadgame) + memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); + memset (client, 0, sizeof(*client)); + client->netconnection = netconnection; + + strcpy (client->name, "unconnected"); + client->active = true; + client->spawned = false; + client->edict = ent; + client->message.data = client->msgbuf; + client->message.maxsize = sizeof(client->msgbuf); + client->message.allowoverflow = true; // we can catch it + client->privileged = false; + + if (sv.loadgame) + memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); + else + { + // call the progs to get default spawn parms for the new client + PR_ExecuteProgram (pr_global_struct->SetNewParms); + for (i=0 ; ispawn_parms[i] = (&pr_global_struct->parm1)[i]; + } + + SV_SendServerinfo (client); +} + + +/* +=================== +SV_CheckForNewClients + +=================== +*/ +void SV_CheckForNewClients (void) +{ + struct qsocket_s *ret; + int i; + +// +// check for new connections +// + while (1) + { + ret = NET_CheckNewConnections (); + if (!ret) + break; + + // + // init a new client structure + // + for (i=0 ; icontents < 0) + { + if (node->contents != CONTENTS_SOLID) + { + pvs = Mod_LeafPVS ( (mleaf_t *)node, worldmodel); //johnfitz -- worldmodel as a parameter + for (i=0 ; iplane; + d = DotProduct (org, plane->normal) - plane->dist; + if (d > 8) + node = node->children[0]; + else if (d < -8) + node = node->children[1]; + else + { // go down both + SV_AddToFatPVS (org, node->children[0], worldmodel); //johnfitz -- worldmodel as a parameter + node = node->children[1]; + } + } +} + +/* +============= +SV_FatPVS + +Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the +given point. +============= +*/ +byte *SV_FatPVS (vec3_t org, model_t *worldmodel) //johnfitz -- added worldmodel as a parameter +{ + fatbytes = (worldmodel->numleafs+31)>>3; + Q_memset (fatpvs, 0, fatbytes); + SV_AddToFatPVS (org, worldmodel->nodes, worldmodel); //johnfitz -- worldmodel as a parameter + return fatpvs; +} + +/* +============= +SV_VisibleToClient -- johnfitz + +PVS test encapsulated in a nice function +============= +*/ +qboolean SV_VisibleToClient (edict_t *client, edict_t *test, model_t *worldmodel) +{ + byte *pvs; + vec3_t org; + int i; + + VectorAdd (client->v.origin, client->v.view_ofs, org); + pvs = SV_FatPVS (org, worldmodel); + + for (i=0 ; i < test->num_leafs ; i++) + if (pvs[test->leafnums[i] >> 3] & (1 << (test->leafnums[i]&7) )) + return true; + + return false; +} + +//============================================================================= + +/* +============= +SV_WriteEntitiesToClient + +============= +*/ +void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) +{ + int e, i; + int bits; + byte *pvs; + vec3_t org; + float miss; + edict_t *ent; + +// find the client's PVS + VectorAdd (clent->v.origin, clent->v.view_ofs, org); + pvs = SV_FatPVS (org, sv.worldmodel); + +// send over all entities (excpet the client) that touch the pvs + ent = NEXT_EDICT(sv.edicts); + for (e=1 ; ev.modelindex || !pr_strings[ent->v.model]) + continue; + + //johnfitz -- don't send model>255 entities if protocol is 15 + if (sv_protocol == PROTOCOL_NETQUAKE && (int)ent->v.modelindex & 0xFF00) + continue; + + // ignore if not touching a PV leaf + for (i=0 ; i < ent->num_leafs ; i++) + if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) + break; + if (i == ent->num_leafs) + continue; // not visible + } + + //johnfitz -- max size for protocol 15 is 18 bytes, not 16 as originally + //assumed here. And, for protocol 85 the max size is actually 24 bytes. + if (msg->cursize + 24 > msg->maxsize) + { + //johnfitz -- less spammy overflow message + if (!dev_overflows.packetsize || dev_overflows.packetsize + CONSOLE_RESPAM_TIME < realtime ) + { + Con_Printf ("Packet overflow!\n"); + dev_overflows.packetsize = realtime; + } + goto stats; + //johnfitz + } + +// send an update + bits = 0; + + for (i=0 ; i<3 ; i++) + { + miss = ent->v.origin[i] - ent->baseline.origin[i]; + if ( miss < -0.1 || miss > 0.1 ) + bits |= U_ORIGIN1<v.angles[0] != ent->baseline.angles[0] ) + bits |= U_ANGLE1; + + if ( ent->v.angles[1] != ent->baseline.angles[1] ) + bits |= U_ANGLE2; + + if ( ent->v.angles[2] != ent->baseline.angles[2] ) + bits |= U_ANGLE3; + + if (ent->v.movetype == MOVETYPE_STEP) + bits |= U_STEP; // don't mess up the step animation + + if (ent->baseline.colormap != ent->v.colormap) + bits |= U_COLORMAP; + + if (ent->baseline.skin != ent->v.skin) + bits |= U_SKIN; + + if (ent->baseline.frame != ent->v.frame) + bits |= U_FRAME; + + if (ent->baseline.effects != ent->v.effects) + bits |= U_EFFECTS; + + if (ent->baseline.modelindex != ent->v.modelindex) + bits |= U_MODEL; + + //johnfitz -- alpha + if (pr_alpha_supported) + { + // TODO: find a cleaner place to put this code + eval_t *val; + val = GetEdictFieldValue(ent, "alpha"); + if (val) + ent->alpha = ENTALPHA_ENCODE(val->_float); + } + + //don't send invisible entities unless they have effects + if (ent->alpha == ENTALPHA_ZERO && !ent->v.effects) + continue; + //johnfitz + + //johnfitz -- PROTOCOL_FITZQUAKE + if (sv.protocol != PROTOCOL_NETQUAKE) + { + + if (ent->baseline.alpha != ent->alpha) bits |= U_ALPHA; + if (bits & U_FRAME && (int)ent->v.frame & 0xFF00) bits |= U_FRAME2; + if (bits & U_MODEL && (int)ent->v.modelindex & 0xFF00) bits |= U_MODEL2; + if (ent->sendinterval) bits |= U_LERPFINISH; + if (bits >= 65536) bits |= U_EXTEND1; + if (bits >= 16777216) bits |= U_EXTEND2; + } + //johnfitz + + if (e >= 256) + bits |= U_LONGENTITY; + + if (bits >= 256) + bits |= U_MOREBITS; + + // + // write the message + // + MSG_WriteByte (msg, bits | U_SIGNAL); + + if (bits & U_MOREBITS) + MSG_WriteByte (msg, bits>>8); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & U_EXTEND1) + MSG_WriteByte(msg, bits>>16); + if (bits & U_EXTEND2) + MSG_WriteByte(msg, bits>>24); + //johnfitz + + if (bits & U_LONGENTITY) + MSG_WriteShort (msg,e); + else + MSG_WriteByte (msg,e); + + if (bits & U_MODEL) + MSG_WriteByte (msg, ent->v.modelindex); + if (bits & U_FRAME) + MSG_WriteByte (msg, ent->v.frame); + if (bits & U_COLORMAP) + MSG_WriteByte (msg, ent->v.colormap); + if (bits & U_SKIN) + MSG_WriteByte (msg, ent->v.skin); + if (bits & U_EFFECTS) + MSG_WriteByte (msg, ent->v.effects); + if (bits & U_ORIGIN1) + MSG_WriteCoord (msg, ent->v.origin[0]); + if (bits & U_ANGLE1) + MSG_WriteAngle(msg, ent->v.angles[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (msg, ent->v.origin[1]); + if (bits & U_ANGLE2) + MSG_WriteAngle(msg, ent->v.angles[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (msg, ent->v.origin[2]); + if (bits & U_ANGLE3) + MSG_WriteAngle(msg, ent->v.angles[2]); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & U_ALPHA) + MSG_WriteByte(msg, ent->alpha); + if (bits & U_FRAME2) + MSG_WriteByte(msg, (int)ent->v.frame >> 8); + if (bits & U_MODEL2) + MSG_WriteByte(msg, (int)ent->v.modelindex >> 8); + if (bits & U_LERPFINISH) + MSG_WriteByte(msg, (byte)(Q_rint((ent->v.nextthink-sv.time)*255))); + //johnfitz + } + + //johnfitz -- devstats +stats: + if (msg->cursize > 1024 && dev_peakstats.packetsize <= 1024) + Con_Warning ("%i byte packet exceeds standard limit of 1024.\n", msg->cursize); + dev_stats.packetsize = msg->cursize; + dev_peakstats.packetsize = max(msg->cursize, dev_peakstats.packetsize); + //johnfitz +} + +/* +============= +SV_CleanupEnts + +============= +*/ +void SV_CleanupEnts (void) +{ + int e; + edict_t *ent; + + ent = NEXT_EDICT(sv.edicts); + for (e=1 ; ev.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH; + } + +} + +/* +================== +SV_WriteClientdataToMessage + +================== +*/ +void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) +{ + int bits; + int i; + edict_t *other; + int items; + eval_t *val; + +// +// send a damage message +// + if (ent->v.dmg_take || ent->v.dmg_save) + { + other = PROG_TO_EDICT(ent->v.dmg_inflictor); + MSG_WriteByte (msg, svc_damage); + MSG_WriteByte (msg, ent->v.dmg_save); + MSG_WriteByte (msg, ent->v.dmg_take); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i])); + + ent->v.dmg_take = 0; + ent->v.dmg_save = 0; + } + +// +// send the current viewpos offset from the view entity +// + SV_SetIdealPitch (); // how much to look up / down ideally + +// a fixangle might get lost in a dropped packet. Oh well. + if ( ent->v.fixangle ) + { + MSG_WriteByte (msg, svc_setangle); + for (i=0 ; i < 3 ; i++) + MSG_WriteAngle (msg, ent->v.angles[i] ); + ent->v.fixangle = 0; + } + + bits = 0; + + if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) + bits |= SU_VIEWHEIGHT; + + if (ent->v.idealpitch) + bits |= SU_IDEALPITCH; + +// stuff the sigil bits into the high bits of items for sbar, or else +// mix in items2 + val = GetEdictFieldValue(ent, "items2"); + + if (val) + items = (int)ent->v.items | ((int)val->_float << 23); + else + items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28); + + bits |= SU_ITEMS; + + if ( (int)ent->v.flags & FL_ONGROUND) + bits |= SU_ONGROUND; + + if ( ent->v.waterlevel >= 2) + bits |= SU_INWATER; + + for (i=0 ; i<3 ; i++) + { + if (ent->v.punchangle[i]) + bits |= (SU_PUNCH1<v.velocity[i]) + bits |= (SU_VELOCITY1<v.weaponframe) + bits |= SU_WEAPONFRAME; + + if (ent->v.armorvalue) + bits |= SU_ARMOR; + +// if (ent->v.weapon) + bits |= SU_WEAPON; + + //johnfitz -- PROTOCOL_FITZQUAKE + if (sv.protocol != PROTOCOL_NETQUAKE) + { + if (bits & SU_WEAPON && SV_ModelIndex(pr_strings+ent->v.weaponmodel) & 0xFF00) bits |= SU_WEAPON2; + if ((int)ent->v.armorvalue & 0xFF00) bits |= SU_ARMOR2; + if ((int)ent->v.currentammo & 0xFF00) bits |= SU_AMMO2; + if ((int)ent->v.ammo_shells & 0xFF00) bits |= SU_SHELLS2; + if ((int)ent->v.ammo_nails & 0xFF00) bits |= SU_NAILS2; + if ((int)ent->v.ammo_rockets & 0xFF00) bits |= SU_ROCKETS2; + if ((int)ent->v.ammo_cells & 0xFF00) bits |= SU_CELLS2; + if (bits & SU_WEAPONFRAME && (int)ent->v.weaponframe & 0xFF00) bits |= SU_WEAPONFRAME2; + if (bits & SU_WEAPON && ent->alpha != ENTALPHA_DEFAULT) bits |= SU_WEAPONALPHA; //for now, weaponalpha = client entity alpha + if (bits >= 65536) bits |= SU_EXTEND1; + if (bits >= 16777216) bits |= SU_EXTEND2; + } + //johnfitz + +// send the data + + MSG_WriteByte (msg, svc_clientdata); + MSG_WriteShort (msg, bits); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & SU_EXTEND1) MSG_WriteByte(msg, bits>>16); + if (bits & SU_EXTEND2) MSG_WriteByte(msg, bits>>24); + //johnfitz + + if (bits & SU_VIEWHEIGHT) + MSG_WriteChar (msg, ent->v.view_ofs[2]); + + if (bits & SU_IDEALPITCH) + MSG_WriteChar (msg, ent->v.idealpitch); + + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1<v.punchangle[i]); + if (bits & (SU_VELOCITY1<v.velocity[i]/16); + } + +// [always sent] if (bits & SU_ITEMS) + MSG_WriteLong (msg, items); + + if (bits & SU_WEAPONFRAME) + MSG_WriteByte (msg, ent->v.weaponframe); + if (bits & SU_ARMOR) + MSG_WriteByte (msg, ent->v.armorvalue); + if (bits & SU_WEAPON) + MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel)); + + MSG_WriteShort (msg, ent->v.health); + MSG_WriteByte (msg, ent->v.currentammo); + MSG_WriteByte (msg, ent->v.ammo_shells); + MSG_WriteByte (msg, ent->v.ammo_nails); + MSG_WriteByte (msg, ent->v.ammo_rockets); + MSG_WriteByte (msg, ent->v.ammo_cells); + + if (standard_quake) + { + MSG_WriteByte (msg, ent->v.weapon); + } + else + { + for(i=0;i<32;i++) + { + if ( ((int)ent->v.weapon) & (1<v.weaponmodel) >> 8); + if (bits & SU_ARMOR2) + MSG_WriteByte (msg, (int)ent->v.armorvalue >> 8); + if (bits & SU_AMMO2) + MSG_WriteByte (msg, (int)ent->v.currentammo >> 8); + if (bits & SU_SHELLS2) + MSG_WriteByte (msg, (int)ent->v.ammo_shells >> 8); + if (bits & SU_NAILS2) + MSG_WriteByte (msg, (int)ent->v.ammo_nails >> 8); + if (bits & SU_ROCKETS2) + MSG_WriteByte (msg, (int)ent->v.ammo_rockets >> 8); + if (bits & SU_CELLS2) + MSG_WriteByte (msg, (int)ent->v.ammo_cells >> 8); + if (bits & SU_WEAPONFRAME2) + MSG_WriteByte (msg, (int)ent->v.weaponframe >> 8); + if (bits & SU_WEAPONALPHA) + MSG_WriteByte (msg, ent->alpha); //for now, weaponalpha = client entity alpha + //johnfitz +} + +/* +======================= +SV_SendClientDatagram +======================= +*/ +qboolean SV_SendClientDatagram (client_t *client) +{ + byte buf[MAX_DATAGRAM]; + sizebuf_t msg; + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + + //johnfitz -- if client is nonlocal, use smaller max size so packets aren't fragmented + if (Q_strcmp (client->netconnection->address, "LOCAL") != 0) + msg.maxsize = DATAGRAM_MTU; + //johnfitz + + MSG_WriteByte (&msg, svc_time); + MSG_WriteFloat (&msg, sv.time); + +// add the client specific data to the datagram + SV_WriteClientdataToMessage (client->edict, &msg); + + SV_WriteEntitiesToClient (client->edict, &msg); + +// copy the server datagram if there is space + if (msg.cursize + sv.datagram.cursize < msg.maxsize) + SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); + +// send the datagram + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) + { + SV_DropClient (true);// if the message couldn't send, kick off + return false; + } + + return true; +} + +/* +======================= +SV_UpdateToReliableMessages +======================= +*/ +void SV_UpdateToReliableMessages (void) +{ + int i, j; + client_t *client; + +// check for changes to be sent over the reliable streams + for (i=0, host_client = svs.clients ; iold_frags != host_client->edict->v.frags) + { + for (j=0, client = svs.clients ; jactive) + continue; + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, i); + MSG_WriteShort (&client->message, host_client->edict->v.frags); + } + + host_client->old_frags = host_client->edict->v.frags; + } + } + + for (j=0, client = svs.clients ; jactive) + continue; + SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); + } + + SZ_Clear (&sv.reliable_datagram); +} + + +/* +======================= +SV_SendNop + +Send a nop message without trashing or sending the accumulated client +message buffer +======================= +*/ +void SV_SendNop (client_t *client) +{ + sizebuf_t msg; + byte buf[4]; + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + + MSG_WriteChar (&msg, svc_nop); + + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) + SV_DropClient (true); // if the message couldn't send, kick off + client->last_message = realtime; +} + +/* +======================= +SV_SendClientMessages +======================= +*/ +void SV_SendClientMessages (void) +{ + int i; + +// update frags, names, etc + SV_UpdateToReliableMessages (); + +// build individual updates + for (i=0, host_client = svs.clients ; iactive) + continue; + + if (host_client->spawned) + { + if (!SV_SendClientDatagram (host_client)) + continue; + } + else + { + // the player isn't totally in the game yet + // send small keepalive messages if too much time has passed + // send a full message when the next signon stage has been requested + // some other message data (name changes, etc) may accumulate + // between signon stages + if (!host_client->sendsignon) + { + if (realtime - host_client->last_message > 5) + SV_SendNop (host_client); + continue; // don't send out non-signon messages + } + } + + // check for an overflowed message. Should only happen + // on a very fucked up connection that backs up a lot, then + // changes level + if (host_client->message.overflowed) + { + SV_DropClient (true); + host_client->message.overflowed = false; + continue; + } + + if (host_client->message.cursize || host_client->dropasap) + { + if (!NET_CanSendMessage (host_client->netconnection)) + { +// I_Printf ("can't write\n"); + continue; + } + + if (host_client->dropasap) + SV_DropClient (false); // went to another level + else + { + if (NET_SendMessage (host_client->netconnection + , &host_client->message) == -1) + SV_DropClient (true); // if the message couldn't send, kick off + SZ_Clear (&host_client->message); + host_client->last_message = realtime; + host_client->sendsignon = false; + } + } + } + + +// clear muzzle flashes + SV_CleanupEnts (); +} + + +/* +============================================================================== + +SERVER SPAWNING + +============================================================================== +*/ + +/* +================ +SV_ModelIndex + +================ +*/ +int SV_ModelIndex (char *name) +{ + int i; + + if (!name || !name[0]) + return 0; + + for (i=0 ; ifree) + continue; + if (entnum > svs.maxclients && !svent->v.modelindex) + continue; + + // + // create entity baseline + // + VectorCopy (svent->v.origin, svent->baseline.origin); + VectorCopy (svent->v.angles, svent->baseline.angles); + svent->baseline.frame = svent->v.frame; + svent->baseline.skin = svent->v.skin; + if (entnum > 0 && entnum <= svs.maxclients) + { + svent->baseline.colormap = entnum; + svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); + svent->baseline.alpha = ENTALPHA_DEFAULT; //johnfitz -- alpha support + } + else + { + svent->baseline.colormap = 0; + svent->baseline.modelindex = SV_ModelIndex(pr_strings + svent->v.model); + svent->baseline.alpha = svent->alpha; //johnfitz -- alpha support + } + + //johnfitz -- PROTOCOL_FITZQUAKE + bits = 0; + if (sv.protocol == PROTOCOL_NETQUAKE) //still want to send baseline in PROTOCOL_NETQUAKE, so reset these values + { + if (svent->baseline.modelindex & 0xFF00) + svent->baseline.modelindex = 0; + if (svent->baseline.frame & 0xFF00) + svent->baseline.frame = 0; + svent->baseline.alpha = ENTALPHA_DEFAULT; + } + else //decide which extra data needs to be sent + { + if (svent->baseline.modelindex & 0xFF00) + bits |= B_LARGEMODEL; + if (svent->baseline.frame & 0xFF00) + bits |= B_LARGEFRAME; + if (svent->baseline.alpha != ENTALPHA_DEFAULT) + bits |= B_ALPHA; + } + //johnfitz + + // + // add to the message + // + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits) + MSG_WriteByte (&sv.signon, svc_spawnbaseline2); + else + MSG_WriteByte (&sv.signon, svc_spawnbaseline); + //johnfitz + + MSG_WriteShort (&sv.signon,entnum); + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits) + MSG_WriteByte (&sv.signon, bits); + + if (bits & B_LARGEMODEL) + MSG_WriteShort (&sv.signon, svent->baseline.modelindex); + else + MSG_WriteByte (&sv.signon, svent->baseline.modelindex); + + if (bits & B_LARGEFRAME) + MSG_WriteShort (&sv.signon, svent->baseline.frame); + else + MSG_WriteByte (&sv.signon, svent->baseline.frame); + //johnfitz + + MSG_WriteByte (&sv.signon, svent->baseline.colormap); + MSG_WriteByte (&sv.signon, svent->baseline.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); + MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); + } + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & B_ALPHA) + MSG_WriteByte (&sv.signon, svent->baseline.alpha); + //johnfitz + } +} + + +/* +================ +SV_SendReconnect + +Tell all the clients that the server is changing levels +================ +*/ +void SV_SendReconnect (void) +{ + char data[128]; + sizebuf_t msg; + + msg.data = data; + msg.cursize = 0; + msg.maxsize = sizeof(data); + + MSG_WriteChar (&msg, svc_stufftext); + MSG_WriteString (&msg, "reconnect\n"); + NET_SendToAll (&msg, 5); + + if (cls.state != ca_dedicated) + Cmd_ExecuteString ("reconnect\n", src_command); +} + + +/* +================ +SV_SaveSpawnparms + +Grabs the current state of each client for saving across the +transition to another level +================ +*/ +void SV_SaveSpawnparms (void) +{ + int i, j; + + svs.serverflags = pr_global_struct->serverflags; + + for (i=0, host_client = svs.clients ; iactive) + continue; + + // call the progs to get default spawn parms for the new client + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram (pr_global_struct->SetChangeParms); + for (j=0 ; jspawn_parms[j] = (&pr_global_struct->parm1)[j]; + } +} + + +/* +================ +SV_SpawnServer + +This is called at the start of each level +================ +*/ +extern float scr_centertime_off; +void SV_SpawnServer (char *server) +{ + edict_t *ent; + int i; + + // let's not have any servers with no name + if (hostname.string[0] == 0) + Cvar_Set ("hostname", "UNNAMED"); + scr_centertime_off = 0; + + Con_DPrintf ("SpawnServer: %s\n",server); + svs.changelevel_issued = false; // now safe to issue another + +// +// tell all connected clients that we are going to a new level +// + if (sv.active) + { + SV_SendReconnect (); + } + +// +// make cvars consistant +// + if (coop.value) + Cvar_SetValue ("deathmatch", 0); + current_skill = (int)(skill.value + 0.5); + if (current_skill < 0) + current_skill = 0; + if (current_skill > 3) + current_skill = 3; + + Cvar_SetValue ("skill", (float)current_skill); + +// +// set up the new server +// + Host_ClearMemory (); + + memset (&sv, 0, sizeof(sv)); + + strcpy (sv.name, server); + + sv.protocol = sv_protocol; // johnfitz + +// load progs to get entity field count + PR_LoadProgs (); + +// allocate server memory + sv.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); //johnfitz -- max_edicts cvar + sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts"); + + sv.datagram.maxsize = sizeof(sv.datagram_buf); + sv.datagram.cursize = 0; + sv.datagram.data = sv.datagram_buf; + + sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); + sv.reliable_datagram.cursize = 0; + sv.reliable_datagram.data = sv.reliable_datagram_buf; + + sv.signon.maxsize = sizeof(sv.signon_buf); + sv.signon.cursize = 0; + sv.signon.data = sv.signon_buf; + +// leave slots at start for clients only + sv.num_edicts = svs.maxclients+1; + for (i=0 ; inumsubmodels ; i++) + { + sv.model_precache[1+i] = localmodels[i]; + sv.models[i+1] = Mod_ForName (localmodels[i], false); + } + +// +// load the rest of the entities +// + ent = EDICT_NUM(0); + memset (&ent->v, 0, progs->entityfields * 4); + ent->free = false; + ent->v.model = sv.worldmodel->name - pr_strings; + ent->v.modelindex = 1; // world model + ent->v.solid = SOLID_BSP; + ent->v.movetype = MOVETYPE_PUSH; + + if (coop.value) + pr_global_struct->coop = coop.value; + else + pr_global_struct->deathmatch = deathmatch.value; + + pr_global_struct->mapname = sv.name - pr_strings; + +// serverflags are for cross level information (sigils) + pr_global_struct->serverflags = svs.serverflags; + + ED_LoadFromFile (sv.worldmodel->entities); + + sv.active = true; + +// all setup is completed, any further precache statements are errors + sv.state = ss_active; + +// run two frames to allow everything to settle + host_frametime = 0.1; + SV_Physics (); + SV_Physics (); + +// create a baseline for more efficient communications + SV_CreateBaseline (); + + //johnfitz -- warn if signon buffer larger than standard server can handle + if (sv.signon.cursize > 8000-2) //max size that will fit into 8000-sized client->message buffer with 2 extra bytes on the end + Con_Warning ("%i byte signon buffer exceeds standard limit of 7998.\n", sv.signon.cursize); + //johnfitz + +// send serverinfo to all connected clients + for (i=0,host_client = svs.clients ; iactive) + SV_SendServerinfo (host_client); + + Con_DPrintf ("Server spawned.\n"); +} + diff --git a/Quake/sv_move.c b/Quake/sv_move.c new file mode 100644 index 00000000..086cd42e --- /dev/null +++ b/Quake/sv_move.c @@ -0,0 +1,420 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_move.c -- monster movement + +#include "quakedef.h" + +#define STEPSIZE 18 + +/* +============= +SV_CheckBottom + +Returns false if any part of the bottom of the entity is off an edge that +is not a staircase. + +============= +*/ +int c_yes, c_no; + +qboolean SV_CheckBottom (edict_t *ent) +{ + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (ent->v.origin, ent->v.mins, mins); + VectorAdd (ent->v.origin, ent->v.maxs, maxs); + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (SV_PointContents (start) != CONTENTS_SOLID) + goto realcheck; + } + + c_yes++; + return true; // we got out easy + +realcheck: + c_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*STEPSIZE; + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + +// the corners must be within 16 of the midpoint + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) + return false; + } + + c_yes++; + return true; +} + + +/* +============= +SV_movestep + +Called by monster program code. +The move will be adjusted for slopes and stairs, but if the move isn't +possible, no move is done, false is returned, and +pr_global_struct->trace_normal is set to the normal of the blocking wall +============= +*/ +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) +{ + float dz; + vec3_t oldorg, neworg, end; + trace_t trace; + int i; + edict_t *enemy; + +// try the move + VectorCopy (ent->v.origin, oldorg); + VectorAdd (ent->v.origin, move, neworg); + +// flying monsters don't step up + if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (ent->v.origin, move, neworg); + enemy = PROG_TO_EDICT(ent->v.enemy); + if (i == 0 && enemy != sv.edicts) + { + dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; + if (dz > 40) + neworg[2] -= 8; + if (dz < 30) + neworg[2] += 8; + } + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); + + if (trace.fraction == 1) + { + if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) + return false; // swim monster left water + + VectorCopy (trace.endpos, ent->v.origin); + if (relink) + SV_LinkEdict (ent, true); + return true; + } + + if (enemy == sv.edicts) + break; + } + + return false; + } + +// push down from a step height above the wished position + neworg[2] += STEPSIZE; + VectorCopy (neworg, end); + end[2] -= STEPSIZE*2; + + trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.allsolid) + return false; + + if (trace.startsolid) + { + neworg[2] -= STEPSIZE; + trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); + if (trace.allsolid || trace.startsolid) + return false; + } + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { + VectorAdd (ent->v.origin, move, ent->v.origin); + if (relink) + SV_LinkEdict (ent, true); + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; +// Con_Printf ("fall down\n"); + return true; + } + + return false; // walked off an edge + } + +// check point traces down for dangling corners + VectorCopy (trace.endpos, ent->v.origin); + + if (!SV_CheckBottom (ent)) + { + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + SV_LinkEdict (ent, true); + return true; + } + VectorCopy (oldorg, ent->v.origin); + return false; + } + + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { +// Con_Printf ("back on ground\n"); + ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND; + } + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + +// the move is ok + if (relink) + SV_LinkEdict (ent, true); + return true; +} + + +//============================================================================ + +/* +====================== +SV_StepDirection + +Turns to the movement direction, and walks the current distance if +facing it. + +====================== +*/ +void PF_changeyaw (void); +qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) +{ + vec3_t move, oldorigin; + float delta; + + ent->v.ideal_yaw = yaw; + PF_changeyaw(); + + yaw = yaw*M_PI*2 / 360; + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + VectorCopy (ent->v.origin, oldorigin); + if (SV_movestep (ent, move, false)) + { + delta = ent->v.angles[YAW] - ent->v.ideal_yaw; + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step + VectorCopy (oldorigin, ent->v.origin); + } + SV_LinkEdict (ent, true); + return true; + } + SV_LinkEdict (ent, true); + + return false; +} + +/* +====================== +SV_FixCheckBottom + +====================== +*/ +void SV_FixCheckBottom (edict_t *ent) +{ +// Con_Printf ("SV_FixCheckBottom\n"); + + ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND; +} + + + +/* +================ +SV_NewChaseDir + +================ +*/ +#define DI_NODIR -1 +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) +{ + float deltax,deltay; + float d[3]; + float tdir, olddir, turnaround; + + olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 ); + turnaround = anglemod(olddir - 180); + + deltax = enemy->v.origin[0] - actor->v.origin[0]; + deltay = enemy->v.origin[1] - actor->v.origin[1]; + if (deltax>10) + d[1]= 0; + else if (deltax<-10) + d[1]= 180; + else + d[1]= DI_NODIR; + if (deltay<-10) + d[2]= 270; + else if (deltay>10) + d[2]= 90; + else + d[2]= DI_NODIR; + +// try direct route + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + if (d[1] == 0) + tdir = d[2] == 90 ? 45 : 315; + else + tdir = d[2] == 90 ? 135 : 215; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + +// try other directions + if ( ((rand()&3) & 1) || abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]!=DI_NODIR && d[1]!=turnaround + && SV_StepDirection(actor, d[1], dist)) + return; + + if (d[2]!=DI_NODIR && d[2]!=turnaround + && SV_StepDirection(actor, d[2], dist)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) + return; + + if (rand()&1) /*randomly determine direction of search*/ + { + for (tdir=0 ; tdir<=315 ; tdir += 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + else + { + for (tdir=315 ; tdir >=0 ; tdir -= 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + + if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) + return; + + actor->v.ideal_yaw = olddir; // can't move + +// if a bridge was pulled out from underneath a monster, it may not have +// a valid standing position at all + + if (!SV_CheckBottom (actor)) + SV_FixCheckBottom (actor); + +} + +/* +====================== +SV_CloseEnough + +====================== +*/ +qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (goal->v.absmin[i] > ent->v.absmax[i] + dist) + return false; + if (goal->v.absmax[i] < ent->v.absmin[i] - dist) + return false; + } + return true; +} + +/* +====================== +SV_MoveToGoal + +====================== +*/ +void SV_MoveToGoal (void) +{ + edict_t *ent, *goal; + float dist; + + ent = PROG_TO_EDICT(pr_global_struct->self); + goal = PROG_TO_EDICT(ent->v.goalentity); + dist = G_FLOAT(OFS_PARM0); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + +// if the next step hits the enemy, return immediately + if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) + return; + +// bump around... + if ( (rand()&3)==1 || + !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) + { + SV_NewChaseDir (ent, goal, dist); + } +} + diff --git a/Quake/sv_phys.c b/Quake/sv_phys.c new file mode 100644 index 00000000..94da9408 --- /dev/null +++ b/Quake/sv_phys.c @@ -0,0 +1,1220 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_phys.c + +#include "quakedef.h" + +/* + + +pushmove 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. + +onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects + +doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH +bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS +corpses are SOLID_NOT and MOVETYPE_TOSS +crates are SOLID_BBOX and MOVETYPE_TOSS +walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP +flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY + +solid_edge items only clip against bsp models. + +*/ + +cvar_t sv_friction = {"sv_friction","4",false,true}; +cvar_t sv_stopspeed = {"sv_stopspeed","100"}; +cvar_t sv_gravity = {"sv_gravity","800",false,true}; +cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"}; +cvar_t sv_nostep = {"sv_nostep","0"}; + +#define MOVE_EPSILON 0.01 + +void SV_Physics_Toss (edict_t *ent); + +/* +================ +SV_CheckAllEnts +================ +*/ +void SV_CheckAllEnts (void) +{ + int e; + edict_t *check; + +// see if any solid entities are inside the final position + check = NEXT_EDICT(sv.edicts); + for (e=1 ; efree) + continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + if (SV_TestEntityPosition (check)) + Con_Printf ("entity in invalid position\n"); + } +} + +/* +================ +SV_CheckVelocity +================ +*/ +void SV_CheckVelocity (edict_t *ent) +{ + int i; + +// +// bound velocity +// + for (i=0 ; i<3 ; i++) + { + if (IS_NAN(ent->v.velocity[i])) + { + Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname); + ent->v.velocity[i] = 0; + } + if (IS_NAN(ent->v.origin[i])) + { + Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname); + ent->v.origin[i] = 0; + } + if (ent->v.velocity[i] > sv_maxvelocity.value) + ent->v.velocity[i] = sv_maxvelocity.value; + else if (ent->v.velocity[i] < -sv_maxvelocity.value) + ent->v.velocity[i] = -sv_maxvelocity.value; + } +} + +/* +============= +SV_RunThink + +Runs thinking code if time. There is some play in the exact time the think +function will be called, because it is called before any movement is done +in a frame. Not used for pushmove objects, because they must be exact. +Returns false if the entity removed itself. +============= +*/ +qboolean SV_RunThink (edict_t *ent) +{ + float thinktime; + float oldframe; //johnfitz + int i; //johnfitz + + thinktime = ent->v.nextthink; + if (thinktime <= 0 || thinktime > sv.time + host_frametime) + return true; + + if (thinktime < sv.time) + thinktime = sv.time; // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + + oldframe = ent->v.frame; //johnfitz + + ent->v.nextthink = 0; + pr_global_struct->time = thinktime; + pr_global_struct->self = EDICT_TO_PROG(ent); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + PR_ExecuteProgram (ent->v.think); + +//johnfitz -- PROTOCOL_FITZQUAKE +//capture interval to nextthink here and send it to client for better +//lerp timing, but only if interval is not 0.1 (which client assumes) + ent->sendinterval = false; + if (!ent->free && ent->v.nextthink && (ent->v.movetype == MOVETYPE_STEP || ent->v.frame != oldframe)) + { + i = Q_rint((ent->v.nextthink-thinktime)*255); + if (i >= 0 && i < 256 && i != 25 && i != 26) //25 and 26 are close enough to 0.1 to not send + ent->sendinterval = true; + } +//johnfitz + + return !ent->free; +} + +/* +================== +SV_Impact + +Two entities have touched, so run their touch functions +================== +*/ +void SV_Impact (edict_t *e1, edict_t *e2) +{ + int old_self, old_other; + + old_self = pr_global_struct->self; + old_other = pr_global_struct->other; + + pr_global_struct->time = sv.time; + if (e1->v.touch && e1->v.solid != SOLID_NOT) + { + pr_global_struct->self = EDICT_TO_PROG(e1); + pr_global_struct->other = EDICT_TO_PROG(e2); + PR_ExecuteProgram (e1->v.touch); + } + + if (e2->v.touch && e2->v.solid != SOLID_NOT) + { + pr_global_struct->self = EDICT_TO_PROG(e2); + pr_global_struct->other = EDICT_TO_PROG(e1); + PR_ExecuteProgram (e2->v.touch); + } + + pr_global_struct->self = old_self; + pr_global_struct->other = old_other; +} + + +/* +================== +ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + int i, blocked; + + blocked = 0; + if (normal[2] > 0) + blocked |= 1; // floor + if (!normal[2]) + blocked |= 2; // step + + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } + + return blocked; +} + + +/* +============ +SV_FlyMove + +The basic solid body movement clip that slides along multiple planes +Returns the clipflags if the velocity was modified (hit something solid) +1 = floor +2 = wall / step +4 = dead stop +If steptrace is not NULL, the trace of any vertical wall hit will be stored +============ +*/ +#define MAX_CLIP_PLANES 5 +int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + int blocked; + + numbumps = 4; + + blocked = 0; + VectorCopy (ent->v.velocity, original_velocity); + VectorCopy (ent->v.velocity, primal_velocity); + numplanes = 0; + + time_left = time; + + for (bumpcount=0 ; bumpcountv.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) + break; + + for (i=0 ; i<3 ; i++) + end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.allsolid) + { // entity is trapped in another solid + VectorCopy (vec3_origin, ent->v.velocity); + return 3; + } + + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, ent->v.origin); + VectorCopy (ent->v.velocity, original_velocity); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + if (!trace.ent) + Sys_Error ("SV_FlyMove: !trace.ent"); + + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1; // floor + if (trace.ent->v.solid == SOLID_BSP) + { + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + } + } + if (!trace.plane.normal[2]) + { + blocked |= 2; // step + if (steptrace) + *steptrace = trace; // save for player extrafriction + } + +// +// run the impact function +// + SV_Impact (ent, trace.ent); + if (ent->free) + break; // removed by the impact function + + + time_left -= time_left * trace.fraction; + + // cliped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + VectorCopy (vec3_origin, ent->v.velocity); + return 3; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + +// +// modify original_velocity so it parallels all of the clip planes +// + for (i=0 ; iv.velocity); + } + else + { // go along the crease + if (numplanes != 2) + { +// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, ent->v.velocity); + return 7; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, ent->v.velocity); + VectorScale (dir, d, ent->v.velocity); + } + +// +// if original velocity is against the original velocity, stop dead +// to avoid tiny occilations in sloping corners +// + if (DotProduct (ent->v.velocity, primal_velocity) <= 0) + { + VectorCopy (vec3_origin, ent->v.velocity); + return blocked; + } + } + + return blocked; +} + + +/* +============ +SV_AddGravity + +============ +*/ +void SV_AddGravity (edict_t *ent) +{ + float ent_gravity; + eval_t *val; + + val = GetEdictFieldValue(ent, "gravity"); + if (val && val->_float) + ent_gravity = val->_float; + else + ent_gravity = 1.0; + + ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime; +} + + +/* +=============================================================================== + +PUSHMOVE + +=============================================================================== +*/ + +/* +============ +SV_PushEntity + +Does not change the entities velocity at all +============ +*/ +trace_t SV_PushEntity (edict_t *ent, vec3_t push) +{ + trace_t trace; + vec3_t end; + + VectorAdd (ent->v.origin, push, end); + + if (ent->v.movetype == MOVETYPE_FLYMISSILE) + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); + else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) + // only clip against bmodels + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); + else + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); + + VectorCopy (trace.endpos, ent->v.origin); + SV_LinkEdict (ent, true); + + if (trace.ent) + SV_Impact (ent, trace.ent); + + return trace; +} + + +/* +============ +SV_PushMove +============ +*/ +void SV_PushMove (edict_t *pusher, float movetime) +{ + int i, e; + edict_t *check, *block; + vec3_t mins, maxs, move; + vec3_t entorig, pushorig; + int num_moved; + edict_t **moved_edict; //johnfitz -- dynamically allocate + vec3_t *moved_from; //johnfitz -- dynamically allocate + int mark; //johnfitz + + if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) + { + pusher->v.ltime += movetime; + return; + } + + for (i=0 ; i<3 ; i++) + { + move[i] = pusher->v.velocity[i] * movetime; + mins[i] = pusher->v.absmin[i] + move[i]; + maxs[i] = pusher->v.absmax[i] + move[i]; + } + + VectorCopy (pusher->v.origin, pushorig); + +// move the pusher to it's final position + + VectorAdd (pusher->v.origin, move, pusher->v.origin); + pusher->v.ltime += movetime; + SV_LinkEdict (pusher, false); + + //johnfitz -- dynamically allocate + mark = Hunk_LowMark (); + moved_edict = Hunk_Alloc (sv.num_edicts*sizeof(edict_t *)); + moved_from = Hunk_Alloc (sv.num_edicts*sizeof(vec3_t)); + //johnfitz + +// see if any solid entities are inside the final position + num_moved = 0; + check = NEXT_EDICT(sv.edicts); + for (e=1 ; efree) + continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + // if the entity is standing on the pusher, it will definately be moved + if ( ! ( ((int)check->v.flags & FL_ONGROUND) + && PROG_TO_EDICT(check->v.groundentity) == pusher) ) + { + if ( check->v.absmin[0] >= maxs[0] + || check->v.absmin[1] >= maxs[1] + || check->v.absmin[2] >= maxs[2] + || check->v.absmax[0] <= mins[0] + || check->v.absmax[1] <= mins[1] + || check->v.absmax[2] <= mins[2] ) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition (check)) + continue; + } + + // remove the onground flag for non-players + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags = (int)check->v.flags & ~FL_ONGROUND; + + VectorCopy (check->v.origin, entorig); + VectorCopy (check->v.origin, moved_from[num_moved]); + moved_edict[num_moved] = check; + num_moved++; + + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity (check, move); + pusher->v.solid = SOLID_BSP; + + // if it is still inside the pusher, block + block = SV_TestEntityPosition (check); + if (block) + { // fail the move + if (check->v.mins[0] == check->v.maxs[0]) + continue; + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { // corpse + check->v.mins[0] = check->v.mins[1] = 0; + VectorCopy (check->v.mins, check->v.maxs); + continue; + } + + VectorCopy (entorig, check->v.origin); + SV_LinkEdict (check, true); + + VectorCopy (pushorig, pusher->v.origin); + SV_LinkEdict (pusher, false); + pusher->v.ltime -= movetime; + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if (pusher->v.blocked) + { + pr_global_struct->self = EDICT_TO_PROG(pusher); + pr_global_struct->other = EDICT_TO_PROG(check); + PR_ExecuteProgram (pusher->v.blocked); + } + + // move back any entities we already moved + for (i=0 ; iv.origin); + SV_LinkEdict (moved_edict[i], false); + } + Hunk_FreeToLowMark (mark); //johnfitz + return; + } + } + + Hunk_FreeToLowMark (mark); //johnfitz + +} + +/* +================ +SV_Physics_Pusher + +================ +*/ +void SV_Physics_Pusher (edict_t *ent) +{ + float thinktime; + float oldltime; + float movetime; + + oldltime = ent->v.ltime; + + thinktime = ent->v.nextthink; + if (thinktime < ent->v.ltime + host_frametime) + { + movetime = thinktime - ent->v.ltime; + if (movetime < 0) + movetime = 0; + } + else + movetime = host_frametime; + + if (movetime) + { + SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked + } + + if (thinktime > oldltime && thinktime <= ent->v.ltime) + { + ent->v.nextthink = 0; + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + PR_ExecuteProgram (ent->v.think); + if (ent->free) + return; + } + +} + + +/* +=============================================================================== + +CLIENT MOVEMENT + +=============================================================================== +*/ + +/* +============= +SV_CheckStuck + +This is a big hack to try and fix the rare case of getting stuck in the world +clipping hull. +============= +*/ +void SV_CheckStuck (edict_t *ent) +{ + int i, j; + int z; + vec3_t org; + + if (!SV_TestEntityPosition(ent)) + { + VectorCopy (ent->v.origin, ent->v.oldorigin); + return; + } + + VectorCopy (ent->v.origin, org); + VectorCopy (ent->v.oldorigin, ent->v.origin); + if (!SV_TestEntityPosition(ent)) + { + Con_DPrintf ("Unstuck.\n"); + SV_LinkEdict (ent, true); + return; + } + + for (z=0 ; z< 18 ; z++) + for (i=-1 ; i <= 1 ; i++) + for (j=-1 ; j <= 1 ; j++) + { + ent->v.origin[0] = org[0] + i; + ent->v.origin[1] = org[1] + j; + ent->v.origin[2] = org[2] + z; + if (!SV_TestEntityPosition(ent)) + { + Con_DPrintf ("Unstuck.\n"); + SV_LinkEdict (ent, true); + return; + } + } + + VectorCopy (org, ent->v.origin); + Con_DPrintf ("player is stuck.\n"); +} + + +/* +============= +SV_CheckWater +============= +*/ +qboolean SV_CheckWater (edict_t *ent) +{ + vec3_t point; + int cont; + + point[0] = ent->v.origin[0]; + point[1] = ent->v.origin[1]; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; + + ent->v.waterlevel = 0; + ent->v.watertype = CONTENTS_EMPTY; + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + { + ent->v.watertype = cont; + ent->v.waterlevel = 1; + point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5; + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + { + ent->v.waterlevel = 2; + point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + ent->v.waterlevel = 3; + } + } + + return ent->v.waterlevel > 1; +} + +/* +============ +SV_WallFriction + +============ +*/ +void SV_WallFriction (edict_t *ent, trace_t *trace) +{ + vec3_t forward, right, up; + float d, i; + vec3_t into, side; + + AngleVectors (ent->v.v_angle, forward, right, up); + d = DotProduct (trace->plane.normal, forward); + + d += 0.5; + if (d >= 0) + return; + +// cut the tangential velocity + i = DotProduct (trace->plane.normal, ent->v.velocity); + VectorScale (trace->plane.normal, i, into); + VectorSubtract (ent->v.velocity, into, side); + + ent->v.velocity[0] = side[0] * (1 + d); + ent->v.velocity[1] = side[1] * (1 + d); +} + +/* +===================== +SV_TryUnstick + +Player has come to a dead stop, possibly due to the problem with limited +float precision at some angle joins in the BSP hull. + +Try fixing by pushing one pixel in each direction. + +This is a hack, but in the interest of good gameplay... +====================== +*/ +int SV_TryUnstick (edict_t *ent, vec3_t oldvel) +{ + int i; + vec3_t oldorg; + vec3_t dir; + int clip; + trace_t steptrace; + + VectorCopy (ent->v.origin, oldorg); + VectorCopy (vec3_origin, dir); + + for (i=0 ; i<8 ; i++) + { +// try pushing a little in an axial direction + switch (i) + { + case 0: dir[0] = 2; dir[1] = 0; break; + case 1: dir[0] = 0; dir[1] = 2; break; + case 2: dir[0] = -2; dir[1] = 0; break; + case 3: dir[0] = 0; dir[1] = -2; break; + case 4: dir[0] = 2; dir[1] = 2; break; + case 5: dir[0] = -2; dir[1] = 2; break; + case 6: dir[0] = 2; dir[1] = -2; break; + case 7: dir[0] = -2; dir[1] = -2; break; + } + + SV_PushEntity (ent, dir); + +// retry the original move + ent->v.velocity[0] = oldvel[0]; + ent->v. velocity[1] = oldvel[1]; + ent->v. velocity[2] = 0; + clip = SV_FlyMove (ent, 0.1, &steptrace); + + if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 + || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) + { +//Con_DPrintf ("unstuck!\n"); + return clip; + } + +// go back to the original pos and try again + VectorCopy (oldorg, ent->v.origin); + } + + VectorCopy (vec3_origin, ent->v.velocity); + return 7; // still not moving +} + +/* +===================== +SV_WalkMove + +Only used by players +====================== +*/ +#define STEPSIZE 18 +void SV_WalkMove (edict_t *ent) +{ + vec3_t upmove, downmove; + vec3_t oldorg, oldvel; + vec3_t nosteporg, nostepvel; + int clip; + int oldonground; + trace_t steptrace, downtrace; + +// +// do a regular slide move unless it looks like you ran into a step +// + oldonground = (int)ent->v.flags & FL_ONGROUND; + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + + VectorCopy (ent->v.origin, oldorg); + VectorCopy (ent->v.velocity, oldvel); + + clip = SV_FlyMove (ent, host_frametime, &steptrace); + + if ( !(clip & 2) ) + return; // move didn't block on a step + + if (!oldonground && ent->v.waterlevel == 0) + return; // don't stair up while jumping + + if (ent->v.movetype != MOVETYPE_WALK) + return; // gibbed by a trigger + + if (sv_nostep.value) + return; + + if ( (int)sv_player->v.flags & FL_WATERJUMP ) + return; + + VectorCopy (ent->v.origin, nosteporg); + VectorCopy (ent->v.velocity, nostepvel); + +// +// try moving up and forward to go up a step +// + VectorCopy (oldorg, ent->v.origin); // back to start pos + + VectorCopy (vec3_origin, upmove); + VectorCopy (vec3_origin, downmove); + upmove[2] = STEPSIZE; + downmove[2] = -STEPSIZE + oldvel[2]*host_frametime; + +// move up + SV_PushEntity (ent, upmove); // FIXME: don't link? + +// move forward + ent->v.velocity[0] = oldvel[0]; + ent->v. velocity[1] = oldvel[1]; + ent->v. velocity[2] = 0; + clip = SV_FlyMove (ent, host_frametime, &steptrace); + +// check for stuckness, possibly due to the limited precision of floats +// in the clipping hulls + if (clip) + { + if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125 + && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 ) + { // stepping up didn't make any progress + clip = SV_TryUnstick (ent, oldvel); + } + } + +// extra friction based on view angle + if ( clip & 2 ) + SV_WallFriction (ent, &steptrace); + +// move down + downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? + + if (downtrace.plane.normal[2] > 0.7) + { + if (ent->v.solid == SOLID_BSP) + { + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); + } + } + else + { +// if the push down didn't end up on good ground, use the move without +// the step up. This happens near wall / slope combinations, and can +// cause the player to hop up higher on a slope too steep to climb + VectorCopy (nosteporg, ent->v.origin); + VectorCopy (nostepvel, ent->v.velocity); + } +} + + +/* +================ +SV_Physics_Client + +Player character actions +================ +*/ +void SV_Physics_Client (edict_t *ent, int num) +{ + if ( ! svs.clients[num-1].active ) + return; // unconnected slot + +// +// call standard client pre-think +// + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPreThink); + +// +// do a move +// + SV_CheckVelocity (ent); + +// +// decide which move function to call +// + switch ((int)ent->v.movetype) + { + case MOVETYPE_NONE: + if (!SV_RunThink (ent)) + return; + break; + + case MOVETYPE_WALK: + if (!SV_RunThink (ent)) + return; + if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) + SV_AddGravity (ent); + SV_CheckStuck (ent); + SV_WalkMove (ent); + break; + + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + SV_Physics_Toss (ent); + break; + + case MOVETYPE_FLY: + if (!SV_RunThink (ent)) + return; + SV_FlyMove (ent, host_frametime, NULL); + break; + + case MOVETYPE_NOCLIP: + if (!SV_RunThink (ent)) + return; + VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); + break; + + default: + Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); + } + +// +// call standard player post-think +// + SV_LinkEdict (ent, true); + + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPostThink); +} + +//============================================================================ + +/* +============= +SV_Physics_None + +Non moving objects can only think +============= +*/ +void SV_Physics_None (edict_t *ent) +{ +// regular thinking + SV_RunThink (ent); +} + +/* +============= +SV_Physics_Noclip + +A moving object that doesn't obey physics +============= +*/ +void SV_Physics_Noclip (edict_t *ent) +{ +// regular thinking + if (!SV_RunThink (ent)) + return; + + VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin); + + SV_LinkEdict (ent, false); +} + +/* +============================================================================== + +TOSS / BOUNCE + +============================================================================== +*/ + +/* +============= +SV_CheckWaterTransition + +============= +*/ +void SV_CheckWaterTransition (edict_t *ent) +{ + int cont; + + cont = SV_PointContents (ent->v.origin); + + if (!ent->v.watertype) + { // just spawned here + ent->v.watertype = cont; + ent->v.waterlevel = 1; + return; + } + + if (cont <= CONTENTS_WATER) + { + if (ent->v.watertype == CONTENTS_EMPTY) + { // just crossed into water + SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + } + ent->v.watertype = cont; + ent->v.waterlevel = 1; + } + else + { + if (ent->v.watertype != CONTENTS_EMPTY) + { // just crossed into water + SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + } + ent->v.watertype = CONTENTS_EMPTY; + ent->v.waterlevel = cont; + } +} + +/* +============= +SV_Physics_Toss + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ +void SV_Physics_Toss (edict_t *ent) +{ + trace_t trace; + vec3_t move; + float backoff; + + // regular thinking + if (!SV_RunThink (ent)) + return; + +// if onground, return without moving + if ( ((int)ent->v.flags & FL_ONGROUND) ) + return; + + SV_CheckVelocity (ent); + +// add gravity + if (ent->v.movetype != MOVETYPE_FLY + && ent->v.movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity (ent); + +// move angles + VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles); + +// move origin + VectorScale (ent->v.velocity, host_frametime, move); + trace = SV_PushEntity (ent, move); + if (trace.fraction == 1) + return; + if (ent->free) + return; + + if (ent->v.movetype == MOVETYPE_BOUNCE) + backoff = 1.5; + else + backoff = 1; + + ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); + +// stop if on ground + if (trace.plane.normal[2] > 0.7) + { + if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) + { + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + VectorCopy (vec3_origin, ent->v.velocity); + VectorCopy (vec3_origin, ent->v.avelocity); + } + } + +// check for in water + SV_CheckWaterTransition (ent); +} + +/* +=============================================================================== + +STEPPING MOVEMENT + +=============================================================================== +*/ + +/* +============= +SV_Physics_Step + +Monsters freefall when they don't have a ground entity, otherwise +all movement is done with discrete steps. + +This is also used for objects that have become still on the ground, but +will fall if the floor is pulled out from under them. +============= +*/ +void SV_Physics_Step (edict_t *ent) +{ + qboolean hitsound; + +// freefall if not onground + if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) + { + if (ent->v.velocity[2] < sv_gravity.value*-0.1) + hitsound = true; + else + hitsound = false; + + SV_AddGravity (ent); + SV_CheckVelocity (ent); + SV_FlyMove (ent, host_frametime, NULL); + SV_LinkEdict (ent, true); + + if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground + { + if (hitsound) + SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); + } + } + +// regular thinking + SV_RunThink (ent); + + SV_CheckWaterTransition (ent); +} + + +//============================================================================ + +/* +================ +SV_Physics + +================ +*/ +void SV_Physics (void) +{ + int i; + edict_t *ent; + +// let the progs know that a new frame has started + pr_global_struct->self = EDICT_TO_PROG(sv.edicts); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + pr_global_struct->time = sv.time; + PR_ExecuteProgram (pr_global_struct->StartFrame); + +//SV_CheckAllEnts (); + +// +// treat each object in turn +// + ent = sv.edicts; + for (i=0 ; ifree) + continue; + + if (pr_global_struct->force_retouch) + { + SV_LinkEdict (ent, true); // force retouch even for stationary + } + + if (i > 0 && i <= svs.maxclients) + SV_Physics_Client (ent, i); + else if (ent->v.movetype == MOVETYPE_PUSH) + SV_Physics_Pusher (ent); + else if (ent->v.movetype == MOVETYPE_NONE) + SV_Physics_None (ent); + else if (ent->v.movetype == MOVETYPE_NOCLIP) + SV_Physics_Noclip (ent); + else if (ent->v.movetype == MOVETYPE_STEP) + SV_Physics_Step (ent); + else if (ent->v.movetype == MOVETYPE_TOSS + || ent->v.movetype == MOVETYPE_BOUNCE + || ent->v.movetype == MOVETYPE_FLY + || ent->v.movetype == MOVETYPE_FLYMISSILE) + SV_Physics_Toss (ent); + else + Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); + } + + if (pr_global_struct->force_retouch) + pr_global_struct->force_retouch--; + + sv.time += host_frametime; +} diff --git a/Quake/sv_user.c b/Quake/sv_user.c new file mode 100644 index 00000000..da26a4b5 --- /dev/null +++ b/Quake/sv_user.c @@ -0,0 +1,630 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_user.c -- server code for moving users + +#include "quakedef.h" + +edict_t *sv_player; + +extern cvar_t sv_friction; +cvar_t sv_edgefriction = {"edgefriction", "2"}; +extern cvar_t sv_stopspeed; + +static vec3_t forward, right, up; + +vec3_t wishdir; +float wishspeed; + +// world +float *angles; +float *origin; +float *velocity; + +qboolean onground; + +usercmd_t cmd; + +cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8"}; +cvar_t sv_altnoclip = {"sv_altnoclip","1",true}; //johnfitz + +/* +=============== +SV_SetIdealPitch +=============== +*/ +#define MAX_FORWARD 6 +void SV_SetIdealPitch (void) +{ + float angleval, sinval, cosval; + trace_t tr; + vec3_t top, bottom; + float z[MAX_FORWARD]; + int i, j; + int step, dir, steps; + + if (!((int)sv_player->v.flags & FL_ONGROUND)) + return; + + angleval = sv_player->v.angles[YAW] * M_PI*2 / 360; + sinval = sin(angleval); + cosval = cos(angleval); + + for (i=0 ; iv.origin[0] + cosval*(i+3)*12; + top[1] = sv_player->v.origin[1] + sinval*(i+3)*12; + top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2]; + + bottom[0] = top[0]; + bottom[1] = top[1]; + bottom[2] = top[2] - 160; + + tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player); + if (tr.allsolid) + return; // looking at a wall, leave ideal the way is was + + if (tr.fraction == 1) + return; // near a dropoff + + z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); + } + + dir = 0; + steps = 0; + for (j=1 ; j -ON_EPSILON && step < ON_EPSILON) + continue; + + if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) + return; // mixed changes + + steps++; + dir = step; + } + + if (!dir) + { + sv_player->v.idealpitch = 0; + return; + } + + if (steps < 2) + return; + sv_player->v.idealpitch = -dir * sv_idealpitchscale.value; +} + + +/* +================== +SV_UserFriction + +================== +*/ +void SV_UserFriction (void) +{ + float *vel; + float speed, newspeed, control; + vec3_t start, stop; + float friction; + trace_t trace; + + vel = velocity; + + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (!speed) + return; + +// if the leading edge is over a dropoff, increase friction + start[0] = stop[0] = origin[0] + vel[0]/speed*16; + start[1] = stop[1] = origin[1] + vel[1]/speed*16; + start[2] = origin[2] + sv_player->v.mins[2]; + stop[2] = start[2] - 34; + + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player); + + if (trace.fraction == 1.0) + friction = sv_friction.value*sv_edgefriction.value; + else + friction = sv_friction.value; + +// apply friction + control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; + newspeed = speed - host_frametime*control*friction; + + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; +} + +/* +============== +SV_Accelerate +============== +*/ +cvar_t sv_maxspeed = {"sv_maxspeed", "320", false, true}; +cvar_t sv_accelerate = {"sv_accelerate", "10"}; +void SV_Accelerate (void) +{ + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct (velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = sv_accelerate.value*host_frametime*wishspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*wishdir[i]; +} + +void SV_AirAccelerate (vec3_t wishveloc) +{ + int i; + float addspeed, wishspd, accelspeed, currentspeed; + + wishspd = VectorNormalize (wishveloc); + if (wishspd > 30) + wishspd = 30; + currentspeed = DotProduct (velocity, wishveloc); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; +// accelspeed = sv_accelerate.value * host_frametime; + accelspeed = sv_accelerate.value*wishspeed * host_frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*wishveloc[i]; +} + + +void DropPunchAngle (void) +{ + float len; + + len = VectorNormalize (sv_player->v.punchangle); + + len -= 10*host_frametime; + if (len < 0) + len = 0; + VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle); +} + +/* +=================== +SV_WaterMove + +=================== +*/ +void SV_WaterMove (void) +{ + int i; + vec3_t wishvel; + float speed, newspeed, wishspeed, addspeed, accelspeed; + +// +// user intentions +// + AngleVectors (sv_player->v.v_angle, forward, right, up); + + for (i=0 ; i<3 ; i++) + wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove; + + if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += cmd.upmove; + + wishspeed = Length(wishvel); + if (wishspeed > sv_maxspeed.value) + { + VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); + wishspeed = sv_maxspeed.value; + } + wishspeed *= 0.7; + +// +// water friction +// + speed = Length (velocity); + if (speed) + { + newspeed = speed - host_frametime * speed * sv_friction.value; + if (newspeed < 0) + newspeed = 0; + VectorScale (velocity, newspeed/speed, velocity); + } + else + newspeed = 0; + +// +// water acceleration +// + if (!wishspeed) + return; + + addspeed = wishspeed - newspeed; + if (addspeed <= 0) + return; + + VectorNormalize (wishvel); + accelspeed = sv_accelerate.value * wishspeed * host_frametime; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed * wishvel[i]; +} + +void SV_WaterJump (void) +{ + if (sv.time > sv_player->v.teleport_time + || !sv_player->v.waterlevel) + { + sv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP; + sv_player->v.teleport_time = 0; + } + sv_player->v.velocity[0] = sv_player->v.movedir[0]; + sv_player->v.velocity[1] = sv_player->v.movedir[1]; +} + +/* +=================== +SV_NoclipMove -- johnfitz + +new, alternate noclip. old noclip is still handled in SV_AirMove +=================== +*/ +void SV_NoclipMove (void) +{ + AngleVectors (sv_player->v.v_angle, forward, right, up); + + velocity[0] = forward[0]*cmd.forwardmove + right[0]*cmd.sidemove; + velocity[1] = forward[1]*cmd.forwardmove + right[1]*cmd.sidemove; + velocity[2] = forward[2]*cmd.forwardmove + right[2]*cmd.sidemove; + velocity[2] += cmd.upmove*2; //doubled to match running speed + + if (Length (velocity) > sv_maxspeed.value) + { + VectorNormalize (velocity); + VectorScale (velocity, sv_maxspeed.value, velocity); + } +} + +/* +=================== +SV_AirMove +=================== +*/ +void SV_AirMove (void) +{ + int i; + vec3_t wishvel; + float fmove, smove; + + AngleVectors (sv_player->v.angles, forward, right, up); + + fmove = cmd.forwardmove; + smove = cmd.sidemove; + +// hack to not let you back into teleporter + if (sv.time < sv_player->v.teleport_time && fmove < 0) + fmove = 0; + + for (i=0 ; i<3 ; i++) + wishvel[i] = forward[i]*fmove + right[i]*smove; + + if ( (int)sv_player->v.movetype != MOVETYPE_WALK) + wishvel[2] = cmd.upmove; + else + wishvel[2] = 0; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + if (wishspeed > sv_maxspeed.value) + { + VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); + wishspeed = sv_maxspeed.value; + } + + if ( sv_player->v.movetype == MOVETYPE_NOCLIP) + { // noclip + VectorCopy (wishvel, velocity); + } + else if ( onground ) + { + SV_UserFriction (); + SV_Accelerate (); + } + else + { // not on ground, so little effect on velocity + SV_AirAccelerate (wishvel); + } +} + +/* +=================== +SV_ClientThink + +the move fields specify an intended velocity in pix/sec +the angle fields specify an exact angular motion in degrees +=================== +*/ +void SV_ClientThink (void) +{ + vec3_t v_angle; + + if (sv_player->v.movetype == MOVETYPE_NONE) + return; + + onground = (int)sv_player->v.flags & FL_ONGROUND; + + origin = sv_player->v.origin; + velocity = sv_player->v.velocity; + + DropPunchAngle (); + +// +// if dead, behave differently +// + if (sv_player->v.health <= 0) + return; + +// +// angles +// show 1/3 the pitch angle and all the roll angle + cmd = host_client->cmd; + angles = sv_player->v.angles; + + VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle); + angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4; + if (!sv_player->v.fixangle) + { + angles[PITCH] = -v_angle[PITCH]/3; + angles[YAW] = v_angle[YAW]; + } + + if ( (int)sv_player->v.flags & FL_WATERJUMP ) + { + SV_WaterJump (); + return; + } +// +// walk +// + //johnfitz -- alternate noclip + if (sv_player->v.movetype == MOVETYPE_NOCLIP && sv_altnoclip.value) + SV_NoclipMove (); + else if (sv_player->v.waterlevel >= 2 && sv_player->v.movetype != MOVETYPE_NOCLIP) + SV_WaterMove (); + else + SV_AirMove (); + //johnfitz +} + + +/* +=================== +SV_ReadClientMove +=================== +*/ +void SV_ReadClientMove (usercmd_t *move) +{ + int i; + vec3_t angle; + int bits; + +// read ping time + host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] + = sv.time - MSG_ReadFloat (); + host_client->num_pings++; + +// read current angles + for (i=0 ; i<3 ; i++) + //johnfitz -- 16-bit angles for PROTOCOL_FITZQUAKE + if (sv.protocol == PROTOCOL_NETQUAKE) + angle[i] = MSG_ReadAngle (); + else + angle[i] = MSG_ReadAngle16 (); + //johnfitz + + VectorCopy (angle, host_client->edict->v.v_angle); + +// read movement + move->forwardmove = MSG_ReadShort (); + move->sidemove = MSG_ReadShort (); + move->upmove = MSG_ReadShort (); + +// read buttons + bits = MSG_ReadByte (); + host_client->edict->v.button0 = bits & 1; + host_client->edict->v.button2 = (bits & 2)>>1; + + i = MSG_ReadByte (); + if (i) + host_client->edict->v.impulse = i; +} + +/* +=================== +SV_ReadClientMessage + +Returns false if the client should be killed +=================== +*/ +qboolean SV_ReadClientMessage (void) +{ + int ret; + int cmd; + char *s; + + do + { +nextmsg: + ret = NET_GetMessage (host_client->netconnection); + if (ret == -1) + { + Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); + return false; + } + if (!ret) + return true; + + MSG_BeginReading (); + + while (1) + { + if (!host_client->active) + return false; // a command caused an error + + if (msg_badread) + { + Sys_Printf ("SV_ReadClientMessage: badread\n"); + return false; + } + + cmd = MSG_ReadChar (); + + switch (cmd) + { + case -1: + goto nextmsg; // end of message + + default: + Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); + return false; + + case clc_nop: +// Sys_Printf ("clc_nop\n"); + break; + + case clc_stringcmd: + s = MSG_ReadString (); + if (host_client->privileged) + ret = 2; + else + ret = 0; + if (Q_strncasecmp(s, "status", 6) == 0) + ret = 1; + else if (Q_strncasecmp(s, "god", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "notarget", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "fly", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "name", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "noclip", 6) == 0) + ret = 1; + else if (Q_strncasecmp(s, "say", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "say_team", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "tell", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "color", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "kill", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "pause", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "spawn", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "begin", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "prespawn", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "kick", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "ping", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "give", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "ban", 3) == 0) + ret = 1; + if (ret == 2) + Cbuf_InsertText (s); + else if (ret == 1) + Cmd_ExecuteString (s, src_client); + else + Con_DPrintf("%s tried to %s\n", host_client->name, s); + break; + + case clc_disconnect: +// Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); + return false; + + case clc_move: + SV_ReadClientMove (&host_client->cmd); + break; + } + } + } while (ret == 1); + + return true; +} + + +/* +================== +SV_RunClients +================== +*/ +void SV_RunClients (void) +{ + int i; + + for (i=0, host_client = svs.clients ; iactive) + continue; + + sv_player = host_client->edict; + + if (!SV_ReadClientMessage ()) + { + SV_DropClient (false); // client misbehaved... + continue; + } + + if (!host_client->spawned) + { + // clear client movement until a new packet is received + memset (&host_client->cmd, 0, sizeof(host_client->cmd)); + continue; + } + +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_ClientThink (); + } +} + diff --git a/Quake/sys.h b/Quake/sys.h new file mode 100644 index 00000000..dbc566b1 --- /dev/null +++ b/Quake/sys.h @@ -0,0 +1,69 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sys.h -- non-portable functions + +// +// file IO +// + +// returns the file size +// return -1 if file is not present +// the file should be in BINARY mode for stupid OSs that care +int Sys_FileOpenRead (char *path, int *hndl); + +int Sys_FileOpenWrite (char *path); +void Sys_FileClose (int handle); +void Sys_FileSeek (int handle, int position); +int Sys_FileRead (int handle, void *dest, int count); +int Sys_FileWrite (int handle, void *data, int count); +int Sys_FileTime (char *path); +void Sys_mkdir (char *path); + +// +// memory protection +// +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length); + +// +// system IO +// +void Sys_DebugLog(char *file, char *fmt, ...); + +void Sys_Error (char *error, ...); +// an error will cause the entire program to exit + +void Sys_Printf (char *fmt, ...); +// send text to the console + +void Sys_Quit (void); + +double Sys_FloatTime (void); + +char *Sys_ConsoleInput (void); + +void Sys_Sleep (void); +// called to yield for a little bit so as +// not to hog cpu when paused or debugging + +void Sys_SendKeyEvents (void); +// Perform Key_Event () callbacks until the input que is empty + + diff --git a/Quake/sys_sdl.c b/Quake/sys_sdl.c new file mode 100644 index 00000000..3f4a3754 --- /dev/null +++ b/Quake/sys_sdl.c @@ -0,0 +1,282 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2005 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" +#include "errno.h" + +#define CONSOLE_ERROR_TIMEOUT 60.0 // # of seconds to wait on Sys_Error running +qboolean isDedicated; +static qboolean sc_return_on_enter = false; + +#define MAX_HANDLES 32 //johnfitz -- was 10 +FILE *sys_handles[MAX_HANDLES]; + +int findhandle (void) +{ + int i; + + for (i=1 ; i width if displayed in a window + unsigned width; + unsigned height; + float aspect; // width / height -- < 0 is taller than wide + int numpages; + int recalc_refdef; // if true, recalc vid-based stuff + pixel_t *conbuffer; + int conrowbytes; + unsigned conwidth; + unsigned conheight; + int maxwarpwidth; + int maxwarpheight; + pixel_t *direct; // direct drawing to framebuffer, if not + // NULL + int type; // kristian +} viddef_t; + +extern viddef_t vid; // global video state +//extern unsigned short d_8to16table[256]; //johnfitz -- never used +extern void (*vid_menudrawfn)(void); +extern void (*vid_menukeyfn)(int key); +extern void (*vid_menucmdfn)(void); //johnfitz + +//johnfitz -- deleted VID_SetPalette and VID_ShiftPalette + +void VID_Init (void); //johnfitz -- removed palette from argument list + +void VID_Shutdown (void); +// Called at shutdown + +void VID_Update (vrect_t *rects); +// flushes the given rectangles from the view buffer to the screen + +int VID_SetMode (int modenum); //johnfitz -- removed palette from argument list +// sets the mode; only used by the Quake engine for resetting to mode 0 (the +// base mode) on memory allocation failures diff --git a/Quake/view.c b/Quake/view.c new file mode 100644 index 00000000..13503566 --- /dev/null +++ b/Quake/view.c @@ -0,0 +1,920 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// view.c -- player eye positioning + +#include "quakedef.h" + +/* + +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. + +*/ + +cvar_t scr_ofsx = {"scr_ofsx","0", false}; +cvar_t scr_ofsy = {"scr_ofsy","0", false}; +cvar_t scr_ofsz = {"scr_ofsz","0", false}; + +cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; +cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; + +cvar_t cl_bob = {"cl_bob","0.02", false}; +cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false}; +cvar_t cl_bobup = {"cl_bobup","0.5", false}; + +cvar_t v_kicktime = {"v_kicktime", "0.5", false}; +cvar_t v_kickroll = {"v_kickroll", "0.6", false}; +cvar_t v_kickpitch = {"v_kickpitch", "0.6", false}; +cvar_t v_gunkick = {"v_gunkick", "1"}; //johnfitz + +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", false}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false}; + +cvar_t v_idlescale = {"v_idlescale", "0", false}; + +cvar_t crosshair = {"crosshair", "0", true}; + +cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false}; + +float v_dmg_time, v_dmg_roll, v_dmg_pitch; + +extern int in_forward, in_forward2, in_back; + +vec3_t v_punchangles[2]; //johnfitz -- copied from cl.punchangle. 0 is current, 1 is previous value. never the same unless map just loaded + +/* +=============== +V_CalcRoll + +Used by view and sv_user +=============== +*/ +vec3_t forward, right, up; + +float V_CalcRoll (vec3_t angles, vec3_t velocity) +{ + float sign; + float side; + float value; + + AngleVectors (angles, forward, right, up); + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs(side); + + value = cl_rollangle.value; +// if (cl.inwater) +// value *= 6; + + if (side < cl_rollspeed.value) + side = side * value / cl_rollspeed.value; + else + side = value; + + return side*sign; + +} + + +/* +=============== +V_CalcBob + +=============== +*/ +float V_CalcBob (void) +{ + float bob; + float cycle; + + cycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value; + cycle /= cl_bobcycle.value; + if (cycle < cl_bobup.value) + cycle = M_PI * cycle / cl_bobup.value; + else + cycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value); + +// bob is proportional to velocity in the xy plane +// (don't count Z, or jumping messes it up) + + bob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value; +//Con_Printf ("speed: %5.1f\n", Length(cl.velocity)); + bob = bob*0.3 + bob*0.7*sin(cycle); + if (bob > 4) + bob = 4; + else if (bob < -7) + bob = -7; + return bob; + +} + + +//============================================================================= + + +cvar_t v_centermove = {"v_centermove", "0.15", false}; +cvar_t v_centerspeed = {"v_centerspeed","500"}; + + +void V_StartPitchDrift (void) +{ +#if 1 + if (cl.laststop == cl.time) + { + return; // something else is keeping it from drifting + } +#endif + if (cl.nodrift || !cl.pitchvel) + { + cl.pitchvel = v_centerspeed.value; + cl.nodrift = false; + cl.driftmove = 0; + } +} + +void V_StopPitchDrift (void) +{ + cl.laststop = cl.time; + cl.nodrift = true; + cl.pitchvel = 0; +} + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards cl.idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. + +Drifting is enabled when the center view key is hit, mlook is released and +lookspring is non 0, or when +=============== +*/ +void V_DriftPitch (void) +{ + float delta, move; + + if (noclip_anglehack || !cl.onground || cls.demoplayback ) + //FIXME: noclip_anglehack is set on the server, so in a nonlocal game this won't work. + { + cl.driftmove = 0; + cl.pitchvel = 0; + return; + } + +// don't count small mouse motion + if (cl.nodrift) + { + if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value) + cl.driftmove = 0; + else + cl.driftmove += host_frametime; + + if ( cl.driftmove > v_centermove.value) + { + V_StartPitchDrift (); + } + return; + } + + delta = cl.idealpitch - cl.viewangles[PITCH]; + + if (!delta) + { + cl.pitchvel = 0; + return; + } + + move = host_frametime * cl.pitchvel; + cl.pitchvel += host_frametime * v_centerspeed.value; + +//Con_Printf ("move: %f (%f)\n", move, host_frametime); + + if (delta > 0) + { + if (move > delta) + { + cl.pitchvel = 0; + move = delta; + } + cl.viewangles[PITCH] += move; + } + else if (delta < 0) + { + if (move > -delta) + { + cl.pitchvel = 0; + move = -delta; + } + cl.viewangles[PITCH] -= move; + } +} + +/* +============================================================================== + + VIEW BLENDING + +============================================================================== +*/ + +cshift_t cshift_empty = { {130,80,50}, 0 }; +cshift_t cshift_water = { {130,80,50}, 128 }; +cshift_t cshift_slime = { {0,25,5}, 150 }; +cshift_t cshift_lava = { {255,80,0}, 150 }; + +float v_blend[4]; // rgba 0.0 - 1.0 + +//johnfitz -- deleted BuildGammaTable(), V_CheckGamma(), gammatable[], and ramps[][] + +/* +=============== +V_ParseDamage +=============== +*/ +void V_ParseDamage (void) +{ + int armor, blood; + vec3_t from; + int i; + vec3_t forward, right, up; + entity_t *ent; + float side; + float count; + + armor = MSG_ReadByte (); + blood = MSG_ReadByte (); + for (i=0 ; i<3 ; i++) + from[i] = MSG_ReadCoord (); + + count = blood*0.5 + armor*0.5; + if (count < 10) + count = 10; + + cl.faceanimtime = cl.time + 0.2; // but sbar face into pain frame + + cl.cshifts[CSHIFT_DAMAGE].percent += 3*count; + if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) + cl.cshifts[CSHIFT_DAMAGE].percent = 0; + if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) + cl.cshifts[CSHIFT_DAMAGE].percent = 150; + + if (armor > blood) + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; + } + else if (armor) + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; + } + else + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; + } + +// +// calculate view angle kicks +// + ent = &cl_entities[cl.viewentity]; + + VectorSubtract (from, ent->origin, from); + VectorNormalize (from); + + AngleVectors (ent->angles, forward, right, up); + + side = DotProduct (from, right); + v_dmg_roll = count*side*v_kickroll.value; + + side = DotProduct (from, forward); + v_dmg_pitch = count*side*v_kickpitch.value; + + v_dmg_time = v_kicktime.value; +} + + +/* +================== +V_cshift_f +================== +*/ +void V_cshift_f (void) +{ + cshift_empty.destcolor[0] = atoi(Cmd_Argv(1)); + cshift_empty.destcolor[1] = atoi(Cmd_Argv(2)); + cshift_empty.destcolor[2] = atoi(Cmd_Argv(3)); + cshift_empty.percent = atoi(Cmd_Argv(4)); +} + + +/* +================== +V_BonusFlash_f + +When you run over an item, the server sends this command +================== +*/ +void V_BonusFlash_f (void) +{ + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; + cl.cshifts[CSHIFT_BONUS].percent = 50; +} + +/* +============= +V_SetContentsColor + +Underwater, lava, etc each has a color shift +============= +*/ +void V_SetContentsColor (int contents) +{ + switch (contents) + { + case CONTENTS_EMPTY: + case CONTENTS_SOLID: + case CONTENTS_SKY: //johnfitz -- no blend in sky + cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; + break; + case CONTENTS_LAVA: + cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; + break; + case CONTENTS_SLIME: + cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; + break; + default: + cl.cshifts[CSHIFT_CONTENTS] = cshift_water; + } +} + +/* +============= +V_CalcPowerupCshift +============= +*/ +void V_CalcPowerupCshift (void) +{ + if (cl.items & IT_QUAD) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } + else if (cl.items & IT_SUIT) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 20; + } + else if (cl.items & IT_INVISIBILITY) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; + cl.cshifts[CSHIFT_POWERUP].percent = 100; + } + else if (cl.items & IT_INVULNERABILITY) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } + else + cl.cshifts[CSHIFT_POWERUP].percent = 0; +} + +/* +============= +V_CalcBlend +============= +*/ +void V_CalcBlend (void) +{ + float r, g, b, a, a2; + int j; + + r = 0; + g = 0; + b = 0; + a = 0; + + for (j=0 ; j 1) + v_blend[3] = 1; + if (v_blend[3] < 0) + v_blend[3] = 0; +} + +/* +============= +V_UpdateBlend -- johnfitz -- V_UpdatePalette cleaned up and renamed +============= +*/ +void V_UpdateBlend (void) +{ + int i, j; + qboolean blend_changed; + + V_CalcPowerupCshift (); + + blend_changed = false; + + for (i=0 ; i 180) + a -= 360; + return a; +} + +/* +================== +CalcGunAngle +================== +*/ +void CalcGunAngle (void) +{ + float yaw, pitch, move; + static float oldyaw = 0; + static float oldpitch = 0; + + yaw = r_refdef.viewangles[YAW]; + pitch = -r_refdef.viewangles[PITCH]; + + yaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4; + if (yaw > 10) + yaw = 10; + if (yaw < -10) + yaw = -10; + pitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4; + if (pitch > 10) + pitch = 10; + if (pitch < -10) + pitch = -10; + move = host_frametime*20; + if (yaw > oldyaw) + { + if (oldyaw + move < yaw) + yaw = oldyaw + move; + } + else + { + if (oldyaw - move > yaw) + yaw = oldyaw - move; + } + + if (pitch > oldpitch) + { + if (oldpitch + move < pitch) + pitch = oldpitch + move; + } + else + { + if (oldpitch - move > pitch) + pitch = oldpitch - move; + } + + oldyaw = yaw; + oldpitch = pitch; + + cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; + cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch); + + cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; + cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; + cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + +/* +============== +V_BoundOffsets +============== +*/ +void V_BoundOffsets (void) +{ + entity_t *ent; + + ent = &cl_entities[cl.viewentity]; + +// absolutely bound refresh reletive to entity clipping hull +// so the view can never be inside a solid wall + + if (r_refdef.vieworg[0] < ent->origin[0] - 14) + r_refdef.vieworg[0] = ent->origin[0] - 14; + else if (r_refdef.vieworg[0] > ent->origin[0] + 14) + r_refdef.vieworg[0] = ent->origin[0] + 14; + if (r_refdef.vieworg[1] < ent->origin[1] - 14) + r_refdef.vieworg[1] = ent->origin[1] - 14; + else if (r_refdef.vieworg[1] > ent->origin[1] + 14) + r_refdef.vieworg[1] = ent->origin[1] + 14; + if (r_refdef.vieworg[2] < ent->origin[2] - 22) + r_refdef.vieworg[2] = ent->origin[2] - 22; + else if (r_refdef.vieworg[2] > ent->origin[2] + 30) + r_refdef.vieworg[2] = ent->origin[2] + 30; +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle (void) +{ + r_refdef.viewangles[ROLL] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; + r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; + r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll (void) +{ + float side; + + side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity); + r_refdef.viewangles[ROLL] += side; + + if (v_dmg_time > 0) + { + r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; + r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch; + v_dmg_time -= host_frametime; + } + + if (cl.stats[STAT_HEALTH] <= 0) + { + r_refdef.viewangles[ROLL] = 80; // dead view angle + return; + } + +} + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef (void) +{ + entity_t *ent, *view; + float old; + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + VectorCopy (ent->origin, r_refdef.vieworg); + VectorCopy (ent->angles, r_refdef.viewangles); + view->model = NULL; + +// allways idle in intermission + old = v_idlescale.value; + v_idlescale.value = 1; + V_AddIdle (); + v_idlescale.value = old; +} + +/* +================== +V_CalcRefdef +================== +*/ +void V_CalcRefdef (void) +{ + entity_t *ent, *view; + int i; + vec3_t forward, right, up; + vec3_t angles; + float bob; + static float oldz = 0; + static vec3_t punch = {0,0,0}; //johnfitz -- v_gunkick + float delta; //johnfitz -- v_gunkick + + V_DriftPitch (); + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + +// transform the view offset by the model's matrix to get the offset from +// model origin for the view + ent->angles[YAW] = cl.viewangles[YAW]; // the model should face the view dir + ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face the view dir + + bob = V_CalcBob (); + +// refresh position + VectorCopy (ent->origin, r_refdef.vieworg); + r_refdef.vieworg[2] += cl.viewheight + bob; + +// never let it sit exactly on a node line, because a water plane can +// dissapear when viewed with the eye exactly on it. +// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + r_refdef.vieworg[0] += 1.0/32; + r_refdef.vieworg[1] += 1.0/32; + r_refdef.vieworg[2] += 1.0/32; + + VectorCopy (cl.viewangles, r_refdef.viewangles); + V_CalcViewRoll (); + V_AddIdle (); + +// offsets + angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are actually backward + angles[YAW] = ent->angles[YAW]; + angles[ROLL] = ent->angles[ROLL]; + + AngleVectors (angles, forward, right, up); + + if (cl.maxclients <= 1) //johnfitz -- moved cheat-protection here from V_RenderView + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] += scr_ofsx.value*forward[i] + scr_ofsy.value*right[i] + scr_ofsz.value*up[i]; + + V_BoundOffsets (); + +// set up gun position + VectorCopy (cl.viewangles, view->angles); + + CalcGunAngle (); + + VectorCopy (ent->origin, view->origin); + view->origin[2] += cl.viewheight; + + for (i=0 ; i<3 ; i++) + view->origin[i] += forward[i]*bob*0.4; + view->origin[2] += bob; + + //johnfitz -- removed all gun position fudging code (was used to keep gun from getting covered by sbar) + + view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->frame = cl.stats[STAT_WEAPONFRAME]; + view->colormap = vid.colormap; + +//johnfitz -- v_gunkick + if (v_gunkick.value == 1) //original quake kick + VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); + if (v_gunkick.value == 2) //lerped kick + { + for (i=0; i<3; i++) + if (punch[i] != v_punchangles[0][i]) + { + //speed determined by how far we need to lerp in 1/10th of a second + delta = (v_punchangles[0][i]-v_punchangles[1][i]) * host_frametime * 10; + + if (delta > 0) + punch[i] = min(punch[i]+delta, v_punchangles[0][i]); + else if (delta < 0) + punch[i] = max(punch[i]+delta, v_punchangles[0][i]); + } + + VectorAdd (r_refdef.viewangles, punch, r_refdef.viewangles); + } +//johnfitz + +// smooth out stair step ups + if (!noclip_anglehack && cl.onground && ent->origin[2] - oldz > 0) //johnfitz -- added exception for noclip + //FIXME: noclip_anglehack is set on the server, so in a nonlocal game this won't work. + { + float steptime; + + steptime = cl.time - cl.oldtime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 80; + if (oldz > ent->origin[2]) + oldz = ent->origin[2]; + if (ent->origin[2] - oldz > 12) + oldz = ent->origin[2] - 12; + r_refdef.vieworg[2] += oldz - ent->origin[2]; + view->origin[2] += oldz - ent->origin[2]; + } + else + oldz = ent->origin[2]; + + if (chase_active.value) + Chase_UpdateForDrawing (); //johnfitz +} + +/* +================== +V_RenderView + +The player's clipping box goes from (-16 -16 -24) to (16 16 32) from +the entity origin, so any view position inside that will be valid +================== +*/ +extern vrect_t scr_vrect; + +void V_RenderView (void) +{ + if (con_forcedup) + return; + + if (cl.intermission) + V_CalcIntermissionRefdef (); + else if (!cl.paused /* && (cl.maxclients > 1 || key_dest == key_game) */) + V_CalcRefdef (); + + //johnfitz -- removed lcd code + + R_RenderView (); + + V_PolyBlend (); //johnfitz -- moved here from R_Renderview (); +} + +/* +============================================================================== + + INIT + +============================================================================== +*/ + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + Cmd_AddCommand ("v_cshift", V_cshift_f); + Cmd_AddCommand ("bf", V_BonusFlash_f); + Cmd_AddCommand ("centerview", V_StartPitchDrift); + + Cvar_RegisterVariable (&v_centermove, NULL); + Cvar_RegisterVariable (&v_centerspeed, NULL); + + Cvar_RegisterVariable (&v_iyaw_cycle, NULL); + Cvar_RegisterVariable (&v_iroll_cycle, NULL); + Cvar_RegisterVariable (&v_ipitch_cycle, NULL); + Cvar_RegisterVariable (&v_iyaw_level, NULL); + Cvar_RegisterVariable (&v_iroll_level, NULL); + Cvar_RegisterVariable (&v_ipitch_level, NULL); + + Cvar_RegisterVariable (&v_idlescale, NULL); + Cvar_RegisterVariable (&crosshair, NULL); + Cvar_RegisterVariable (&gl_cshiftpercent, NULL); + + Cvar_RegisterVariable (&scr_ofsx, NULL); + Cvar_RegisterVariable (&scr_ofsy, NULL); + Cvar_RegisterVariable (&scr_ofsz, NULL); + Cvar_RegisterVariable (&cl_rollspeed, NULL); + Cvar_RegisterVariable (&cl_rollangle, NULL); + Cvar_RegisterVariable (&cl_bob, NULL); + Cvar_RegisterVariable (&cl_bobcycle, NULL); + Cvar_RegisterVariable (&cl_bobup, NULL); + + Cvar_RegisterVariable (&v_kicktime, NULL); + Cvar_RegisterVariable (&v_kickroll, NULL); + Cvar_RegisterVariable (&v_kickpitch, NULL); + Cvar_RegisterVariable (&v_gunkick, NULL); //johnfitz +} + + diff --git a/Quake/view.h b/Quake/view.h new file mode 100644 index 00000000..fae058b4 --- /dev/null +++ b/Quake/view.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// view.h + +extern cvar_t vid_gamma; + +extern float v_blend[4]; + +void V_Init (void); +void V_RenderView (void); +float V_CalcRoll (vec3_t angles, vec3_t velocity); +//void V_UpdatePalette (void); //johnfitz + diff --git a/Quake/wad.c b/Quake/wad.c new file mode 100644 index 00000000..7faeaf19 --- /dev/null +++ b/Quake/wad.c @@ -0,0 +1,168 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// wad.c + +#include "quakedef.h" + +int wad_numlumps; +lumpinfo_t *wad_lumps; +byte *wad_base = NULL; //johnfitz -- set to null + +void SwapPic (qpic_t *pic); + +/* +================== +W_CleanupName + +Lowercases name and pads with spaces and a terminating 0 to the length of +lumpinfo_t->name. +Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time +Space padding is so names can be printed nicely in tables. +Can safely be performed in place. +================== +*/ +void W_CleanupName (char *in, char *out) +{ + int i; + int c; + + for (i=0 ; i<16 ; i++ ) + { + c = in[i]; + if (!c) + break; + + if (c >= 'A' && c <= 'Z') + c += ('a' - 'A'); + out[i] = c; + } + + for ( ; i< 16 ; i++ ) + out[i] = 0; +} + +/* +==================== +W_LoadWadFile +==================== +*/ +void W_LoadWadFile (void) //johnfitz -- filename is now hard-coded for honesty +{ + lumpinfo_t *lump_p; + wadinfo_t *header; + unsigned i; + int infotableofs; + char *filename = WADFILENAME; + + //johnfitz -- modified to use malloc + //TODO: use cache_alloc + int h, len; + + Draw_BeginDisc (); + free (wad_base); + len = COM_OpenFile (filename, &h); + if (h == -1) + Sys_Error ("W_LoadWadFile: couldn't load %s", filename); + wad_base = (unsigned char *)malloc (len); + Sys_FileRead (h, wad_base, len); + COM_CloseFile (h); + //johnfitz + + header = (wadinfo_t *)wad_base; + + if (header->identification[0] != 'W' || header->identification[1] != 'A' + || header->identification[2] != 'D' || header->identification[3] != '2') + Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename); + + wad_numlumps = LittleLong(header->numlumps); + infotableofs = LittleLong(header->infotableofs); + wad_lumps = (lumpinfo_t *)(wad_base + infotableofs); + + for (i=0, lump_p = wad_lumps ; ifilepos = LittleLong(lump_p->filepos); + lump_p->size = LittleLong(lump_p->size); + W_CleanupName (lump_p->name, lump_p->name); + if (lump_p->type == TYP_QPIC) + SwapPic ( (qpic_t *)(wad_base + lump_p->filepos)); + } +} + + +/* +============= +W_GetLumpinfo +============= +*/ +lumpinfo_t *W_GetLumpinfo (char *name) +{ + int i; + lumpinfo_t *lump_p; + char clean[16]; + + W_CleanupName (name, clean); + + for (lump_p=wad_lumps, i=0 ; iname)) + return lump_p; + } + + Con_SafePrintf ("W_GetLumpinfo: %s not found\n", name); //johnfitz -- was Sys_Error + return NULL; +} + +void *W_GetLumpName (char *name) +{ + lumpinfo_t *lump; + + lump = W_GetLumpinfo (name); + + if (!lump) return NULL; //johnfitz + + return (void *)(wad_base + lump->filepos); +} + +void *W_GetLumpNum (int num) +{ + lumpinfo_t *lump; + + if (num < 0 || num > wad_numlumps) + Sys_Error ("W_GetLumpNum: bad number: %i", num); + + lump = wad_lumps + num; + + return (void *)(wad_base + lump->filepos); +} + +/* +============================================================================= + +automatic byte swapping + +============================================================================= +*/ + +void SwapPic (qpic_t *pic) +{ + pic->width = LittleLong(pic->width); + pic->height = LittleLong(pic->height); +} diff --git a/Quake/wad.h b/Quake/wad.h new file mode 100644 index 00000000..e94b0e88 --- /dev/null +++ b/Quake/wad.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// wad.h + +//=============== +// TYPES +//=============== + +#define CMP_NONE 0 +#define CMP_LZSS 1 + +#define TYP_NONE 0 +#define TYP_LABEL 1 + +#define TYP_LUMPY 64 // 64 + grab command number +#define TYP_PALETTE 64 +#define TYP_QTEX 65 +#define TYP_QPIC 66 +#define TYP_SOUND 67 +#define TYP_MIPTEX 68 + +#define WADFILENAME "gfx.wad" //johnfitz -- filename is now hard-coded for honesty + +typedef struct +{ + int width, height; + byte data[4]; // variably sized +} qpic_t; + +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +extern int wad_numlumps; +extern lumpinfo_t *wad_lumps; +extern byte *wad_base; + +void W_LoadWadFile (void); //johnfitz -- filename is now hard-coded for honesty +void W_CleanupName (char *in, char *out); +lumpinfo_t *W_GetLumpinfo (char *name); +void *W_GetLumpName (char *name); +void *W_GetLumpNum (int num); + +void SwapPic (qpic_t *pic); diff --git a/Quake/world.c b/Quake/world.c new file mode 100644 index 00000000..68ff4daf --- /dev/null +++ b/Quake/world.c @@ -0,0 +1,899 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others +Copyright (C) 2007-2008 Kristian Duske + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// world.c -- world query functions + +#include "quakedef.h" + +/* + +entities never clip against themselves, or their owner + +line of sight checks trace->crosscontent, but bullets don't + +*/ + + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; +} moveclip_t; + + +int SV_HullPointContents (hull_t *hull, int num, vec3_t p); + +/* +=============================================================================== + +HULL BOXES + +=============================================================================== +*/ + + +static hull_t box_hull; +static mclipnode_t box_clipnodes[6]; //johnfitz -- was dclipnode_t +static mplane_t box_planes[6]; + +/* +=================== +SV_InitBoxHull + +Set up the planes and clipnodes so that the six floats of a bounding box +can just be stored out and get a proper hull_t structure. +=================== +*/ +void SV_InitBoxHull (void) +{ + int i; + int side; + + box_hull.clipnodes = box_clipnodes; + box_hull.planes = box_planes; + box_hull.firstclipnode = 0; + box_hull.lastclipnode = 5; + + for (i=0 ; i<6 ; i++) + { + box_clipnodes[i].planenum = i; + + side = i&1; + + box_clipnodes[i].children[side] = CONTENTS_EMPTY; + if (i != 5) + box_clipnodes[i].children[side^1] = i + 1; + else + box_clipnodes[i].children[side^1] = CONTENTS_SOLID; + + box_planes[i].type = i>>1; + box_planes[i].normal[i>>1] = 1; + } + +} + + +/* +=================== +SV_HullForBox + +To keep everything totally uniform, bounding boxes are turned into small +BSP trees instead of being compared directly. +=================== +*/ +hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs) +{ + box_planes[0].dist = maxs[0]; + box_planes[1].dist = mins[0]; + box_planes[2].dist = maxs[1]; + box_planes[3].dist = mins[1]; + box_planes[4].dist = maxs[2]; + box_planes[5].dist = mins[2]; + + return &box_hull; +} + + + +/* +================ +SV_HullForEntity + +Returns a hull that can be used for testing or clipping an object of mins/maxs +size. +Offset is filled in to contain the adjustment that must be added to the +testing object's origin to get a point to use with the returned hull. +================ +*/ +hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) +{ + model_t *model; + vec3_t size; + vec3_t hullmins, hullmaxs; + hull_t *hull; + +// decide which clipping hull to use, based on the size + if (ent->v.solid == SOLID_BSP) + { // explicit hulls in the BSP model + if (ent->v.movetype != MOVETYPE_PUSH) + Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); + + model = sv.models[ (int)ent->v.modelindex ]; + + if (!model || model->type != mod_brush) + Sys_Error ("MOVETYPE_PUSH with a non bsp model"); + + VectorSubtract (maxs, mins, size); + if (size[0] < 3) + hull = &model->hulls[0]; + else if (size[0] <= 32) + hull = &model->hulls[1]; + else + hull = &model->hulls[2]; + +// calculate an offset value to center the origin + VectorSubtract (hull->clip_mins, mins, offset); + VectorAdd (offset, ent->v.origin, offset); + } + else + { // create a temp hull from bounding box sizes + + VectorSubtract (ent->v.mins, maxs, hullmins); + VectorSubtract (ent->v.maxs, mins, hullmaxs); + hull = SV_HullForBox (hullmins, hullmaxs); + + VectorCopy (ent->v.origin, offset); + } + + + return hull; +} + +/* +=============================================================================== + +ENTITY AREA CHECKING + +=============================================================================== +*/ + +typedef struct areanode_s +{ + int axis; // -1 = leaf node + float dist; + struct areanode_s *children[2]; + link_t trigger_edicts; + link_t solid_edicts; +} areanode_t; + +#define AREA_DEPTH 4 +#define AREA_NODES 32 + +static areanode_t sv_areanodes[AREA_NODES]; +static int sv_numareanodes; + +/* +=============== +SV_CreateAreaNode + +=============== +*/ +areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) +{ + areanode_t *anode; + vec3_t size; + vec3_t mins1, maxs1, mins2, maxs2; + + anode = &sv_areanodes[sv_numareanodes]; + sv_numareanodes++; + + ClearLink (&anode->trigger_edicts); + ClearLink (&anode->solid_edicts); + + if (depth == AREA_DEPTH) + { + anode->axis = -1; + anode->children[0] = anode->children[1] = NULL; + return anode; + } + + VectorSubtract (maxs, mins, size); + if (size[0] > size[1]) + anode->axis = 0; + else + anode->axis = 1; + + anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); + VectorCopy (mins, mins1); + VectorCopy (mins, mins2); + VectorCopy (maxs, maxs1); + VectorCopy (maxs, maxs2); + + maxs1[anode->axis] = mins2[anode->axis] = anode->dist; + + anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2); + anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); + + return anode; +} + +/* +=============== +SV_ClearWorld + +=============== +*/ +void SV_ClearWorld (void) +{ + SV_InitBoxHull (); + + memset (sv_areanodes, 0, sizeof(sv_areanodes)); + sv_numareanodes = 0; + SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs); +} + + +/* +=============== +SV_UnlinkEdict + +=============== +*/ +void SV_UnlinkEdict (edict_t *ent) +{ + if (!ent->area.prev) + return; // not linked in anywhere + RemoveLink (&ent->area); + ent->area.prev = ent->area.next = NULL; +} + + +/* +==================== +SV_TouchLinks +==================== +*/ +void SV_TouchLinks ( edict_t *ent, areanode_t *node ) +{ + link_t *l, *next; + edict_t *touch; + int old_self, old_other; + +// touch linked edicts + for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next) + { + //johnfitz -- fixes a crash when a touch function deletes an entity which comes later in the list + if (!l) + { + Con_Printf ("SV_TouchLinks: null link\n"); + break; + } + //johnfitz + + next = l->next; + touch = EDICT_FROM_AREA(l); + if (touch == ent) + continue; + if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) + continue; + if (ent->v.absmin[0] > touch->v.absmax[0] + || ent->v.absmin[1] > touch->v.absmax[1] + || ent->v.absmin[2] > touch->v.absmax[2] + || ent->v.absmax[0] < touch->v.absmin[0] + || ent->v.absmax[1] < touch->v.absmin[1] + || ent->v.absmax[2] < touch->v.absmin[2] ) + continue; + old_self = pr_global_struct->self; + old_other = pr_global_struct->other; + + pr_global_struct->self = EDICT_TO_PROG(touch); + pr_global_struct->other = EDICT_TO_PROG(ent); + pr_global_struct->time = sv.time; + PR_ExecuteProgram (touch->v.touch); + + //johnfitz -- the PR_ExecuteProgram above can alter the linked edicts -- fix from tyrquake + if (next != l->next && l->next) + { + Con_Printf ("SV_TouchLinks: next != l->next\n"); + next = l->next; + } + //johnfitz + + pr_global_struct->self = old_self; + pr_global_struct->other = old_other; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( ent->v.absmax[node->axis] > node->dist ) + SV_TouchLinks ( ent, node->children[0] ); + if ( ent->v.absmin[node->axis] < node->dist ) + SV_TouchLinks ( ent, node->children[1] ); +} + + +/* +=============== +SV_FindTouchedLeafs + +=============== +*/ +void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) +{ + mplane_t *splitplane; + mleaf_t *leaf; + int sides; + int leafnum; + + if (node->contents == CONTENTS_SOLID) + return; + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (ent->num_leafs == MAX_ENT_LEAFS) + return; + + leaf = (mleaf_t *)node; + leafnum = leaf - sv.worldmodel->leafs - 1; + + ent->leafnums[ent->num_leafs] = leafnum; + ent->num_leafs++; + return; + } + +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); + +// recurse down the contacted sides + if (sides & 1) + SV_FindTouchedLeafs (ent, node->children[0]); + + if (sides & 2) + SV_FindTouchedLeafs (ent, node->children[1]); +} + +/* +=============== +SV_LinkEdict + +=============== +*/ +void SV_LinkEdict (edict_t *ent, qboolean touch_triggers) +{ + areanode_t *node; + // model_t *mod = NULL; //johnfitz unused -- kristian + + if (ent->area.prev) + SV_UnlinkEdict (ent); // unlink from old position + + if (ent == sv.edicts) + return; // don't add the world + + if (ent->free) + return; + +// set the abs box + VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin); + VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); + +// +// to make items easier to pick up and allow them to be grabbed off +// of shelves, the abs sizes are expanded +// + if ((int)ent->v.flags & FL_ITEM) + { + ent->v.absmin[0] -= 15; + ent->v.absmin[1] -= 15; + ent->v.absmax[0] += 15; + ent->v.absmax[1] += 15; + } + else + { // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + ent->v.absmin[0] -= 1; + ent->v.absmin[1] -= 1; + ent->v.absmin[2] -= 1; + ent->v.absmax[0] += 1; + ent->v.absmax[1] += 1; + ent->v.absmax[2] += 1; + } + +// link to PVS leafs + ent->num_leafs = 0; + if (ent->v.modelindex) + SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + + if (ent->v.solid == SOLID_NOT) + return; + +// find the first node that the ent's box crosses + node = sv_areanodes; + while (1) + { + if (node->axis == -1) + break; + if (ent->v.absmin[node->axis] > node->dist) + node = node->children[0]; + else if (ent->v.absmax[node->axis] < node->dist) + node = node->children[1]; + else + break; // crosses the node + } + +// link it in + + if (ent->v.solid == SOLID_TRIGGER) + InsertLinkBefore (&ent->area, &node->trigger_edicts); + else + InsertLinkBefore (&ent->area, &node->solid_edicts); + +// if touch_triggers, touch all entities at this node and decend for more + if (touch_triggers) + SV_TouchLinks ( ent, sv_areanodes ); +} + + + +/* +=============================================================================== + +POINT TESTING IN HULLS + +=============================================================================== +*/ + +/* +================== +SV_HullPointContents + +================== +*/ +int SV_HullPointContents (hull_t *hull, int num, vec3_t p) +{ + float d; + mclipnode_t *node; //johnfitz -- was dclipnode_t + mplane_t *plane; + + while (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_HullPointContents: bad node number"); + + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + d = p[plane->type] - plane->dist; + else + d = DotProduct (plane->normal, p) - plane->dist; + if (d < 0) + num = node->children[1]; + else + num = node->children[0]; + } + + return num; +} + + +/* +================== +SV_PointContents + +================== +*/ +int SV_PointContents (vec3_t p) +{ + int cont; + + cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + cont = CONTENTS_WATER; + return cont; +} + +int SV_TruePointContents (vec3_t p) +{ + return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); +} + +//=========================================================================== + +/* +============ +SV_TestEntityPosition + +This could be a lot more efficient... +============ +*/ +edict_t *SV_TestEntityPosition (edict_t *ent) +{ + trace_t trace; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent); + + if (trace.startsolid) + return sv.edicts; + + return NULL; +} + + +/* +=============================================================================== + +LINE TESTING IN HULLS + +=============================================================================== +*/ + +// 1/32 epsilon to keep floating point happy +#define DIST_EPSILON (0.03125) + +/* +================== +SV_RecursiveHullCheck + +================== +*/ +qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) +{ + mclipnode_t *node; //johnfitz -- was dclipnode_t + mplane_t *plane; + float t1, t2; + float frac; + int i; + vec3_t mid; + int side; + float midf; + +// check for empty + if (num < 0) + { + if (num != CONTENTS_SOLID) + { + trace->allsolid = false; + if (num == CONTENTS_EMPTY) + trace->inopen = true; + else + trace->inwater = true; + } + else + trace->startsolid = true; + return true; // empty + } + + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_RecursiveHullCheck: bad node number"); + +// +// find the point distances +// + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, p1) - plane->dist; + t2 = DotProduct (plane->normal, p2) - plane->dist; + } + +#if 1 + if (t1 >= 0 && t2 >= 0) + return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); + if (t1 < 0 && t2 < 0) + return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); +#else + if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) + return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); + if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) + return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); +#endif + +// put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < 0) + frac = (t1 + DIST_EPSILON)/(t1-t2); + else + frac = (t1 - DIST_EPSILON)/(t1-t2); + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f)*frac; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac*(p2[i] - p1[i]); + + side = (t1 < 0); + +// move up to the node + if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) + return false; + +#ifdef PARANOID + if (SV_HullPointContents (sv_hullmodel, mid, node->children[side]) + == CONTENTS_SOLID) + { + Con_Printf ("mid PointInHullSolid\n"); + return false; + } +#endif + + if (SV_HullPointContents (hull, node->children[side^1], mid) + != CONTENTS_SOLID) +// go past the node + return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); + + if (trace->allsolid) + return false; // never got out of the solid area + +//================== +// the other side of the node is solid, this is the impact point +//================== + if (!side) + { + VectorCopy (plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; + } + else + { + VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; + } + + while (SV_HullPointContents (hull, hull->firstclipnode, mid) + == CONTENTS_SOLID) + { // shouldn't really happen, but does occasionally + frac -= 0.1; + if (frac < 0) + { + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + Con_DPrintf ("backup past 0\n"); + return false; + } + midf = p1f + (p2f - p1f)*frac; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac*(p2[i] - p1[i]); + } + + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + + return false; +} + + +/* +================== +SV_ClipMoveToEntity + +Handles selection or creation of a clipping hull, and offseting (and +eventually rotation) of the end points +================== +*/ +trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) +{ + trace_t trace; + vec3_t offset; + vec3_t start_l, end_l; + hull_t *hull; + +// fill in a default trace + memset (&trace, 0, sizeof(trace_t)); + trace.fraction = 1; + trace.allsolid = true; + VectorCopy (end, trace.endpos); + +// get the clipping hull + hull = SV_HullForEntity (ent, mins, maxs, offset); + + VectorSubtract (start, offset, start_l); + VectorSubtract (end, offset, end_l); + +// trace a line through the apropriate clipping hull + SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); + +// fix trace up by the offset + if (trace.fraction != 1) + VectorAdd (trace.endpos, offset, trace.endpos); + +// did we clip the move? + if (trace.fraction < 1 || trace.startsolid ) + trace.ent = ent; + + return trace; +} + +//=========================================================================== + +/* +==================== +SV_ClipToLinks + +Mins and maxs enclose the entire area swept by the move +==================== +*/ +void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip ) +{ + link_t *l, *next; + edict_t *touch; + trace_t trace; + +// touch linked edicts + for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) + { + next = l->next; + touch = EDICT_FROM_AREA(l); + if (touch->v.solid == SOLID_NOT) + continue; + if (touch == clip->passedict) + continue; + if (touch->v.solid == SOLID_TRIGGER) + Sys_Error ("Trigger in clipping list"); + + if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP) + continue; + + if (clip->boxmins[0] > touch->v.absmax[0] + || clip->boxmins[1] > touch->v.absmax[1] + || clip->boxmins[2] > touch->v.absmax[2] + || clip->boxmaxs[0] < touch->v.absmin[0] + || clip->boxmaxs[1] < touch->v.absmin[1] + || clip->boxmaxs[2] < touch->v.absmin[2] ) + continue; + + if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) + continue; // points never interact + + // might intersect, so do an exact clip + if (clip->trace.allsolid) + return; + if (clip->passedict) + { + if (PROG_TO_EDICT(touch->v.owner) == clip->passedict) + continue; // don't clip against own missiles + if (PROG_TO_EDICT(clip->passedict->v.owner) == touch) + continue; // don't clip against owner + } + + if ((int)touch->v.flags & FL_MONSTER) + trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end); + else + trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end); + if (trace.allsolid || trace.startsolid || + trace.fraction < clip->trace.fraction) + { + trace.ent = touch; + if (clip->trace.startsolid) + { + clip->trace = trace; + clip->trace.startsolid = true; + } + else + clip->trace = trace; + } + else if (trace.startsolid) + clip->trace.startsolid = true; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( clip->boxmaxs[node->axis] > node->dist ) + SV_ClipToLinks ( node->children[0], clip ); + if ( clip->boxmins[node->axis] < node->dist ) + SV_ClipToLinks ( node->children[1], clip ); +} + + +/* +================== +SV_MoveBounds +================== +*/ +void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) +{ +#if 0 +// debug to test against everything +boxmins[0] = boxmins[1] = boxmins[2] = -9999; +boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999; +#else + int i; + + for (i=0 ; i<3 ; i++) + { + if (end[i] > start[i]) + { + boxmins[i] = start[i] + mins[i] - 1; + boxmaxs[i] = end[i] + maxs[i] + 1; + } + else + { + boxmins[i] = end[i] + mins[i] - 1; + boxmaxs[i] = start[i] + maxs[i] + 1; + } + } +#endif +} + +/* +================== +SV_Move +================== +*/ +trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict) +{ + moveclip_t clip; + int i; + + memset ( &clip, 0, sizeof ( moveclip_t ) ); + +// clip to world + clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end ); + + clip.start = start; + clip.end = end; + clip.mins = mins; + clip.maxs = maxs; + clip.type = type; + clip.passedict = passedict; + + if (type == MOVE_MISSILE) + { + for (i=0 ; i<3 ; i++) + { + clip.mins2[i] = -15; + clip.maxs2[i] = 15; + } + } + else + { + VectorCopy (mins, clip.mins2); + VectorCopy (maxs, clip.maxs2); + } + +// create the bounding box of the entire move + SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); + +// clip to entities + SV_ClipToLinks ( sv_areanodes, &clip ); + + return clip.trace; +} + diff --git a/Quake/world.h b/Quake/world.h new file mode 100644 index 00000000..4354d901 --- /dev/null +++ b/Quake/world.h @@ -0,0 +1,79 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// world.h + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t *ent; // entity the surface is on +} trace_t; + + +#define MOVE_NORMAL 0 +#define MOVE_NOMONSTERS 1 +#define MOVE_MISSILE 2 + + +void SV_ClearWorld (void); +// called after the world model has been loaded, before linking any entities + +void SV_UnlinkEdict (edict_t *ent); +// call before removing an entity, and before trying to move one, +// so it doesn't clip against itself +// flags ent->v.modified + +void SV_LinkEdict (edict_t *ent, qboolean touch_triggers); +// Needs to be called any time an entity changes origin, mins, maxs, or solid +// flags ent->v.modified +// sets ent->v.absmin and ent->v.absmax +// if touchtriggers, calls prog functions for the intersected triggers + +int SV_PointContents (vec3_t p); +int SV_TruePointContents (vec3_t p); +// returns the CONTENTS_* value from the world at the given point. +// does not check any entities at all +// the non-true version remaps the water current contents to content_water + +edict_t *SV_TestEntityPosition (edict_t *ent); + +trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict); +// mins and maxs are reletive + +// if the entire move stays in a solid volume, trace.allsolid will be set + +// if the starting point is in a solid, it will be allowed to move out +// to an open area + +// nomonsters is used for line of sight or edge testing, where mosnters +// shouldn't be considered solid objects + +// passedict is explicitly excluded from clipping checks (normally NULL) diff --git a/Quake/zone.c b/Quake/zone.c new file mode 100644 index 00000000..5d04b5e3 --- /dev/null +++ b/Quake/zone.c @@ -0,0 +1,954 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// zone.c + +#include "quakedef.h" + +#define DYNAMIC_SIZE 256*1024 //johnfitz: was 48k + +#define ZONEID 0x1d4a11 +#define MINFRAGMENT 64 + +typedef struct memblock_s +{ + int size; // including the header and possibly tiny fragments + int tag; // a tag of 0 is a free block + int id; // should be ZONEID + struct memblock_s *next, *prev; + int pad; // pad to 64 bit boundary +} memblock_t; + +typedef struct +{ + int size; // total bytes malloced, including header + memblock_t blocklist; // start / end cap for linked list + memblock_t *rover; +} memzone_t; + +void Cache_FreeLow (int new_low_hunk); +void Cache_FreeHigh (int new_high_hunk); + + +/* +============================================================================== + + ZONE MEMORY ALLOCATION + +There is never any space between memblocks, and there will never be two +contiguous free memblocks. + +The rover can be left pointing at a non-empty block + +The zone calls are pretty much only used for small strings and structures, +all big things are allocated on the hunk. +============================================================================== +*/ + +memzone_t *mainzone; + +void Z_ClearZone (memzone_t *zone, int size); + + +/* +======================== +Z_ClearZone +======================== +*/ +void Z_ClearZone (memzone_t *zone, int size) +{ + memblock_t *block; + +// set the entire zone to one free block + + zone->blocklist.next = zone->blocklist.prev = block = + (memblock_t *)( (byte *)zone + sizeof(memzone_t) ); + zone->blocklist.tag = 1; // in use block + zone->blocklist.id = 0; + zone->blocklist.size = 0; + zone->rover = block; + + block->prev = block->next = &zone->blocklist; + block->tag = 0; // free block + block->id = ZONEID; + block->size = size - sizeof(memzone_t); +} + + +/* +======================== +Z_Free +======================== +*/ +void Z_Free (void *ptr) +{ + memblock_t *block, *other; + + if (!ptr) + Sys_Error ("Z_Free: NULL pointer"); + + block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); + if (block->id != ZONEID) + Sys_Error ("Z_Free: freed a pointer without ZONEID"); + if (block->tag == 0) + Sys_Error ("Z_Free: freed a freed pointer"); + + block->tag = 0; // mark as free + + other = block->prev; + if (!other->tag) + { // merge with previous free block + other->size += block->size; + other->next = block->next; + other->next->prev = other; + if (block == mainzone->rover) + mainzone->rover = other; + block = other; + } + + other = block->next; + if (!other->tag) + { // merge the next free block onto the end + block->size += other->size; + block->next = other->next; + block->next->prev = block; + if (other == mainzone->rover) + mainzone->rover = block; + } +} + + +/* +======================== +Z_Malloc +======================== +*/ +void *Z_Malloc (int size) +{ + void *buf; + +Z_CheckHeap (); // DEBUG + buf = Z_TagMalloc (size, 1); + if (!buf) + Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size); + Q_memset (buf, 0, size); + + return buf; +} + +void *Z_TagMalloc (int size, int tag) +{ + int extra; + memblock_t *start, *rover, *new, *base; + + if (!tag) + Sys_Error ("Z_TagMalloc: tried to use a 0 tag"); + +// +// scan through the block list looking for the first free block +// of sufficient size +// + size += sizeof(memblock_t); // account for size of block header + size += 4; // space for memory trash tester + size = (size + 7) & ~7; // align to 8-byte boundary + + base = rover = mainzone->rover; + start = base->prev; + + do + { + if (rover == start) // scaned all the way around the list + return NULL; + if (rover->tag) + base = rover = rover->next; + else + rover = rover->next; + } while (base->tag || base->size < size); + +// +// found a block big enough +// + extra = base->size - size; + if (extra > MINFRAGMENT) + { // there will be a free fragment after the allocated block + new = (memblock_t *) ((byte *)base + size ); + new->size = extra; + new->tag = 0; // free block + new->prev = base; + new->id = ZONEID; + new->next = base->next; + new->next->prev = new; + base->next = new; + base->size = size; + } + + base->tag = tag; // no longer a free block + + mainzone->rover = base->next; // next allocation will start looking here + + base->id = ZONEID; + +// marker for memory trash testing + *(int *)((byte *)base + base->size - 4) = ZONEID; + + return (void *) ((byte *)base + sizeof(memblock_t)); +} + + +/* +======================== +Z_Print +======================== +*/ +void Z_Print (memzone_t *zone) +{ + memblock_t *block; + + Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone); + + for (block = zone->blocklist.next ; ; block = block->next) + { + Con_Printf ("block:%p size:%7i tag:%3i\n", + block, block->size, block->tag); + + if (block->next == &zone->blocklist) + break; // all blocks have been hit + if ( (byte *)block + block->size != (byte *)block->next) + Con_Printf ("ERROR: block size does not touch the next block\n"); + if ( block->next->prev != block) + Con_Printf ("ERROR: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Con_Printf ("ERROR: two consecutive free blocks\n"); + } +} + + +/* +======================== +Z_CheckHeap +======================== +*/ +void Z_CheckHeap (void) +{ + memblock_t *block; + + for (block = mainzone->blocklist.next ; ; block = block->next) + { + if (block->next == &mainzone->blocklist) + break; // all blocks have been hit + if ( (byte *)block + block->size != (byte *)block->next) + Sys_Error ("Z_CheckHeap: block size does not touch the next block\n"); + if ( block->next->prev != block) + Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Sys_Error ("Z_CheckHeap: two consecutive free blocks\n"); + } +} + +//============================================================================ + +#define HUNK_SENTINAL 0x1df001ed + +typedef struct +{ + int sentinal; + int size; // including sizeof(hunk_t), -1 = not allocated + char name[8]; +} hunk_t; + +byte *hunk_base; +int hunk_size; + +int hunk_low_used; +int hunk_high_used; + +qboolean hunk_tempactive; +int hunk_tempmark; + +void R_FreeTextures (void); + +/* +============== +Hunk_Check + +Run consistancy and sentinal trahing checks +============== +*/ +void Hunk_Check (void) +{ + hunk_t *h; + + for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; ) + { + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + h = (hunk_t *)((byte *)h+h->size); + } +} + +/* +============== +Hunk_Print + +If "all" is specified, every single allocation is printed. +Otherwise, allocations with the same name will be totaled up before printing. +============== +*/ +void Hunk_Print (qboolean all) +{ + hunk_t *h, *next, *endlow, *starthigh, *endhigh; + int count, sum; + int totalblocks; + char name[9]; + + name[8] = 0; + count = 0; + sum = 0; + totalblocks = 0; + + h = (hunk_t *)hunk_base; + endlow = (hunk_t *)(hunk_base + hunk_low_used); + starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + endhigh = (hunk_t *)(hunk_base + hunk_size); + + Con_Printf (" :%8i total hunk size\n", hunk_size); + Con_Printf ("-------------------------\n"); + + while (1) + { + // + // skip to the high hunk if done with low hunk + // + if ( h == endlow ) + { + Con_Printf ("-------------------------\n"); + Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); + Con_Printf ("-------------------------\n"); + h = starthigh; + } + + // + // if totally done, break + // + if ( h == endhigh ) + break; + + // + // run consistancy checks + // + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + + next = (hunk_t *)((byte *)h+h->size); + count++; + totalblocks++; + sum += h->size; + + // + // print the single block + // + memcpy (name, h->name, 8); + if (all) + Con_Printf ("%8p :%8i %8s\n",h, h->size, name); + + // + // print the total + // + if (next == endlow || next == endhigh || + strncmp (h->name, next->name, 8) ) + { + if (!all) + Con_Printf (" :%8i %8s (TOTAL)\n",sum, name); + count = 0; + sum = 0; + } + + h = next; + } + + Con_Printf ("-------------------------\n"); + Con_Printf ("%8i total blocks\n", totalblocks); + +} + +/* +=================== +Hunk_Print_f -- johnfitz -- console command to call hunk_print +=================== +*/ +void Hunk_Print_f (void) +{ + Hunk_Print (false); +} + +/* +=================== +Hunk_AllocName +=================== +*/ +void *Hunk_AllocName (int size, char *name) +{ + hunk_t *h; + +#ifdef PARANOID + Hunk_Check (); +#endif + + if (size < 0) + Sys_Error ("Hunk_Alloc: bad size: %i", size); + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + Sys_Error ("Hunk_Alloc: failed on %i bytes",size); + + h = (hunk_t *)(hunk_base + hunk_low_used); + hunk_low_used += size; + + Cache_FreeLow (hunk_low_used); + + memset (h, 0, size); + + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + +/* +=================== +Hunk_Alloc +=================== +*/ +void *Hunk_Alloc (int size) +{ + return Hunk_AllocName (size, "unknown"); +} + +int Hunk_LowMark (void) +{ + return hunk_low_used; +} + +void Hunk_FreeToLowMark (int mark) +{ + if (mark < 0 || mark > hunk_low_used) + Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark); + memset (hunk_base + mark, 0, hunk_low_used - mark); + hunk_low_used = mark; +} + +int Hunk_HighMark (void) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + + return hunk_high_used; +} + +void Hunk_FreeToHighMark (int mark) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + if (mark < 0 || mark > hunk_high_used) + Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark); + memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark); + hunk_high_used = mark; +} + + +/* +=================== +Hunk_HighAllocName +=================== +*/ +void *Hunk_HighAllocName (int size, char *name) +{ + hunk_t *h; + + if (size < 0) + Sys_Error ("Hunk_HighAllocName: bad size: %i", size); + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + +#ifdef PARANOID + Hunk_Check (); +#endif + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + { + Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size); + return NULL; + } + + hunk_high_used += size; + Cache_FreeHigh (hunk_high_used); + + h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + + memset (h, 0, size); + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + + +/* +================= +Hunk_TempAlloc + +Return space from the top of the hunk +================= +*/ +void *Hunk_TempAlloc (int size) +{ + void *buf; + + size = (size+15)&~15; + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + + hunk_tempmark = Hunk_HighMark (); + + buf = Hunk_HighAllocName (size, "temp"); + + hunk_tempactive = true; + + return buf; +} + +/* +=============================================================================== + +CACHE MEMORY + +=============================================================================== +*/ + +typedef struct cache_system_s +{ + int size; // including this header + cache_user_t *user; + char name[16]; + struct cache_system_s *prev, *next; + struct cache_system_s *lru_prev, *lru_next; // for LRU flushing +} cache_system_t; + +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); + +cache_system_t cache_head; + +/* +=========== +Cache_Move +=========== +*/ +void Cache_Move ( cache_system_t *c) +{ + cache_system_t *new; + +// we are clearing up space at the bottom, so only allocate it late + new = Cache_TryAlloc (c->size, true); + if (new) + { +// Con_Printf ("cache_move ok\n"); + + Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) ); + new->user = c->user; + Q_memcpy (new->name, c->name, sizeof(new->name)); + Cache_Free (c->user, false); //johnfitz -- added second argument + new->user->data = (void *)(new+1); + } + else + { +// Con_Printf ("cache_move failed\n"); + + Cache_Free (c->user, true); // tough luck... //johnfitz -- added second argument + } +} + +/* +============ +Cache_FreeLow + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeLow (int new_low_hunk) +{ + cache_system_t *c; + + while (1) + { + c = cache_head.next; + if (c == &cache_head) + return; // nothing in cache at all + if ((byte *)c >= hunk_base + new_low_hunk) + return; // there is space to grow the hunk + Cache_Move ( c ); // reclaim the space + } +} + +/* +============ +Cache_FreeHigh + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeHigh (int new_high_hunk) +{ + cache_system_t *c, *prev; + + prev = NULL; + while (1) + { + c = cache_head.prev; + if (c == &cache_head) + return; // nothing in cache at all + if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) + return; // there is space to grow the hunk + if (c == prev) + Cache_Free (c->user, true); // didn't move out of the way //johnfitz -- added second argument + else + { + Cache_Move (c); // try to move it + prev = c; + } + } +} + +void Cache_UnlinkLRU (cache_system_t *cs) +{ + if (!cs->lru_next || !cs->lru_prev) + Sys_Error ("Cache_UnlinkLRU: NULL link"); + + cs->lru_next->lru_prev = cs->lru_prev; + cs->lru_prev->lru_next = cs->lru_next; + + cs->lru_prev = cs->lru_next = NULL; +} + +void Cache_MakeLRU (cache_system_t *cs) +{ + if (cs->lru_next || cs->lru_prev) + Sys_Error ("Cache_MakeLRU: active link"); + + cache_head.lru_next->lru_prev = cs; + cs->lru_next = cache_head.lru_next; + cs->lru_prev = &cache_head; + cache_head.lru_next = cs; +} + +/* +============ +Cache_TryAlloc + +Looks for a free block of memory between the high and low hunk marks +Size should already include the header and padding +============ +*/ +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom) +{ + cache_system_t *cs, *new; + +// is the cache completely empty? + + if (!nobottom && cache_head.prev == &cache_head) + { + if (hunk_size - hunk_high_used - hunk_low_used < size) + Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size); + + new = (cache_system_t *) (hunk_base + hunk_low_used); + memset (new, 0, sizeof(*new)); + new->size = size; + + cache_head.prev = cache_head.next = new; + new->prev = new->next = &cache_head; + + Cache_MakeLRU (new); + return new; + } + +// search from the bottom up for space + + new = (cache_system_t *) (hunk_base + hunk_low_used); + cs = cache_head.next; + + do + { + if (!nobottom || cs != cache_head.next) + { + if ( (byte *)cs - (byte *)new >= size) + { // found space + memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = cs; + new->prev = cs->prev; + cs->prev->next = new; + cs->prev = new; + + Cache_MakeLRU (new); + + return new; + } + } + + // continue looking + new = (cache_system_t *)((byte *)cs + cs->size); + cs = cs->next; + + } while (cs != &cache_head); + +// try to allocate one at the very end + if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size) + { + memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = &cache_head; + new->prev = cache_head.prev; + cache_head.prev->next = new; + cache_head.prev = new; + + Cache_MakeLRU (new); + + return new; + } + + return NULL; // couldn't allocate +} + +/* +============ +Cache_Flush + +Throw everything out, so new data will be demand cached +============ +*/ +void Cache_Flush (void) +{ + while (cache_head.next != &cache_head) + Cache_Free ( cache_head.next->user, true); // reclaim the space //johnfitz -- added second argument +} + + +/* +============ +Cache_Print + +============ +*/ +void Cache_Print (void) +{ + cache_system_t *cd; + + for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) + { + Con_Printf ("%8i : %s\n", cd->size, cd->name); + } +} + +/* +============ +Cache_Report + +============ +*/ +void Cache_Report (void) +{ + Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) ); +} + +/* +============ +Cache_Compact + +============ +*/ +void Cache_Compact (void) +{ +} + +/* +============ +Cache_Init + +============ +*/ +void Cache_Init (void) +{ + cache_head.next = cache_head.prev = &cache_head; + cache_head.lru_next = cache_head.lru_prev = &cache_head; + + Cmd_AddCommand ("flush", Cache_Flush); +} + +/* +============== +Cache_Free + +Frees the memory and removes it from the LRU list +============== +*/ +void Cache_Free (cache_user_t *c, qboolean freetextures) //johnfitz -- added second argument +{ + cache_system_t *cs; + + if (!c->data) + Sys_Error ("Cache_Free: not allocated"); + + cs = ((cache_system_t *)c->data) - 1; + + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + cs->next = cs->prev = NULL; + + c->data = NULL; + + Cache_UnlinkLRU (cs); + + //johnfitz -- if a model becomes uncached, free the gltextures. This only works + //becuase the cache_user_t is the last component of the model_t struct. Should + //fail harmlessly if *c is actually part of an sfx_t struct. I FEEL DIRTY + if (freetextures) + TexMgr_FreeTexturesForOwner ((model_t *)(c + 1) - 1); +} + + + +/* +============== +Cache_Check +============== +*/ +void *Cache_Check (cache_user_t *c) +{ + cache_system_t *cs; + + if (!c->data) + return NULL; + + cs = ((cache_system_t *)c->data) - 1; + +// move to head of LRU + Cache_UnlinkLRU (cs); + Cache_MakeLRU (cs); + + return c->data; +} + + +/* +============== +Cache_Alloc +============== +*/ +void *Cache_Alloc (cache_user_t *c, int size, char *name) +{ + cache_system_t *cs; + + if (c->data) + Sys_Error ("Cache_Alloc: allready allocated"); + + if (size <= 0) + Sys_Error ("Cache_Alloc: size %i", size); + + size = (size + sizeof(cache_system_t) + 15) & ~15; + +// find memory for it + while (1) + { + cs = Cache_TryAlloc (size, false); + if (cs) + { + strncpy (cs->name, name, sizeof(cs->name)-1); + c->data = (void *)(cs+1); + cs->user = c; + break; + } + + // free the least recently used cahedat + if (cache_head.lru_prev == &cache_head) + Sys_Error ("Cache_Alloc: out of memory"); // not enough memory at all + + Cache_Free (cache_head.lru_prev->user, true); //johnfitz -- added second argument + } + + return Cache_Check (c); +} + +//============================================================================ + + +/* +======================== +Memory_Init +======================== +*/ +void Memory_Init (void *buf, int size) +{ + int p; + int zonesize = DYNAMIC_SIZE; + + hunk_base = buf; + hunk_size = size; + hunk_low_used = 0; + hunk_high_used = 0; + + Cache_Init (); + p = COM_CheckParm ("-zone"); + if (p) + { + if (p < com_argc-1) + zonesize = Q_atoi (com_argv[p+1]) * 1024; + else + Sys_Error ("Memory_Init: you must specify a size in KB after -zone"); + } + mainzone = Hunk_AllocName (zonesize, "zone" ); + Z_ClearZone (mainzone, zonesize); + + Cmd_AddCommand ("hunk_print", Hunk_Print_f); //johnfitz +} + diff --git a/Quake/zone.h b/Quake/zone.h new file mode 100644 index 00000000..f7de6ff0 --- /dev/null +++ b/Quake/zone.h @@ -0,0 +1,132 @@ +/* +Copyright (C) 1996-2001 Id Software, Inc. +Copyright (C) 2002-2009 John Fitzgibbons and others + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* + memory allocation + + +H_??? The hunk manages the entire memory block given to quake. It must be +contiguous. Memory can be allocated from either the low or high end in a +stack fashion. The only way memory is released is by resetting one of the +pointers. + +Hunk allocations should be given a name, so the Hunk_Print () function +can display usage. + +Hunk allocations are guaranteed to be 16 byte aligned. + +The video buffers are allocated high to avoid leaving a hole underneath +server allocations when changing to a higher video mode. + + +Z_??? Zone memory functions used for small, dynamic allocations like text +strings from command input. There is only about 48K for it, allocated at +the very bottom of the hunk. + +Cache_??? Cache memory is for objects that can be dynamically loaded and +can usefully stay persistant between levels. The size of the cache +fluctuates from level to level. + +To allocate a cachable object + + +Temp_??? Temp memory is used for file loading and surface caching. The size +of the cache memory is adjusted so that there is a minimum of 512k remaining +for temp memory. + + +------ Top of Memory ------- + +high hunk allocations + +<--- high hunk reset point held by vid + +video buffer + +z buffer + +surface cache + +<--- high hunk used + +cachable memory + +<--- low hunk used + +client and server low hunk allocations + +<-- low hunk reset point held by host + +startup hunk allocations + +Zone block + +----- Bottom of Memory ----- + + + +*/ + +void Memory_Init (void *buf, int size); + +void Z_Free (void *ptr); +void *Z_Malloc (int size); // returns 0 filled memory +void *Z_TagMalloc (int size, int tag); + +void Z_DumpHeap (void); +void Z_CheckHeap (void); +int Z_FreeMemory (void); + +void *Hunk_Alloc (int size); // returns 0 filled memory +void *Hunk_AllocName (int size, char *name); + +void *Hunk_HighAllocName (int size, char *name); + +int Hunk_LowMark (void); +void Hunk_FreeToLowMark (int mark); + +int Hunk_HighMark (void); +void Hunk_FreeToHighMark (int mark); + +void *Hunk_TempAlloc (int size); + +void Hunk_Check (void); + +typedef struct cache_user_s +{ + void *data; +} cache_user_t; + +void Cache_Flush (void); + +void *Cache_Check (cache_user_t *c); +// returns the cached data, and moves to the head of the LRU list +// if present, otherwise returns NULL + +void Cache_Free (cache_user_t *c, qboolean freetextures); //johnfitz -- added second argument + +void *Cache_Alloc (cache_user_t *c, int size, char *name); +// Returns NULL if all purgable data was tossed and there still +// wasn't enough room. + +void Cache_Report (void); + + + diff --git a/Windows/Fitzquake.cbp b/Windows/Fitzquake.cbp new file mode 100644 index 00000000..b4bc6900 --- /dev/null +++ b/Windows/Fitzquake.cbp @@ -0,0 +1,292 @@ + + + + + + diff --git a/Windows/Fitzquake.depend b/Windows/Fitzquake.depend new file mode 100644 index 00000000..79ee99db --- /dev/null +++ b/Windows/Fitzquake.depend @@ -0,0 +1,1180 @@ +# depslib dependency file v1.0 +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cd_sdl.c + "quakedef.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\quakedef.h + + + + + + + "common.h" + "bspfile.h" + "vid.h" + "sys.h" + "zone.h" + "mathlib.h" + "platform.h" + "SDL/SDL.h" + "SDL/SDL_opengl.h" + "wad.h" + "draw.h" + "cvar.h" + "screen.h" + "net.h" + "protocol.h" + "cmd.h" + "sbar.h" + "sound.h" + "render.h" + "client.h" + "progs.h" + "server.h" + "gl_model.h" + "input.h" + "world.h" + "keys.h" + "console.h" + "view.h" + "menu.h" + "crc.h" + "cdaudio.h" + "glquake.h" + "image.h" + "gl_texmgr.h" + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\common.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\bspfile.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\vid.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sys.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\zone.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\mathlib.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\wad.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\draw.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cvar.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\screen.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\protocol.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cmd.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sbar.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sound.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\render.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\client.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progs.h + "pr_comp.h" + "progdefs.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_comp.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progdefs.h + "progdefs.q1" + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\progdefs.q1 + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\server.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_model.h + "modelgen.h" + "spritegn.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\modelgen.h + + + + + "cmdlib.h" + "scriplib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\spritegn.h + + + + + "cmdlib.h" + "scriplib.h" + "dictlib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\input.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\world.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\keys.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\console.h + +1204388359 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\view.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\menu.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\crc.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cdaudio.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\glquake.h + +1093037525 c:\programme\sdl\include\sdl_opengl.h + + + + + + + + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\image.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_texmgr.h + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\chase.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_demo.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_input.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_main.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_parse.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cl_tent.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cmd.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\common.c + "quakedef.h" + +1204384758 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\conproc.c + + "conproc.h" + "quakedef.h" + +1204384758 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\conproc.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\console.c + + + + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\crc.c + "quakedef.h" + "crc.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\cvar.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_draw.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_fog.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_mesh.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_model.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_refrag.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rlight.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rmain.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_rmisc.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_screen.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_sky.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_test.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_texmgr.c + "quakedef.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_opengl.h + "SDL_config.h" + + + + + + + + + + +1215262654 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\platform.h + +1199055973 c:\programme\sdl\include\sdl\sdl.h + "SDL_main.h" + "SDL_stdinc.h" + "SDL_audio.h" + "SDL_cdrom.h" + "SDL_cpuinfo.h" + "SDL_endian.h" + "SDL_error.h" + "SDL_events.h" + "SDL_loadso.h" + "SDL_mutex.h" + "SDL_rwops.h" + "SDL_thread.h" + "SDL_timer.h" + "SDL_video.h" + "SDL_version.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_main.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + "begin_code.h" + "close_code.h" + +1090382006 c:\programme\sdl\include\sdl\sdl_types.h + +1199055973 c:\programme\sdl\include\sdl\begin_code.h + +1199055973 c:\programme\sdl\include\sdl\close_code.h + +1018532113 c:\programme\sdl\include\sdl\sdl_getenv.h + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_error.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_rwops.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_timer.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_audio.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_endian.h" + "SDL_mutex.h" + "SDL_thread.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1100297357 c:\programme\sdl\include\sdl\sdl_byteorder.h + +1199055973 c:\programme\sdl\include\sdl\sdl_cdrom.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_joystick.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_events.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_active.h" + "SDL_keyboard.h" + "SDL_mouse.h" + "SDL_joystick.h" + "SDL_quit.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_active.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_keyboard.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_keysym.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_keysym.h + +1199055973 c:\programme\sdl\include\sdl\sdl_mouse.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_video.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_video.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_mutex.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_quit.h + "SDL_stdinc.h" + "SDL_error.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_version.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_stdinc.h + "SDL_config.h" + + + + + + + + + + + + + + + + + "begin_code.h" + + + + + + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_config.h + "SDL_platform.h" + + +1199055973 c:\programme\sdl\include\sdl\sdl_platform.h + +1199055973 c:\programme\sdl\include\sdl\sdl_endian.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_thread.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_mutex.h" + "begin_code.h" + + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_cpuinfo.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_loadso.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_vidsdl.c + "quakedef.h" + "resource.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\resource.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_warp.c + "quakedef.h" + "gl_warp_sin.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\gl_warp_sin.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\host.c + "quakedef.h" + +1212339700 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\host_cmd.c + + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\image.c + "quakedef.h" + +1205497698 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\in_sdl.c + "quakedef.h" + +1212339700 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\keys.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\main.c + + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\mathlib.c + + "quakedef.h" + +1212339701 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\menu.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_dgrm.c + + + + "quakedef.h" + "net_dgrm.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_dgrm.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_loop.c + "quakedef.h" + "net_loop.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_loop.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_main.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_sdl.c + "quakedef.h" + "net_loop.h" + "net_dgrm.h" + "net_sdlnet.h" + +1204384759 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_ser.h + +1204384758 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_wins.h + +1204384758 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_wipx.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_cmds.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_edict.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pr_exec.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_alias.c + "quakedef.h" + "anorms.h" + "anorm_dots.h" + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\anorms.h + +1204388358 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\anorm_dots.h + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_brush.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_part.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_sprite.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\r_world.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sbar.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_dma.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_mem.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_mix.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\snd_sdl.c + + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_main.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_move.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_phys.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sv_user.c + "quakedef.h" + +1215257376 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\sys_sdl.c + "quakedef.h" + "errno.h" + +1204384758 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\test.c + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\view.c + "quakedef.h" + +1204388359 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\wad.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\world.c + "quakedef.h" + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\zone.c + "quakedef.h" + +1200781489 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\windows\main.c + + "../Quake/quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cd_sdl.c + "quakedef.h" + +1200943109 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\quakedef.h + + + + + + + "common.h" + "bspfile.h" + "vid.h" + "sys.h" + "zone.h" + "mathlib.h" + "platform.h" + "SDL/SDL.h" + "SDL/SDL_opengl.h" + "wad.h" + "draw.h" + "cvar.h" + "screen.h" + "net.h" + "protocol.h" + "cmd.h" + "sbar.h" + "sound.h" + "render.h" + "client.h" + "progs.h" + "server.h" + "gl_model.h" + "input.h" + "world.h" + "keys.h" + "console.h" + "view.h" + "menu.h" + "crc.h" + "cdaudio.h" + "glquake.h" + "image.h" + "gl_texmgr.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\common.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\bspfile.h + +1201204952 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\vid.h + +1201118997 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sys.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\zone.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\mathlib.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\wad.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\draw.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cvar.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\screen.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\protocol.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cmd.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sbar.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sound.h + +1200827895 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\render.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\client.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\progs.h + "pr_comp.h" + "progdefs.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\pr_comp.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\progdefs.h + "progdefs.q1" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\progdefs.q1 + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\server.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_model.h + "modelgen.h" + "spritegn.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\modelgen.h + + + + + "cmdlib.h" + "scriplib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\spritegn.h + + + + + "cmdlib.h" + "scriplib.h" + "dictlib.h" + "trilib.h" + "lbmlib.h" + "mathlib.h" + +1201204952 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\input.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\world.h + +1201118997 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\keys.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\console.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\view.h + +1201204952 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\menu.h + +1200940564 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\crc.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cdaudio.h + +1201204952 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\glquake.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\image.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_texmgr.h + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\chase.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cl_demo.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cl_input.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cl_main.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cl_parse.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cl_tent.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cmd.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\common.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\conproc.c + + "conproc.h" + "quakedef.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\conproc.h + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\console.c + + + + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\crc.c + "quakedef.h" + "crc.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\cvar.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_draw.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_fog.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_mesh.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_model.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_refrag.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_rlight.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_rmain.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_rmisc.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_screen.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_sky.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_test.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_texmgr.c + "quakedef.h" + "imdebug-0.931b-bin/imdebug.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_warp.c + "quakedef.h" + "gl_warp_sin.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_warp_sin.h + +1200828862 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\host.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\host_cmd.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\image.c + "quakedef.h" + +1200829987 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\in_sdl.c + "quakedef.h" + +1201118997 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\keys.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\mathlib.c + + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\menu.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_dgrm.c + + + + "quakedef.h" + "net_dgrm.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_dgrm.h + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_loop.c + "quakedef.h" + "net_loop.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_loop.h + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_main.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_sdl.c + "quakedef.h" + "net_loop.h" + "net_dgrm.h" + "net_ser.h" + "net_wins.h" + "net_wipx.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_ser.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_wins.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\net_wipx.h + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\pr_cmds.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\pr_edict.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\pr_exec.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\r_alias.c + "quakedef.h" + "anorms.h" + "anorm_dots.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\anorms.h + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\anorm_dots.h + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\r_brush.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\r_part.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\r_sprite.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\r_world.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sbar.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\snd_dma.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\snd_mem.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\snd_mix.c + "quakedef.h" + +1200940564 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\snd_sdl.c + + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sv_main.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sv_move.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sv_phys.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sv_user.c + "quakedef.h" + +1200827895 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\sys_sdl.c + "quakedef.h" + + "errno.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\test.c + +1201118997 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\view.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\wad.c + "quakedef.h" + +1200827894 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\world.c + "quakedef.h" + +1200647148 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\zone.c + "quakedef.h" + +1200827898 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\windows\main.c + + "../Quake/quakedef.h" + +1200945244 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\gl_vidsdl.c + "quakedef.h" + "resource.h" + +1200647148 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\resource.h + +1200830311 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\main.c + + "quakedef.h" + +1201204952 c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\platform.h + +1200945266 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\quake\pl_win.c + "quakedef.h" + + "SDL/SDL_syswm.h" + +1200944787 source:c:\dokumente und einstellungen\kristian\desktop\fitzquake\windows\fitzquake.rc + +1204388358 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\pl_win.c + "quakedef.h" + + "SDL/SDL_syswm.h" + +1199055973 c:\programme\sdl\include\sdl\sdl_syswm.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_version.h" + "begin_code.h" + + + + + + + "close_code.h" + +1204388360 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\windows\fitzquake.rc + +1212339700 c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_sdlnet.h + +1215266189 source:c:\dokumente und einstellungen\kristian\eigene dateien\fitzquake\quake\net_sdlnet.c + "quakedef.h" + + + + "net_sdlnet.h" + +1184972882 c:\programme\sdl\include\sdl_net\sdl_net.h + "SDL.h" + "SDL_endian.h" + "SDL_version.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl.h + "SDL_main.h" + "SDL_stdinc.h" + "SDL_audio.h" + "SDL_cdrom.h" + "SDL_cpuinfo.h" + "SDL_endian.h" + "SDL_error.h" + "SDL_events.h" + "SDL_loadso.h" + "SDL_mutex.h" + "SDL_rwops.h" + "SDL_thread.h" + "SDL_timer.h" + "SDL_video.h" + "SDL_version.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_main.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_stdinc.h + "SDL_config.h" + + + + + + + + + + + + + + + + + "begin_code.h" + + + + + + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_config.h + "SDL_platform.h" + + +1199055973 c:\programme\sdl\include\sdl_net\sdl_platform.h + +1199055973 c:\programme\sdl\include\sdl_net\begin_code.h + +1199055973 c:\programme\sdl\include\sdl_net\close_code.h + +1199055973 c:\programme\sdl\include\sdl_net\sdl_audio.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_endian.h" + "SDL_mutex.h" + "SDL_thread.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_error.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_endian.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_mutex.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_thread.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_mutex.h" + "begin_code.h" + + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_rwops.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_cdrom.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_cpuinfo.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_events.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_active.h" + "SDL_keyboard.h" + "SDL_mouse.h" + "SDL_joystick.h" + "SDL_quit.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_active.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_keyboard.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_keysym.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_keysym.h + +1199055973 c:\programme\sdl\include\sdl_net\sdl_mouse.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_video.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_video.h + "SDL_stdinc.h" + "SDL_error.h" + "SDL_rwops.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_joystick.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_quit.h + "SDL_stdinc.h" + "SDL_error.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_loadso.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_timer.h + "SDL_stdinc.h" + "SDL_error.h" + "begin_code.h" + "close_code.h" + +1199055973 c:\programme\sdl\include\sdl_net\sdl_version.h + "SDL_stdinc.h" + "begin_code.h" + "close_code.h" + diff --git a/Windows/Fitzquake.layout b/Windows/Fitzquake.layout new file mode 100644 index 00000000..a1952df1 --- /dev/null +++ b/Windows/Fitzquake.layout @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Windows/Fitzquake.rc b/Windows/Fitzquake.rc new file mode 100644 index 00000000..b6c4c58b --- /dev/null +++ b/Windows/Fitzquake.rc @@ -0,0 +1 @@ +icon ICON "fitzquake.ico" diff --git a/Windows/Fitzquake.workspace b/Windows/Fitzquake.workspace new file mode 100644 index 00000000..5a4ed4a9 --- /dev/null +++ b/Windows/Fitzquake.workspace @@ -0,0 +1,6 @@ + + + + + + diff --git a/Windows/cb.bmp b/Windows/cb.bmp new file mode 100644 index 00000000..f912a9e6 Binary files /dev/null and b/Windows/cb.bmp differ diff --git a/Windows/dirent.c b/Windows/dirent.c new file mode 100644 index 00000000..08ea8007 --- /dev/null +++ b/Windows/dirent.c @@ -0,0 +1,145 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ + +#include +#include +#include /* _findfirst and _findnext set errno iff they return -1 */ +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct DIR +{ + long handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (long) _findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus +} +#endif + +/* + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ diff --git a/Windows/dirent.h b/Windows/dirent.h new file mode 100644 index 00000000..a02a0d82 --- /dev/null +++ b/Windows/dirent.h @@ -0,0 +1,50 @@ +#ifndef DIRENT_INCLUDED +#define DIRENT_INCLUDED + +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct DIR DIR; + +struct dirent +{ + char *d_name; +}; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +/* + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Windows/fitzquake.ico b/Windows/fitzquake.ico new file mode 100644 index 00000000..514d613c Binary files /dev/null and b/Windows/fitzquake.ico differ diff --git a/gnu.txt b/gnu.txt new file mode 100644 index 00000000..2f3289af --- /dev/null +++ b/gnu.txt @@ -0,0 +1,87 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +Preamble +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + +a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. + +c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + +END OF TERMS AND CONDITIONS